profile
viewpoint
scottmcm Pacific Northwest, USA This is a personal account. My actions and opinions are my own, and are not taken on behalf of my employer.

scottmcm/rev_slice 3

A simple alternative to negative indexing on rust slices

scottmcm/pawn-rs 1

An unchecked borrow-like operation for Cells.

scottmcm/rust 1

A safe, concurrent, practical language.

scottmcm/simd-trick 1

A crate to trick the optimizer into generating SIMD instructions.

scottmcm/compiler-builtins 0

Porting `compiler-rt` intrinsics to Rust

scottmcm/edition-guide 0

A guide to changes between various editions of Rust

scottmcm/jpeg-decoder 0

JPEG decoder written in Rust

scottmcm/lang-team 0

Home of the Rust language design team.

pull request commentrust-lang/rust

consider assignments of union field of ManuallyDrop type safe

This sounds good to me.

I agree that it can be safe (which is itself a weak should), and I don't think it's materially more likely to lead to accidental leaking than other things that have already been made safe. Notably, if you have union(u32, ManuallyDrop<String>), the safe assignment to the u32 is already a safe way to leak that String. And the assignment some_union.f = some_manually_drop; is just as leak-inducing as if it were some_local = some_manually_drop; -- the "lint" about leaking is the ManuallyDrop::new call.

And the fact that it's wrapped in ManuallyDrop means it can never need dropping, so there are no semver worries.

So while we haven't actually talked about this in a meeting yet, let's see what happens with @rfcbot merge (I see at least one other lang thumb right now.)

RalfJung

comment created time in 3 hours

Pull request review commentrust-lang/rust

consider assignments of union field of ManuallyDrop type safe

 union U4<T: Copy> {     a: T } +union URef {+    p: &'static mut i32,+}++union URefCell { // field that does not drop but is not `Copy`, either+    a: (RefCell<i32>, i32),+}++fn deref_union_field(mut u: URef) {+    // Not an assignment but an access to the union field!+    *(u.p) = 13; //~ ERROR access to union field is unsafe+}++fn assign_noncopy_union_field(mut u: URefCell) {+    u.a = (RefCell::new(0), 1); //~ ERROR assignment to union field that needs dropping

nit: You mention on line 25 that the field doesn't actually need dropping, so I wonder if there's a way to rephrase this to avoid a potential "no it doesn't" reaction from someone reading it. The best that comes to mind is "... that is neither Copy nor ManuallyDrop<_>", but that's not great either.

RalfJung

comment created time in 3 hours

PullRequestReviewEvent

issue commentrust-lang/rust

Tracking issue for `X..`, `..X`, and `..=X` (`#![feature(half_open_range_patterns)]`)

(Posting separately to wear a slightly-different hat.)

One possible answer to potential confusion might be to somehow (clippy?) encourage using 0..N in patterns even for unsigned types when that would be equivalent to ..N. That's easy to type and still polymorphic (unlike uWhatever::MIN..N) and might set the convention that would thus emphasize that ..N isn't starting from zero.

Centril

comment created time in 3 hours

issue commentrust-lang/rust

Tracking issue for `X..`, `..X`, and `..=X` (`#![feature(half_open_range_patterns)]`)

We discussed this in the lang team meeting today.

There was some disagreement on the right thing to do with the range-to patterns that are open on the left. This was particularly around the most common experience with ..N being in slicing, where the minimum of the type is zero, and thus the potential surprise when in a pattern ..N ends up being -128..N and not 0..N. (Despite the meaning of the left being Unbounded being consistent in other, albeit less common, APIs like RangeBounds::contains and BTreeMap::range.)

However, everyone was in favour of X.., and it was felt that it was fine to move forward with that without blocking on the others. As such, it would be great if someone were to make a stabilization PR for that subset, which we could then fcp.

@rustbot modify labels: +E-help-wanted +E-medium

Centril

comment created time in 4 hours

push eventscottmcm/rust

flip1995

commit sha 7ea42be0362073d1a36b7bf4140bb0e9df15c491

Update Cargo.lock

view details

Mateusz Mikuła

commit sha 0c97c24a6c681d0c84d4b0730fec1a6b80415c48

Remove some dead code in windows-gnu std

view details

Mateusz Mikuła

commit sha 8818fda7f0ba5ed9e83f89d760647c3203c00e8e

Remove useless `all` in cfg

view details

flip1995

commit sha 7f846c930b9d35061e6eb6b8dbfbc890d38d539c

Update backport documentation to the subtree workflow

view details

bors

commit sha cad10fa3b35a3b09c686579a8ef9f8e55d6cea20

Auto merge of #6146 - woshilapin:patch-1, r=flip1995 clippy_lint: Fix doc on 'option_if_let_else' changelog: none

view details

bors

commit sha 53a4c3b0baed8fb224e19380c576c86c12c38d8c

Auto merge of #77690 - est31:llvm_8_required, r=matthewjasper Simplify some code in rustc_llvm/build.rs now that LLVM 8 is required LLVM 8 is required since 8506bb006040cf8e8cb004202706c81e62ddacee so this is safe to do.

view details

bors

commit sha e87c028a2ac93e95d807c1c44da5cbbf383502dd

Auto merge of #6131 - Ambroisie:fix-doc-tools, r=flip1995 Rename tables to typecheck_result() While working on #6130, I noticed that part of the documentation was updated to use `LateContext::typeck_results`, but the paragraph still referred to the old `tables` field of `LateContext`. --- *Please keep the line below* changelog: none

view details

bors

commit sha ed2b457fbeeccf3dab9f1dfb998f2a4db0badb4d

Auto merge of #6148 - flip1995:release_doc, r=ebroto Update release documentation When updating the beta branch, we want to reset, instead of rebase. Otherwise we might produce again new commits on the beta branch, that aren't on the master branch. changelog: none

view details

Pietro Albini

commit sha 8d2b15943b0dad58959f5fcac1664bfdd7c201b7

bootstrap: always use the Rust version in package names The format of the tarballs produced by CI is roughly the following: {component}-{release}-{target}.{ext} While on the beta and nightly channels `{release}` is just the channel name, on the stable channel is either the Rust version or the version of the component we're shipping: cargo-0.47.0-x86_64-unknown-linux-gnu.tar.xz clippy-0.0.212-x86_64-unknown-linux-gnu.tar.xz llvm-tools-1.46.0-x86_64-unknown-linux-gnu.tar.xz miri-0.1.0-x86_64-unknown-linux-gnu.tar.xz rls-1.41.0-x86_64-unknown-linux-gnu.tar.xz rust-1.46.0-x86_64-unknown-linux-gnu.tar.xz ... This makes it really hard to get the package URL without having access to the manifest (and there is no manifest on ci-artifacts.rlo), as there is no consistent version number to use. This commit addresses the problem by always using the Rust version number as `{release}` for the stable channel, regardless of the version number of the component we're shipping. I chose that instead of "stable" to avoid breaking the URL scheme *that* much. Rustup should not be affected by this change, as it fetches the URLs from the manifest. Unfortunately we don't have a way to test other clients before making a stable release, as this change only affects the stable channel.

view details

bors

commit sha 36e3c41368c9c4f2005c599a48e0d2a82983b943

Auto merge of #6149 - flip1995:update_actions, r=ebroto Remove deprecated set-env from GHA This updates all of our action dependencies and removes every usage of `set-env`. `set-env` and `add-path` has been deprecated: https://github.blog/changelog/2020-10-01-github-actions-deprecating-set-env-and-add-path-commands/ changelog: none

view details

bors

commit sha fcf22d90bb9087f03e60c03ccccdc2f95668bf88

Auto merge of #6150 - flip1995:backport_doc_update, r=ebroto Update backport documentation to the subtree workflow changelog: none

view details

Dániel Buga

commit sha 7993ddd89d8d2e0754bf9b12756573f56b76e254

Add find_map_relevant_impl

view details

Dániel Buga

commit sha 18318a9d848950680c12c17183f175c7c511c2ce

Reimplement for_each_relevant_impl on top of find_map...

view details

Tom Eccles

commit sha a4a0342cf59a1bff43ed79586065eb97dba0cddb

ci: disabled: riscv: work around QEMU regression This bumps the version of the bbl bootloader not to perform 64-bit accesses to the PLIC. Doing so resulted in the QEMU test machine to fail to boot: bbl loader ../machine/mtrap.c:21: machine mode: unhandlable trap 7 @ 0x0000000080001f6e Power off Signed-off-by: Tom Eccles <tom.eccles@codethink.co.uk>

view details

bors

commit sha be719d11e56817753d4196291bc427c2704dab3d

Auto merge of #77609 - ortem:fix-lldb-commands, r=Mark-Simulacrum Remove redundant backslashes from `lldb_commands`

view details

Dániel Buga

commit sha 217d6f9741819aedfe22e6d3ec9cca6e4a49f77d

Revert calculate_dtor signature change

view details

Tom Eccles

commit sha e0b033e965a7d422da70a409a028af7c8b64e709

doc: fix broken link for crate::os::linux::raw::stat Fixing: Documenting std v0.0.0 (/checkout/library/std) error: `self::os::linux::raw::stat` is both a struct and a function --> library/std/src/os/linux/fs.rs:23:19 | 23 | /// [`stat`]: crate::os::linux::raw::stat | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ambiguous link | = note: `-D broken-intra-doc-links` implied by `-D warnings` help: to link to the struct, prefix with `struct@` | 23 | /// [`stat`]: struct@self::os::linux::raw::stat | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: to link to the function, add parentheses | 23 | /// [`stat`]: self::os::linux::raw::stat() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error error: could not document `std` Signed-off-by: Tom Eccles <tom.eccles@codethink.co.uk>

view details

bors

commit sha 947516f0184a7845577de1f0162f172b89965692

Auto merge of #6130 - Ambroisie:lint-ptr-eq, r=Manishearth New lint: Recommend using `ptr::eq` when possible This is based almost entirely on the code available in the previous PR #4596. I merely updated the code to make it compile. Fixes #3661. - [ ] I'm not sure about the lint name, but it was the one used in the original PR. - [X] Added passing UI tests (including committed `.stderr` file) - [X] `cargo test` passes locally - [X] Executed `cargo dev update_lints` - [X] Added lint documentation - [X] Run `cargo dev fmt` --- changelog: none

view details

Josh Stone

commit sha c1297eca3ebd899f0329892542af40a211300115

unix/vxworks: make DirEntry slightly smaller `DirEntry` contains a `ReadDir` handle, which used to just be a wrapper on `Arc<InnerReadDir>`. Commit af75314ecdbc5 added `end_of_stream: bool` which is not needed by `DirEntry`, but adds 8 bytes after padding. We can let `DirEntry` have an `Arc<InnerReadDir>` directly to avoid that.

view details

Josh Stone

commit sha 365e00aeeee4c84e29a2fdbee18faa69edcae2ee

remove ReadDir.end_of_stream on targets that don't use it

view details

push time in 5 hours

Pull request review commentrust-lang/rust

consider assignments of union field of ManuallyDrop type safe

 impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {                     UnsafetyViolationKind::GeneralAndConstFn,                     UnsafetyViolationDetails::DerefOfRawPointer,                 ),-                ty::Adt(adt, _) => {-                    if adt.is_union() {-                        if context == PlaceContext::MutatingUse(MutatingUseContext::Store)-                            || context == PlaceContext::MutatingUse(MutatingUseContext::Drop)-                            || context == PlaceContext::MutatingUse(MutatingUseContext::AsmOutput)-                        {-                            let elem_ty = match elem {-                                ProjectionElem::Field(_, ty) => ty,-                                _ => span_bug!(-                                    self.source_info.span,-                                    "non-field projection {:?} from union?",-                                    place-                                ),-                            };-                            if !elem_ty.is_copy_modulo_regions(+                ty::Adt(adt, _) if adt.is_union() => {+                    let assign_to_field = context+                        == PlaceContext::MutatingUse(MutatingUseContext::Store)

Ouch. This is poor even in isolation, but with the || chain it's terrible 🙁

You're in the compiler, so I guess you could try matches!(context, PlaceContext::MutatingUse(MutatingUseContext::Store | MutatingUseContext::Drop | MutatingUseContext::AsmOutput)?

RalfJung

comment created time in 6 hours

PullRequestReviewEvent

issue commentrust-lang/rust

repr(transparent) on generic type skips "exactly one non-zero-sized field" check

+1 to anything order-dependent in a braced-struct.

Hmm, the lint considers () an improper_ctype. But then an empty struct is UB(!?) in C, so I guess there isn't a canonical ABI for this.

@rfcbot reviewed

mahkoh

comment created time in 7 hours

pull request commentrust-lang/rust

change the order of type arguments on ControlFlow

@bors rollup=maybe

NoraCodes

comment created time in 2 days

Pull request review commentrust-lang/rust

TypeVisitor: use `std::ops::ControlFlow` instead of `bool`

 impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<OP> where     OP: FnMut(ty::Region<'tcx>), {-    fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> bool {+    fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ControlFlow<(), ()> {         t.as_ref().skip_binder().visit_with(self);

Another thing you could consider to avoid the conversation on the type would be to just mark the methods on the trait as #[must_use]. It looks like that works even for calls on concrete things that don't copy the attribute to their implementation. Probably still not this PR, though.

LeSeulArtichaut

comment created time in 3 days

PullRequestReviewEvent

pull request commentrust-lang/rust

change the order of type arguments on ControlFlow

Rebased.

@bors r+

NoraCodes

comment created time in 4 days

push eventNoraCodes/rust

Yuki Okushi

commit sha 69f2cf5ad9f472facb25b6057d4f6fa05a2d3bab

Rollup merge of #77473 - Mark-Simulacrum:check-limited, r=ecstatic-morse Make --all-targets in x.py check opt-in In particular due to #76822, making this the default is currently suboptimal. r? @ecstatic-morse

view details

Yuki Okushi

commit sha f5db16639713a9a3e6730a59c5a03007557df057

Rollup merge of #77508 - camelid:patch-8, r=jonas-schievink Fix capitalization in blog post name

view details

Camelid

commit sha adfba2b694b19e4aa6a99289eeda7b48ae402ab8

Only use Fira Sans for the first `td` in item lists Fixes an issue where links in the one-line version of an item's docs would be in Fira Sans, while the rest would be in a serifed font.

view details

Lzu Tao

commit sha 6cb062dacfed8e647361bc94694c7177beb17390

mips32: Add f64 hard-float support co-authored-by: Amanieu <amanieu@gmail.com>

view details

bors

commit sha 2251766944f355a039e67aeb13ab630b2d46bf9b

Auto merge of #77517 - JohnTitor:rollup-msbd49e, r=JohnTitor Rollup of 11 pull requests Successful merges: - #75143 (Use `tracing` spans to trace the entire MIR interp stack) - #75699 (Uplift drop-bounds lint from clippy) - #76768 (Test and reject out-of-bounds shuffle vectors) - #77190 (updated p! macro to accept literals) - #77388 (Add some regression tests) - #77419 (Create E0777 error code for invalid argument in derive) - #77447 (BTreeMap: document DrainFilterInner better) - #77468 (Fix test name) - #77469 (Improve rustdoc error for failed intra-doc link resolution) - #77473 (Make --all-targets in x.py check opt-in) - #77508 (Fix capitalization in blog post name) Failed merges: r? `@ghost`

view details

bors

commit sha 32cbc65e6bf793d99dc609d11f4a4c93176cdbe2

Auto merge of #77380 - fusion-engineering-forks:unbox-the-mutex, r=dtolnay Unbox mutexes and condvars on some platforms Both mutexes and condition variables contained a Box containing the actual os-specific object. This was done because moving these objects may cause undefined behaviour on some platforms. However, this is not needed on Windows[1], Wasm[2], cloudabi[2], and 'unsupported'[3], were the box was only needlessly making them less efficient. This change gets rid of the box on those platforms. On those platforms, `Condvar` can no longer verify it is only used with one `Mutex`, as mutexes no longer have a stable address. This was addressed and considered acceptable in #76932. [1]\: https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-initializesrwlock [2]\: These are just a single atomic integer together with futex wait/wake calls/instructions. [3]\: The `unsupported` platform doesn't support multiple threads at all.

view details

bors

commit sha 0d37dca25a51fb900a402c94c8818ad1c2789e30

Auto merge of #76448 - haraldh:default_alloc_error_handler_reduced, r=Amanieu Implement Make `handle_alloc_error` default to panic (for no_std + liballoc) Related: https://github.com/rust-lang/rust/issues/66741 Guarded with `#![feature(default_alloc_error_handler)]` a default `alloc_error_handler` is called, if a custom allocator is used and no other custom `#[alloc_error_handler]` is defined.

view details

bjorn3

commit sha 17d1cbbbe0dc59509cf0f889d241cf58099076d4

Move target feature whitelist from cg_llvm to cg_ssa These target features have to be supported or at least emulated by alternative codegen backends anyway as they are used by common crates. By moving this list to cg_ssa, other codegen backends don't have to copy this code.

view details

Guillaume Gomez

commit sha 3641a37455939cbd913117a1921909c9cb16d349

Enforce crate level attributes checks

view details

bors

commit sha 0644cc1242dbeebb69b1b2496562751ba5d23ffb

Auto merge of #76610 - hch12907:master, r=LukasKalbertodt Implement as_ne_bytes() for integers and floats This is related to issue #64464. I am pretty sure that these functions are actually const-ify-able, and technically as_bits() can also be implemented for floats, but I might need some comments on both.

view details

Matthew Jasper

commit sha fa3e2fcbe4bb6c878d137eb427fc34daf49b8c69

Defer creating drop trees in MIR lowering until leaving that scope

view details

Matthew Jasper

commit sha f810e600cd7b128ec167937bbd87cfabc52b403e

Reduce the number of drop-flag assignments in unwind paths

view details

Matthew Jasper

commit sha 1e71862046bdea989e4a25c266b2df768cb4f0bb

Add some more comments

view details

Matthew Jasper

commit sha 8902ce5d848f0b58f02b72725f195ec9022449a6

Address review comments

view details

Aaron Hill

commit sha 4c83eec00883e10e7b859d039dcc0e937a0706d5

Fix rebase fallout

view details

Aaron Hill

commit sha f23e9a1adf9fff618b9a40cb6e5e570c18e2a226

Add regression test for issue #72470 This was fixed with the upgrade to LLVM 11 in #73526. It seems extremely unlikey that this exact issue will ever reoccur, since slight modifications to the code caused the crash to stop happening. However, it can't hurt to have a test for it.

view details

Aaron Hill

commit sha 8478385ea49ea0cfa0b11ec3ed4f2aa9a76eaf9c

Fix broken link

view details

Aaron Hill

commit sha 33337bb855d453c0077764f6a5488b3ff109b6f5

Bless mir-opt tests

view details

Aaron Hill

commit sha eb94cdd85e2b48030684a38fa1d6f58e2c301a7d

Apply suggestions from review Co-authored-by: matthewjasper <20113453+matthewjasper@users.noreply.github.com>

view details

Lzu Tao

commit sha 79f477bb1fe81385aebde628e5a3f5c9168b24e0

Add asm! support for mips64

view details

push time in 4 days

pull request commentrust-lang/rust

Add `ControlFlow::is_{break,continue}` methods

@bors r+ rollup

(This will probably end up merge-conflicting with one of the other PRs, but maybe we'll get lucky.)

LeSeulArtichaut

comment created time in 5 days

pull request commentrust-lang/rust

impl<A, B> IntoIterator for (A, B) as Zip

Do you see any that are particularly compelling in your opinion?

No idea 🙃 There's also some value in volume to show prevalence...

I guess one I really liked was image since rustfmt seems to really accentuate the asymmetry of the zip form.

That said, the niceness there does have the objection of "well, use Iterator::zip(modules.iter(), names.iter()) then".

it could have been .zip(args) already.

Ah, cool. I didn't look into what the types actually were.

cuviper

comment created time in 5 days

pull request commentrust-lang/rust

impl<A, B> IntoIterator for (A, B) as Zip

I may have gone overboard with example conversions throughout the compiler, but I can back any of that out if so.

Consider restricting it to ones where it's particularly good at showing its value, because this will need an FCP and you probably want to avoid the 10+ days of merge conflicts.

Nit: these ones distracted me as I was scrolling, image thinking "wait, if it was .iter() before, shouldn't it be (param_tys, &args) now?" I'm sure that with CI passing the changes work fine, but I don't know if that distraction or potential weird perf impacts (like carrying a vector in the iterator instead of 2 pointers) are worth having those additional examples.

cuviper

comment created time in 5 days

pull request commentrust-lang/rust

Improve slice.binary_search_by()'s best-case performance to O(1)

Note that after https://github.com/rust-lang/rust/pull/77751 there's a binary_search on VecDeque too -- if the slice version is updated to be ternary then the branch in that method that delegates to the slice version should probably also be updated to (go back to) having a ternary check instead of the binary one.

I'm definitely used to the conventional wisdom that the ternary implementation is worse because the extra log N branches in the majority case don't outweigh the stopping-early.

Maybe this is a place (like sort_by_key and sort_by_cached_key was) where having a different method to opt into the "my predicate in this case is actually expensive" behaviour would be worth it?

Folyd

comment created time in 5 days

pull request commentrust-lang/rust

Make `ControlFlow` `#[must_use]`

Hmm, I don't have a good sense for how to decide whether to do this. It makes total sense in the visitor recursion scenario, but seems suboptimal in the updated doctest's scenario of try_for_each with a closure that mutates locals. (And we saw in the fold_mut conversation (https://github.com/rust-lang/rust/pull/76746) that using for_each with a mutable closure can be better than rewriting it to fold.)

Maybe @rust-lang/libs would have some advice? Sadly there's nothing I could find in the api-guidelines about #[must_use].

cc @NoraCodes and @ecstatic-morse, as other participants in the tracking issue, to comment on whether this makes sense in their situations.

LeSeulArtichaut

comment created time in 5 days

issue openedrust-lang/api-guidelines

Guidelines for `must_use`?

I got assigned a pr (https://github.com/rust-lang/rust/pull/78202) to add this to something, and realized I didn't have a great sense of when something should or shouldn't be must_use -- in some ways most things could be.

Would be nice to have a checklist of things to consider.

This is especially true with must_use stable on functions now -- some people would like to put it on essentially everything, which seems like not what's desirable. I suppose guidelines on this could also push feedback up to lang to change the rules for it...

created time in 5 days

PullRequestReviewEvent

issue commentrust-lang/lang-team

Types as const Parameters

We discussed this in the 2020-10-19 lang team triage meeting.

This sounds like it could be a nice simplification in the future, and the idea of reifying more of the type system into values is interesting. However, this builds on const generics, which are still ongoing. There are also still plenty of unknowns here, like how to use these values to produce items. So like we've been doing with other steps-to-variadic-generics RFCs for now,

@rfcbot fcp close

(As this is a close I'll check the boxes of those who were in the meeting.)

pthariensflame

comment created time in 5 days

pull request commentrust-lang/rust

change the order of type arguments on ControlFlow

Thanks, @NoraCodes!

@bors r+ rollup=iffy

NoraCodes

comment created time in 5 days

Pull request review commentrust-lang/rust

TypeVisitor: use `std::ops::ControlFlow` instead of `bool`

 impl DefIdVisitor<'tcx> for TypePrivacyVisitor<'tcx> {     fn tcx(&self) -> TyCtxt<'tcx> {         self.tcx     }-    fn visit_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {-        self.check_def_id(def_id, kind, descr)+    fn visit_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> ControlFlow<(), ()> {+        if self.check_def_id(def_id, kind, descr) {

There has been almost no thought put into what methods the ControlFlow type should have, so if you come up with reasonable ones definitely add them. It used to be an internal implementation detail, so doesn't even have the usual combinators.

LeSeulArtichaut

comment created time in 5 days

PullRequestReviewEvent

issue commentrust-lang/rust

Tracking issue for panics in mem::uninitialized/zeroed

From https://github.com/rust-lang/rust/pull/66059#issuecomment-586734747:

It is not entirely clear whether, when a violation of validity is detected, we should panic or abort. For now, we panic, which has the advantage of printing a backtrace where possible. However, unsafe could could be surprised by the panic and not expect unwinding, and that has lead to segfaults on crater. The issue with aborting, however, is that we have no good way to print a backtrace.

RalfJung

comment created time in 6 days

issue commentrust-lang/rust

Tracking issue for `ControlFlow` enum, for use with `try_fold` and in `Try`

An MCP to use this more often in the compiler: https://github.com/rust-lang/compiler-team/issues/374

Conveniently that also suggests that ControlFlow<BreakType> would be better than the current ControlFlow<(), BreakType>.

NoraCodes

comment created time in 6 days

pull request commentrust-lang/lang-team

Initial draft of copy ergonomics design note

@Mark-Simulacrum Annoyingly the GitHub UI refused to let me suggest additions as a PR, so I just pushed it. Feel free to rebase-disappear the updates if you dislike them.

Mark-Simulacrum

comment created time in 6 days

push eventMark-Simulacrum/lang-team

scottmcm

commit sha 0dcb35ad3d1828e737cafc65f14e259dab67accb

More text for ref-to-Copy section Mention some more things I remembered from https://users.rust-lang.org/t/why-cannot-we-pass-t-to-function-which-requires-t/13792/4?u=scottmcm

view details

push time in 6 days

fork scottmcm/lang-team

Home of the Rust language design team.

https://lang-team.rust-lang.org/

fork in 6 days

delete branch scottmcm/rust

delete branch : fewer-try-trait-method-references

delete time in 7 days

pull request commentrust-lang/rust

[net] apply clippy lints

Now that this is just changing some true/false matches to matches!, LGTM.

r? @scottmcm @bors r+ rollup

wcampbell0x2a

comment created time in 7 days

issue commentrust-lang/rust

ICE when matching with an opaque constant pattern

This was an error back in 1.25,

error[E0658]: non-reference pattern used to match a reference (see issue #42640)
  --> <source>:11:9
   |
11 |         Opaque(_) => {}
   |         ^^^^^^^^^ help: consider using a reference: `&Opaque(_)`

But has been an ICE since as fast back as 1.26.

Nadrieril

comment created time in 8 days

issue commentrust-lang/rust

Feature request: Preventing dropping fields of a dropped struct for better C++ interoperability

but also leaks memory if Inner allocates memory

ManuallyDrop is safely DerefMut, so instead of

o.invar = ManuallyDrop::new(Inner{});

you can instead do

*o.invar = Inner{};

which will run Drop on the previous value.

Now that doesn't completely solve "can't be automated nicely", but it's better at least.

Volker-Weissmann

comment created time in 8 days

Pull request review commentrust-lang/rust

[net] apply clippy lints

 impl SocketAddrV6 {                 sin6_addr: *ip.as_inner(),                 sin6_flowinfo: flowinfo,                 sin6_scope_id: scope_id,-                ..unsafe { mem::zeroed() }

Reverting it seems reasonable. Then the other changes can go in easily.

wcampbell0x2a

comment created time in 8 days

PullRequestReviewEvent

pull request commentrust-lang/rust

Improve readability of range docs

r? @scottmcm @bors r+ rollup

camelid

comment created time in 8 days

PullRequestReviewEvent

Pull request review commentrust-lang/rust

Improve readability of range docs

 use crate::hash::Hash; /// `RangeFull` is primarily used as a [slicing index], its shorthand is `..`. /// It cannot serve as an [`Iterator`] because it doesn't have a starting point. ///+/// `RangeFull` is a [*zero-sized type*][ZST], which means it is a singleton –+/// there is only one instance of the `RangeFull` type.

suggestion: I would avoid the "singleton" and "instance" language here, since one can have (.., 4, ..) and such which could easily be argued to be two instances. (Just because something is a ZST doesn't mean that their addresses are always ptr::eq, which is demonstrated most clearly by the slice iterators.)

Maybe just leave the mention off? It's defined as pub struct RangeFull;, so I don't think we need to say this on every such type -- people can look it up in the book if they're curious. (For example, fmt::Error doesn't say it's a ZST.)

camelid

comment created time in 8 days

PullRequestReviewEvent
PullRequestReviewEvent

issue commentrust-lang/unsafe-code-guidelines

Meaning of Undefined and Justification for UB

One point, I've noticed that UB has to be justified by the optimizations it enables. I would add that undefined behaviour was never intended to be a key to optimizations

I'm not convinced by that. Certainly for some things it was more about portability, but I think optimizations have been core from the beginning.

My go-to example: One of the very first things that people wanted compilers to do was register allocation for local variables. Without that optimization things would have to be loaded and stored to the stack all over the place, which would be terrible for runtime performance. But doing that requires making certain things undefined behaviour -- int a, b; can't go in registers if (&a)[1] = 2; is defined to update b.

chorman0773

comment created time in 8 days

Pull request review commentrust-lang/rust

Note that `BasicBlock` is just a pointer

 rustc_index::newtype_index! {     /// are edges that go from a multi-successor node to a multi-predecessor node. This pass is     /// needed because some analyses require that there are no critical edges in the CFG.     ///+    /// Note that this type is just a pointer; the actual data that a basic block holds is in+    /// [`BasicBlockData`].

It's definitely an index -- note that the type is defined by the rustc_index::newtype_index! macro. (And the START_BLOCK constant is index 0.)

camelid

comment created time in 9 days

PullRequestReviewEvent

Pull request review commentrust-lang/rust

Note that `BasicBlock` is just a pointer

 rustc_index::newtype_index! {     /// are edges that go from a multi-successor node to a multi-predecessor node. This pass is     /// needed because some analyses require that there are no critical edges in the CFG.     ///+    /// Note that this type is just a pointer; the actual data that a basic block holds is in+    /// [`BasicBlockData`].

nit: Consider avoiding the word "pointer" here -- maybe "index"?

Great to have the link to BasicBlockData in here!

camelid

comment created time in 10 days

PullRequestReviewEvent

issue closedrust-lang/rust

Autoreferencing copy types

This is a specific issue to track the changes proposed by @cramertj in RFC 2111. We decided to roll this into a larger experiment around coercions, generics, and Copy type ergonomics and are therefore ready to implement (but not yet stabilize).

closed time in 10 days

nikomatsakis

issue commentrust-lang/rust

Autoreferencing copy types

Given the op mentions rolling this into https://github.com/rust-lang/rust/issues/44619#issuecomment-703842299, I'll close this based on the FCP close in that other issue.

If anyone else shows up here, lang is still potentially interested in experiments in this area, but since nothing's happening right now this issue being open doesn't help. Feel free to drop by zulip and chat about things!

nikomatsakis

comment created time in 10 days

pull request commentrust-lang/blog.rust-lang.org

backlog bonanza post

Looks good to me.

nikomatsakis

comment created time in 10 days

pull request commentrust-lang/rust

liballoc: VecDeque: Add binary search functions

Stability attributes and code updates look good to me; thanks!

@bors r=scottmcm,dtolnay

(Feel free to r- again if needed, but based on your review being a ✔ I assume you're ok with this.)

vojtechkral

comment created time in 10 days

pull request commentrust-lang/rust

Remove shrink_to_fit from default ToString::to_string implementation.

Wow! I never would have guessed it would make that much of a difference!

m-ou-se

comment created time in 10 days

Pull request review commentrust-lang/rust

liballoc: VecDeque: Add binary search functions

 impl<T> VecDeque<T> {             self.wrap_copy(self.tail, self.head, k);         }     }++    /// Binary searches this sorted `VecDeque` for a given element.+    ///+    /// If the value is found then [`Result::Ok`] is returned, containing the+    /// index of the matching element. If there are multiple matches, then any+    /// one of the matches could be returned. If the value is not found then+    /// [`Result::Err`] is returned, containing the index where a matching+    /// element could be inserted while maintaining sorted order.+    ///+    /// # Examples+    ///+    /// Looks up a series of four elements. The first is found, with a+    /// uniquely determined position; the second and third are not+    /// found; the fourth could match any position in `[1, 4]`.+    ///+    /// ```+    /// #![feature(vecdeque_binary_search)]+    /// use std::collections::VecDeque;+    ///+    /// let deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();+    ///+    /// assert_eq!(deque.binary_search(&13),  Ok(9));+    /// assert_eq!(deque.binary_search(&4),   Err(7));+    /// assert_eq!(deque.binary_search(&100), Err(13));+    /// let r = deque.binary_search(&1);+    /// assert!(matches!(r, Ok(1..=4)));+    /// ```+    ///+    /// If you want to insert an item to a sorted `VecDeque`, while maintaining+    /// sort order:+    ///+    /// ```+    /// #![feature(vecdeque_binary_search)]+    /// use std::collections::VecDeque;+    ///+    /// let mut deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();+    /// let num = 42;+    /// let idx = deque.binary_search(&num).unwrap_or_else(|x| x);+    /// deque.insert(idx, num);+    /// assert_eq!(deque, &[0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]);+    /// ```+    #[unstable(feature = "vecdeque_binary_search", issue = "1")]+    #[inline]+    pub fn binary_search(&self, x: &T) -> Result<usize, usize>+    where+        T: Ord,+    {+        self.binary_search_by(|e| e.cmp(x))+    }++    /// Binary searches this sorted `VecDeque` with a comparator function.+    ///+    /// The comparator function should implement an order consistent+    /// with the sort order of the underlying `VecDeque`, returning an+    /// order code that indicates whether its argument is `Less`,+    /// `Equal` or `Greater` than the desired target.+    ///+    /// If the value is found then [`Result::Ok`] is returned, containing the+    /// index of the matching element. If there are multiple matches, then any+    /// one of the matches could be returned. If the value is not found then+    /// [`Result::Err`] is returned, containing the index where a matching+    /// element could be inserted while maintaining sorted order.+    ///+    /// # Examples+    ///+    /// Looks up a series of four elements. The first is found, with a+    /// uniquely determined position; the second and third are not+    /// found; the fourth could match any position in `[1, 4]`.+    ///+    /// ```+    /// #![feature(vecdeque_binary_search)]+    /// use std::collections::VecDeque;+    ///+    /// let deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();+    ///+    /// assert_eq!(deque.binary_search_by(|x| x.cmp(&13)),  Ok(9));+    /// assert_eq!(deque.binary_search_by(|x| x.cmp(&4)),   Err(7));+    /// assert_eq!(deque.binary_search_by(|x| x.cmp(&100)), Err(13));+    /// let r = deque.binary_search_by(|x| x.cmp(&1));+    /// assert!(matches!(r, Ok(1..=4)));+    /// ```+    #[unstable(feature = "vecdeque_binary_search", issue = "1")]+    pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result<usize, usize>+    where+        F: FnMut(&'a T) -> Ordering,+    {+        if self.is_empty() {+            return Err(0);+        }++        let (front, back) = self.as_slices();++        match back.first().map(|elem| f(elem)) {+            Some(Ordering::Equal) => return Ok(front.len()),

nit: I'll note that the existing binary_search on slices just looks at if cmp == Greater, it doesn't ever exit early on Equal -- that's generally better because 50% of the time (for random searches) it can't exit early, so the code path to check for it isn't worth it, especially not at every level.

As such, maybe this should do the same? Delegate to binary-searching back if needle >= back[0], otherwise binary-search on front?

vojtechkral

comment created time in 16 days

Pull request review commentrust-lang/rust

liballoc: VecDeque: Add binary search functions

 impl<T> VecDeque<T> {             self.wrap_copy(self.tail, self.head, k);         }     }++    /// Binary searches this sorted `VecDeque` for a given element.+    ///+    /// If the value is found then [`Result::Ok`] is returned, containing the+    /// index of the matching element. If there are multiple matches, then any+    /// one of the matches could be returned. If the value is not found then+    /// [`Result::Err`] is returned, containing the index where a matching+    /// element could be inserted while maintaining sorted order.+    ///+    /// # Examples+    ///+    /// Looks up a series of four elements. The first is found, with a+    /// uniquely determined position; the second and third are not+    /// found; the fourth could match any position in `[1, 4]`.+    ///+    /// ```+    /// #![feature(vecdeque_binary_search)]+    /// use std::collections::VecDeque;+    ///+    /// let deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();+    ///+    /// assert_eq!(deque.binary_search(&13),  Ok(9));+    /// assert_eq!(deque.binary_search(&4),   Err(7));+    /// assert_eq!(deque.binary_search(&100), Err(13));+    /// let r = deque.binary_search(&1);+    /// assert!(matches!(r, Ok(1..=4)));+    /// ```+    ///+    /// If you want to insert an item to a sorted `VecDeque`, while maintaining+    /// sort order:+    ///+    /// ```+    /// #![feature(vecdeque_binary_search)]+    /// use std::collections::VecDeque;+    ///+    /// let mut deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();+    /// let num = 42;+    /// let idx = deque.binary_search(&num).unwrap_or_else(|x| x);+    /// deque.insert(idx, num);+    /// assert_eq!(deque, &[0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]);+    /// ```+    #[unstable(feature = "vecdeque_binary_search", issue = "1")]+    #[inline]+    pub fn binary_search(&self, x: &T) -> Result<usize, usize>+    where+        T: Ord,+    {+        self.binary_search_by(|e| e.cmp(x))+    }++    /// Binary searches this sorted `VecDeque` with a comparator function.+    ///+    /// The comparator function should implement an order consistent+    /// with the sort order of the underlying `VecDeque`, returning an+    /// order code that indicates whether its argument is `Less`,+    /// `Equal` or `Greater` than the desired target.+    ///+    /// If the value is found then [`Result::Ok`] is returned, containing the+    /// index of the matching element. If there are multiple matches, then any+    /// one of the matches could be returned. If the value is not found then+    /// [`Result::Err`] is returned, containing the index where a matching+    /// element could be inserted while maintaining sorted order.+    ///+    /// # Examples+    ///+    /// Looks up a series of four elements. The first is found, with a+    /// uniquely determined position; the second and third are not+    /// found; the fourth could match any position in `[1, 4]`.+    ///+    /// ```+    /// #![feature(vecdeque_binary_search)]+    /// use std::collections::VecDeque;+    ///+    /// let deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();+    ///+    /// assert_eq!(deque.binary_search_by(|x| x.cmp(&13)),  Ok(9));+    /// assert_eq!(deque.binary_search_by(|x| x.cmp(&4)),   Err(7));+    /// assert_eq!(deque.binary_search_by(|x| x.cmp(&100)), Err(13));+    /// let r = deque.binary_search_by(|x| x.cmp(&1));+    /// assert!(matches!(r, Ok(1..=4)));+    /// ```+    #[unstable(feature = "vecdeque_binary_search", issue = "1")]+    pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result<usize, usize>+    where+        F: FnMut(&'a T) -> Ordering,+    {+        if self.is_empty() {

pondering: this is_empty check and the "is back empty?" check in the line-2525 map are equivalent -- is it worth checking it separately here rather than just relying on the one in front.binary_search_by(f)?

vojtechkral

comment created time in 16 days

PullRequestReviewEvent
PullRequestReviewEvent

pull request commentrust-lang/rust

Show type for docs slice Chunks

I feel like this should have libs or doc come to a bigger decision about examples on all the adapter types. Most of them just point to the method on Iterator and say "See its documentation for more", which has always seemed fine to me -- following the hyperlink isn't a problem, and is better than copying the documentation since the type is never used in isolation. (And almost never typed out explicitly, in my experience, especially now that -> impl Iterator<Item = T> works.)

If this PR is desirable, it seems like that would imply that there should also be ones for Cloned, Copied, Cycle, Empty, Enumerate, and more.

pickfire

comment created time in 12 days

issue commentrust-lang/rust

Add Min-Max Heap to `std::collections`

After the conversation about trying to stabilize BinaryHeap::into_iter_sorted ended up making me unhappy with the state of things there (https://github.com/rust-lang/rust/pull/76234#issuecomment-708505210), I'm personally more interested that I was previously in seeing this happen.

Having such a heap would address a bunch of things:

  • https://github.com/rust-lang/rust/issues/58174 talks about how the current one being a max-heap isn't inherently obvious, and while BinaryHeap<Reverse<T>> works great, there's something really nice about just having .pop_min() and .pop_max() for clarity.
  • A new heap could remove the iterate-in-unspecified-order problems of the existing one, and the min-max nature would mean that there'd be the natural .into_iter() for ascending, .into_iter().rev() for descending. (There'd still be Vec::from(...) or maybe some sort of .buffer_unordered() -> &[T] if people want to do something that doesn't care about the ordering.)

In a way it'd be like the VecDeque-vs-Vec pair.

ArniDagur

comment created time in 12 days

PR closed rust-lang/rust

Stabilize feature(binary_heap_into_iter_sorted) S-waiting-on-review T-libs needs-fcp relnotes

This came up on an itertools issue, and looks like it's baked sufficiently, so I figured I'd ask about stabilization.

This would stabilize the following API: https://doc.rust-lang.org/nightly/std/collections/struct.BinaryHeap.html#method.into_iter_sorted

impl<T: Ord> BinaryHeap {
    fn into_iter_sorted(self) -> IntoIterSorted<T>;
}
impl<T: Ord> Iterator for IntoIterSorted<T> { type Item = T; }
impl<T: Ord> ExactSizeIterator for IntoIterSorted<T> ;
impl<T: Ord> FusedIterator for IntoIterSorted<T> ;
impl<T: Clone> Clone for IntoIterSorted<T>;
impl<T: Debug> Debug for IntoIterSorted<T>;

There were comments about wishing that the ordinary .into_iter() could just be the sorted one, but .iter() cannot be in that order so that's not necessarily good. And anyways, IntoIter already implements DoubleEndedIterator so we can't really change the order even if we wanted to.

So I think the remaining potential questions are naming (it was originally proposed as into_iter_ordered but went in as into_iter_sorted, which I agree is more consistent with elsewhere in the library) and the standard whether this is useful enough (one could certainly use from_fn on the heap's pop, but that's potentially suboptimal as it doesn't have a size_hint).

This needs an FCP, so picking a libs member explicitly: r? @KodrAus

Tracking issue #59278 (which also covers a drain version which I've intentionally not included here)

+22 -7

16 comments

2 changed files

scottmcm

pr closed time in 12 days

pull request commentrust-lang/rust

Stabilize feature(binary_heap_into_iter_sorted)

I'm going to withdraw this PR, since the conversation has convinced me that things aren't ready yet here.

My personal conclusions:

  • Given a time machine I'd remove direct iteration in heap order, and would make that go through Vec: From<Heap<_>> or some sort of .as_unordered_slice().
  • Assuming it can be implemented efficiently, .into_iter() and something-like-.drain() on a heap should both be double-ended in sorted order. (With probably no .iter() nor .iter_mut().)
  • As a bonus, that would avoid issues like https://github.com/rust-lang/rust/issues/58174 as such a heap would natively have .pop_min() and .pop_max()
scottmcm

comment created time in 12 days

pull request commentrust-lang/rust

Use `try{}` in `try_fold` to decouple iterators in the library from `Try` details

Perf results look essentially unchanged to me, as expected.

scottmcm

comment created time in 12 days

delete branch scottmcm/rustfmt

delete branch : fix-try-parse

delete time in 13 days

pull request commentrust-lang/rust

Use `try{}` in `try_fold` to decouple iterators in the library from `Try` details

@bors try @rust-timer queue

scottmcm

comment created time in 13 days

push eventscottmcm/rust

Scott McMurray

commit sha 8374c1702c1d9858d8906051cd531757be63998d

Bump the version of rustfmt used in tidy To pick up https://github.com/rust-lang/rustfmt/pull/4461 So that rustfmt has the parsing fix from https://github.com/rust-lang/rust/pull/76274 ...and do a reformat that it wants.

view details

push time in 13 days

pull request commentrust-lang/rust

Add [T]::as_chunks(_mut)

@LukasKalbertodt Friendly one-week re-review ping.

scottmcm

comment created time in 14 days

PR opened rust-lang/rustfmt

Add some basic tests for `try{}` expressions

They failed to parse in rustfmt on me in https://github.com/rust-lang/rust/pull/77877, which looks like it's since been fixed, but I figured I'd send in some tests anyway.

+59 -0

0 comment

2 changed files

pr created time in 14 days

create barnchscottmcm/rustfmt

branch : fix-try-parse

created branch time in 14 days

fork scottmcm/rustfmt

Format Rust code

fork in 14 days

Pull request review commentrust-lang/rust

Improve readability of range docs

 impl fmt::Debug for RangeFull { /// assert_eq!(3 + 4 + 5, (3..6).sum()); /// /// let arr = [0, 1, 2, 3, 4];-/// assert_eq!(arr[ ..  ], [0,1,2,3,4]);-/// assert_eq!(arr[ .. 3], [0,1,2    ]);-/// assert_eq!(arr[ ..=3], [0,1,2,3  ]);-/// assert_eq!(arr[1..  ], [  1,2,3,4]);-/// assert_eq!(arr[1.. 3], [  1,2    ]);  // Range

It looks like these must have been copy-pasted to all the Range* types? So the comment is probably to emphasize that that particular line is the one for this type.

Seems like this example should be maybe somewhere where we reference it from all the types, and call-out Range, RangeTo, etc on every line. I guess there's not a core::range module to put it on...

Maybe this example could go on RangeBounds, and all the Range* types could link over there as a way to jump between them?

camelid

comment created time in 14 days

PullRequestReviewEvent

PR opened rust-lang/rust

Use `try{}` in `try_fold` to decouple iterators in the library from `Try` details

I'd like to experiment with changing the ?/try desugaring and correspondingly the Try trait (see #42327 for discussions about the suboptimalities of the current one) and this change would keep from needing any cfg(bootstrap) in iterator things.

This will be lowered to the same thing, so shouldn't cause any perf issues: https://github.com/rust-lang/rust/blob/08e2d4616613716362b4b49980ff303f2b9ae654/compiler/rustc_ast_lowering/src/expr.rs#L428-L429

But I'll trigger a perf run just in case.

+31 -30

0 comment

8 changed files

pr created time in 14 days

push eventscottmcm/rust

Tim Nielens

commit sha 390a13b06c79d4177b829097b06453e38188081f

needless-lifetime - fix nested elision site FPs

view details

Tim Nielens

commit sha a60e5de90c7370d4fb3e6561d3cb55495cda2e2a

needless-lifetime / nested elision sites / PR remarks

view details

Tim Nielens

commit sha c8e9e52303da6dff4bc5cc4db3021d608fca6c70

needless-lifetime / add test cases for nested elision sites

view details

Takayuki Nakata

commit sha 1778a1ec4615a42a8ba9497006b07859186c08a1

Restrict `same_item_push` to suppress false positives It emits a lint when the pushed item is a literal, a constant and an immutable binding that are initialized with those.

view details

Takayuki Nakata

commit sha 0117ea2b016133145f9e02e27421ac3672b42f57

Refactoring: use inner function

view details

Takayuki Nakata

commit sha b80576fba633e1fc214c9f6900d7ca3424bda6d0

Some refactoring

view details

Takayuki Nakata

commit sha 14faebe20ea82392f393c3ff5efaab7250e51989

Add some tests to `same_item_push` Add tests in which the variable is initialized with a match expression and function call

view details

Takayuki Nakata

commit sha 2972ad3ef661071531a61ec8999b668a6b734b74

Refactoring: tests in `same_item_push`

view details

Takayuki Nakata

commit sha 730ca457f580247667ed0cd5965bc08752ebc0b3

Address `items_after_statement`

view details

Dylan MacKenzie

commit sha 72b402ed38f0c71461038aef8a49a02e49280788

Add pass names to some common dataflow analyses

view details

Aaron Hill

commit sha cfe07cd42a92610219d6ffc1ae5eefef42f5254a

Use llvm::computeLTOCacheKey to determine post-ThinLTO CGU reuse During incremental ThinLTO compilation, we attempt to re-use the optimized (post-ThinLTO) bitcode file for a module if it is 'safe' to do so. Up until now, 'safe' has meant that the set of modules that our current modules imports from/exports to is unchanged from the previous compilation session. See PR #67020 and PR #71131 for more details. However, this turns out be insufficient to guarantee that it's safe to reuse the post-LTO module (i.e. that optimizing the pre-LTO module would produce the same result). When LLVM optimizes a module during ThinLTO, it may look at other information from the 'module index', such as whether a (non-imported!) global variable is used. If this information changes between compilation runs, we may end up re-using an optimized module that (for example) had dead-code elimination run on a function that is now used by another module. Fortunately, LLVM implements its own ThinLTO module cache, which is used when ThinLTO is performed by a linker plugin (e.g. when clang is used to compile a C proect). Using this cache directly would require extensive refactoring of our code - but fortunately for us, LLVM provides a function that does exactly what we need. The function `llvm::computeLTOCacheKey` is used to compute a SHA-1 hash from all data that might influence the result of ThinLTO on a module. In addition to the module imports/exports that we manually track, it also hashes information about global variables (e.g. their liveness) which might be used during optimization. By using this function, we shouldn't have to worry about new LLVM passes breaking our module re-use behavior. In LLVM, the output of this function forms part of the filename used to store the post-ThinLTO module. To keep our current filename structure intact, this PR just writes out the mapping 'CGU name -> Hash' to a file. To determine if a post-LTO module should be reused, we compare hashes from the previous session. This should unblock PR #75199 - by sheer chance, it seems to have hit this issue due to the particular CGU partitioning and optimization decisions that end up getting made.

view details

Hanif Bin Ariffin

commit sha dc655b28424549a4775bc2e8c9021d44482bccb1

Prevent stackoverflow

view details

rail

commit sha 5e393c7747d081c45414060f81016e9ea3cb961f

Fix a FP in `explicit_counter_loop` Fix a false positive in `explicit_counter_loop` where the loop counter is used after incremented, adjust the test so that counters are incremented at the end of the loop and add the test for this false positive.

view details

Eduardo Broto

commit sha 3e294b22a43be349262405715cf4885296c284ba

Revert "or_fn_call: ignore nullary associated const fns" This reverts commit 7a66e6502dc3c7085b3f4078c01d4957d96175ed.

view details

Eduardo Broto

commit sha ce83d8d4d1b28e73888a616d3ffbf19c6a620588

Revert "Avoid or_fun_call for const_fn with no args" This reverts commit 5d66bd7bb3fd701d70ec11217e3f89fabe5cb0a7.

view details

Eduardo Broto

commit sha 9365660a2fc57210996df733efe468019c671b2f

unnecessary sort by: avoid dereferencing closure param

view details

flip1995

commit sha d1f9cad102b5686f2b827f3c62a02dfe419128a6

Merge commit 'e636b88aa180e8cab9e28802aac90adbc984234d' into clippyup

view details

bors

commit sha 019c0d5f7f90f959ff92684a04b0d766b22527a5

Auto merge of #6076 - rail-rain:fix_fp_explicit_counter_loop, r=matthiaskrgr Fix a FP in `explicit_counter_loop` Fixes #4677 and #6074 Fix a false positive in `explicit_counter_loop` where the loop counter is used after incremented, adjust the test so that counters are incremented at the end of the loop and add the test for this false positive. --- changelog: Fix a false positive in `explicit_counter_loop` where the loop counter is used after incremented

view details

bors

commit sha cc1998f7b3cc04c891f92c62a52c0c45fa4c145a

Auto merge of #6077 - ebroto:revert_or_fun_call_const, r=matthiaskrgr Revert: or_fun_call should lint calls to `const fn`s with no args The changes in #5889 and #5984 were done under the incorrect assumption that a `const fn` with no args was guaranteed to be evaluated at compile time. A `const fn` is only guaranteed to be evaluated at compile time if it's inside a const context (the initializer of a `const` or a `static`). See this [zulip conversation](https://rust-lang.zulipchat.com/#narrow/stream/122651-general/topic/Common.20misconception.3A.20.60const.20fn.60.20and.20its.20effect.20on.20codegen/near/208059113) for more details on this common misconception. Given that none of the linted methods by `or_fun_call` can be called in const contexts, the lint should make no exceptions. changelog: [`or_fun_call`] lints again calls to `const fn` with no args

view details

Takayuki Nakata

commit sha 2892a2b0f578edd290b3be6f5e5c3280bc160f24

Fix FP in `print_stdout` This lint shouldn't be emitted in `build.rs` as `println!` and `print!` are used for the build script.

view details

push time in 14 days

issue commentrust-lang/rust

Unreachable code optimization failure when matching on Rust enum

Hmm, there's nothing that would force that type and the HIR->MIR desugaring to use the same internal construct value, though, right? Like we could change the MIR Rvalue::Discriminant to return the same width as it's actually stored, and the discriminant_value intrinsic to [sz]ext to whatever DiscriminantKind wants?

That way LLVM would just see a switch on the loaded value, not an extended one. (So this might still happen if the if g != Variant::Zero { check were replaced with mem::Discriminant one, but that would be a different problem.)

MSxDOS

comment created time in 14 days

issue commentrust-lang/rust

Breaking change/regression in nightly? Hash of `Discriminant` now produces different results across CPU architectures

this is a new opportunity for a cycle

Is this worse in some way than the [u16; sizeof(Self)] cycles for structs?

The error on using sizeof(Self) in a variant initializer says "computing layout of Foo [...] requires const-evaluating + checking Foo::Bar::{{constant}}#0", which implies to me that this wouldn't actually be a new dependency.

That makes me curious about things like

pub enum Foo {
    Bar = 12345,
    Baz = 1 + Foo::Bar as isize,
}

But the MIR for Baz's initializer there already avoids making a mention of Foo, just summoning the value somehow

_3 = CheckedAdd(const 12345, const 0_isize);

So I guess that potential issue has already been avoided.


The "the DiscriminantKind trait is implemented for every type" part and the choice of associated type is magical as far as the standard library is concerned, though.

Hmm, I guess I wasn't thinking about the DiscriminantKind trait, which describes itself as "unlikely to ever be stabilized". The mem::Discriminant<_> type itself could, hypothetically, cast to i64 in its Hash implementation if it wanted, as a way to resolve this issue. (Which would even be fine for a u128 discriminant, because it's just Hash. Not that that would necessarily be good -- I'd certainly like enum { A, B, C } to only have to hash one byte.)

Right now I think the only stable way to get the value out is with as _____, which truncates/extends to the requested type, so lang might be able to avoid making a guarantee here. (Until someone wants to offer an API like Discriminant<T>: Into<T::Discriminant>, but that's not here.)

This issue is now old enough that it's a de-facto decision that the breakage isn't important enough to just do the i64::wrapping_from(discriminant) change. So I don't know what the correct scope of a change would be here, if any. Given that [T]: Hash appears to be platform-dependent, I do think it's not unreasonable for Discriminant: Hash to be platform-dependent as well -- as has already been said, a specific Hasher can choose to extend (or truncate) [ui]size as part of hashing if it wants.


Meta: It'd also be a shame to end up with folk wisdom of "you should #[repr(u8)] your enums because it makes the derive(Hash) implementation faster".

korken89

comment created time in 14 days

Pull request review commentrust-lang/rfcs

Safer Transmute

+# Safer Transmute RFC++- Feature Name: `safer_transmute`+- Start Date: 2020-08-31+- RFC PR: [rust-lang/rfcs#2981](https://github.com/rust-lang/rfcs/pull/2981)+- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000)+++# Summary+[summary]: #summary++We propose traits, namely `TransmuteInto` and `TransmuteFrom`, that are implemented *automatically* for combinations of types that may be safely transmuted. In other words, this RFC makes safe transmutation *as easy as 1..., 2..., `repr(C)`!*+```rust+use core::transmute::{+    transmute,+    stability::{PromiseTransmutableInto, PromiseTransmutableFrom},+};++#[derive(PromiseTransmutableInto, PromiseTransmutableFrom)] // declare `Foo` to be *stably* transmutable+#[repr(C)]+pub struct Foo(pub u8, pub u16);+//                    ^ there's a padding byte here, between these fields++// Transmute fearlessly!+let _ : Foo = transmute!(64u32); // Alchemy Achieved!++let _ : u32 = transmute!(Foo(16, 12)); // Compile Error!++// error[E0277]: the trait bound `u32: TransmuteFrom<Foo, _>` is not satisfied+//   --> src/demo.rs:14:27+//    |+// 14 | let _ : u32 = transmute!(Foo(16, 12)); // Compile Error!+//    |                          ^^^^^^^^^^^ the trait `TransmuteFrom<Foo, _, _>` is not implemented for `u32`+//    |+//   = note: byte 8 of the source type may be uninitialized; byte 8 of the destination type cannot be uninitialized.+```+++# Motivation+[motivation]: #motivation++Byte-reinterpretation conversions (such as those performed by `mem::transmute`, `mem::transmute_copy`, pointer casts, and `union`s) are invaluable in high performance contexts, are `unsafe`, and easy to get wrong. This RFC provides mechanisms that make many currently-unsafe transmutations entirely safe. For transmutations that are not entirely safe, this RFC's mechanisms make mistakes harder to make.++This RFC's comprehensive approach provides additional benefits beyond the mere act of transmutation; namely:+ - [authoritatively codifies language layout guarantees](#codifying-language-layout-guarantees)+ - [allows crate authors to codify their types' layout stability guarantees](#expressing-library-layout-guarantees)+ - [allows crate authors to codify their abstractions' layout requirements](#expressing-layout-requirements)++Given the expressive foundation provided by this RFC, we also envision a range of future possibilities that will *not* require additional compiler support, including:+ - [safe slice and `Vec` casting][0000-ext-container-casting.md]+ - [a unified, generic `Atomic<T>` type][0000-ext-generic-atomic.md]+ - [a safe, generic alternative to `include_bytes!`][0000-ext-include-data.md]+ - [traits for asserting the size and alignment relationships of types][0000-ext-layout-traits.md]+ - [zerocopy-style traits for safe initialization][0000-ext-byte-transmutation.md]+ - [bytemuck-style mechanisms for fallible reference casting][ext-ref-casting]+++## Codifying Language Layout Guarantees+Documentation of Rust's layout guarantees for a type are often spread across countless issues, pull requests, RFCs and various official resources. It can be very difficult to get a straight answer. When transmutation is involved, users must reason about the *combined* layout properties of the source and destination types.++This RFC proposes mechanisms that programmers will use to confidently answer such questions—by checking whether the `TransmuteFrom` and `TransmuteInto` traits are implemented.++## Expressing Library Layout Guarantees+There is no canonical way for crate authors to declare the SemVer layout guarantees of their types. Crate authors currently must state their layout guarantees using prose in their documentation. In contrast to structural stability (e.g., the declared visibility of fields), layout stability is expressed extra-linguistically.++This isn't satisfactory: guarantees expressed in prose outside of the Rust programming language are guarantees that cannot be reasoned about *inside* the language. Whereas `rustc` can dutifully deny programmers access to private fields, it is unable to prevent programmers from making unfounded expectations of types' in-memory layouts.++This RFC proposes simple-but-powerful [mechanisms][stability] for declaring layout stability guarantees.++## Expressing Layout Requirements+Similarly, there is no canonical way for crate authors to declare the layout requirements of generic abstractions over types that have certain layout properties. ++For instance, a common bit-packing technique involves using the relationship between allocations and alignment. If a type is aligned to 2<sup>n</sup>, then the *n* least significant bits of pointers to that type will equal `0`. These known-zero bits can be packed with data. Since alignment cannot be currently reasoned about at the type-level, it's currently impossible to bound instantiations of a generic parameter based on minimum alignment.++The mechanisms proposed by the RFC enable this, see [here][0000-ext-layout-traits.md].++# Guide-level explanation+[guide-level-explanation]: #guide-level-explanation++## Terminology & Concepts++### 📖 Transmutation+**Transmutation** is the act of reinterpreting the bytes corresponding to a value of one type as if they corresponded to a different type. Concretely, we mean the behavior of this function:+```rust+#[inline(always)]+unsafe fn transmute<Src, Dst>(src: Src) -> Dst+{+    #[repr(C)]+    union Transmute<Src, Dst> {+        src: ManuallyDrop<Src>,+        dst: ManuallyDrop<Dst>,+    }++    ManuallyDrop::into_inner(Transmute { src: ManuallyDrop::new(src) }.dst)+}+```++### 📖 Safer Transmutation+By **safer transmutation** we mean: *what `where` bound could we add to `transmute` restricts its type parameters `Src` and `Dst` in ways that statically limit the function's misuse?* Our answer to this question will ensure that transmutations are, by default, *well-defined*, *safe* and *stable*.++### 📖 Well-Definedness+A transmutation is ***well-defined*** if the mere act of transmuting a value from one type to another is not unspecified or undefined behavior.++### 📖 Safety+A well-defined transmutation is ***safe*** if *using* the transmuted value cannot violate memory safety.++### 📖 Stability+A safe transmutation is ***stable*** if the authors of the source type and destination types have indicated that the layouts of those types is part of their libraries' stability guarantees.++## Concepts in Depth++***Disclaimer:** While the high-level definitions of transmutation well-definedness, safety and stability are a core component of this RFC, the detailed rules and examples in this section are **not**. We expect that the initial implementation of `TransmuteFrom` may initially be considerably less sophisticated than the examples in this section (and thus forbid valid transmutations). Nonetheless, this section explores nuanced cases of transmutation well-definedness and safety to demonstrate that the APIs we propose can grow to handle that nuance.*+++### 📖 When is a transmutation well-defined?+[sound transmutation]: #-when-is-a-transmutation-well-defined+A transmutation is ***well-defined*** if the mere act of transmuting a value from one type to another is not unspecified or undefined behavior.++#### Well-Defined Representation+[`u8`]: core::u8+[`f32`]: core::f32++Transmutation is ill-defined if it occurs between types with unspecified representations.++Most of Rust's primitive types have specified representations. That is, the precise layout characteristics of [`u8`], [`f32`] is a documented and guaranteed aspect of those types.++In contrast, most `struct` and `enum` types defined without an explicit `#[repr(C)]` attribute do ***not*** have well-specified layout characteristics.++To ensure that types you've define are transmutable, you almost always (with very few exceptions) must mark them with the `#[repr(C)]` attribute.++#### Requirements on Owned Values+[transmute-owned]: #requirements-on-owned-values++Transmutations involving owned values must adhere to two rules to be well-defined. They must:+ * [preserve or broaden the bit validity][owned-validity], and+ * [preserve or shrink the size][owned-size].++##### Preserve or Broaden Bit Validity+[owned-validity]: #Preserve-or-Broaden-Bit-Validity+[`NonZeroU8`]: https://doc.rust-lang.org/beta/core/num/struct.NonZeroU8.html++The bits of any valid instance of the source type must be a bit-valid instance of the destination type.++For example, we are permitted to transmute a `Bool` into a [`u8`]:+```rust+#[derive(Default, PromiseTransmutableFrom, PromiseTransmutableInto)]+#[repr(u8)]+enum Bool {+    True = 1,+    False = 0,+}++let _ : u8 = transmute!(Bool::True);+let _ : u8 = transmute!(Bool::False);+```+<sup>+(Note: <code>#[derive(PromiseTransmutableFrom, PromiseTransmutableInto)]</code> annotation connotes that <i>all</i> aspects of <code>Bool</code>'s layout are part of its <a href="#-when-is-a-transmutation-stable">library stability guarantee</a>.)+</sup>++...because all possible instances of `Bool` are also valid instances of [`u8`]. However, transmuting a [`u8`] into a `Bool` is forbidden:+```rust+/* ⚠️ This example intentionally does not compile. */+let _ : Bool = transmute!(u8::default()); // Compile Error!+```+...because not all instances of [`u8`] are valid instances of `Bool`.++Another example: While laying out certain types, Rust may insert padding bytes between the layouts of fields. In the below example `Padded` has two padding bytes, while `Packed` has none:+```rust+#[repr(C)]+#[derive(Default, PromiseTransmutableFrom, PromiseTransmutableInto)]+struct Padded(pub u8, pub u16, pub u8);++#[repr(C)]+#[derive(Default, PromiseTransmutableFrom, PromiseTransmutableInto)]+struct Packed(pub u16, pub u16, pub u16);++assert_eq!(mem::size_of::<Packed>(), mem::size_of::<Padded>());+```++We may safely transmute from `Packed` to `Padded`:+```rust+let _ : Padded = transmute!(Packed::default());+```+...but not from `Padded` to `Packed`:+```rust+/* ⚠️ This example intentionally does not compile. */+let _ : Packed = transmute!(Padded::default()); // Compile Error!+```+...because doing so would expose two uninitialized padding bytes in `Padded` as if they were initialized bytes in `Packed`.++##### Preserve or Shrink Size+[owned-size]: #Preserve-or-Shrink-Size++It's well-defined to transmute into a type with fewer bytes than the source type; e.g.:+```rust+let _ : [u8; 16] = transmute!([u8; 32]::default());+```+This transmute truncates away the final sixteen bytes of the `[u8; 32]` value.++A value may ***not*** be transmuted into a type of greater size, if doing so would expose uninitialized bytes as initialized:+```rust+/* ⚠️ This example intentionally does not compile. */+let _ : [u8; 32] = transmute!([u8; 16]::default()); // Compile Error!+```++A `differing_sizes` lint reports warnings for invocations of `transmute!()` where the source and destination types are different sizes.++#### Requirements on References+[transmute-references]: #requirements-on-references++The [restrictions above that apply to transmuting owned values][transmute-owned] also apply to transmuting references. However, references carry a few *additional* restrictions.++A [well-defined transmutation] of references must:+ - [preserve or shrink size][reference-size],+ - [preserve or relax alignment][reference-alignment],+ - [preserve or shrink lifetimes][reference-lifetimes],+ - [preserve or shrink uniqueness][reference-mutability], and+ - and if the destination type is a mutate-able reference, [preserve validity][reference-validity].++##### Preserve or Shrink Size+[reference-size]: #Preserve-or-Shrink-Size++You may preserve or decrease the size of the referent type via transmutation:+```rust+let _: &[u8; 3] = transmute!(&[0u8; 9]);+```++However, you may **not**, under any circumstances, *increase* the size of the referent type:+```rust+/* ⚠️ This example intentionally does not compile. */+let _: &[u8; 9] = transmute!(&[0u8; 3]); // Compile Error!+```+##### Preserve or Relax Alignment+[reference-alignment]: #Preserve-or-Relax-Alignment++Unaligned loads are undefined behavior. You may transmute a reference into reference of more relaxed alignment:+```rust+let _: &[u8; 0] = transmute!(&[0u16; 0]);+```++However, you may **not** transmute a reference into a reference of more-restrictive alignment:+```rust+/* ⚠️ This example intentionally does not compile. */+let _: &[u16; 0] = transmute!(&[0u8; 0]); // Compile Error!+```++##### Preserve or Shrink Lifetimes+[reference-lifetimes]: #Preserve-or-Shrink-Lifetimes++You may transmute a reference into a reference of lesser lifetime:+```rust+fn shrink<'a>() -> &'a u8 {+    static long : &'static u8 = &16;+    transmute!(long)+}+```++However, you may **not** transmute a reference into a reference of greater lifetime:+```rust+/* ⚠️ This example intentionally does not compile. */+fn extend<'a>(short: &'a u8) -> &'static u8 {+    transmute!(short) // Compile Error!+}+```++##### Preserve or Shrink Uniqueness+[reference-mutability]: #Preserve-or-Shrink-Uniqueness++You may preserve or decrease the uniqueness of a reference through transmutation:+```rust+let _: &u8 = transmute!(&42u8);+let _: &u8 = transmute!(&mut 42u8);+```++However, you may **not** transmute a shared reference into a unique reference:+```rust+/* ⚠️ This example intentionally does not compile. */+let _: &mut u8 = transmute!(&42u8); // Compile Error!+```++##### Mutate-able References Must Preserve Validity+[reference-validity]: #Mutate-able-References-Must-Preserve-Validity++A mutate-able reference is:+- all unique (i.e., `&mut T`) references+- all shared (i.e., `&T`) references whose referent type contain any bytes produced by the contents of `UnsafeCell`.++Unlike transmutations of owned values, the transmutation of a mutate-able reference may also not expand the bit-validity of the referenced type. For instance:+```rust+/* ⚠️ This example intentionally does not compile. */+let mut x = NonZeroU8::new(42).unwrap();+{+    let y : &mut u8 = transmute!(&mut x); // Compile Error!+    *y = 0;+}++let z : NonZeroU8 = x;+```+If this example did not produce a compile error, the value of `z` would not be a bit-valid instance of its type, [`NonZeroU8`].++++### 📖 When is a transmutation safe?+A well-defined transmutation is ***safe*** if *using* the transmuted value safely cannot violate memory safety. Whereas well-definedness solely concerns the act of transmutation, *safety* is concerned with what might happen with a value *after* transmutation occurs. A well-defined transmutation must be safe if the involved types are *implicitly constructable*.++#### Implicit Constructability+A struct or enum variant is *fully implicitly constructable* at a given location only if, at that location, that type can be instantiated via its *implicit constructor*, and its fields are also *implicitly constructable*.++The *implicit constructor* of a struct or enum variant is the constructor Rust creates implicitly from its definition; e.g.:+```rust+struct Point<T> {+    x: T,+    y: T,+}++let p = Point { x: 4, y: 2 };+     // ^^^^^^^^^^^^^^^^^^^^ An instance of `Point` is created here, via its implicit constructor.+```++Limiting implicit constructability is the fundamental mechanism with which type authors build safe abstractions for `unsafe` code, whose soundness is dependent on preserving invariants on fields. Usually, this takes the form of restricting the visibility of fields. For instance, consider the type `NonEmptySlice`, which enforces a validity constraint on its fields via its constructor:++```rust+pub mod crate_a {++    #[repr(C)]+    pub struct NonEmptySlice<'a, T> {+        data: *const T,+        len: usize,+        lifetime: core::marker::PhantomData<&'a ()>,+    }++    impl<'a, T> NonEmptySlice<'a, T> {+        pub fn from_array<const N: usize>(arr: &'a [T; N], len: usize) -> Self {+            assert!(len <= N);+            assert!(len > 0);+            Self {+                data: arr as *const T,+                len,+                lifetime: core::marker::PhantomData,+            }+        }++        pub fn first(&self) -> &'a T {+            unsafe { &*self.data }+        }+    }++}+```+It is sound for `first` to be a *safe* method is because the `from_array` constructor ensures that `data` is safe to dereference, and because `from_array` is the *only* way to safely initialize `NonEmptySlice` outside of `crate_a` (note that `NonEmptySlice`'s fields are *not* `pub`). As a rule: any field that is not marked `pub` should be assumed to be private *because* it is subject to safety invariants.++Unfortunately, field visibility modifiers are not a surefire indicator of whether a type is *fully* implicitly constructable. A type author may restrict the implicit constructability of a type even in situations where all fields of that type (*and all fields of those fields*) are `pub`; consider:+```rust+pub mod crate_a {++    #[repr(C)]+    pub struct NonEmptySlice<'a, T>(pub private::NonEmptySliceInner<'a, T>);++    impl<'a, T> NonEmptySlice<'a, T> {+        pub fn from_array<const N: usize>(arr: &'a [T; N], len: usize) -> Self {+            assert!(len <= N && len > 0);+            Self(+                private::NonEmptySliceInner {+                    data: arr as *const T,+                    len,+                    lifetime: core::marker::PhantomData,+                }+            )+        }++        pub fn first(&self) -> &'a T {+            unsafe { &*self.0.data }+        }+    }++    // introduce a private module to avoid `private_in_public` error (E0446):+    pub(crate) mod private {+        #[repr(C)]+        pub struct NonEmptySliceInner<'a, T> {+            pub data: *const T,+            pub len: usize,+            pub lifetime: core::marker::PhantomData<&'a ()>,+        }+    }++}+```+In the above example, the definitions of both `NonEmptySlice` and its field `NonEmptySliceInner` are marked `pub`, and all fields of these types are marked `pub`. However, `NonEmptySlice` is *not* fully implicitly constructible outside of `crate_a`, because the module containing `NonEmptySliceInner` is not visibile outside of `crate_a`.++#### Constructability and Transmutation+Transmutation supplies a mechanism for constructing instances of a type *without* invoking its implicit constructor, nor any constructors defined by the type's author. In the previous examples, it would be *unsafe* to transmute `[usize; 2]` into `NonEmptySlice` outside `crate_a`, because subsequent *safe* use of that value (namely, calling `first`) would violate memory safety:+```rust+/* ⚠️ This example intentionally does not compile. */+// [usize; 2] ⟶ NonEmptySlice+let _: NonEmptySlice<'static, u8> = transmute!([0usize; 2]); // Compile Error: `NonEmptySlice<_, _>` is not constructible here.+```+If a field is private, then instantiating or modifying it via transmutation is not, generally speaking, safe.++For transmutations where the destination type involves mutate-able references, the constructability of the *source* type is also relevant. Consider:+```rust+/* ⚠️ This example intentionally does not compile. */+let arr = [0u8, 1u8, 2u8];+let mut x = NonEmptySlice::from_array(&arr, 2);+{+    // &mut NonEmptySlice ⟶ &mut [usize; 2]+    let y : &mut u128 = transmute!(&mut x) // Compile Error! `&mut NonEmptySlice` is not constructible here.+    *y[0] = 0;+    *y[1] = 0;+}++let z : NonEmptySlice<u8> = x;+```+If this example did not produce a compile error, the value of `z` would not be a safe instance of its type, `NonEmptySlice`, because `z.first()` would dereference a null pointer.++#### Constructability and Scope+Whether a type is fully implicitly constructable will depends on the *scope* in which that question is asked. Consider:+```rust+pub mod a {++    #[repr(C)] pub struct Foo(private::Bar);++    mod private {+        #[repr(C)] pub struct Bar;+    }++    // `Foo` is fully implicitly constructible in this module.+    const _: Foo = Foo { private::Bar };++    // Thus, `Foo` is transmutable in this module!+    const _: Foo = transmute!(());+}++pub mod b {+    use super::a;++    // `Foo` is NOT fully implicitly constructible in this module.+    const _: Foo = a::Foo { a::private::Bar }; // Compile Error: the module `a::private` is private.++    // Thus, `Foo` is NOT transmutable in this module:+    const _: Foo = transmute!(()); // Compile Error: `Foo` is not constructible here.+}+```++The `transmute!` macro provides a shorthand for safely transmuting a value using its invocation scope as its reference frame:+```rust+pub macro transmute($expr: expr) {+    TransmuteFrom::<_, Here!()>::transmute_from($expr)+    //              ┯  ━━━┯━━━+    //              │     ┕ check constructability from `transmute!`'s invocation scope+    //              ┕ the destination type of the transmute (`_` used to infer the type from context)+}+```+The `Here!()` macro produces a type that uniquely identifies its invocation scope.++This explicit `Scope` parameter of `TransmuteFrom` makes possible the creation of generic abstractions over it. For instance, consider a hypothetical `FromZeros` trait that indicates whether `Self` is safely initializable from a a sufficiently large buffer of zero-initialized bytes:+```rust+pub mod zerocopy {+    pub unsafe trait FromZeros {+        /// Safely initialize `Self` from zeroed bytes.+        fn zeroed() -> Self;+    }++    #[derive(Copy, Clone, PromiseTransmutableInto)]+    #[repr(u8)]+    enum Zero {+        Zero = 0u8+    }++    unsafe impl<Dst> FromZeros<Neglect> for Dst+    where+        Dst: TransmuteFrom<[Zero; usize::MAX], ??? >,+    {+        fn zeroed() -> Self {+            [Zero; size_of::<Self>].transmute_into()+        }+    }+}+```+The above definition leaves ambiguous (`???`) the scope in which the constructability of `Dst` is checked: is it from the perspective of where this trait is defined, or where this trait is *used*? You probably do *not* intend for this trait to *only* be usable with `Dst` types that are defined in the same scope as the `FromZeros` trait!++Adding an explicit `Scope` parameter to `FromZeros` makes this unambiguous; the transmutability of `Dst` should be assessed from where the trait is used, *not* where it is defined:+```rust+pub unsafe trait FromZeros<Scope> {+    /// Safely initialize `Self` from zeroed bytes.+    fn zeroed() -> Self;+}++unsafe impl<Dst, Scope> FromZeros<Scope> for Dst+where+    Dst: TransmuteFrom<[Zero; usize::MAX], Scope>+{+    fn zeroed() -> Self {+        [Zero; size_of::<Self>].transmute_into()+    }+}+```++A thid-party could then use `FromZeros` like so:+```rust+use zerocopy::FromZeros;++#[derive(PromiseTransmutableInto)]+#[repr(C)]+struct Foo {+    ...+}++// Initialize `Foo` from zero-initialized bytes.+let _: Foo = FromZeros::<_, Here!()>::zeroed();+```+++### 📖 When is a transmutation stable?+[stability]: #-when-is-a-transmutation-stable++Since the well-definedness and safety of a transmutation is affected by the layouts of the source and destination types, changes to those types' layouts may cause code which previously compiled to produce errors. In other words, transmutation causes a type's layout to become part of that type's API for the purposes of SemVer stability.++The question is, then: *how can the author of a type reason about transmutations they did not write, from-or-to types they did not write?* We address this problem by introducing two traits which both allow an author to opt-in to stability guarantees for their types, and allow third-parties to reason at compile-time about what guarantees are provided for such types.++#### `PromiseTransmutableFrom` and `PromiseTransmutableInto`++You may declare the stability guarantees of your type by implementing one or both of two traits:+```rust+pub trait PromiseTransmutableFrom<Scope>+{+    type Archetype: TransmuteInto<Self, Scope, NeglectStability>;+}++pub trait PromiseTransmutableInto<Scope>+{+    type Archetype: TransmuteFrom<Self, Scope, NeglectStability>;+}+```++To implement each of these traits, you must specify an `Archetype`. An `Archetype` is a type whose layout exemplifies the extremities of your stability promise (i.e., the least/most constrained type for which it is valid to transmute your type into/from).++By implementing `PromiseTransmutableFrom`, you promise that your type is guaranteed to be safely transmutable *from* `PromiseTransmutableFrom::Archetype`. Conversely, by implementing `PromiseTransmutableInto`, you promise that your type is guaranteed to be safely transmutable *into* `PromiseTransmutableInto::Archetype`.++You are free to change the layout of your type however you like between minor crate versions so long as that change does not violates these promises. These two traits are capable of expressing simple and complex stability guarantees.++#### Stability & Transmutation+Together with the `PromiseTransmutableFrom` and `PromiseTransmutableInto` traits, this impl of `TransmuteFrom` constitutes the formal definition of transmutation stability:+```rust+unsafe impl<Src, Dst, Scope> TransmuteFrom<Src, Scope> for Dst+where+    Src: PromiseTransmutableInto<Scope>,+    Dst: PromiseTransmutableFrom<Scope>,++    Dst::Archetype: TransmuteFrom<Src::Archetype, Scope, NeglectStability>+{}+```+Why is this safe? Can we really safely judge whether `Dst` is transmutable from `Src` by assessing the transmutability of two different types? Yes! Transmutability is *transitive*. Concretely, if we can safely transmute:+  - `Src` to `Src::Archetype` (enforced by `Src: PromiseTransmutableInto`), and+  - `Dst::Archetype` to `Dst` (enforced by `Dst: PromiseTransmutableFrom`), and+  - `Src::Archetype` to `Dst::Archetype` (enforced by `Dst::Archetype: TransmuteFrom<Src::Archetype, Scope, NeglectStability>`),++...then it follows that we can safely transmute `Src` to `Dst` in three steps:+  1. we transmute `Src` to `Src::Archetype`,+  2. we transmute `Src::Archetype` to `Dst::Archetype`,+  3. we transmute `Dst::Archetype` to `Dst`.++#### Common Use-Case: As-Stable-As-Possible+[stability-common]: #common-use-case-as-stable-as-possible+To promise that all transmutations which are currently safe for your type will remain so in the future, simply annotate your type with:+```rust+#[derive(PromiseTransmutableFrom, PromiseTransmutableInto)]+#[repr(C)]+pub struct Foo(pub Bar, pub Baz);+```+This expands to:+```rust+#[repr(C)]+pub struct Foo(pub Bar, pub Baz);++/// Generated `PromiseTransmutableFrom` for `Foo`+const _: () = {+    use core::transmute::stability::PromiseTransmutableFrom;++    #[repr(C)]+    pub struct TransmutableFromArchetype<Scope>(+        pub <Bar as PromiseTransmutableFrom<Scope>>::Archetype,+        pub <Baz as PromiseTransmutableFrom<Scope>>::Archetype,+    );++    impl<Scope> PromiseTransmutableFrom<Scope> for TransmutableFromArchetype<Scope> {+        type Archetype = Self;+    }++    impl<Scope> PromiseTransmutableFrom<Scope> for Foo {+        type Archetype = TransmutableFromArchetype<Scope>;+    }+};++/// Generated `PromiseTransmutableInto` for `Foo`+const _: () = {+    use core::transmute::stability::PromiseTransmutableInto;++    #[repr(C)]+    pub struct TransmutableIntoArchetype<Scope>(+        pub <Bar as PromiseTransmutableInto<Scope>>::Archetype,+        pub <Baz as PromiseTransmutableInto<Scope>>::Archetype,+    );++    impl<Scope> PromiseTransmutableInto<Scope> for TransmutableIntoArchetype<Scope> {+        type Archetype = Self;+    }++    impl<Scope> PromiseTransmutableInto<Scope> for Foo<Scope> {+        type Archetype = TransmutableIntoArchetype<Scope>;+    }+};+```+Since deriving *both* of these traits together is, by far, the most common use-case, we [propose][extension-promisetransmutable-shorthand] `#[derive(PromiseTransmutable)]` as an ergonomic shortcut.+++#### Uncommon Use-Case: Weak Stability Guarantees+[stability-uncommon]: #uncommon-use-case-weak-stability-guarantees++We also can specify *custom* `Archetype`s to finely constrain the set of transmutations we are willing to make stability promises for. Consider, for instance, if we want to leave ourselves the future leeway to change the alignment of a type `Foo` without making a SemVer major change:+```rust+#[repr(C)]+pub struct Foo(pub Bar, pub Baz);+```+The alignment of `Foo` affects transmutability of `&Foo`. A `&Foo` cannot be safely transmuted from a `&Bar` if the alignment requirements of `Foo` exceed those of `Bar`. If we don't want to promise that `&Foo` is stably transmutable from virtually *any* `Bar`, we simply make `Foo`'s `PromiseTransmutableFrom::Archetype` a type with maximally strict alignment requirements:+```rust+const _: () = {+    use core::transmute::stability::PromiseTransmutableFrom;++    // 2^29 is currently the maximum alignment+    #[repr(C, align(536870912))]+    pub struct TransmutableFromArchetype<Scope>(+        pub <Bar as PromiseTransmutableFrom<Scope>>::Archetype,+        pub <Baz as PromiseTransmutableFrom<Scope>>::Archetype,+    );++    impl<Scope> PromiseTransmutableFrom<Scope> for Foo {+        type Archetype = TransmutableFromArchetype<Scope>;+    }+};+```+Conversely, a `&Foo` cannot be safely transmuted *into* a `&Bar` if the alignment requirements of `Bar` exceed those of `Foo`. We reduce this set of stable transmutations by making `PromiseTransmutableFrom::Archetype` a type with minimal alignment requirements:+```rust+const _: () = {+    use core::transmute::stability::PromiseTransmutableInto;++    #[repr(C, packed(1))]+    pub struct TransmutableIntoArchetype<Scope>(+        pub <Bar as TransmutableIntoArchetype<Scope>>::Archetype,+        pub <Baz as TransmutableIntoArchetype<Scope>>::Archetype,+    );++    impl<Scope> PromiseTransmutableInto<Scope> for Foo {+        type Archetype = TransmutableIntoArchetype<Scope>;+    }+};+```+Given these two stability promises, we are free to modify the alignment of `Foo` in SemVer-minor changes without running any risk of breaking dependent crates.+++## Mechanisms of Transmutation++Two traits provide mechanisms for transmutation between types: +```rust+// this trait is implemented automagically by the compiler+#[lang = "transmute_from"]+pub unsafe trait TransmuteFrom<Src: ?Sized, Scope, Neglect = ()>+where+    Neglect: TransmuteOptions,+{+    #[inline(always)]+    fn transmute_from(src: Src) -> Self+    where+        Src: Sized,+        Self: Sized,+        Neglect: SafeTransmuteOptions,+    {+        unsafe { Self::unsafe_transmute_from(src) }+    }++    #[inline(always)]+    unsafe fn unsafe_transmute_from(src: Src) -> Self+    where+        Src: Sized,+        Self: Sized,+        Neglect: TransmuteOptions,+    {+        use core::mem::ManuallyDrop;++        #[repr(C)]+        union Transmute<Src, Dst> {+            src: ManuallyDrop<Src>,+            dst: ManuallyDrop<Dst>,+        }++        unsafe {+            ManuallyDrop::into_inner(Transmute { src: ManuallyDrop::new(src) }.dst)+        }+    }+}++// implemented in terms of `TransmuteFrom`+pub unsafe trait TransmuteInto<Dst: ?Sized, Scope, Neglect = ()>+where+    Neglect: TransmuteOptions,+{+    fn transmute_into(self) -> Dst+    where+        Self: Sized,+        Dst: Sized,+        Neglect: SafeTransmuteOptions;++    unsafe fn unsafe_transmute_into(self) -> Dst+    where+        Self: Sized,+        Dst: Sized,+        Neglect: TransmuteOptions;+}++unsafe impl<Src, Dst, Scope, Neglect> TransmuteInto<Dst, Scope, Neglect> for Src+where+    Src: ?Sized,+    Dst: ?Sized + TransmuteFrom<Src, Scope, Neglect>,+    Neglect: TransmuteOptions,+{+    ...+}+```++In the above definitions, `Src` represents the source type of the transmutation, `Dst` represents the destination type of the transmutation, and `Neglect` is a parameter that [encodes][options] which static checks the compiler ought to neglect when considering if a transmutation is valid. The default value of `Neglect` is `()`, which reflects that, by default, the compiler does not neglect *any* static checks.++### Neglecting Static Checks+[options]: #Neglecting-Static-Checks++The default value of the `Neglect` parameter, `()`, statically forbids transmutes that are unsafe, ill-defined, or unstable. However, you may explicitly opt-out of some static checks; e.g.:++| Transmute Option    | Usable With                                             |+|---------------------|---------------------------------------------------------|+| `NeglectStabilty`   | `transmute_{from,into}`, `unsafe_transmute_{from,into}` |+| `NeglectAlignment`  | `unsafe_transmute_{from,into}`                          |+| `NeglectValidity`   | `unsafe_transmute_{from,into}`                          |++`NeglectStabilty` implements the `SafeTransmuteOptions` and `TransmuteOptions` marker traits, as it can be used in both safe and unsafe code. The selection of multiple options is encoded by grouping them as a tuple; e.g., `(NeglectAlignment, NeglectValidity)` is a selection of both the `NeglectAlignment` and `NeglectValidity` options.++We introduce two marker traits which serve to group together the options that may be used with safe transmutes, and those which may be used with `unsafe` transmutes:+```rust+pub trait SafeTransmuteOptions: private::Sealed+{}++pub trait TransmuteOptions: SafeTransmuteOptions+{}++impl SafeTransmuteOptions for () {}+impl TransmuteOptions for () {}+```++#### `NeglectStability`+[`NeglectStability`]: #neglectstability++By default, `TransmuteFrom` and `TransmuteInto`'s methods require that the [layouts of the source and destination types are SemVer-stable][stability]. The `NeglectStability` option disables this requirement.+```rust+pub struct NeglectStability;++impl SafeTransmuteOptions for NeglectStability {}+impl TransmuteOptions for NeglectStability {}+```++Prior to the adoption of the [stability declaration traits][stability], crate authors documented the layout guarantees of their types with doc comments. The `TransmuteFrom` and `TransmuteInto` traits and methods may be used with these types by requesting that the stability check is neglected; for instance:++```rust+fn serialize<W: Write, Scope>(val : LibraryType, dst: W) -> std::io::Result<()>+where+    LibraryType: TransmuteInto<[u8; size_of::<LibraryType>()], Scope, NeglectStability>+{+    ...+}+```++Neglecting stability over-eagerly cannot cause ill-definedness or unsafety. For this reason, it is the only transmutation option available on the safe methods `transmute_from` and `transmute_into`. However, neglecting stability over-eagerly may cause your code to behave incorrectly or cease compiling if the authors of the source and destination types make changes that affect their layout.++By using the `NeglectStability` option to transmute types you do not own, you are committing to ensure that your reliance on these types' layouts is consistent with their documented stability guarantees.++#### `NeglectAlignment`+[ext-ref-casting]: #NeglectAlignment++By default, `TransmuteFrom` and `TransmuteInto`'s methods require that, when transmuting references, the minimum alignment of the destination's referent type is no greater than the minimum alignment of the source's referent type. The `NeglectAlignment` option disables this requirement.+```rust+pub struct NeglectAlignment;++impl TransmuteOptions for NeglectAlignment {}+```++By using the `NeglectAlignment` option, you are committing to ensure that the transmuted reference satisfies the alignment requirements of the destination's referent type. For instance:+```rust+/// Try to convert a `&T` into `&U`.+///+/// This produces `None` if the referent isn't appropriately+/// aligned, as required by the destination type.+pub fn try_cast_ref<'t, 'u, Scope, T, U>(src: &'t T) -> Option<&'u U>+where+    &'t T: TransmuteInto<&'u U, Scope, NeglectAlignment>,+{+    if (src as *const T as usize) % align_of::<U>() != 0 {+        None+    } else {+        // Safe because we dynamically enforce the alignment+        // requirement, whose static check we chose to neglect.+        Some(unsafe { src.unsafe_transmute_into() })+    }+}+```++#### `NeglectValidity`+By default, `TransmuteFrom` and `TransmuteInto`'s methods require that all instantiations of the source type are guaranteed to be valid instantiations of the destination type. This precludes transmutations which *might* be valid depending on the source value:+```rust+#[derive(PromiseTransmutableFrom, PromiseTransmutableInto)]+#[repr(u8)]+enum Bool {+    True = 1,+    False = 0,+}++/* ⚠️ This example intentionally does not compile. */+let _ : Bool  = transmute!(some_u8_value); // Compile Error!+```+The `NeglectValidity` option disables this check.+```rust+pub struct NeglectValidity;++impl TransmuteOptions for NeglectValidity {}+```++By using the `NeglectValidity` option, you are committing to ensure dynamically source value is a valid instance of the destination type. For instance:+```rust+#[derive(PromiseTransmutableFrom, PromiseTransmutableInto)]+#[repr(u8)]+enum Bool {+    True = 1,+    False = 0,+}++pub trait TryIntoBool<Scope>+{+    fn try_into_bool(self) -> Option<Bool>;+}++impl<T, Scope> TryIntoBool<Scope> for T+where+    T: TransmuteInto<u8>,+    u8: TransmuteInto<Bool, Scope, NeglectValidity>+{+    fn try_into_bool(self) -> Option<Bool> {+        let val: u8 = self.transmute_into();++        if val > 1 {+            None+        } else {+            // Safe, because we've first verified that+            // `val` is a bit-valid instance of a boolean.+            Some(unsafe {val.unsafe_transmute_into()})+        }+    }+}+```++Even with `NeglectValidity`, the compiler will statically reject transmutations that cannot possibly be valid:+```rust+#[derive(PromiseTransmutableInto)]+#[repr(C)] enum Foo { A = 24 }++#[derive(PromiseTransmutableFrom)]+#[repr(C)] enum Bar { Z = 42 }++let _ = <Bar as TransmuteFrom<Foo, Here!(), NeglectValidity>::unsafe_transmute_from(Foo::N) // Compile error!+```++# Reference-level explanation+[reference-level-explanation]: #reference-level-explanation++## Implementation Guidance+Three items in this RFC require special compiler support:+  - `Here!()`+  - `Constructible` (a private implementation detail of `TransmuteFrom`)+  - `TransmuteFrom`++### Implementing `Here!()`+The `Here!` macro produces a type that uniquely identifies its invocation scope. For instance:+```rust+use static_assertions::*;++type A = Here!();+type B = Here!();++/* Types A and !::B are equal */+assert_type_eq_all!(A, B);++trait Foo {+    type C;+    const CONST: ();+}++impl Foo for ! {+    type C = Here!();++    const CONST: () = {+        type D = Here!();++        /* A, B and !::C are equal */+        assert_type_eq_all!(A, B, !::C);++        /* C and D are NOT equal; C and D inhabit different scopes */+        assert_type_ne_all!(C, D);+    };+}+```+Scope types should (as much as possible) pretty print in compiler error messages as their definition path.++These scope types should generated with `pub(self)` visibility. We are not currently aware of any reason why publicly re-exporting a scope type via a type alias would be a good idea; restricting the visibility of these types will warn users against doing so. If compelling use-cases for re-exported scope types are discovered in the future, a broader visibility could be used instead without breaking backwards compatibility.++### Implementing `Constructible`+The compiler implements `Constructible<Scope>` for `T` if `T` is fully implicitly constructible in the scope uniquely identified by the type `Scope`.++A type `T` is fully implicitly constructible in a particular scope if:+  - `T`'s implicit constructor is reachable from the scope, and either:+    - `T` has no fields, or+    - `T`'s fields are fully implicitly constructible from the scope.++The `Constructible` trait does not ever need to be made stable, or even visible (à la the virtual `Freeze` trait). It is merely a useful device for implementing `TransmuteFrom`.++### Implementing `TransmuteFrom`+The implementation of `TransmuteFrom` is completely internal to the compiler (à la [`Sized`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyS.html#method.is_sized) and [`Freeze`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyS.html#method.is_freeze)).++#### Stability and Transmutation+Unless `NeglectStability` is used as a `Neglect` option, a `Src` is *stably* transmutable into `Dst` in a given `Scope` if:+  1. `Src: PromiseTransmutableInto`+  2. `Dst: PromiseTransmutableFrom`+  3. `Dst::Archetype: TransmuteFrom<Src::Archetype, Scope, Neglect>`++#### Constructability and Transmutation+Unless `NeglectConstructability` is used as `Neglect` option, a `Src` is *safely* transmutable into `Dst` in a given `Scope` if:+  1. `Dst: Constructible<Scope>`+  2. `Dst: TransmuteFrom<Src, Scope, Neglect>`++If `Src` is a mutatable reference, then additionally:+  1. `Src: Constructible<Scope>`++### Implementing `differing_sizes`+The `differing_sizes` lint reports a compiler warning when the source and destination types of a `transmute!()`, `transmute_into` or `transmute_from` invocation differ. This lint shall be warn-by-default.++### Minimal Useful Stabilization Surface+Stabilizing *only* these items of the Initial Smart Implementation will cover many use-cases:+  - `transmute!()`+  - `#[derive(PromiseTransmutableFrom)]`+  - `#[derive(PromiseTransmutableInto)]`++(If the [`PromiseTransmutable` shorthand extension][extension-promisetransmutable-shorthand] is accepted, this may be further reduced to just *two* items: `transmute!()` and `#[derive(PromiseTransmutable)]`.)++To define traits that generically abstract over `TransmuteFrom`, these items must be stabilized:+  - `Here!()`+  - `TransmuteFrom`+  - `TransmuteOptions` and `SafeTransmuteOptions`++Stabilizing `PromiseTransmutableFrom` and `PromiseTransmutableInto` will additionally allow end-users make limited stability promises, and to make stability promises for types where `derive` is too restrictive (namely, types containing `PhantomData`).++Additionally stabilizing `TransmuteInto` and `NeglectStability` will additionally allow end-users to implement `PromiseTransmutableFrom` and `PromiseTransmutableInto` in cases where the `Archetype`'s trait bounds must be repeated for lack of [implied bounds](https://github.com/rust-lang/rust/issues/44491); e.g.:+```rust+impl<T, N, Scope> PromiseTransmutableFrom<Scope> for GenericArray<T, N>+where+    T: PromiseTransmutableFrom<Scope>,+    N: ArrayLength<T>,++    // for lack of implied bounds, we must repeat the bounds on `Archetype`,+    // which requires naming `NeglectStability`+    GenericArray<T::Archetype, N>: TransmuteInto<Self, Scope, NeglectStability>+{+    type Archetype = GenericArray<T::Archetype, N>;+}+```+++### Complete API Surface+[minimal-impl]: #Listing-for-Initial-Minimal-Implementation+This listing is both a **canonical specification** of this RFC's API surface ([playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=ec5c618d843acd7c40855ebfb386d49a)):+```rust+#![feature(untagged_unions,const_fn,const_fn_union)] // for the impl of unsafe_transmute_from+#![feature(const_generics)] // for stability declarations on `[T; N]`+#![feature(decl_macro)] // for stub implementations of derives+#![feature(never_type)] // for stability declarations on `!`+#![allow(warnings)]++/// Transmutation conversions.+// suggested location: `core::convert`+pub mod transmute {++    use {options::*, stability::*};++    /// Safely and stably transmute $expr+    pub macro transmute($expr: expr) {+        TransmuteFrom::<_, Here!()>::transmute_from($expr)+    }++    /// `Self: TransmuteInto<Dst, Neglect`, if the compiler accepts the stability,+    /// safety, and soundness of transmuting `Self` into `Dst`, notwithstanding+    /// a given set of static checks to `Neglect`.+    pub unsafe trait TransmuteInto<Dst: ?Sized, Scope, Neglect = ()>+    where+        Neglect: TransmuteOptions,+    {+        /// Reinterpret the bits of a value of one type as another type, safely.+        fn transmute_into(self) -> Dst+        where+            Self: Sized,+            Dst: Sized,+            Neglect: SafeTransmuteOptions;++        /// Reinterpret the bits of a value of one type as another type, potentially unsafely.+        ///+        /// The onus is on you to ensure that calling this method is safe.+        unsafe fn unsafe_transmute_into(self) -> Dst+        where+            Self: Sized,+            Dst: Sized,+            Neglect: TransmuteOptions;+    }++    unsafe impl<Src, Dst, Scope, Neglect> TransmuteInto<Dst, Scope, Neglect> for Src+    where+        Src: ?Sized,+        Dst: ?Sized + TransmuteFrom<Src, Scope, Neglect>,+        Neglect: TransmuteOptions,+    {+        #[inline(always)]+        fn transmute_into(self) -> Dst+        where+            Self: Sized,+            Dst: Sized,+            Neglect: SafeTransmuteOptions,+        {+            Dst::transmute_from(self)+        }++        #[inline(always)]+        unsafe fn unsafe_transmute_into(self) -> Dst+        where+            Self: Sized,+            Dst: Sized,+            Neglect: TransmuteOptions,+        {+            unsafe { Dst::unsafe_transmute_from(self) }+        }+    }++    /// `Self: TransmuteInto<Src, Neglect`, if the compiler accepts the stability,+    /// safety, and soundness of transmuting `Src` into `Self`, notwithstanding+    /// a given set of static checks to `Neglect`.+    pub unsafe trait TransmuteFrom<Src: ?Sized, Scope, Neglect = ()>+    where+        Neglect: TransmuteOptions,+    {+        /// Reinterpret the bits of a value of one type as another type, safely.+        #[inline(always)]+        fn transmute_from(src: Src) -> Self+        where+            Src: Sized,+            Self: Sized,+            Neglect: SafeTransmuteOptions,+        {+            unsafe { Self::unsafe_transmute_from(src) }+        }++        /// Reinterpret the bits of a value of one type as another type, potentially unsafely.+        ///+        /// The onus is on you to ensure that calling this function is safe.+        #[inline(always)]+        unsafe fn unsafe_transmute_from(src: Src) -> Self+        where+            Src: Sized,+            Self: Sized,+            Neglect: TransmuteOptions,+        {+            use core::mem::ManuallyDrop;++            #[repr(C)]+            union Transmute<Src, Dst> {+                src: ManuallyDrop<Src>,+                dst: ManuallyDrop<Dst>,+            }++            unsafe {+                ManuallyDrop::into_inner(Transmute { src: ManuallyDrop::new(src) }.dst)+            }+        }+    }++    /// A type is always transmutable from itself.+    // This impl will be replaced with a compiler-supported for arbitrary source and destination types.+    unsafe impl<T: ?Sized, Scope, Neglect> TransmuteFrom<T, Scope, Neglect> for T+    where+        Neglect: TransmuteOptions+    {}++    /// Traits for declaring the SemVer stability of types.+    pub mod stability {++        use super::{TransmuteFrom, TransmuteInto, options::NeglectStability};++        /// Declare that transmuting `Self` into `Archetype` is SemVer-stable.+        pub trait PromiseTransmutableInto<Scope> {+            /// The `Archetype` must be safely transmutable from `Self`.+            type Archetype: TransmuteFrom<Self, Scope, NeglectStability>;+        }++        /// Declare that transmuting `Self` from `Archetype` is SemVer-stable.+        pub trait PromiseTransmutableFrom<Scope>+        {+            /// The `Archetype` must be safely transmutable into `Self`.+            type Archetype: TransmuteInto<Self, Scope, NeglectStability>;+        }+++        /// Derive macro generating an impl of the trait `PromiseTransmutableInto`.+        //#[rustc_builtin_macro]+        pub macro PromiseTransmutableInto($item:item) {+            /* compiler built-in */+        }++        /// Derive macro generating an impl of the trait `PromiseTransmutableFrom`.+        //#[rustc_builtin_macro]+        pub macro PromiseTransmutableFrom($item:item) {+            /* compiler built-in */+        }+++        impl<Scope> PromiseTransmutableInto<Scope> for     ! {type Archetype = Self;}+        impl<Scope> PromiseTransmutableFrom<Scope> for     ! {type Archetype = Self;}+        impl<Scope> PromiseTransmutableInto<Scope> for    () {type Archetype = Self;}+        impl<Scope> PromiseTransmutableFrom<Scope> for    () {type Archetype = Self;}++        impl<Scope> PromiseTransmutableInto<Scope> for   f32 {type Archetype = Self;}+        impl<Scope> PromiseTransmutableFrom<Scope> for   f32 {type Archetype = Self;}+        impl<Scope> PromiseTransmutableInto<Scope> for   f64 {type Archetype = Self;}+        impl<Scope> PromiseTransmutableFrom<Scope> for   f64 {type Archetype = Self;}++        impl<Scope> PromiseTransmutableInto<Scope> for    i8 {type Archetype = Self;}+        impl<Scope> PromiseTransmutableFrom<Scope> for    i8 {type Archetype = Self;}+        impl<Scope> PromiseTransmutableInto<Scope> for   i16 {type Archetype = Self;}+        impl<Scope> PromiseTransmutableFrom<Scope> for   i16 {type Archetype = Self;}+        impl<Scope> PromiseTransmutableInto<Scope> for   i32 {type Archetype = Self;}+        impl<Scope> PromiseTransmutableFrom<Scope> for   i32 {type Archetype = Self;}+        impl<Scope> PromiseTransmutableInto<Scope> for   i64 {type Archetype = Self;}+        impl<Scope> PromiseTransmutableFrom<Scope> for   i64 {type Archetype = Self;}+        impl<Scope> PromiseTransmutableInto<Scope> for  i128 {type Archetype = Self;}+        impl<Scope> PromiseTransmutableFrom<Scope> for  i128 {type Archetype = Self;}+        impl<Scope> PromiseTransmutableInto<Scope> for isize {type Archetype = Self;}+        impl<Scope> PromiseTransmutableFrom<Scope> for isize {type Archetype = Self;}++        impl<Scope> PromiseTransmutableInto<Scope> for    u8 {type Archetype = Self;}+        impl<Scope> PromiseTransmutableFrom<Scope> for    u8 {type Archetype = Self;}+        impl<Scope> PromiseTransmutableInto<Scope> for   u16 {type Archetype = Self;}+        impl<Scope> PromiseTransmutableFrom<Scope> for   u16 {type Archetype = Self;}+        impl<Scope> PromiseTransmutableInto<Scope> for   u32 {type Archetype = Self;}+        impl<Scope> PromiseTransmutableFrom<Scope> for   u32 {type Archetype = Self;}+        impl<Scope> PromiseTransmutableInto<Scope> for   u64 {type Archetype = Self;}+        impl<Scope> PromiseTransmutableFrom<Scope> for   u64 {type Archetype = Self;}+        impl<Scope> PromiseTransmutableInto<Scope> for  u128 {type Archetype = Self;}+        impl<Scope> PromiseTransmutableFrom<Scope> for  u128 {type Archetype = Self;}+        impl<Scope> PromiseTransmutableInto<Scope> for usize {type Archetype = Self;}+        impl<Scope> PromiseTransmutableFrom<Scope> for usize {type Archetype = Self;}++        use core::marker::PhantomData;+        impl<T: ?Sized, Scope> PromiseTransmutableInto<Scope> for PhantomData<T> { type Archetype = Self; }+        impl<T: ?Sized, Scope> PromiseTransmutableFrom<Scope> for PhantomData<T> { type Archetype = Self; }+++        impl<T, Scope, const N: usize> PromiseTransmutableInto<Scope> for [T; N]+        where+            T: PromiseTransmutableInto<Scope>,+            [T::Archetype; N]: TransmuteFrom<Self, Scope, NeglectStability>+        {+            type Archetype = [T::Archetype; N];+        }++        impl<T, Scope, const N: usize> PromiseTransmutableFrom<Scope> for [T; N]+        where+            T: PromiseTransmutableFrom<Scope>,+            [T::Archetype; N]: TransmuteInto<Self, Scope, NeglectStability>+        {+            type Archetype = [T::Archetype; N];+        }+++        impl<T: ?Sized, Scope> PromiseTransmutableInto<Scope> for *const T+        where+            T: PromiseTransmutableInto<Scope>,+            *const T::Archetype: TransmuteFrom<Self, Scope, NeglectStability>+        {+            type Archetype = *const T::Archetype;+        }++        impl<T: ?Sized, Scope> PromiseTransmutableFrom<Scope> for *const T+        where+            T: PromiseTransmutableFrom<Scope>,+            *const T::Archetype: TransmuteInto<Self, Scope, NeglectStability>+        {+            type Archetype = *const T::Archetype;+        }+++        impl<T: ?Sized, Scope> PromiseTransmutableInto<Scope> for *mut T+        where+            T: PromiseTransmutableInto<Scope>,+            *mut T::Archetype: TransmuteFrom<Self, Scope, NeglectStability>+        {+            type Archetype = *mut T::Archetype;+        }++        impl<T: ?Sized, Scope> PromiseTransmutableFrom<Scope> for *mut T+        where+            T: PromiseTransmutableFrom<Scope>,+            *mut T::Archetype: TransmuteInto<Self, Scope, NeglectStability>,+        {+            type Archetype = *mut T::Archetype;+        }+++        impl<'a, T: ?Sized, Scope> PromiseTransmutableInto<Scope> for &'a T+        where+            T: PromiseTransmutableInto<Scope>,+            T::Archetype: 'a,+            &'a T::Archetype: TransmuteFrom<&'a T, Scope, NeglectStability>+        {+            type Archetype = &'a T::Archetype;+        }++        impl<'a, T: ?Sized, Scope> PromiseTransmutableFrom<Scope> for &'a T+        where+            T: PromiseTransmutableFrom<Scope>,+            T::Archetype: 'a,+            &'a T::Archetype: TransmuteInto<&'a T, Scope, NeglectStability>+        {+            type Archetype = &'a T::Archetype;+        }+++        impl<'a, T: ?Sized, Scope> PromiseTransmutableInto<Scope> for &'a mut T+        where+            T: PromiseTransmutableInto<Scope>,+            T::Archetype: 'a,+            &'a mut T::Archetype: TransmuteFrom<&'a mut T, Scope, NeglectStability>+        {+            type Archetype = &'a mut T::Archetype;+        }++        impl<'a, T: ?Sized, Scope> PromiseTransmutableFrom<Scope> for &'a mut T+        where+            T: PromiseTransmutableFrom<Scope>,+            T::Archetype: 'a,+            &'a mut T::Archetype: TransmuteInto<&'a mut T, Scope, NeglectStability>+        {+            type Archetype = &'a mut T::Archetype;+        }+    }++    /// Static checks that may be neglected when determining if a type is `TransmuteFrom` some other type.+    pub mod options {++        /// Options that may be used with safe transmutations.+        pub trait SafeTransmuteOptions: TransmuteOptions {}++        /// Options that may be used with unsafe transmutations.+        pub trait TransmuteOptions: private::Sealed {}++        impl SafeTransmuteOptions for () {}+        impl TransmuteOptions for () {}++        /// Neglect the stability check of `TransmuteFrom`.+        pub struct NeglectStability;++        impl SafeTransmuteOptions for NeglectStability {}+        impl TransmuteOptions for NeglectStability {}++        // prevent third-party implementations of `TransmuteOptions`+        mod private {+            use super::*;++            pub trait Sealed {}++            impl Sealed for () {}+            impl Sealed for NeglectStability {}+        }+    }+}+```+++# Drawbacks+[drawbacks]: #drawbacks++## No Notion of Platform Stability+The stability declaration traits communicate library layout stability, but not *platform* layout stability. A transmutation is platform-stable if it compiling one one platform implies it will compile on all other platforms. Unfortunately, platform-unstable types are common;  e.g.:++- All primitive number types have platform-dependent [endianness](https://en.wikipedia.org/wiki/Endianness).+- All pointer-related primitive types (`usize`, `isize`, `*const T`, `*mut T`, `&T`, `&mut T`) possess platform-dependent layouts; their sizes and alignments are well-defined, but vary between platforms. Concretely, whether `usize` is `TransmuteInto<[u8; 4]>` or `TransmuteInto<[u8; 8]>` will depend on  the platform.+- The very existence of some types depends on platform, too; e.g., the contents of [`core::arch`](https://doc.rust-lang.org/stable/core/arch/), [`std::os`](https://doc.rust-lang.org/stable/std/os/), and [`core::sync::atomic`](https://doc.rust-lang.org/stable/std/sync/atomic/) all depend on platform.++Our proposed stability system is oblivious to the inter-platform variations of these types. Expanding our stability system to be aware of inter-platform variations would introduce considerable additional complexity:+<ol>+<li>++**Cognitive Complexity:** For types whose layout varies between platforms, the [stability] declaration traits could, *perhaps*, be adapted to encode platform-related guarantees. We anticipate this would contribute substantial cognitive complexity. Type authors, even those with no interest in cross-platform stability, would nonetheless need to reason about the layout properties of their types on platforms that might not yet exist.+</li>+<li>++**Ergonomic Complexity:** Platform instabilities are contagious: a type that *contains* a platform-unstable type is, itself, platform-unstable. Due to the sheer virulence of types with platform-dependent layouts, an explicit '`NeglectPlatformStability`' option would need to be used for *many* simple transmutations. The ergonomic cost of this would also be substantial.++</li>+<li>++**Implementation Complexity:** The mechanisms proposed by this RFC are, fundamentally, applications of and additions to Rust's type system (i.e., they're traits). Mechanisms that impact platform stability, namely `#[cfg(...)]` annotations, long precede type-resolution and layout computation in the compilation process. For instance, it's possible to define types with impossible layouts:    +```rust+#[cfg(any())]+struct Recursive(Recursive);+```+This program compiles successfully on all platforms because, from the perspective of later compilation stages, `Recursive` may as well not exist.++</li>+</ol>++The issues of platform layout stability exposed by this RFC are not fundamentally different from the challenges of platform API stability. These challenges are already competently addressed by the mechanisms proposed in [RFC1868](https://github.com/rust-lang/rfcs/pull/1868). For this reason, and for the aforementioned concerns of additional complexity, we argue that communicating and enforcing platform layout stability must remain outside the scope of this RFC.++## Stability of *Unsafe* Transmutations+[drawback-unsafe-stability]: #Stability-of-Unsafe-Transmutations++The model of stability proposed by this RFC frames stability as a quality of *safe* transmutations. A type author cannot specify stability archetypes for *unsafe* transmutations, and it is reasonable to want to do so.++To accommodate this, we may modify the definitions of `PromiseTransmutableFrom` and `PromiseTransmutableInto` to consume an optional `Neglect` parameter, to allow for stability declarations for unsafe transmutations:+```rust+pub trait PromiseTransmutableFrom<Scope, Neglect = ()>+where+    Neglect: TransmuteOptions+{+    type Archetype: TransmuteInto<Self, Scope, Sum<Neglect, NeglectStability>>;+}++pub trait PromiseTransmutableInto<Scope, Neglect = ()>+where+    Neglect: TransmuteOptions+{+    type Archetype: TransmuteFrom<Self, Scope, Sum<Neglect, NeglectStability>>;+}+```+Implementations of these traits for a given `Neglect` declares that a transmutation which is accepted while neglecting a particular set of checks (namely the set encoded by `Neglect`) will *continue* to be possible.++We omit these definition from this RFC's recommendations because they are not completely satisfying. For instance, `Neglect` is a *logically* unordered set of options, but is encoded as a tuple (which *is* ordered). To declare a transmutation that requires neglecting validity and alignment checks as stable, only *one* of these impls ought to be necessary:++```rust+impl<Scope> PromiseTransmutableFrom<Scope, (NeglectAlignment, NeglectValidity)> for Foo+{+    ...+}++impl<Scope> PromiseTransmutableFrom<Scope, (NeglectValidity, NeglectAlignment)> for Foo+{+    ...+}+```+Writing *both* impls (as we do above) is logically nonsense, but is nonetheless supported by Rust's coherence rules.+++# Rationale and alternatives+[rationale-and-alternatives]: #rationale-and-alternatives+++## Rationale: `TransmuteFrom`/`TransmuteInto`++### Why support arbitrary transmutation?+Some [prior art][prior-art], especially in the crate ecosystem, provides an API that [only supports transmutations involving particular types](#Source-and-Destination-Types-Supported) (e.g., from/into bytes). As we discuss in the [prior art][prior-art] section, we believe that the inflexibility of such approaches make them a poor basis of a language proposal. In particular, these restrictive approaches don't leave room to grow: supporting additional transmutations requires additional traits.++The API advocated by this proposal is unopinionated about what transmutations users might wish to do, and what transmutations the compiler is able to reason about. The implementation of this RFC may be initially very simple (and perhaps support no more than the restrictive approaches allow for), but then subsequently grow in sophistication—*without* necessitating public API changes.++### Why *two* traits?+If `TransmuteInto` is implemented in terms of `TransmuteFrom`, why provide it at all? We do so for consistency with libcore's [`From`/`Into`](https://doc.rust-lang.org/stable/rust-by-example/conversion/from_into.html) traits, and because directionality conveys intent: `TransmuteFrom` connotes *conversion*, whereas `TransmuteInto` connotes initialization. We believe that the supporting code examples of this RFC demonstrate the explanatory benefits of providing *both* traits.++## Rationale: Transmutation Options++### Granularity+Although the focus of our API is statically-correct, infalible transmutations, the ability to opt-out of particular static checks is essential for building safer *fallible* mechanisms, such as alignment-fallible [reference casting][ext-ref-casting], or validity-fallible transmutations (e.g., `bool` to `u8`).++### Representation+Although transmutations options exist at a type-level, they're represented as type-level tuples, whose familiar syntax is identical to value-level tuples. An empty tuple seems like the natural choice for encoding *don't neglect anything*.++We could not identify any advantages to representing options with const-generics. There is no clear syntactic advantage: tuples remain the most natural way to encode ad-hoc products of items. The comparative lack of default values for const-generic parameters poses an ergonomic *disadvantage*.

The lack of defaults in const generics is interesting here. If = [] worked, would that be preferred? Intuitively here I was expecting one #[non_exhaustive] enum, not a sealed trait with N non-instantiable types and a bunch of wants-variadic-generics impls of the trait. I guess the normal case here is passing one thing, so passing NeglectStability is marginally nicer than something like [Neglect::Stability]?

jswrenn

comment created time in 14 days

PullRequestReviewEvent

Pull request review commentrust-lang/rfcs

Safer Transmute

+# Safer Transmute RFC++- Feature Name: `safer_transmute`+- Start Date: 2020-08-31+- RFC PR: [rust-lang/rfcs#2981](https://github.com/rust-lang/rfcs/pull/2981)+- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000)+++# Summary+[summary]: #summary++We propose traits, namely `TransmuteInto` and `TransmuteFrom`, that are implemented *automatically* for combinations of types that may be safely transmuted. In other words, this RFC makes safe transmutation *as easy as 1..., 2..., `repr(C)`!*+```rust+use core::transmute::{+    transmute,+    stability::{PromiseTransmutableInto, PromiseTransmutableFrom},+};++#[derive(PromiseTransmutableInto, PromiseTransmutableFrom)] // declare `Foo` to be *stably* transmutable+#[repr(C)]+pub struct Foo(pub u8, pub u16);+//                    ^ there's a padding byte here, between these fields++// Transmute fearlessly!+let _ : Foo = transmute!(64u32); // Alchemy Achieved!++let _ : u32 = transmute!(Foo(16, 12)); // Compile Error!++// error[E0277]: the trait bound `u32: TransmuteFrom<Foo, _>` is not satisfied+//   --> src/demo.rs:14:27+//    |+// 14 | let _ : u32 = transmute!(Foo(16, 12)); // Compile Error!+//    |                          ^^^^^^^^^^^ the trait `TransmuteFrom<Foo, _, _>` is not implemented for `u32`+//    |+//   = note: byte 8 of the source type may be uninitialized; byte 8 of the destination type cannot be uninitialized.+```+++# Motivation+[motivation]: #motivation++Byte-reinterpretation conversions (such as those performed by `mem::transmute`, `mem::transmute_copy`, pointer casts, and `union`s) are invaluable in high performance contexts, are `unsafe`, and easy to get wrong. This RFC provides mechanisms that make many currently-unsafe transmutations entirely safe. For transmutations that are not entirely safe, this RFC's mechanisms make mistakes harder to make.++This RFC's comprehensive approach provides additional benefits beyond the mere act of transmutation; namely:+ - [authoritatively codifies language layout guarantees](#codifying-language-layout-guarantees)+ - [allows crate authors to codify their types' layout stability guarantees](#expressing-library-layout-guarantees)+ - [allows crate authors to codify their abstractions' layout requirements](#expressing-layout-requirements)++Given the expressive foundation provided by this RFC, we also envision a range of future possibilities that will *not* require additional compiler support, including:+ - [safe slice and `Vec` casting][0000-ext-container-casting.md]+ - [a unified, generic `Atomic<T>` type][0000-ext-generic-atomic.md]+ - [a safe, generic alternative to `include_bytes!`][0000-ext-include-data.md]+ - [traits for asserting the size and alignment relationships of types][0000-ext-layout-traits.md]+ - [zerocopy-style traits for safe initialization][0000-ext-byte-transmutation.md]+ - [bytemuck-style mechanisms for fallible reference casting][ext-ref-casting]+++## Codifying Language Layout Guarantees+Documentation of Rust's layout guarantees for a type are often spread across countless issues, pull requests, RFCs and various official resources. It can be very difficult to get a straight answer. When transmutation is involved, users must reason about the *combined* layout properties of the source and destination types.++This RFC proposes mechanisms that programmers will use to confidently answer such questions—by checking whether the `TransmuteFrom` and `TransmuteInto` traits are implemented.++## Expressing Library Layout Guarantees+There is no canonical way for crate authors to declare the SemVer layout guarantees of their types. Crate authors currently must state their layout guarantees using prose in their documentation. In contrast to structural stability (e.g., the declared visibility of fields), layout stability is expressed extra-linguistically.++This isn't satisfactory: guarantees expressed in prose outside of the Rust programming language are guarantees that cannot be reasoned about *inside* the language. Whereas `rustc` can dutifully deny programmers access to private fields, it is unable to prevent programmers from making unfounded expectations of types' in-memory layouts.++This RFC proposes simple-but-powerful [mechanisms][stability] for declaring layout stability guarantees.++## Expressing Layout Requirements+Similarly, there is no canonical way for crate authors to declare the layout requirements of generic abstractions over types that have certain layout properties. ++For instance, a common bit-packing technique involves using the relationship between allocations and alignment. If a type is aligned to 2<sup>n</sup>, then the *n* least significant bits of pointers to that type will equal `0`. These known-zero bits can be packed with data. Since alignment cannot be currently reasoned about at the type-level, it's currently impossible to bound instantiations of a generic parameter based on minimum alignment.++The mechanisms proposed by the RFC enable this, see [here][0000-ext-layout-traits.md].++# Guide-level explanation+[guide-level-explanation]: #guide-level-explanation++## Terminology & Concepts++### 📖 Transmutation+**Transmutation** is the act of reinterpreting the bytes corresponding to a value of one type as if they corresponded to a different type. Concretely, we mean the behavior of this function:+```rust+#[inline(always)]+unsafe fn transmute<Src, Dst>(src: Src) -> Dst+{+    #[repr(C)]+    union Transmute<Src, Dst> {+        src: ManuallyDrop<Src>,+        dst: ManuallyDrop<Dst>,+    }++    ManuallyDrop::into_inner(Transmute { src: ManuallyDrop::new(src) }.dst)+}+```++### 📖 Safer Transmutation+By **safer transmutation** we mean: *what `where` bound could we add to `transmute` restricts its type parameters `Src` and `Dst` in ways that statically limit the function's misuse?* Our answer to this question will ensure that transmutations are, by default, *well-defined*, *safe* and *stable*.++### 📖 Well-Definedness+A transmutation is ***well-defined*** if the mere act of transmuting a value from one type to another is not unspecified or undefined behavior.++### 📖 Safety+A well-defined transmutation is ***safe*** if *using* the transmuted value cannot violate memory safety.++### 📖 Stability+A safe transmutation is ***stable*** if the authors of the source type and destination types have indicated that the layouts of those types is part of their libraries' stability guarantees.++## Concepts in Depth++***Disclaimer:** While the high-level definitions of transmutation well-definedness, safety and stability are a core component of this RFC, the detailed rules and examples in this section are **not**. We expect that the initial implementation of `TransmuteFrom` may initially be considerably less sophisticated than the examples in this section (and thus forbid valid transmutations). Nonetheless, this section explores nuanced cases of transmutation well-definedness and safety to demonstrate that the APIs we propose can grow to handle that nuance.*+++### 📖 When is a transmutation well-defined?+[sound transmutation]: #-when-is-a-transmutation-well-defined+A transmutation is ***well-defined*** if the mere act of transmuting a value from one type to another is not unspecified or undefined behavior.++#### Well-Defined Representation+[`u8`]: core::u8+[`f32`]: core::f32++Transmutation is ill-defined if it occurs between types with unspecified representations.++Most of Rust's primitive types have specified representations. That is, the precise layout characteristics of [`u8`], [`f32`] is a documented and guaranteed aspect of those types.++In contrast, most `struct` and `enum` types defined without an explicit `#[repr(C)]` attribute do ***not*** have well-specified layout characteristics.++To ensure that types you've define are transmutable, you almost always (with very few exceptions) must mark them with the `#[repr(C)]` attribute.

(fairly-minor point) To me I'd think there another common case: repr(transparent) newtypes. That one's obviously sound, and the opt-in safety can be asymmetrical. I'm particularly interested in that for &impl !Sized. And I guess repr(uN) enums are also a plausible, more-asymmetric, case.

Should this thus be something like "a non-repr(rust) layout attribute"?

jswrenn

comment created time in 14 days

PullRequestReviewEvent

issue commentrust-lang/rust

Unreachable code optimization failure when matching on Rust enum

So is the fix here to codegen it using <T as DiscriminantKind>::Discriminant instead of i64?

MSxDOS

comment created time in 15 days

issue commentrust-lang/rust

Unreachable code optimization failure when matching on Rust enum

This is weird; LLVM has plenty enough information to be able to do this from what's emitted.

The IR it currently produces: https://rust.godbolt.org/z/GWacEc

define void @_ZN7example4test17h9c70bf34953e7145E() unnamed_addr #0 !dbg !6 {
start:
  %_2.i = alloca %"std::fmt::Arguments", align 8
  %0 = load i8, i8* getelementptr inbounds (<{ [1 x i8] }>, <{ [1 x i8] }>* @GLOBAL, i64 0, i32 0, i64 0), align 1, !dbg !10, !range !11
  %_10.i.i.not = icmp eq i8 %0, 0, !dbg !12
  br i1 %_10.i.i.not, label %bb8, label %bb3, !dbg !22

bb3:                                              ; preds = %start
  %_6 = zext i8 %0 to i64, !dbg !23
  switch i64 %_6, label %bb5 [
    i64 0, label %bb4
    i64 1, label %bb6
    i64 2, label %bb7
  ], !dbg !23

That clearly has sufficient information to know that bb4 is unreachable, but it's not taking advantage of it.

Curiosity: why is rustc insisting on zexting to i64 for the discriminant comparison? That's something rust is doing; it's there even in -O0 https://rust.godbolt.org/z/a1nxzx

MSxDOS

comment created time in 16 days

issue commentrust-lang/rust

Code bloat from monomorphization of methods applied to arrays

Given that these things are already implemented by calling the slice versions, I don't know that there's actually anything array-specific here. This is just the inliner doing what it's told to do. The same thing will plausibly happen with impl AsRef<Path> methods with outlined bodies too in -O3.

Given that -O1 is doing the right thing here, I suspect -Os is too, which is the particularly-important part IMHO.

Even for debug it's not obvious to me that inline(never) is desirable here. I could easily imagine someone expecting monomorphization of something like <[u32; 4]>::debug because there's no other way to stringify such an array in std.

Note that neither the array nor slice implementations of Debug are currently even marked #[inline]: https://github.com/rust-lang/rust/blob/9a8ca69602fac58362df66a3fc9028211c6d6f2a/library/core/src/array/mod.rs#L184-L189 https://github.com/rust-lang/rust/blob/9a8ca69602fac58362df66a3fc9028211c6d6f2a/library/core/src/fmt/mod.rs#L2166-L2171 so this is all LLVM's inlining heuristic deciding that this is a good bet with no extra encouragement.

glandium

comment created time in 16 days

pull request commentrust-lang/rust

Widen TypeId from 64 bits to 128.

We're certainly adding more checking to things like uninitialized, so could to transmute as well. If nothing else it could be cool to add a validity check in debug mode.

I don't know how effective this would be, however, for this change. Given that at least one of the cases is aware they shouldn't but are doing it anyway, I feel like they'd just end up doing this with pointer casts instead, which we can't feasibly block.

I guess that would at least change it to a runtime problem, not a compile-time one. But they can then just assert_eq_size! to turn it back into a compilation failure, and we're back to where we started...

eddyb

comment created time in 16 days

pull request commentrust-lang/blog.rust-lang.org

Add post about using regression labels

A regression template sounds like a great idea. And it'd have prompts for things like which version it worked on, so it'd also be helpful when we gets comments like https://github.com/rust-lang/rust/issues/34162#issuecomment-705441467

camelid

comment created time in 18 days

Pull request review commentrust-lang/rust

Reduce size of lexer::Token from 72 to 16 bytes

 pub enum LiteralKind {     /// "b"abc"", "b"abc"     ByteStr { terminated: bool },     /// "r"abc"", "r#"abc"#", "r####"ab"###"c"####", "r#"a"-    RawStr { n_hashes: u16, err: Option<RawStrError> },+    RawStr { n_hashes: u16, valid: bool },     /// "br"abc"", "br#"abc"#", "br####"ab"###"c"####", "br#"a"-    RawByteStr { n_hashes: u16, err: Option<RawStrError> },+    RawByteStr { n_hashes: u16, valid: bool },

Could n_hashes be NonZeroU16 to reduce size such that bool could be a niche?

(NonZeroU16, bool) can't space-optimize anyway.

Julian-Wollersberger

comment created time in 19 days

PullRequestReviewEvent

create barnchscottmcm/rust

branch : fewer-try-trait-method-references

created branch time in 19 days

pull request commentrust-lang/rust

Eliminate bounds checking in slice::Windows

TBH I was surprised that NonZeroUSize was working for this, since it works reliably for layout optimizations but often doesn't work for code optimization, see https://github.com/rust-lang/rust/issues/49572

AnthonyMikh

comment created time in 19 days

pull request commentrust-lang/rust

Add in-place optimization for array map

That does look better.

I've been playing around some more, though, and I don't think that the "in-place" idea is the right way to get to the outcome.

As far as I can tell, the real problem is that the various moves are confusing llvm. But the code can be restructured to accommodate that. Check out this way: https://godbolt.org/z/enhWf8

That's not the normal way to write Rust code, but manual-NRVO'ing it like this also gets rid of the alloca and the loop. And, even better, it works without needing to care about the sizes nor alignments of T and U.

JulianKnodt

comment created time in 20 days

pull request commentrust-lang/rust

Add in-place optimization for array map

it didn't generate LLVM for the second function

Godbolt has some filtering, IIRC. I moves your example over to https://play.rust-lang.org/?version=nightly&mode=release&edition=2018&gist=e5d8917a6d171da7e69653a813384f54 and if you git "Show LLVM IR" there, you'll see

@example_2 = unnamed_addr alias void ([8 x float]*, [8 x i32]*), void ([8 x float]*, [8 x i32]*)* @example_1

which means the functions are producing (α-)identical LLVM-IR and getting deduped.

JulianKnodt

comment created time in 20 days

issue commentrust-lang/rust

interface inconsistency with char::is_ascii_... functions

I am aware that the API can probably not be changed anymore. But maybe there is another solution?

Personally I'd like to see this solved at the language level -- it's annoyingly common that .foo(bar) doesn't work but .foo(|x| bar(x)) does, and it would be nice to just have the appropriate coercions apply to function types as well.

Johann150

comment created time in 20 days

issue commentrust-lang/rust

Tracking issue for slice_partition_at_index

@jagill It's nightly so it's allowed, but to make it a bit easier on nightly users it's generally preferable to to stabilize it under a different feature gate name so the old method can be left there for a month or two before being removing.

Mokosha

comment created time in 20 days

pull request commentrust-lang/rust

Implement advance_by, advance_back_by for slice::{Iter, IterMut}

We'll see what perf says, but honestly I'd recommend leaving the specific nth -- on normal user iterators it would be fine to just have advance_by, but slice iterators tend to implement all of them rather leaving it to the optimizer (to fold the checks between advance_by+next, for example) because they're used so pervasively that making LLVM's life easier helps compile times.

timvermeulen

comment created time in 20 days

pull request commentrust-lang/rust

Stabilize slice_partition_at_index

Waiting on FCP from https://github.com/rust-lang/rust/issues/55300#issuecomment-694995118 to finish; expected 2020-10-09.

jagill

comment created time in 20 days

pull request commentrust-lang/rust

Add Iterator::advance_by and DoubleEndedIterator::advance_back_by

Yeah, that does sound like a reasonable thing to try. I'd also suggest manually implementing it for slice::Iter -- that's the common iterator usage and apparently hand-coding things for that can help.

timvermeulen

comment created time in 20 days

pull request commentrust-lang/rust

Add Iterator::advance_by and DoubleEndedIterator::advance_back_by

That's this one, right? https://github.com/rust-lang/rustc-perf/blob/master/collector/benchmarks/deeply-nested/src/lib.rs

I think that one will regress massively any time an object-safe method is added to Iterator, since it uses Box<dyn Iterator> so all those methods need to be codegened for the vtable. So I don't think reverting the nth changes will fix that part; we might just have to accept it -- unless we decide we just can't add another object-safe method ever again. (Also, that test is massively unrealistic because it's an empty iterator of ()s, and even changing it to an empty iterator of i32 already makes it take 30+ minutes, let alone making it actually have elements.)

That said, the small regressions in other things are worth looking at.

timvermeulen

comment created time in 20 days

issue commentrust-lang/rust

Compiler help: &str -> String suggestion about to_string

to_string() is the idiomatic way of performing this transformation

Citation? The closest thing to decision I have is https://users.rust-lang.org/t/what-is-the-idiomatic-way-to-convert-str-to-string/12160/10?u=scottmcm from carols10cents in 2017, which I think linked to roughly https://doc.rust-lang.org/1.22.0/book/second-edition/ch08-02-strings.html#creating-a-new-string back when that link worked, and that section uses String::from more than .to_string(). I'd love to have a newer link 🙃

(Personally I prefer different things based on context.)

darnuria

comment created time in 21 days

issue commentrust-lang/rust

Panic in Firefox (rusqlite/lru_cache/linked_hash_map) built with recent Rust nightlies

Though the fact that runtime checks are added to new compiler versions, not just compile-time checks, is a bit surprising.

It would be nice to just make this kind of thing a compilation error, but that's against the stability guarantee -- even if the call is known to be bad, the code might be written so that the UB cases are never executed, so we can't break it.

(There's arguably no runtime check here; it's just the codegen level noticing UB and taking advantage of its freedom to emit whatever it wants there. And -- helpfully for debugging emitting a panic -- rather than the unreachable it could.)

myfreeweb

comment created time in 21 days

issue commentrust-lang/rust

Poorly optimized assembly generation around Ipv4Addr, Ipv6Addr

This is a trivial method on a concrete type, so yeah, probably just needs #[inline]. Or you want to turn on LTO.

(If it were generic it wouldn't be necessary, but for concrete things the bodies aren't in the meta.)

TyPR124

comment created time in 21 days

PullRequestReviewEvent

pull request commentrust-lang/rust

Implement advance_by, advance_back_by for iter::Chain

Thanks! Looks like a plausible helper to use in more tests (try_fold jumps to mind, obviously).

@bors r+

timvermeulen

comment created time in 21 days

pull request commentrust-lang/rust-forge

Updates to Libs docs

I'm not on libs, compiler, or libs-impl. Did you mean someone else?

That said, all these changes look good to me.

KodrAus

comment created time in 21 days

more