#rust-lang

/

      • ubsan
        ah, yes
      • the C standard is not perfect
      • it's... pretty crap, in fact
      • arielby
        I'm quite sure practical compiler use "accessed" to mean "read"
      • ubsan
        they also use it to mean write
      • otherwise, they couldn't optimize this:
      • void foo(int* x, short const* y) { *x = *y * 2; *x = *y * 2; *x = *y * 2; }
      • because you could be doing
      • short x = 1; foo((int*)&x, &x);
      • guess I should probably make the second type bigger...
      • arielby
        ubsan: that would be UB
      • SilverKey joined the channel
      • because the read at statement 2 would sync with the write at statement 1
      • ubsan
        arielby: why?
      • what
      • arielby
        after the first write, the stored type is int
      • and then the second read is UB
      • because short is not TBAA-compatible with int
      • ubsan
        okay, sure
      • your reading works
      • hmm...
      • I think you're right, actually
      • arielby
      • Zoxc joined the channel
      • ubsan: and memcpy
      • yeah, it has to be a primitive
      • because slices
      • ubsan
        arielby: with memcpy:
      • arielby
        and yeah, if we have memcpy as a primitive, unaligned_read is semi-redundant
      • except for guaranteeing no copies
      • but finding the best set of primitives is not something we want to get to
      • ubsan
        The effective type of an object for an access to its stored value is the declared type of the object, if any. If a value is stored into an object having no declared type through an lvalue having a type that is not a character type, then the type of the lvalue becomes the effective type of the object for that access and for subsequent accesses that do not modify the stored value. If a value is copied into an object
      • having no declared type using memcpy or memmove, or is copied as an array of character type, then the effective type of the modified object for that access and for subsequent accesses that do not modify the value is the effective type of the object from which the value is copied, if it has one. For all other accesses to an object having no declared type, the effective type of the object is simply the type of the lvalue used for the access.
      • arielby
        ubsan: memcpy does char writes
      • ubsandroid has quit
      • and char is TBAA-compatible with anything
      • ubsan
        yeah
      • just showing what effective type is
      • arielby
        " If a value is stored into an object having no declared type through an lvalue having a type that is not a character type, then the type of the lvalue becomes the effective type of the object for that access and for subsequent accesses that do not modify the stored value. "
      • ?
      • that sounds bad
      • ubsan
        yeah
      • TBAA is awful
      • arielby
        the "write-to-read" variant is OK
      • I mean, LLVM-style TBAA
      • and that's what compilers in practice use
      • ubsan
        'kay
      • I'll trust you there
      • I have to read about it
      • anyways, so, the point is
      • besides all the TBAA stuff
      • memcpy is, I would argue, a primitive
      • ptr::copy_nonoverlapping
      • brson joined the channel
      • and, secondly, transmute_copy might take DSTs for T
      • it would make it a heck of a lot more useful
      • but that's not really what interests me
      • nmatsakis: casts!
      • nmatsakis
        :)
      • yes!
      • Ericson2314 has quit
      • arielby
        ubsan: ok
      • so we'll write transmute_copy in terms of copy_nonoverlapping
      • ubsan
        yeah
      • nmatsakis: basically, right now, there are two options for casts which are both hella overloaded
      • as
      • and you know my stance on transmute :3
      • basically, I want to create a rust where there are four cast types: as, transmute, lifetime_cast, and ptr_cast
      • `as` will be for safe casts, like usize as u32, or fn() as u8
      • `transmute` will be for bitcasts, like struct X { u32 } -> u32
      • lifetime_cast will allow for both lifetime shortening *and* lengthening, of any lifetime included
      • (in the type)
      • SilverKey has quit
      • arielby
        ubsan: we basically got casts from C++
      • ubsan
        arielby: right, exactly
      • that's where the inspiration comes from
      • arielby
        because we couldn't be bothered to declare an intrinsic for everything
      • nmatsakis
        ubsan: I like the sound of this, certainly
      • ubsan
        ermm
      • arielby
        if it was up to me, float <-> int would be an intrinsic
      • not a cast
      • ubsan
        arielby: C++ has their shit together :P
      • they have all the casts
      • nmatsakis
        I am imagining that you are envisioning things like lifetime_cast<T>(U)
      • ubsan
        we got our casts from C :3
      • nmatsakis
        i.e., a keyword?
      • ubsan
        nmatsakis: well, originally
      • nmatsakis
        since you're citing C++ :)
      • ubsan
        but scott wants it to be an intrinsic
      • and I'm fine with that
      • nmatsakis
        (the other big factor in our cast story has been constant expressions; we've often tried to remove `as` but run up against that wall)
      • arielby
        ubsan: intrinsic-like-things should be intrinsics
      • ubsan
        arielby: yeah, makes sense
      • nmatsakis
        yeah, an intrinsic seems fine.
      • ubsan
        so, finally
      • ptr_cast
      • which is an unsafe cast
      • nmatsakis
        the only reason `as` is not, imo, is the const fn thing I was mentioning
      • that is, that we didn't have it at the time when we were talking about it, and weren't sure about adding it
      • I think moving casts -> intrinsics is definitely doubling down on const fn, which is a thing to think about, but I don't see that as esp. controversial these days
      • arielby
        nmatsakis: it is also oddly-typed
      • ubsan
        which turns any pointer into any other, and also turns a usize|isize into a pointer
      • which means no more transmute for void* -> fn()
      • that was a weird mix of C and rust
      • ubsan shrugs
      • nmatsakis: cool :)
      • arielby
        ubsan: pointer, not reference
      • ubsan
        arielby: pointer, including reference
      • arielby
        ptr -> ref casts != ref -> ptr casts
      • ubsan
        yes
      • but this does both
      • 'swhy it's unsafe
      • nmatsakis
        I remain ... pretty unpersuaded that it is worth distinguishing fn pointers from other pointers. Or, maybe, pretty unsure how to handle portability in cases like these.
      • but anyway the broad strokes of the idea seem good to me
      • ubsan
        nmatsakis: the issue is that you can't use `as` with fn()
      • so you end up using transmute
      • this has you not use transmute for that
      • nmatsakis
        and I think giving intentionality to the purpose of your cast (a la C++) has to be a win
      • ubsan
        yeah :)
      • nmatsakis
        ok maybe I misunderstood what you were saying re: fn
      • ubsan
        yeah, the point is to make them less specialized
      • and if an impl *can't* convert, well then, it wouldn't allow those conversions
      • arielby
        ubsan: I think that now
      • the C-enum+char+bool -> int casts
      • should be discriminant_value
      • ubsan
        arielby: I feel like that's too specialized
      • arielby
        ubsan: we already have discriminant_value
      • ubsan
        I would want something that goes int->int and C-enum+char+bool->int and u8|i8->char
      • playbot: -1i8 as char
      • NOTICE: error: only `u8` can be cast as `char`, not `i8`
      • NOTICE: --> <anon>:10:10
      • NOTICE: 10 |> -1i8 as char
      • NOTICE: (output truncated; full output at http://bit.ly/2awgFY9)
      • huh
      • okay, well, u8->char
      • arielby
        ubsan: so u8 -> char is the odd one out
      • ubsan
        oh, and flt->int and int->flt and flt->flt
      • of course
      • call it something like "prim_cast"
      • arielby
        ubsan: you create chars via transmute anyway
      • so I say just nix it
      • or have an unsafe version so you don't need to transmute or w/e
      • char::from_u32_unchecked
      • ubsan
        arielby: hmm?
      • like, nix the u8->char cast?
      • arielby
        yea
      • you can `char::from_u32_unchecked(c as u32)`
      • ubsan
        I'd want char::from_u8(c)