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/miri 0

An interpreter for Rust's mid-level intermediate representation

delete branch scottmcm/rust

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

delete time in 16 hours

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 19 hours

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 2 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 2 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 2 days

PullRequestReviewEvent

pull request commentrust-lang/rust

Improve readability of range docs

r? @scottmcm @bors r+ rollup

camelid

comment created time in 2 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 2 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 2 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 3 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 3 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 3 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 3 days

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

backlog bonanza post

Looks good to me.

nikomatsakis

comment created time in 4 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 4 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 4 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 9 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 9 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 6 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 6 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 6 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 6 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 6 days

delete branch scottmcm/rustfmt

delete branch : fix-try-parse

delete time in 7 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 7 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 7 days

pull request commentrust-lang/rust

Add [T]::as_chunks(_mut)

@LukasKalbertodt Friendly one-week re-review ping.

scottmcm

comment created time in 7 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 7 days

create barnchscottmcm/rustfmt

branch : fix-try-parse

created branch time in 7 days

fork scottmcm/rustfmt

Format Rust code

fork in 7 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 8 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 8 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 8 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 8 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 8 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 8 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 8 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 9 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 9 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 9 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 9 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 12 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 13 days

PullRequestReviewEvent

create barnchscottmcm/rust

branch : fewer-try-trait-method-references

created branch time in 13 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 13 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 13 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 13 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 13 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 13 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 13 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 13 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 14 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 14 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 15 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 15 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 15 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 15 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 15 days

pull request commentrust-lang/rust

Lint for unused borrows as part of `UNUSED_MUST_USE`

@craterbot check

ecstatic-morse

comment created time in 15 days

PullRequestReviewEvent
PullRequestReviewEvent

pull request commentrust-lang/rust

Implement advance_by, advance_back_by for iter::Chain

Sure, I'll take this one. r? @scottmcm

timvermeulen

comment created time in 15 days

pull request commentrust-lang/rust

Lint for unused borrows as part of `UNUSED_MUST_USE`

@bors try

ecstatic-morse

comment created time in 15 days

issue commentrust-lang/rust

Tracking issue for experiments around coercions, generics, and Copy type ergonomics

I'd definitely like to see experimentation in these areas -- I still like the "discarding ownership" idea -- but realistically it doesn't seem like anything is happening right now so this issue isn't providing value, so ☑.

aturon

comment created time in 15 days

issue commentrust-lang/rust

create a lint for tracking "tainted" fallback around abrupt expressions and `!` type

Zulip stream: https://rust-lang.zulipchat.com/#narrow/stream/259160-t-lang.2Fproject-never-type

nikomatsakis

comment created time in 15 days

pull request commentrust-lang/rust

Update lang item list in unstable book

(Sorry, this is a meta point and not directly about the proposed change)

Hmm, having this in the unstable book is slightly odd to me, since AFAIK they're never going to be on stabilization-track.

With my personal lang hat, I don't know that I care that much about how this works. I've always considered lang items to be a compiler decision about how to implement the defined semantics. Between the reference, the documentation for a feature while it's unstable, the comments on the lang items, and the rustc-dev-guide, I don't know where best to have this stuff.

MikailBag

comment created time in 15 days

issue closedrust-lang/rfcs

Proposal for last_val() for Vectors

Hi, you have for Vec's the methods last() and last_mut() but if you want to get the value itself you have to use pop() and it breaks the semantic. I would propose to introduce last_val() that could be a simple alias to pop() since a moved value cannot exist two times, so it has to be deleted from the list. But last_val() would confuse fewer users searching for something that returns the last value instead of a reference.

closed time in 15 days

rudolfschmidt

issue commentrust-lang/rfcs

Proposal for last_val() for Vectors

This is one of those changes that realistically would have had to happen more than 5 years ago to be worth it. Even assuming (without taking a position on it) that last_val is a slightly better name than pop, that's not worth the churn to switch a common method nor worth the added confusion of two methods that do the same thing.

The description of pop in the docs says

Removes the last element from a vector and returns it so hopefully this is still sufficiently discoverable for anyone looking to perform this operation.

rudolfschmidt

comment created time in 15 days

Pull request review commentrust-lang/rust

Replace some once(x).chain(once(y)) with [x, y] IntoIter

 impl<T> PerNS<Option<T>> {      /// Returns an iterator over the items which are `Some`.     pub fn present_items(self) -> impl Iterator<Item = T> {-        use std::iter::once;--        once(self.type_ns).chain(once(self.value_ns)).chain(once(self.macro_ns)).filter_map(|it| it)+        IntoIter::new([self.type_ns, self.value_ns, self.macro_ns]).filter_map(|it| it)

Frustratingly, flatten gives worse size_hints than filter_map today (https://github.com/rust-lang/rust/pull/48544) and has more complicated code (needs to keep the iterator in its state after giving out an item, since unlike Option it doesn't know if that's the only item), so that's potentially a pessimization.

scottmcm

comment created time in 15 days

PullRequestReviewEvent

pull request commentrust-lang/rust

Add in-place optimization for array map

@JulianKnodt Sorry for forgetting this PR.

You might want to check out https://www.llvm.org/docs/CommandGuide/FileCheck.html#tutorial, as we use that for codegen tests.

Do you have an example of the IR emitted with and without this change? We could maybe help identify the core things that are worth checking. Looking at what it currently emits in https://rust.godbolt.org/z/ezfPxr, maybe you're trying to get rid of that 1000-item memcpy at the end? Or maybe the 1000-item alloca?

Though, looking at the LLVM signature of the API,

define void @array_inc([1000 x i8]* noalias nocapture sret dereferenceable(1000) %0, [1000 x i8]* noalias nocapture readonly dereferenceable(1000) %x) unnamed_addr #0 personality i32 (i32, i32, i64, %"unwind::libunwind::_Unwind_Exception"*, %"unwind::libunwind::_Unwind_Context"*)* @rust_eh_personality !dbg !6 {

I'm not sure that this in-place is actually a win, because at the llvm level it needs to be dst[i] = f(src[i]) anyway.

Makes me wonder if this just needs NRVO to be turned on, instead of actually needing code changes...

JulianKnodt

comment created time in 16 days

pull request commentrust-lang/rust

stabilize union with 'ManuallyDrop' fields and 'impl Drop for Union'

We've had enums of Copy types stable for a while, but non-Copy was an open question largely about the potential non-obviousness about drop glue not happening. This proposes to sidestep that question by allowing ManuallyDrop<T> in unions for all Ts, since that way people visibly opt-in to the leaking behaviour. And that's also safe, so creating a union remains safe, even if that union has a non-drop type in it (via ManuallyDrop).

This also proposes allowing Drop implementations on union types, which seems hard to me to actually use, but I don't really have a problem with allowing if someone can find a way that they'd care.

See the OP here for more details.

@rfcbot fcp merge

--

@RalfJung Would this also be enough to remove #![feature(untagged_unions)] from at least core and std? I did a quick rg and everything looked like it's either using Copy types or is already doing ManuallyDrop.

RalfJung

comment created time in 16 days

push eventscottmcm/rust

Bastian Kauschke

commit sha a219ad64a6ee025b9a5c83de390280f818cd81c6

extend `is_ty_or_ty_ctxt` to self types

view details

Bastian Kauschke

commit sha 67f319c30bed5c83ae3b4872109999a8a574f29e

take `TyCtxt` by value

view details

ishitatsuyuki

commit sha 7c98f6f58440d80f6116e4d060778ab0a9b98131

Add fast path for match checking

view details

Simon Vandel Sillesen

commit sha cad050b002ff36c65b68833fcd90824eceee1993

Add regression test showcasing miscompilation

view details

Bastian Kauschke

commit sha bfa2030ccbbabc4944b719c9194e190e1726fc8c

update docs

view details

Simon Vandel Sillesen

commit sha 738ed9b5ec62259eb0f2aced549feec2f7e7c75a

Fix #76803 Check that the variant index matches the target value from the SwitchInt we came from

view details

rijenkii

commit sha a60f97849b240c69052e58ada45cff5515fb66b2

Add tracking issue for feature(unix_socket_peek)

view details

Stein Somers

commit sha c6a8cfbde848352271ee143fe5d458dcac7c397f

BTreeMap: code readability tweaks

view details

Bastian Kauschke

commit sha 1146c39da74b3875e6667aeeafde2773644dc8b6

cache types during normalization

view details

Mara Bos

commit sha 26d6081f1d1a2005be87bbe47f6fcda270cfd016

Relax promises about condition variable. This allows for futex or thread parking based implementations in the future.

view details

Stein Somers

commit sha 0661b0a36d483dfb7041a3526b07eeec2b67b2d0

BTreeMap: wrap node's raw parent pointer in NonNull

view details

bors

commit sha f68e08933d8f519a9655934fedebbc509661b219

Auto merge of #76929 - ssomers:btree_cleanup_2, r=Mark-Simulacrum BTreeMap: wrap node's raw parent pointer in NonNull Now that the other `*const` (root) is gone, seemed like a small step forward. r? `@Mark-Simulacrum`

view details

Ralf Jung

commit sha 4d1ef03c9ed28b6855c3f73535e21dc9cd6f6c5d

cleanup promotion const_kind checks in particular allow a few more promotions for consistency when they were already allowed in other contexts

view details

Ralf Jung

commit sha 7febd5a25770cb20805f20e43ab0d773ed2834ed

fix doc comment

view details

Ralf Jung

commit sha 7b99c8e1cf096c1ba71ba3ee58b19527a5b69c1a

never promote non-const operations; revert STATIC promotion change

view details

Ralf Jung

commit sha 9216eb825839ecd17d67c2731537e5d6afffc54a

fix some comments

view details

Bastian Kauschke

commit sha d4039c55c9ef392261aeaba6c14ae81f5098139a

wip emit errors during AbstractConst building

view details

Bastian Kauschke

commit sha 30cbc9729654c66b9f54779d18f023e47112cdf2

words

view details

Aaron Hill

commit sha 367efa86d5df6c4aacbd0f1b28c4008527722d4c

Don't allow implementing trait directly on type-alias-impl-trait This is specifically disallowed by the RFC, but we never added a check for it. Fixes #76202

view details

Simon Vandel Sillesen

commit sha a875c7a1ea31f86d4a796209f50303564ce15a16

Add assertion for len of vecs

view details

push time in 16 days

Pull request review commentrust-lang/rust

Add [T]::as_chunks(_mut)

 impl<T> [T] {         ChunksExactMut::new(self, chunk_size)     } +    /// Splits the slice into a slice of `N`-element arrays,+    /// starting at the beginning of the slice,+    /// and a remainder slice with length strictly less than `N`.+    ///+    /// # Panics+    ///+    /// Panics if `N` is 0. This check will most probably get changed to a compile time+    /// error before this method gets stabilized.+    ///+    /// # Examples+    ///+    /// ```+    /// #![feature(slice_as_chunks)]+    /// let slice = ['l', 'o', 'r', 'e', 'm'];+    /// let (chunks, remainder) = slice.as_chunks();+    /// assert_eq!(chunks, &[['l', 'o'], ['r', 'e']]);+    /// assert_eq!(remainder, &['m']);+    /// ```+    #[unstable(feature = "slice_as_chunks", issue = "74985")]+    #[inline]+    pub fn as_chunks<const N: usize>(&self) -> (&[[T; N]], &[T]) {+        assert_ne!(N, 0);+        let len = self.len() / N;+        let (fst, snd) = self.split_at(len * N);

These names are just moved over from the previous code. I'm not tied to them; new commit to update them incoming.

scottmcm

comment created time in 16 days

PullRequestReviewEvent

Pull request review commentrust-lang/rust

Add [T]::as_chunks(_mut)

 impl<T> [T] {         ChunksExactMut { v: fst, rem: snd, chunk_size }     } +    /// Splits the slice into a slice of `N`-element arrays,+    /// starting at the beginning of the slice,+    /// and a remainder slice with length strictly less than `N`.+    ///+    /// # Panics+    ///+    /// Panics if `N` is 0. This check will most probably get changed to a compile time+    /// error before this method gets stabilized.

Yeah, or a trait that's only implemented for [T; N+1] or something, implicitly causing that restriction.

This is copied from the same text in https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.array_chunks

scottmcm

comment created time in 16 days

PullRequestReviewEvent

pull request commentrust-lang/rust

Add `try_remove` to `Vec`

Maybe we should have had all these methods returning some kind of Result<T, E> or Option<T> since their inception.

This kind of thing comes up periodically, seemingly from a perspective of Result being always better than panic, but that's not really true. If 99% of the time people will just .unwrap() anyway, that's not an improvement -- and indexing seems to be the most common place where it's extremely common for people to have algorithmic invariants that mean they want to be able to just do v[i], not v.get(i).unwrap(). If the precondition is simple to explain and check ahead of time, I'm a big fan of just assert!ing it. This is especially true, to me, for "datastructure-y" things -- there's nothing the user can ever do with a ?ed error about "the index was out of range". It's a bug that needs to go to a programmer, and thus quite different from "I couldn't reach the internet" or whatever.

For the exact same reasons of fallibility, we have

I don't think those are all that useful as precedent here. As mentioned in my other post, try_reserve is about the allocator's fallibility (not about indexing) and both needed an RFC to happen -- which explicitly chose not to have try_push and friends -- and is still unstable. try_fold (and try_for_each) are actually about early-exiting of loops, and they and try_find are about calling closures that themselves return Try types, but of course there's no closures in try_remove. Yes, get is available as a fallible version of indexing. But it's uncommonly used and is only about indexing.

If users were to avoid double bound checks, this is the approach that they'd have to take:

Remember to give LLVM appropriate credit here. The number of checks that appear in the source code isn't necessarily the number of checks that happen at runtime; just the opposite. For example, https://rust.godbolt.org/z/rPbGah

pub fn looks_like_2_checks_actually_2_checks(x: &[i32]) -> i32 {
    x[0] + x[1]
}
pub fn looks_like_2_checks_actually_1_check(x: &[i32]) -> i32 {
    x[1] + x[0]
}
pub fn looks_like_3_checks_actually_1_check(x: &[i32]) -> i32 {
    assert!(x.len() >= 2);
    x[0] + x[1]
}

Similarly, something like this https://rust.godbolt.org/z/559fWe

fn my_remove<T>(v: &mut Vec<T>, i: usize) -> Option<T> {
    v.get(i)?;
    Some(v.remove(i))
}

Also optimizes out the panic check and code path from remove, because LLVM can see that it was already checked -- even though it was checked not-all-that-obviously through get.

ohsayan

comment created time in 16 days

PR opened rust-lang/rust

Replace some once(x).chain(once(y)) with [x, y] IntoIter

Now that we have by-value array iterators...

For example,

-        once(self.type_ns).chain(once(self.value_ns)).chain(once(self.macro_ns)).filter_map(|it| it)
+        IntoIter::new([self.type_ns, self.value_ns, self.macro_ns]).filter_map(|it| it)
+11 -9

0 comment

7 changed files

pr created time in 17 days

create barnchscottmcm/rust

branch : less-once-chain-once

created branch time in 17 days

issue commentrust-lang/rust

Suboptimal performance of BinaryHeap::append

Naively, when I look at the graphs in the OP what I see isn't that extend is always going to be better -- the slopes seem to be clearly different, though two graphs with different scales and extra lines makes that comparison harder than it ought to be -- but that the current heuristic is doing a bad job of accounting for constant factors when picking the switchover point.

Why isn't the answer here just use a number other than two in the heuristic?

2 * (len1 + len2) < len2 * log2_fast(len1)
hanmertens

comment created time in 17 days

push eventscottmcm/rust

Nazım Can Altınova

commit sha a313abe3ba989ba4b6c041627c903488886f8559

Manually implement Debug for BTreeMap::{IntoKeys,IntoValues} structs

view details

Nazım Can Altınova

commit sha 456738e3d1ad7dadffaed287d3055ca38b5fa375

Only print values in the Debug of HashMap::ValuesMut struct

view details

Nazım Can Altınova

commit sha c346e89db8a57e15111daa35685a2542d3be7c77

Manually implement Debug for BTreeMap::ValuesMut struct Deriving debug prints all the values including keys. But ValuesMut struct should only print the values.

view details

Nazım Can Altınova

commit sha 8faf550e5f7211188bc9560ae459c155fb1aafdf

Remove the unused bounds from Debug impl of HashMap::{IntoKeys,IntoValues}

view details

CAD97

commit sha 728938346b02a9688c44253c19b15baa7551fd80

Adjust rc::Weak::from_raw to support unsized T

view details

CAD97

commit sha 0c61ce2cf0560577923abafab2e5bfce14516525

?Sized bounds for rc::Weak::as_ptr and friends

view details

CAD97

commit sha 5e7406c9569dce75a042ce079918cf03cfca842a

Adjust sync::Weak::from_raw to support unsized T

view details

CAD97

commit sha 9d9903c5a50bb1f5b5fc3045b86172279eff7d30

Allow Weak::as_ptr and friends for unsized T

view details

CAD97

commit sha 3d07108d3600dff50e564f57dd390337dbe14d55

Add tests for weak into/from raw

view details

Jubilee Young

commit sha 247b73939a619ea4dcb2affbe1c285d20d93a0b8

Move Wrapping<T> ui tests into library

view details

Jubilee Young

commit sha 797cb9526a627c37b9bb9f6be6d3b54789b67c26

Fix to libstd test

view details

Mara Bos

commit sha 84ef603c8400db203fefd714de963c88e5523424

Fix 'FIXME' about using NonZeroU32 instead of u32. It was blocked by #58732 (const fn NonZeroU32::new), which is fixed now.

view details

Without Boats

commit sha 82f5928ca68acceb1d1bd9e2b09554744e4a1dfe

Make RawFd implement the RawFd traits

view details

Without Boats

commit sha acc136ce0a665a32ddf1a16544b6f6d7a7153c30

fix typos

view details

Without Boats

commit sha 3fe279fc658450a3e3140f014554139493674217

spend another CI build to delete a double newline

view details

Without Boats

commit sha 35b30e29bffe8c4aa896ce53ded67c54401f7643

try again to appease tidy

view details

Tim Vermeulen

commit sha ecacc7534b6bf50205c37c89402565b82d95a257

Add advance_by and advance_back_by

view details

Eric Huss

commit sha c29a29cba099aef1e05c83970decdcbedaabd69a

Defer Apple SDKROOT detection to link time.

view details

Eric Huss

commit sha de725fe56f338a2ceedf5dd9df5bcd86a24f8f53

Remove note about missing ios/tvos targets in platform docs. I misunderstood how this works, and I have fixed the linux builds to support ios/tvos.

view details

Guillaume Gomez

commit sha 980e1ff40f51b6b4b86ee70809d0a0055e6f9cc6

Add missing examples for Fd traits

view details

push time in 17 days

issue commentrust-lang/rust

Tracking Issue for slice_check_range

I think having the https://github.com/rust-lang/rust/pull/76885 version of this for precondition checking is great.

I'm dropping by from https://github.com/rust-lang/rust/pull/77480#issuecomment-703152193 to ponder whether there's other, more user-focused versions of this that could make sense too. Spitballing: something on SliceIndex like .check_index(x) that could return Result<Range<usize>, _>, targeted more at users who want to check things before calling other methods than at people implementing APIs that take RangeBounds.

dylni

comment created time in 17 days

pull request commentrust-lang/rust

Add `try_remove` to `Vec`

I feel like this is a convention change to Vec, and thus needs more than just a PR.

Because, as @timvermeulen mentioned, why is this just to remove? If we have try_remove, why not also try_drain and try_split_off and try_splice and try_swap_remove and try_insert? (Not to mention slice methods, like try_split_at or try_rotate_left or ... And should VecDeque get all these methods too?)

The preconditions for the indexes on all these are simple enough to check yourself, so I don't think it's worth the API bloat to have non-panicking versions of all of them, and I don't think that any of them are special enough to have such a version when the others don't.

That said, maybe it would make sense to have a fallible form of an API like https://github.com/rust-lang/rust/pull/76885 that people could use to check bounds without panicking or hand-coding it? Though I suppose v.get(x)?; can already serve as that just fine.

(Note also that it took https://github.com/rust-lang/rfcs/pull/2116 to add try_reserve, and that's not even stable yet. That's not quite the same, because it's about the fallibility of the allocation, but that does mean that a hypothetical try_insert would have to get into questions about fallibility in the allocation too. Of course that particular consideration doesn't apply to try_swap_remove and such that don't need to allocate, but I think it's still interesting prior art to look at for try_* on Vec.)

ohsayan

comment created time in 17 days

issue commentrust-lang/rust

[ER] Int::RANGE constants

where I look for the first integer value that satisfies a predicate

Even then, though, I'd probably just use 0.. -- I'm not going to finish scanning all the u64s anyway, so if there isn't one I'm in trouble regardless.

If this is mostly dependent on subrange types, then I think this should just be a note in an item in the rfcs repo, since as I understand https://github.com/rust-lang/rfcs/pull/2979 they're looking at cleaning up issues here. Or if you think this is useful enough now to pull its weight it can just be a PR. (But of course I'm not on libs, so I might be wrong.)

leonardo-m

comment created time in 18 days

pull request commentrust-lang/rust

Clean up on example doc fixes for ptr::copy

@bors r+

pickfire

comment created time in 18 days

pull request commentrust-lang/rfcs

Destructuring assignment

@thepowersgang There was some discussion about that above, https://github.com/rust-lang/rfcs/pull/2909#issuecomment-615416370 ; does anything there change your feeling?

varkor

comment created time in 18 days

pull request commentrust-lang/rfcs

Add 0000-vecdeque-binary-search.md: Binary search fns for VecDeque

The benefit of this design is that it's very simple and just follows what's already established for slice and Vec.

I agree, and as such I think you can just submit it as a PR. This would be an inherent method, thus can be stabilization gated, and there are no API questions since it's just following the existing precedent.

(The more general version would probably be setting new precedents -- for example, we only have sort on slices, not general iterators -- so that one would probably have more value in being an RFC.)

But of course I'm not on libs so you can always wait and see what they say.

vojtechkral

comment created time in 18 days

more