<!-- Thank you for creating a tracking issue! Tracking issues are for tracking a feature from implementation to stabilization. Make sure to include the relevant RFC for the feature if it has one. If the new feature is small, it may be fine to skip the RFC process. In that case, you can use use in your initial implementation PR. The reviewer will ask you to open a tracking issue if they agree your feature can be without an RFC. --Feature gate: This is a tracking issue for making the function . <!-- Include a short description of the feature. --<!-- For most library features, it'd be useful to include a summarized version of the public API. (E.g. just the public function signatures without their doc comments or implementation.) --<!-- For larger features, more steps might be involved. If the feature is changed later, please add those PRs here as well. --- [x] Implementation: [ ] Final commenting period (FCP) [ ] Stabilization PR <!-- Once the feature has gone through a few release cycles and there are no unresolved questions left, the feature might be ready for stabilization. If this feature didn't go through the RFC process, a final commenting period (FCP) is always needed before stabilization. This works as follows: A library team member can kick off the stabilization process, at which point the rfcbot will ask all the team members to verify they agree with stabilization. Once enough members agree and there are no concerns, the final commenting period begins: this issue will be marked as such and will be listed in the next This Week in Rust newsletter. If no blocking concerns are raised in that period of 10 days, a stabilzation PR can be opened by anyone. --<!-- Include any open questions that need to be answered before the feature can be stabilised. If multiple (unrelated) big questions come up, it can be a good idea to open a separate issue for each, to make it easier to keep track of the discussions. It's useful to link any relevant discussions and conclusions (whether on GitHub, Zulip, or the internals forum) here. --- None yet.
This got reverted again by , but hopefully we can re-land it soon.
Sorry, I misread, this feature gate is not affected (but some others are).
Any news on this?


I don't see anything holding it back; especially now that transmute itself is const. EDIT: Never mind, I just saw
Since is const-stable nowadays, I think this can be stabilized as well. Feel free to open a PR. :) Cc
I didn't do this before, I am reading the docs for how to do this, and there's an rfcbot final commenting period thing. Should this be done? If yes, how? I probably don't have the rights to do it.
You just need to prepare a PR. I can help get the FCP process started in the PR.


I'm pretty sure it is possible to set custom paths for , & in but not for clippy.
label +T-bootstrap


and I are working on diagnostics for the rest idiom in slice patterns () and came across this issue when an attempt is made to use it in tuples and tuple structs. IIUC, this is allowed: and this is not allowed (note the addition of ): The error messages for the tuple and tuple struct cases include the following incorrect information: This should state that the id binding to rest is not allowed. patterns are allowed. is only allowed in slice patterns, not in tuple or tuple struct patterns. This should state that the idiom is only allowed in slice patterns. <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
appears to be the site of the check: This method is called:
Perhaps it's worth supporting "tuple slicing" pattern too in Rust:
that would implicitly create a tuple for (or a slice?). I don't think it'd be a good addition. We already support , which is much more useful in my eyes.
That syntax is meant to produce a shorter tuple xs with the omission of the first item of the tuple. lf you think it's an useless idea then let's ignore it :)
claim


Currently, will panic, but will not, because the expression is not evaluated in that case.
Also, crashes the compiler. Maybe it's the same issue?
Thanks for the reminder, fixes that as well.


Mm, we have "method macros" but now there are other things that can go in a trait.
Seems to be fixed by , but I don't see tests for it specifically, so I guess this needs tests.


Rust Version: rustc 1.0.0-nightly ( 2015-02-12 00:38:24 +0000) Description: When compiling the following code with rustc the output is: ERROR:rbml::reader: failed to find block with tag 7 error: internal compiler error: unexpected panic note: the compiler unexpectedly panicked. this is a bug. note: we would appreciate a bug report: note: run with for a backtrace thread 'rustc' panicked at 'explicit panic', C:botslavenightly-dist-rustc-win-64buildsrclibrbml stack backtrace: 1: 0x69bfbbeb - sys::backtrace::write::h57b621d79849130fitB 2: 0x69c13974 - rt::unwind::register::h686925f8fa692ab9GSJ 3: 0x69b836ef - rt::unwind::beginunwindinner::hc2a974b1bdaa4639YPJ 4: 0x302da8 - reader::maybegetdoc::h2547f886a15a227erHa 5: 0x301d2f - reader::getdoc::hc198b8918d0de179nLa 6: 0x1138635 - metadata::decoder::itemtype::h7f6e008c4a79af18mck 7: 0x11480d9 - metadata::decoder::gettype::h9620389d7a7d23c0Xok 8: 0x10fb7a8 - metadata::csearch::gettype::h3af5a6a2534b2d8bCkn 9: 0x6d605059 - collect::CollectCtxt<'a, 'tcx.AstConv<'tcx::getitemtypescheme::he174d5be00f2627cMFw 10: 0x6d5f49ab - rscope::ShiftedRscope<'r.RegionScope::anonregions::h0a5ed4a2d46d3aeeqlu 11: 0x6d5f64ef - rscope::ShiftedRscope<'r.


RegionScope::anonregions::h0a5ed4a2d46d3aeeqlu 12: 0x6d5978bd - astconv::asttytoty::h1dadfccc9ddb5e90VHv 13: 0x6d5ef523 - rscope::ShiftedRscope<'r.RegionScope::anonregions::h0a5ed4a2d46d3aeeqlu 14: 0x6d5fa734 - rscope::ShiftedRscope<'r.RegionScope::anonregions::h0a5ed4a2d46d3aeeqlu 15: 0x6d61330f - collect::CollectCtxt<'a, 'tcx.AstConv<'tcx::tcx::hf449f596d422460aAFw 16: 0x6d60a79a - collect::CollectCtxt<'a, 'tcx.


AstConv<'tcx::getitemtypescheme::he174d5be00f2627cMFw 17: 0x6d643867 - checkcrate::h72731a5b4298723fkrB 18: 0x6d64131c - checkcrate::h72731a5b4298723fkrB 19: 0x70b1eb58 - driver::phase3runanalysispasses::hc863f28a1bd50b11SGa 20: 0x70b02618 - driver::compileinput::hd580d8c011d24ba3Eba 21: 0x70bcfc4c - runcompiler::hb48a33a057cced0e5bc 22: 0x70bcd85b - run::h3df2025cf41d43b3Ibc 23: 0x70bcc56a - run::h3df2025cf41d43b3Ibc 24: 0x69c4180c - rusttry 25: 0x69c417e9 - rusttry 26: 0x70bccbdc - run::h3df2025cf41d43b3Ibc 27: 0x69c03ae2 - sys::tcp::TcpListener::bind::h2319ec78a0f49dc2faF 28: 0x770f59ed - BaseThreadInitThunk
Same error as .


I got this while trying to implement something similar to a FromStr trait and tried to rely on a lot of inferencing when calling it. I can try to extract a standalone example if needed.
This ICE is also producible by trying to refer to an associated type that's never defined. is accepted by the compiler when it clearly should not be - what on earth is ? The following and code cases the same ICE. Here's the stack trace:


I get the ICE below when I compile this fragment of code: The above structs are defined here: The above fragment is part of That crate depends on And that crate requires erlang-17.4 to be installed.
A minimal program to demonstrate the crash is...


compile with opt-level = 2 (works fine with opt-level=0)
strange. the program looks legit to me.
this works for me now, as of
This prints on all opt levels for me at .


I tried compiling this code: which resulted in the following output of rustc: So the compiler says So I tried adding a borrow and recompiling the code: which resulted in: so the compiler says and so I'm stuck in a loop. The compiler can't decide whether I should borrow or not. As a newbie to Rust, this is very frustrating and the opposite of helpful, it just confuses me further. Please fix this indecisiveness :) :
For reference, what you likely want to do is one of the following which means they cannot be the type of a local binding. You can give a binding a slice type (), because that's morally equivalent to a pointer (with sizing info), which has a compile time determined size, as all borrows are .
Current output: After :


Implemented in rust impl<T: PartialEqVec<T{ pub fn remove_item(&mut self, item: &T) -Option<T{ /…/ } }
PR moved to due to reasons
Comments from original thread: think that we should add this method to too. desired?
for you can simply do
I meant specifically a method that searches for the item from the end of the vec instead of the beginning
What do you think about adding ? Just as reduces the runtime complexity from O(n) to O(1) compared to , would reduce it from O(n + (n-m)) to O(n).
I like .
It would be nice if this was more generic. let v: Vec<String= Vec::new(); v.removeitem("s"); <-- fails because &str is not a &String we really want the removeitem "item: &T" to be "something that we can compare equality with the type in the container". This would let remove_item() walk the T items, compare equality, and remove if equal.
Seems reasonable to change the signature to
Reviewing the naming used in method names and the docs, it would seem that iterators yield items while vecs contain elements. Considering that we then we should also remove elements and the method should be called . That name is a bit long so I'd propose simply . However I wonder if we should favor a more general , or have both.
Any plan to stabilize this?
This has been in nightly for a year with no issue reported on the method itself. There are proposals for additional methods, but that shouldn’t block this one. Please submit separate PRs or RFCs. fcp merge
Team member has proposed to merge this. The next step is review by the rest of the tagged team members: [x] [x] [ ] [x] [x] [x] [x] Concerns: resolved by Once a majority of reviewers approve (and none object), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See for info about what commands tagged team members can give me.
Are we switching to a bound?
Oops, sorry I missed that. Yes, let’s.


Again here, as a maintainer of collections that offer the Vec and VecDeque APIs I'd like at least a summary comment explaining what this method does, why this design was followed, alternatives, and addressing the issues mentioned here that have received zero replies: should this method be to ? : naming issue: why s instead of elements? why instead of , etc.
concern rationale-and-vecdeque Just gonna formally register concern above
Not an issue with the method per se, but it may need to be very clearly documented that the reference is not supposed to be to an item that is in the already, as it creates impossible borrow-checker conundrum. Users coming from the C world of pointers but no proper equality comparison, may be confused by this method, e.g. The name mentioned previously would help.
as the proposer for FCP, do you have thoughts on concern?
My thinking is that the suggested by would sidestep most of the issues here.
cc re.
I don’t have a strong desire for this particular feature myself, I proposed FCP as an effort to reduce the number of features in "unstable limbo". That said: Regarding , sure, I don’t see a reason not to add it there as well. as proposed in sounds good to me. It is more general, and goes with precedent of also taking a boolean callable predicate rather than relying on . (Even further, the precedent of not having a method like that would rely on .)
I notice two things: are a lot of methods similar to this we could add, and its not obvious to me which set of those methods is the ideal set. has sat in FCP concern limbo for 8 months without anyone complaining. I think we should not stabilize this just because it exists, but instead someone should come up with a well justified explanation of exactly what the best "find and remove" set of methods of vec-likes would be.
Good points. (which is stable) and also fit the "find and remove" description, and we had a similar concern about the combinations of filtering v.s. non-filtering and self-exhausting on drop () v.s. not.
resolve rationale-and-vecdeque I don't want to personally be on the hook for blocking this any more
:bell: This is now entering its final comment period, as per the .


:bell:
The final comment period, with a disposition to merge, as per the , is now complete. As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed. The RFC will be merged soon.
I still think this should be called instead of .
My problem with that name is that it only removes the first matching item, not all that are (though I haven't read the relevant RFC to know whether the name has been hashed out already; I assume it has been).
I don't think the naming issue has been resolved. The implementation is still using the name. then?
Can someone clarify what the status of this is wrt. the conversation above?
An example: I'm writing a proc macro attribute, and amongst the tokens, I expect other attribute to be there. This would be useful to add:
Until we sort this out, you can use
Ping. What's the status of this? Could we stabilize something?
? Given we already have drainfilter for accepting a predicate, it would be nice to have a method that removed a single object from the vector (if there). Removing something from a vec is exceedingly common code. Getting the position and then removing that position is longwinded for such a common operation. (Btw, I think bit of naming is excellent as it highlights that there may be others still in the vec - a method name that prompts one to think is a good thing.)
I use for this, and haven't found it too cumbersome. It differs in that it removes all copies of a given item, but is very easy for many purposes.
Retain everything but the object? As work-arounds go that's shorter, but it's not ideal for expressing intent. Still keen on and .
Just to bring up a different opinion: how about removing this method instead of stabilizing it? While yes, it would be convenient to have, it might not be worth it. For one, is not a good name, as many already said. The name doesn't imply that the first item from the start is removed. is better in that regard, but still doesn't feel completely right. More importantly, if we have , we should certainly also have . Having one but not the other feels arbitrary to me and makes for a surprising API (that's bad).


Similarly, we would also want to add the variant of both of those methods. Potentially, we also want to add a variant that removes all items equal to the given . And as also already mentioned, we can also add all those methods to . And why not (without the versions)? Consequently, we would have to add 10 or 15 new methods. Adding fewer would make the API inconsistent IMO. All the functionality can be implemented with very little extra code with iterators.
How do you propose this be implemented with iterators? How about this signature: This uses to make it clear exactly what is removed. The argument and the return type makes it clear that we remove many items. The user has the option of how many to remove ( means all). The returned iterator can be implemented efficiently by shifting the items and then pulling a similar trick (using ) to to yield the removed items.
already mentioned this : I think that one is too complex. Especially when considering the call site, I think it's fairly hard to understand. And the name still does not imply that the search begins at the beginning, which is a big nono for me.
Removing an item from a vec is a very common codepath. Somehow it needs to be a one liner. Having swapremovefirst() and not having removefirst() would be nudging people in the direction of great performance. That seems quite rustic to me. swapremovelast is interesting as there maybe no swap needed if it happens to be the last item - cute. Just have those two functions. That’s the 80% case covered. People who wish to maintain order will just have to have slightly more code. On Fri, 15 Nov 2019 at 19:20, Lukas Kalbertodt <:
I don't understand the focus on removing here. Vec has a lot more members taking an index than and , and only a few to get hold of an index value ( variants and , sort of). Most of the complication in the "workaround" for this remove_item is finding the first index of something: v.iter().position( n == 2) Not too bad, the reminds you it's a linear search, but could be easier.


<delWorse for the last index: ().rev().position( v.len() - i - 1) Contrast to the and in that famous vector called string that (ugly names but at least they convey that a search is involved). I've vary rarely needed this, I don't advocate making linear searches easy, it just seems more useful to try to make searching easier, before making search-and-removing easier.
(so does ). And even if it didn't exist, that has no relevance to whether should exist or not, they're separate features, so they can both exist, it isn't either/or. (I personally have had many cases where would have been useful, it's a common operation in any language.)
Waaait! It's getting stabilized without fixing the confusing name! Please please don't call it , as this is the same name as in other languages that can remove item from an array by presenting an item from the same array. Rust's version can't do that due to borrow checker and it's a trap for users.
I absolutely wouldn't call it a trap.
It seems like many people agree that the name should at least be up for debate again. Really unfortunate how the name discussion was somehow forgotten during FCP. So I guess we should revert stabilization as soon as possible so it won't end up in beta?
Sounds reasonable. Maybe someone wants to volunteer to lead the process about settling on a name for this ?
The next release is scheduled for Jan 30th. So we have about 3 weeks to figure out a new name.
I went through the thread again and it seems like the following names are suggestions for the method as it currently exists: (iterators have "items", Vec has "elements") - Personally, I would absolutely include , as that's an important information and . I have no preference between and . However, from reading the thread again it seems there are plenty of other concerns and suggestions that haven't been resolved yet: Adding similar methods: ? ? Replace the method with:  (although I don't understand that one. Is it just a with flipped predicate? In that case I don't think it's useful. If it just removes the first element, then absolutely needs to be in the name IMO.) Do not stabilize this method at all: ,
mentioned : also raised some more concerns , and I raised some concerns .


I don't see where these concerns have been resolved. From re-reading this whole discussion, it isn't clear to me what the goal of adding this method is nor what problem does this method solve or whether this is a problem worth solving. What's more or less clear to me is that there is at least some design work to be done to at least ensure that libstd exposes a consistent API, and that sounds like this would warrant an RFC to me. The current discussion about using a method hints that these APIs might not only want to be consistent for the ordered collections (Vec, VecDeque, List) for which a notion of a "first" element makes sense, but might also want to be consistent with the e.g. and methods of slices. The main arguments for FCPing this appear to be that this has sit on nightly for too long without anybody complaining, and the main argument for stabilizing this has been that this has been in FCP for too long. I think it would be better to just encourage and support those that want to land this feature to write a small RFC for it. If somebody is interested in doing that, I would be able to help and give feedback.
Unless a concern is made with by a relevant team member, then it won't stop FCP. And it won't go into FCP unless the majority of team members have voted for it (and there aren't any formal concerns listed). So the fact it passed FCP means that all relevant team members that they were okay with the current design and did not have any outstanding concerns at the time. Things do not go into FCP simply because it's been "sitting around too long". Of course if any team members do have any concerns, now would be the best time to make them.
Mistakes happen. And to me this thread clearly looks like many concerns were overlooked accidentally and no one explicitly marked them as concerns for rfcbot. Luckily those mistakes were caught.
Reopening because
The current signature is missing a ?Sized bound. Could I ask for a PR to fix the bound and add a test that covers remove_item("...") on a Vec<String? This use case was requested in and
Separately: I am leaning toward removing removeitem.


I agree with and The currently design involves: start with a reference to a value not in the vec, use its PartialEq impl to do a linear scan, remove the first found, shift everything after the removed element. To generalize almost all of the discussion above, people are questioning whether the conjunction of all 5 of these decisions is really as common as a name like removeitem would suggest, whether a different permutation of choices might be more widely applicable, and how to adjust naming to leave room for all the other equally or more common permutations: ones where the ref we want to remove is a ref to a vec element, or we want to remove by FnMut instead of PartialEq, or we want a binary search, or we want to remove the last, or all matches, or we want the more efficient swapremove behavior. Fortunately Vec already supports all permutations of these use cases equally well, with nice independent APIs for searching and removing. Many people have voiced opinions equivalent to "removing an item from a vec is so common that there absolutely must be a function for it". I think what they mean is that the union of all permutations of the above 5 choices is common, which is true; they don't necessarily mean the specific choices that go into removeitem as it exists would justify a method specific to those choices. points out that satisfying the set of use cases which all together are common would take a much larger number of new methods.
Per , I think we should go ahead and remove . fcp close
That is not what I meant. When I said that I need in my code, I meant exactly that: that I could take my existing code and replace it with and it would have exactly the same behavior, because I really do need specifically, not the other fancier methods. I'm perfectly fine with changing the name so that we can accommodate other fancier methods in the future, but why would that mean that we shouldn't have at all?
fcp cancel
proposal cancelled.
Per , I think we should go ahead and remove . fcp close
Team member has proposed to close this. The next step is review by the rest of the tagged team members: [x] [x] [x] [x] [ ] [x] No concerns currently listed. Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period.


If you spot a major issue that hasn't been raised at any point in this process, please speak up! See for info about what commands tagged team members can give me.
Checking KodrAus’ checkbox per
:bell: This is now entering its final comment period, as per the . :bell:
The final comment period, with a disposition to close, as per the , is now complete. As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed.
Since we've merged the deprecation would we like to close this tracking issue now? Or keep it open until the unstable deprecated method is removed entirely?
I think keeping this open until we removed the method is a good idea. How long do we want to wait with that by the way? I guess a couple of cycles is sufficient?
Before closing, it would be great if someone could suggest a "one clean and obvious" way to remove the first/last occurance of an item from a Vector. Irrespective of the arguments made here, a method removing the first/last occurance of an item is provided across all major programming languages, and is to be "expected" Anyone new to rust is bound to google "remove from vec rust" and end up on this discussion which would only leave them more confused.
should answer those questions. But here is a copy of my answer for convenience: You can of course handle the case however you like (panic and ignoring are not the only possibilities). Like the first element, but replace with . Remember that has a runtime of O(n) as all elements after the index need to be shifted. has a runtime of O(1) as it swaps the to-be-removed element with the last one. If the order of elements is not important in your case, use instead of !
It might be worth adding more examples (maybe all of the ones above) to the docs.
I'd like to add those to the docs, should they go along the example that we currently have?
What examples are you referring to? I could imagine those "remove examples" either going on the type (as a new section "Removing elements" or something like that) or directly on the method (below the existing docs). And by the way, feel free to add (parts of) my text/examples verbatim.
Thank you.


I was referring to those "remove examples" as to whether I should append them to what we currently have in docs for , put them somewhere else or perhaps modify examples for to include removal of specific element
That sounds fine to me. Feel free to just open a PR and we can still see about the specifics then :)


<!-- Thank you for finding an Internal Compiler Error! If possible, try to provide a minimal verifiable example. You can read "Rust Bug Minimization Patterns" for how to create smaller examples. -- On stable the code produces the following error as expected: <details<summary<strongExpected result</strong</summary<p</p</details<!-- If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. --: <!-- Include a backtrace in the code block by setting in your environment. E.g. . --<details<summary<strongBacktrace</strong</summary<p</p</detailssearched nightlies: from nightly-2021-10-04 to nightly-2021-10-23 regressed nightly: nightly-2021-10-16 searched commit range: regressed commit: <details<summarybisected with <a href=''cargo-bisect-rustc</av0.6.1</summaryHost triple: x8664-pc-windows-msvc Reproduce with: </details<!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOT_END --
Also ICEs on beta. label regression-from-stable-to-beta
Interesting, this is rustc now, right? There has been as similar rustdoc ice:
Yes, this can be hit with or for example. I tried running the code in , but it seems to have been fixed by now.
claim I'll try to take a look at this.


Steps to reproduce: The output of is: does as suggested by the message, but that fails too (as expected): Proposed fix: in the beta and stable channels (i.e. whenever is forbidden), the message that suggests adding should not be shown. (Clean up the test case with .) CC
Gonna milestone this real quick, as it seems quite important.
I might be able to whip up a quick fix, though I'm not 100% sure about testing it properly ... (I've never actually tried building something for a non-dev release channel before...)
after chatting with it seems like I have a patch, building it now
gonna leave to it
Hello good Rust folks :smile: Before the beta, I used which is in . Is there any way to use this trait during the beta ? I'm not sure how I can get the code to compile. Thanks for any tip / hints you can offer :+1:
Hi Commenting on random unrelated issues is usually not the right thing to do. You should rather open a new issue, or ask on . But to answer your question anyway, that trait only has : … and is stable and can be used on beta. So I’d recommend you copy/paste the trait into your code, or make a function.
Thanks for taking the time to answer. I appreciate it. I don't see how this is unrelated. This is related, since the code I'm talking about used to compile with and the compiler suggests to do that, during the beta period. Thanks for your tip on copying the function :+1: I guess I'll just do that if nothing better is available and change this again when the trait is stable.
This specific issue is about fixing one of the compiler’s error message, not about fixing code that triggers that error. It really helps everyone to keep discussions on topic.
Alright. I understand. I'll make sure to open a new issue or go on StackOverflow next time if appropriate. Thanks again :+1:
This doesn't seem to be properly fixed in the beta channel. I'm still being recommended to add in the errors, and then told it's not available in the beta channel. Rust version: The code I used (snappy example in the docs with the extra addition on the first line:
This happened after Beta release.


We'll see the effect of this patch in 1.0 and afterwards Beta, etc.
Whoops, I thought this made it in before beta. Thanks!
are there plans to release updates to the beta channel within a given 6 weeks cycle? Either this one or in the future.
I'm certain there will be updates; see discussion from last night here:
So how does one fix this error? I'm a new user of the rust library and I can't seem to use the collections library during the beta due to this problem. Given this git issue is a top google result, it would be nice if there were a solution here. Edit: Looks like the solution is to switch to the rust nightly. Is the entire collections library off-limits in the beta?
by design, you have access to the parts of that are re-exported from (and are stable).


Rust compiler (rustc 1.1.0-nightly ( 2015-05-14) (built 2015-05-14) fails to compile this source: With the error: I can reproduce this ICE also on
Reduced it a bit:
The broken IR:
Looking through it quickly, it seems like the order of the cleanups is messed up? If is then from the switch we go to the label which just jumps to where we memcpy the value for into the alloca and then continue to the label. This is where the problem is since it tries to call on the value returned from . But that's the thing, we wouldn't have called in that arm of the branch and hence shouldn't need to call free either.
Adding a block around suppresses the error. I feel like we had a similar problem not too long ago.
This is "caused" by the micro optimization for dereferencing owned pointer rvalues in . Since is the "trailing" expression for the arm its cleanup will be scheduled in the same scope as the match expression. cc
Either way, this is a dupe of I believe had an idea for a fix.
it's simple, we remove the micro-optimization and always return an datum from . The possibility of returning datum also caused issues with field accesses - see for that fix. We have a static type system and the / marker types are there for a reason. If there is no answer to "how is an rvalue dereference or field meaningful?", then the return type for both of those should be .


Original testcase by (reduced from ): The debug log reveals that a (shallow free) cleanup of the rvalue is scheduled in the scope of AST node , while the dereference expression itself has id : reveals that id refers to the entire function's block: This means the cleanup of a value valid only within a match arm is scheduled outside the arm. cc
Dupe of Leaving open for now but we can close either.
This is caused by a micro-optimization specific to dereferences of rvalues. Is this used oftenly enough to justify its existence in the first place? Even if it is, I guess we can disable it in problematic cases like this, where the temporary scope of the match arm's RHS is outside the arm.
I think we can probably remove it, in general removing special treatment of seems like a Good Thing
Triage: this still ICEs.
can you point me/us at the micro-optimization that you mentioned above, so that I (we) can try removing it ourselves and measure the impact?
I only vaguely recall this issue, but I'm pretty sure I was talking about .
triage: still ICEs.
Indeed, it doesn't even need : Does this at least continue to ICE even if LLVM is compiled without assertions? If not, we may want to up the priority on this ticket.


<!-- ICE: Rustc '' 'thread 'rustc' panicked at 'no entry found for key'', 'thread 'rustc' panicked at 'no entry found for key'' File: --auto-reduced (treereduce-rust): original: Version information ` Command: <!-- Include a backtrace in the code block by setting in your environment. E.g. . --<details<summary<strongProgram output</strong</summary<p</p</details<!-- query stack: [resolverforlowering_raw] getting the resolver for lowering --
this probably crashes since but I haven't verified that yet
smaller
even smaller


Rustdoc on [nightly documents][1] methods have signature of as while it only has to document it as . ! On [rustdoc stable][2], things are normal: ! : Version 1.49.0 ( 2020-12-29) [1]: [2]:
I'd like to investigate this :)
searched nightlies: from nightly-2020-12-29 to nightly-2021-01-22 regressed nightly: nightly-2021-01-09 searched commits: from to regressed commit: This regressed in , so this is probably caused by
This also affects Where will generate:
So a few observations: which displays mutability in patterns, causing to be displayed the mechanism for detecting and eliding works by , but as returns instead of , the comparison fails and displays the type.
I see two path to solving this bug: an option for to not display the mutability in patterns revert cc what do you think?
I would prefer to go for 1, there's no reason to have two completely different functions for pretty-printing.
Assigning and removing as in the prioritization working group.
(now a beta regression)


New contributors haven't use before, so there's no reason for them to read the changelog: nothing has changed.
I can tackle this.
that would be great! To get started, take a look at . In addition to adding , also add . You'll have to move from to so you can access it in . You should also double check that the changelog warning isn't printed during the command itself. I'm not sure exactly how to do that without reading the code, but I expect it to be a simple or something like that.


is unacceptably slow. Consider this code: When trying this code, make sure you have enabled release mode. On my local machine I see this output: So is 15x slower than . My rustc version is . My OS is Debian Stretch x86_64
label +A-process +I-slow
On windows they are both equally fast, so it seems to be a unix-specific thing. Also note that these two programs are not equivalent, as also reads , while you don't (this probably introduces some overhead). Still seems worth at least investigating.
What's the magnitude of slowness here? and what's the time taken on windows? Here's it on my computer, built with release mode My computer : Apple M1 Mac Mini, 16gb RAM and 8 CPU Cores
. I just compared old rustc () and new one, with this fix (). I see that the bug is actually fixed, thanks a lot! Moreover, both benchmarks became faster


For this code: You get the following error message: The suggestion may be excused to be not 100% perfect, but here it suggests to add an use statement despite that same item being imported already. What I want is this exactly: that it removes stuff from the suggestion list that is already being imported. Note that changing the glob import to a non glob one doesn't change anything.
cc
Why is that even an error?
tuple structs have private fields by default, you can't construct instances of B outside of the foo module.
oh ^^ maybe we should simply modify this error message then to say that the "function" is private?
It already says "constructor is not visible here due to private fields". That's okay, but maybe you might have meant another B from another module or something. However, the candidate offered is not any better as its the same one you are attempting to use.
Reopening to track "removal of suggestion" work for pub tuple structs with private fields.


<!-- Thank you for finding an Internal Compiler Error! If possible, try to provide a minimal verifiable example. You can read "Rust Bug Minimization Patterns" for how to create smaller examples. --<!-- If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. --: Not posting the entire 1.7K lines backtrace :upsidedownface: <!-- Include a backtrace in the code block by setting in your environment. E.g. . --<details<summary<strongBacktrace</strong</summary<p</p</details
You can also reproduce this in the rustc repo itself where will encounter the error with
Reduced: label F-typealiasimpl_trait
Found another repro I think: this one bisects to
`
prioritize
going to also link and as other reports of the same issue
WG-prioritization assigning priority (). label -I-prioritize +P-medium
Ok, after a bit more back ond forth , I'm tentatively bumping this issue to P-critical and raise these questions (echoing the comments from the discussion): would it make sense to revert ? cc or would it make sense to revert (which IIUC leaked in the std library an unstable nightly only feature) ? cc Next week Rust 1.72 will be released, artifacts are going to be build real soon, I think. Thanks for additional comments to help improve my understanding of the context here. label -P-medium +P-critical
The underlying issue here is an issue with TAIT. was an implementation-only change simplifying some backtrace code in that was made under the assumption that TAIT was reliable enough to be used inside . As it is not user-facing it should be easily revertible. So the question here is whether it is safer to get TAIT working (potentially by reverting ?) so it can be used internally or to just hold off on using it until the issue has been resolved, reapplying once that happens. I have no compiler experience, but my initial hunch would be that the library change is preferable for now. I'll get a PR ready until tomorrow, unless someone beats me to it.
should not be reverted.


All it does is cause us to now eagerly reveal opaques that were being skipped over during normalization, which means that we're just not hitting this code anymore: It does not introduce a bug, it just reveals one that already existed. I'm gonna use the minimized example () here. What's happening here is that we're generating a drop shim for that looks like: which then tries to validate that . However, it has type , where is a , which does not hit the code I linked above. Before , we'd emit something that looks like: which is a field that is incompletely normalized, but does* hit the code above.
Submitted the PR reverting : .
fixes this issue by not considering mir validity on shims until they have been optimized, which uses the reveal-all param-env for that shim. This ICE shouldn't be possible to trigger without , since it has to do with one of the intra-pass mir validations that are only done when that flag is active: I don't personally think that needs to be reverted, either.
This was also possible to trigger even before using an associated type. The test in exercises this too.


The expansion of and both currently cause code to fail the stability check because they expand to reveal unstable implementation details. A seemingly reasonable solution to this would be to just not run the analysis on any code that has been macro-expanded. cc
I definitely agree with this approach: we should be able to annotate a macro with a stability level, and that's what should count for its users. Do we have a way of telling what part of an AST was generated via macro expansion by the time we get to linting?
Mostly; there's the field of a : for normal code, for macro generated code (basically containing the backtrace of macro invocations that led to that point).
OK, that makes this sound like a pretty easy fix. I'll take a quick look at it tomorrow (unless wants to?)
Hm, this seems slightly subtle, since the contents of a macro would then never be checked for stability. This differs to a conventional function, e.g. given , won't warn, but the contents of is still checked, while where is just never checked. (Of course, macros and phasing are both feature gated so you have to opt-in to instability to use non-standard macros anyway.)
Good point. Also, it looks tricky with the current infrastructure to even lint on the macro invocation -- the backtrace of macro expansion does not appear to link to the def_id of the macro (or give any other way of getting at the macro's stability). Nevertheless, I think we should bail out of the lint when we hit the results of expansion; those should be checked, if anywhere, at the site of macro definition. One other question: do syntax extensions also produce the span information you mentioned above? I ask because original problematic cases are written syntax extensions. If not, is there some other way of telling that an expansion happened?
I have a patch ready that bails of out the lint on expanded code. This also seems to mask uses of . If y'all are ok with this strategy for now, I'll file a PR.
Sounds good to me. Thanks!
cc


<!-- Thank you for finding an Internal Compiler Error! If possible, try to provide a minimal verifiable example. You can read "Rust Bug Minimization Patterns" for how to create smaller examples. --<!-- If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. --: <!-- Include a backtrace in the code block by setting in your environment. E.g. . --<details<summary<strongBacktrace</strong</summary<p</p</details<!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
Slightly minimized:
I understand the issue here, and have a solution but it might not be optimal. claim


suggested an optimization for , and it was implemented in . However, for some reason, was not optimized the same way: It can be implemented in terms of : Is this deliberate or just something that no-one noticed?
By the way, you don't need to open an issue if you're about to open a PR. Just include what you would put in the issue in the PR!


The multi-line errors should be extended to include this testcase. missed this because the didn't go through . I tried but that didn't work either. If someone can point me to to where to catch it, I can probably fix this too. cc Code: Error: Change to:


Following , we realized that rustdoc users would prefer to have a syntax extension rather than using plain HTML to have warning blocks. suggested the following: suggested: What do you think? cc
Personal Opinions: The first style will look fine for short forms, but I'm not sure for longer text. A possible syntax: Which to me pushes the text too far right. Not having any spacing, but just separating with newlines, seems hard to parse at a glance what is part of the WARNING, and prevents multiple line breaks inside the warning. Also, it's not as extensible. INFO can be , but if we ever want more extensions, they would increasingly possibly conflict with other things. The second style makes it immediately clear what is part of the block, and is unlikely to accidentally conflict if we ever want to add more block styles. It also supports multiple lines or inner blocks trivially. A final advantage is that it may support nested blocks, in case those ever come to be useful. Overall: I prefer the second form, both aesthetically and for future-proofing
I think I agree with in preferring the second form. I like the first form's simplicity, but it also seems surprising that is treated as a 'keyword' and will change the formatting of the docs.
That's why we have this debate. :stuckouttongue:
I personally actually prefer stabilizing a CSS class, I think we should do more of that, just because parsing can get annoying. But this is not that hard to parse anyway. The problem with is precisely that you can't scope it easily: what if you want to add code blocks? bullet points?
The problem with this is it ties rustdoc to the HTML backend; like I said nothing rustdoc currently does guarentees that it will generate HTML from the markdown. Changing that means that to make the JSON backend have the same info, we'd have to add a full HTML parser to rustdoc just to read the HTML in the markdown, because pulldown does not parse HTML for us. I really think we should avoid making the JSON backend a second-class citizen.
Also there's not much point to this if it's just a little CSS IMO, you can add that yourself with and it will look just as good and be more flexible since you can control the styles yourself.


I'm not a giant fan of the syntax because it looks odd when rendered by anything other than rustdoc, which I'd rather avoid, one of the major design concerns for intra-doc links was compatibility with other markdown parsers:
So, I agree, but I'm not convinced that the warning class is something that needs to be surfaced in the JSON backend as anything special. Also, bear in mind, HTML is a part of markdown: valid HTML (well a subset of HTML) is valid markdown. Users already can , and they do that in many cases. Markdown parsers already need to be able to handle HTML. There's nothing new there. Whatever consumes the JSON backend will need to be able to handle that too. I mean, yes, in theory, in practice people don't do this because of the barrier to entry (you have to get your tools to use that, including )
Also, this is incorrect, pulldown absolutely parses HTML. It has to, like I said valid HTML is valid Markdown. It doesn't parse it thoroughly, I believe you can mess it up with sufficiently complex HTML, but it parses HTML. What this changes is subtler: up till now you did not need any particular stylesheet to acceptably render rustdoc markdown from the JSON backend on your own (just use your favorite markdown renderer's stylesheet), but now you will need other css classes to handle rendering warnings as warnings.
I do not agree that this is a problem. I've used Phabricator's implementation of this approach happily and it is by design that warning banners are one paragraph. It is not the intention that you would put entire sections of documentation into a warning banner. They are for a brief callout. It's fine to refer to a subsequent section of the documentation from the callout if needed. I suppose this is a matter of taste but it's one where I believe the opinionatedness of the syntax is a positive thing.
So I discussed this a bit with on the side, we agree that the effect on the JSON backend isn't major since HTML is already a subset of markdown and docs use HTML already (especially for images and tables). My position is as follows: I strictly prefer HTML over some other scoped syntax with nuances people have to learn. I don't think there's as much value in unscoped syntax which makes my position "HTML or nothing", basically.


I'm not wholly against unscoped single-line syntax. We and syntax in W3C specs and you invariably need to add more stuff to it (there's an HTML class in these specs for this reason). Furthermore, Rust has a strong culture of wrapping text, so this means we need to work well while wrapped, and that means we're again introducing some form of scoping mechanism (e.g. indenting the text), which editors will have to learn, as well.
I don't know about admonitions specifically but there seems to be something of a community habit to use "magic tags" on fenced code blocks for this sort of features (e.g. github has a tag), maybe that could be an option? I don't know if pulldown_cmark has a hook for manipulating code blocks but… So a warning would be or maybe the tag would be to leave room for things like note/todo/danger/… Alternatively, take a gander at how other markdown implementations extend the language for this sort of features? e.g. seems to be using for admonitions.
Hmm, but is still for code, even if it has some extra behavior. Aside from the design concerns, this would be feasible to implement: we just extract the language string from the code block with pulldown.
Could you use something that's already built into markdown? For example, rustdoc could take and render it as an admonition.
That's what suggested: to use markdown and make some changes on rustdoc side. I think the codeblock approach is the best personally.
My bad, I didn't see that.
I wonder if it makes more sense to add this as a proc-macro. Rustdoc can still provide the CSS classes and things, and you could use them with HTML directly, but you could use or something and it would expand to the correct HTML tags and classes.
Might be better to have a then, no?
Is that going to be a special header similar to the "unsafe"/"experimental"/etc ones, or is that going to also be used within docs in an order-sensitive way? If the latter we should probably just use a CSS class; mixing and is ugly
Agreed.


Among the suggested ideas, my favourite one remains the code block with "warning" as tag:
Yeah, but triple backticks is also for preformatted text without further markup, so you won't be able to e.g. use text formatting (or other code) in there
True... Finding the right syntax is much more complicated than expected...
That's the issue of using markdown, for all that it has a pretty nice baseline syntax it really was not designed for extensibility.
We can always use : it'd allow to have text formatting inside it.
I would use , it's not quite kosher to invent arbitrary HTML tags (though you can use Custom Elements, which is more heavyweight)
Sounds good to me. It's funny because we kinda came back to the . :rofl:
I just thought: we could use tag in the markdown and then transform it into in the generated HTML?
My main objection to all of these is that rustdoc shouldn't be adding custom markdown syntax that no one else supports. Any new syntax we use should look reasonable even if rendered with the default renderer.
Well, it remains valid markdown since it's HTML (even though it's custom tag). I'm completely fine with , but it might be simpler/better for users to simply write .
Coming back to this (because of ), it seems like the conversation kinda agreed on adding a CSS class directly and then it would look like this in the docs: . I'll send a PR in the next days and then we can open an FCP to see if everyone is ok with it (and if not, we'll have code to help the debate).
This indeed seems like a better solution than the HTML block. It also plays better with something said about not linking it too much too HTML. This will look like a proper warning or note, mostly independent of the HTML generation.
They also seemed to not be too favourable to anything that needs some extra parsing from rustdoc iuc. I'm fine with bot the github solution and the CSS class.
Maybe one more comment to make here. The note-taking app, which uses Markdown also has a similar syntax to create these blocks. It is called . It uses a syntax similar to the syntax that is used for doc intra-links currently, and it is fully compatible with them.


I am uncertain if this is any better than what suggested from the GitHub syntax, but because of the similarity to the doc intra-link syntax. I do feel like this might be interesting because it should go well with backwards compatibility. However, this may look worse than the GitHub syntax solution when not going through cargo doc.
I thought I'd already left this comment, but I'd really like to avoid adding more markdown syntax where possible. This feature works fine without special syntax, I don't think we need it. edit: copying over the reasoning from the :
Although, I might not agree fully, I can fully appreciate and understand the reasoning you left in the corresponding PR. Still, I do think it might be worth to standardize some kind of syntax for some kind of warning block. This does not actually require customized markdown. Alternatively, I can suggest adding the GitHub flavor with emojis to the . This may help in standardizing short form warnings and notes within documentation. We could for example propose to standardize: which should look like the following I do value people's opinion on this. Is this a possible compromise?
That's a valid alternative, I think the yellow color is pretty important though, and it's useful for themes to be able to make styling decisions about warnings so I do think that having some way of marking it is important. I just don't think the way of marking it should be some magic invocation as opposed to CSS classes. (And I think that the bar for a feature that is adding new semantics to the Rustdoc markdown parser is much, much higher than that of one stabilizing a CSS class)
100% agree. I will look at the Rust API guidelines issue and possibly an RFC to rust to track the adoption in GitHub and possibly eventually merge. Thank you :smile:
Beyond all this discussion of third-party tools, I'd really like to make sure that whatever new syntax and presentation we add to rustdoc can also be to [mdBook]. That way, when the standard library starts using callouts, we can make sure the same style also gets used in The Book. Mostly, The Book seems to just use blockquotes, often with headings like [this one about ownership]. mdBook doesn't do anything special with it: it's [just a block quote with a header].


[mdBook]: [this one about ownership]: [just a block quote with a header]:
This is a good point. Once we have something merged here, I'll send a PR there to have an equivalent.
CC
I'd be happy to add some CSS rules to mdbook if that is what you are proposing.
Yeah, it is.
FYI, using a is not semantic and Microsoft GitHub is setting a bad precedence. — CommonMark Spec v0.30, denotes a in Markdown and is rendered as such. — W3C HTML spec, Unless you are quoting a source, this is not the correct element to use. While I disagree with even using altogether, at least some tools out there are at least translating the blockquote in admonition context into a (div has no semantic meaning which is unfortunately the best HTML option for admonitions). It would be ill-advised to follow Microsoft GitHub’s Markdown syntax fork—especially with their disregard for semantics. Similarly using a block would also be breaking semantics as an admonition is not preformatted text. CommonMark does have that could be used if the solution was preferred. There’s also other reasonable options noted here that don’t break semantics.
I agree that block quotes for callouts are bad, and would like to work with mdBook to roll out a common syntax (probably ) that will replace the ad-hoc, unsemantic markup that they use right now.
Using is what we agreed upon in The debate now is on the look itself.
Unfortunately isn't great because markdown has a "boundary" when HTML tags are used. I wanted to add a warning indicating that users probably wanted another trait, but intra-doc links don't work (which is the correct behavior per markdown spec).
Works perfectly fine though (well, minus the UI bug I just discovered haha): ! I used this code: I'll send a PR to improve documentation.
Ah. Well I suppose the issue wasn't with intra-doc links, but with inline code blocks. What I tried was that but with bar`, and it failed.
Works too: !
I opened which adds extra explanation on how to use markdown inside html tags. That should solve your issue.
That note is exactly what I was just looking in to. I had it inline, given my familiarity with HTML. TIL that matters.


It doesn't hurt to have it and if it can helps users, well, why not doing it. :)


cc
cc
This was caused in the TOML refactor in Cargo, the fallback support to support malformed is likely broken.
Fixes are sent to Cargo, I'll send PRs to rust-lang/rust when they're merged
Submodules landed!


https://crater-
searched nightlies: from nightly-2024-02-01 to nightly-2024-03-20 regressed nightly: nightly-2024-02-10 searched commit range: regressed commit: <details<summarybisected with <a href=''cargo-bisect-rustc</av0.6.8</summaryHost triple: x86_64-unknown-linux-gnu Reproduce with: </detailsprobably
WG-prioritization assigning priority (). label -I-prioritize +P-high
MCVE


The following code fails on stable: When compiled in release mode, the assert is optimized out by LLVM even though it checks the exact same condition as the other assert, as can be verified by testing in debug mode. Note that it's theoretically possible for the stack to be aligned correctly such that the bug is suppressed, but that's not likely. The 256's can be replaced with larger alignments if that happens. The bug is caused by the impl of copying to the stack with the default alignment of 16. ()
and seem related
This is a soundness hole.
So... I guess the problem is that the that rustc emits for the unsized local doesn't use ? That's... kind of bad, because it doesn't look like even supports dynamically setting the alignment: If this is correct, the issue should be renamed to something like "unsized locals do not respect alignment".
A way to fix this would be to change the ABI for dynamic trait calls that take by value to always pass by address. When the trait object is created is where the trampoline function would be generated, so there is no additional cost for static calls.
This can also be fixed by not allowing dynamically-sized local variables with an alignment more than some maximum value and having all dynamically-sized locals use that maximum alignment unless optimizations can prove that a smaller alignment suffices.
Messing with the ABI wouldn't help with unsized locals in general (assuming is correct), since e.g. will also need an alloca with dynamic alignment in general. Given only a value, there is no static way to say anything about its alignment, so how would you distinguish whether calling a method on it is OK?
Can we call and then align the pointer for the local ourselves as a workaround until we come up with a good solution?
In clang there's a function which might or might not be useful in this case.
requires a constant alignment. Non constant alignments are . This matches semantics of LLVM instruction, so it's not helping, as alignment of value in is unknown at compile time when moving from .
I think that overallocating for unsized locals of unknown alignment may make sense. You can and then make use of to compute the offset. Sure, it increases stack requirements, but it seems acceptable for , and in most cases you end up with extra 7 bytes on stack or less. 256 alignment seems like an edge case where wasting 255 bytes doesn't matter.


if we keep setting as the default alignment we can skip the overallocating and offset dance for types with an alignment below that.
My idea was that rustc would prohibit coercing overaligned types to a dyn trait that takes by value. So:
The alignment is dynamically determined though, not sure if saving 15 bytes of stack space is worth the conditional branch?
Oh right. Yea that's probably not helpful.
Since , this would be backwards incompatible (at latest) once trait object upcasting is finally implemented: and trait objects would have to have the same alignment restriction (because you can upcast to ), but today you can freely create such objects with any alignment.
I was under the impression that calling didn't require dynamic , is that related to missing MIR optimizations, meaning we have unnecessary moves which end up duplicating the data on the stack using a dynamic ?
Correctness shouldn't rely on optimizations to fire...
Sure, I was just hoping we weren't relying on "unsized locals", only unsized parameters (i.e. ), for what we're exposing as stable. And I was hoping an optimization wouldn't need to be involved to get there. I wonder if it would even be possible to restrict "unsized locals" to the subset where we can handle it entirely through ABI, and not actually have dynamic s anywhere, since that would make me far more comfortable with 's implementation or even stabilization. Ironically, if that works, it's also the subset we could've implemented years earlier than we did, since most of the complexity, unknowns (and apparently bugs) are around dynamic s, not calling trait object methods on a dereference of .
That should be possible. I think everything that is necessary is performing the deref of the box as argument () instead of moving the box contents to a local first () That would also make it possible to call in cg_clif. Cranelift doesn't have alloca support, so the current MIR is untranslatable.
Hmm, but that's not trivially sound because it could lead to MIR calls where argument and return places overlap, which is UB. We'd potentially have to special-case it to derefs, but even then what's to stop someone from doing ? Maybe we could introduce a temporary for the return value instead, for these kinds of virtual calls? That should remove any potential overlap while allowing the call.


(Unrelatedly, I just realize we use a copying-out shim for vtable entries that take by value, even when would be passed as at the call ABI level. We would probably have to make computing the call ABI a query for this microopt to not be expensive)
That would result in being moved to a temp first before dropping and calling the boxed closure. If it wasn't moved first before the drop of , then borrowck would give an error. (I meant for this change to be done at mir construction level, not as an optimization pass, so borrowck should catch any soundness issues)
We can try it, I guess, but right now a lot relies on many redundant copies/moves being created by MIR building and may not catch edge cases like this. But also I don't think moving out of a moves the itself today. Me too, but I was going with the "correct by construction" approach of creating a redundant copy/move, just on the return side, instead of the argument side, of the call.
After revisiting on triage, removing nomination.
pre-triage: nominated for discussion in the next weekly meeting.
I just checked and, a function call roughly this (touched up for clarity): Some of my previous comments assumed the wasn't there and the call would use the destination directly, but given that there is a move, that simplifies my suggestion. <hr/For virtual by-value calls, we can skip one move when building the MIR, specifically the move out of the dereference of a for the argument. Given that we already move the result of the call, there should be no aliasing caused by this, but if we decide to change anything about how we build MIR calls, we'd need to be extra careful. We can also make this pattern be gated by a separate feature-gate (rather than ), and make sure the standard library only uses that feature-gate and not . This should solve any alignment issues might have, because we'd not be using dynamic unless the broader feature is used.
OK, if I understand what's being proposed here, it is to excerpt a subset of the "original unsized-locals plan" -- specifically, to permit locals with unsized types, but only in contexts where we can be guaranteed that we can point to the original storage and don't actually have to move any value (and hence we don't require variable size stack frames).


I'm in favor of this proposal, but I do think we want to be slightly careful to ensure we're not violating soundness. The main concern would be if there is some way to access or re-use the variable that was moved. I attempted to do so with this example () but it fails to compile: The error here arises because the closure would need to capture a to do anything, which prevents a later move. But maybe there is some kind of tricky example that can arise where we re-assign the value during argument evaluation?
compiles and does before , where is the result of .
Borrowck should prevent that, right?
borrowck may rely on MIR building creating extraneous copies, so we can't just assume it helps us. IMO we should limit it to functions taking unsized parameters and function calls passing such parameters or dereferences of es (any other pointer/reference doesn't support moving out of).
Well, I think is right that borrowck would catch violations of soundness in some strict sense, but I guess what I meant is that we might be breaking backwards compatibility.
The example that feels pretty relevant. If I understood your proposal, it would no longer compile. If I recall (thinking back), I had a plan to handle this by save the to an alternate location in the actual call, we pass ownership of and then do a shallow free of the This still seems like it would work, though I'm not sure how easy/elegant it is to formulate. In a sense we'd be rewriting to .
Isn't example dependent on doing a direct virtual call? My understanding is that you can't do this on stable with because the virtual call exists in one place, in libstd, and it doesn't do anything weird, so it would work with a restricted ruleset. EDIT: if it can work on stable, it's because calling 's will move the whole before the assignment is evaluated, which is fine, because the shallow drop is actually inside that , not its caller.
I agree that this code doesn't compile on stable today, but I'm not sure if that's the point. I guess you're saying it's ok for it to stop compiling? I think what I would like is that our overall behavior is as consistent as possible between Sized and Unsized parameters. I think we could actually do a more general change that doesn't special case Sized vs Unsized or anything else.


I think I am basically proposing the same thing as earlier, but with a twist: Today, when building the parameters, we introduce a temporary for each parameter. So if we had we might do: What I am saying is that we could say: If the argument is moved (not copied), and the "place" has outer derefs (e.g., we are passing where is some place), then we assign the place to a temporary and we make the argument to the function be : I don't believe this is observable to end-users, except potentially for when the destructor on runs. I believe that it accepts all the same code we used to accept. It also has nothing specific to or types at all. Does that make sense? I'm very curious to know if anyone sees any problems with it. (One obvious thing: if we ever add , its design would have to accommodate this requirement, but I think that's fine, in fact the complications around getting moves right for precisely this case are one of the reasons we've held off on thus far.)
Can you not reinitialize today? If you move the whole , it is indeed more conservative (and should let us skip unnecessary moves even in cases). But also, do you want to move the locals check from typeck to borrowck? I don't have an intuition for when your approach wouldn't create unsized MIR locals, from the perspective of typeck. However, this is only relevant if we want a stricter feature-gate. At the very least it seems like it would be easier to implement a change only to MIR building, and it should fix problems with for the time being, even without a separate feature-gate.
Hmm, that's a good point, I think do that. Sigh. I knew that seemed too easy. I remember we used to try and prevent that, but we never did it fully, and in the move to NLL we loosened those rules back up, so this compiles: Still, you could do my proposal for unsized types, though it would introduce an incongruity. UPDATE: Oh, wait, I remember now. For unsized types, reinitialization is not possible, because you can't do with an unsized rvalue (we wouldn't know how many bytes to move). So in fact there isn't really the same incongruity.


To be clear, I wasn't proposing changing anything apart from MIR building either, I don't think. IIUC, what you proposed is that would be compiled to: whereas under my proposal (limited to apply to unsized parameters, instead of moved parameters) would yield: I think I mis-stated the problem earlier. It's not so much that your proposal will introduce compilation errors, it's that I think it changes the semantics of code like this in what I see as a surprising way: I believe that this code would compile to the following under your proposal: which means that would be invoked with the new value of , right? Under my proposal, the code would still compile, but it would behave in what I see as the expected fashion. Specifically, it would generate:
Isn't there a way to "lock" that value through the borrow-checker, so further accesses would be disallowed, until the call returns? I'd rather be stricter here. <hr/My point was that if your proposal affects sized moves, you're breaking stable reinitialization. If it doesn't affect sized moves, I don't see how this applies anymore:
Let me just chime in here and say that this is a pain in Miri. Unsized locals are pretty different from sized locals, I had to introduce a bunch of special hacks to make them work. MIR locals even needed a new state just for them: Lazily allocating locals seems odd to me, but at least we can consistently do that for all locals. Elsewhere however to make this lazy initialization actually work out and catch mistakes where an unsized local is "overwritten" with a value of different size: This all feels really unprincipled, and it would be great if at some point we could come up with a coherent semantics for unsized locals in MIR. The worst part is that the size of a local is implicitly determined on the first write to it. It would be much better to be explicit about that, e.g. at time.
I don't think we have anything like this today, but presumably we could add such a thing, but I'm not quite sure what you have in mind. When does this prohibition on further accesses take effect?


In particular, the IR for under your proposal, if I understood, would be But the access to that (I believe) we wish to prevent takes place in the "evaluate remaining arguments" part of things. So I think we'd have to add some sort of "pseudo-move" that tells borrowck that should not be assignable from that point forward, right? Well, it depends on your perspective. It's true that, given the need to permit reinitialization, the check is now specific to unsized values -- i.e., MIR construction will be different depending on whether we know the type to be sized or not. That's unfortunate. However, I think we still maintain a degree of congruence, from an end-user perspective. In particular, users could not have reinitialized a anyhow. However, under my proposal, users can write things like and the code works as expected (versus either having an unexpected result or getting an error). In any case, it seems like we're sort of "narrowing in" on a proposal here: when we see a function call with a parameter that is , and the value being passed is a deref, we want to modify the IR to not introduce a temporary and instead pass that parameter directly from its location, either we do some sort of "no more assignments" lock, or we move the pointer and introduce a temporary (and then pass in a deref of that temporary) Does that sound right so far?
If it's easier to do the more flexible approach (by moving the pointer) than the "locking" approach (which is a bit like borrowing the pointer until all arguments are evaluated, then releasing the borrow and doing a move instead), I don't mind it, I was only arguing with the "uniformity" aspect. Something important here: your approach is stabilizable, while mine is meant more for that one in the standard library, and not much else.
Yes, I was kind of shooting for something that we could conceivably stabilize.
Removing nomination, this was already discussed in triage meeting and it's under control.
So should we maybe try out the approach I proposed and see how well it works?
yes, going to try that out.
For the record, the "new plan" is this.


When generating the arguments to a call, we ordinarily will make a temporary containing the value of each argument: But we will modify this such that, for arguments that meet the following conditions: The argument is moved (not copied), and its type is not known to be , and the "place" has outer derefs (e.g., we are passing P where P is some place), then we assign the place P (instead of ) to a temporary and we make the argument to the function be (instead of ). This means that given where , we used to generate but now we generate We are now moving the box itself, which is slightly different than the semantics for values known to be sized. In particular, it does not permit of the box after having moved its contents. But that is not supported for unsized types anyway. The change does permit modifications to the callee during argument evaluation and they will work in an analogous way to how they would work with sized values. So given something like: we will find that we (a) save the old value of to a temporary and then (b) overwrite while evaluating the arguments and then (c) invoke the with the old value of .
Update: There is also
is a perfectly normal operand, I don't know what you mean. It's the same kind of as we currently have in (on the RHS)
Oh sorry, somehow I thought operands could only refer directly to locals, not also dereference them. I think I am beginning to see the pieces here -- together with function argument handling, this entirely avoids having to dynamically determine the size of a local. I have to agree that is quite elegant, even though baking "pass-by-reference" into MIR semantics still seems like a heavy hammer to me. On the other hand this places a severe restriction on now unsized locals may be used, basically taking back large parts of Is there some long-term plan to bring that back (probably requires with dynamic alignment in LLVM)? Or should we amend the RFC or at least the tracking issue with the extra restrictions?
I would keep the more general feature but use two different feature-gates (if we can). And just like with a few other feature-gates () we could warn that (the general one) is incomplete and could lead to misaligned variables (or something along those lines).


We could also add runtime asserts that the (dynamic) alignment is respected, once we know could never trigger them (e.g. from stable code).
I was wondering about that too. It seems like it'd be good to review the more general feature in any case. This is partly why I brought up the idea of wanting a guaranteed "no alloca" path -- this was something I remember us discussing long ago, and so in some sense I feel like the work we're doing here isn't just working around LLVM's lack of dynamic alignment support (though it is doing that, too) but also working to complete the feature as originally envisioned.
I two notes to the tracking issue so we don't overlook this in the future.
This is probably expected, but the fix failed to actually make sound:


The feature gate for the issue is . Tracking issues are used to record the overall progress of implementation. They are also uses as hubs connecting to other relevant issues, e.g., bugs or open design questions. A tracking issue is however not meant for large scale discussion, questions, or bug reports about a feature. Instead, open a dedicated issue for the specific matter and add the relevant feature gate label. [ ] Adjust documentation ([see instructions on rustc-dev-guide][doc-guide]) [ ] Stabilization PR ([see instructions on rustc-dev-guide][stabilization-guide]) [stabilization-guide]: https://rustc-dev- [doc-guide]: https://rustc-dev- Initial implementation ()
FWIW, here is a full-featured API provided by an external crate:
I wonder how this API relates to . It would be great if there was some safe API that wrapped around the use of to access a 's spare capacity, then updated based on the s .
Maybe we should follow that example and generalize to return ?
has implemented that, albeit as a private function. Sounds like a good idea to me.
Since exists now I think is redundant.
That's not actually true due to pointer invalidation, see and
I think it would be better to have this feature sooner rather than later. I'm starting to notice instances where people are doing things that are probably or definitely UB because they want this functionality. So I think this API falls squarely into the standard library's mission to provide pre-built and correct implementations of things that are subtle or difficult to get right.   (originally posted on but per Ralf's comments there, it is probably better to have this method for the above use cases)
I agree. I've been using this in my code and found it to be very useful. Even though is more general, I've never had a need for it and I feel that is useful on its own. The API being stabilized is: merge
Team member has proposed to merge this. The next step is review by the rest of the tagged team members: [x] [x] [x] [x] [x] [ ] No concerns currently listed. Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!


See for info about what commands tagged team members can give me.
while waiting for this feature to be stabilized, you should suggest that and use one of the convenience methods in:
:bell: This is now entering its final comment period, as per the . :bell:
Ralf mentioned this on , mostly rewording with my own opinion: I would prefer not to recommend that function, because even if you just want access to the spare region, under SB, these interfaces invalidate all pointers to the initialized region. I think that's too much of a footgun for codebases where people are already writing code that is rejected by Miri.
I wonder how many people do keep outstanding pointers to the initialized part while toying with the extra part 's implementation is already better than their 0-elems slices that get -ly converted into non-empty slices (and currently better than the stdlib one since it doesn't involve a 12-week delay for stable Rust). Anyhow, I've just released a new version () with a dedicated adapter: , for extra good measure.
To be clear, my concern is that the splitting interfaces are adding a landmine for the future. If I'm sending someone a PR I'll make sure it passes Miri at the time, but that's a hard condition to maintain. Especially because the two aforementioned codebases have dependencies that do int-ptr casts, an operation that Miri just doesn't understand at the moment, so it would be hard to advocate Miri in CI.
The final comment period, with a disposition to merge, as per the , is now complete. As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed. This will be merged soon.


I tried to document this code: I expected to see this happen: charstd::char` points to module page of char type points to char primitive page Instead, this happened: type points to module page of char :
I think the problem is that modules are in the type namespace, so is doing exactly what you are asking it for (the module, since it has higher priority). Since the built-in types scope is the lowest precedence, perhaps there needs to be a way to access it directly? Maybe something like or ? Or maybe should skip over modules, and keep looking deeper in the scope hierarchy? (cc )
Oh hmm I see what you mean. There are : Types, values, and macros. Since modules and types are in the same namespace, it uses the first one it finds. Maybe we could work around this by first resolving in an empty module (so it has nothing in scope), then only falling back to the current scope if we don't find something there?
I'm surprised this hasn't caused trouble before now. Does the root of never use the primitive?
I don't know how it works, but the resolver is smart enough to know that in a type context won't match a module (like , the won't match a module named "char". Maybe it has something to do with late-resolution  which has a to give it some context?
Adding that would be more of area ... I can give it a shot though.
It looks like doesn't even return a resolution and only records it for later use ... I'm going to go with the empty module workaround and we can fix it later if it turns out to cause issues.
The double resolve seems hacky. We could probably make type@ specifically not resolve to a module, perhaps? Also, note that modules are in all namespaces
How would that work? We could skip any module resolutions, but since modules have precedence over types I don't know how we'd get the primitive type to resolve afterwards.
Oh hold on we have a function already. We can look at directly.
This doesn't have anything to do with primitives, this has to do with glob imports vs non-glob imports. You can get the same issue with the following:
This also doesn't have to do with modules being "resolved first" or anything. Things that are non-glob in-scope are resolved first.


Actually, my bad: This does have to do with primitives in the sense that primitives are the only thing that still work when shadowed because of some special code in checking the primitive tables. I think when the string matches one of the primitive table entries for TypeNS lookups that were explicitly annotated with type@ and resolve to a module we can hack this in. In the future we might want to tighten up this code so that e.g. can't resolve to an enum, etc.
do you mind if I fix at the same time and resolve primitives even before modules? That seems like the less surprising behavior to me, the module can still be disambiguated with .
I'm a bit wary of doing this because having the char module in scope is not a common situation, and it will get weirder for people who have a different char module. I think we should resolve to whatever is in scope, but if is explicitly mentioned we can then force resolve to the primitive.


https://crater-
I'll need to re-check later but this seems to bisect to somehow.
The UI test changes from that PR appear to back this up, as confusing as it is.
I'm not sure what's going on in that crate, if it built successfully by mistake, or how that PR interacts with it, so let's cc the PR author and reviewer for validation.
After , no longer implements and , because the context now contains a which doesn't implement those traits. So this is an issue with the standard library and not the crate being built. Repro: label -T-compiler +T-libs +S-has-mcve
WG-prioritization assigning priority (). Noticing this on which says that was meant to be confined on nightly. Unsure about the fallout of this regression but for now marking as critical for tracking purposes. label -I-prioritize +P-critical
Revert up:
Isn't not unwind safe?
That line was by your PR, so while what you say is technically true, talking about what "already happened" when we are traveling back and forth through time via version control may be more confusing than helpful.
That line was already there. I the line below it though. Original PR:
Apologies, I guess I can't count numbers today? Hm, so, the full error of the regression is this: Note that it's trying to make a pointer implement . And for what it's worth, stable does indeed document is . Thus unfortunately that line you pointed to, as opposed to the one I thought you were referring to, is effectively just documenting that all are , and that will include regardless of whether it is is . And confusingly, , unlike .
I have opened as an alternative.


The following code () panics the compiler in stable 1.38.0, beta 1.39.0-beta.6, and nightly 2019-10-17: Removing the bound or filling it with makes it compile just fine. Error + backtrace:
cc
Hmm, I didn't know that adding a "syntactically trivial bound" could cause something like this. Is there some implicit bound that gets in cases like this?
minimized test case ():
The minimized test worked in previous stable Rust versions (at least in 1.33 under 2015 edition; though 2018 edition breaks there, which indicates this is with 99.999% certainty injected by MIR-borrowck...)
triage: P-high. Adding self to assignee list; removing I-nominated.


The following snippet works fine before but now it reports a warning: Steps to reproduce: clone rustup override set nightly-2017-08-11 cargo test Is this an expected behavior, or a bug? Thank you!
cc -- probably related to the new lint implementation
Yes this was caused by The bug is on . The check for whether is in scope is not checking the current set of attributes being linted. For example this does not warn: but this warns: (as you've noticed) The fix is to just take the local variable into account which has the up-to-that-point set of lint attributes collected.
I've opened a PR for this at


<!-- Thank you for filing a regression report! A regression is something that changed between versions of Rust but was not supposed to. Please provide a short summary of the regression, along with any information you feel is relevant to replicate it. --I tried this code: I expected to see this happen: same codegen or similar in performance Instead, this happened: array has way worse codegen <details<summaryAssembly</summary<p</p</details<!-- Provide the most recent version this worked on, for example: It most recently worked on: Rust 1.47 --It most recently worked on: 1.64 <!-- Provide the version you are using that has the regression. --65 till now. Regressed in nightly-2022-08-13, maybe LLVM 15 ?: : <!-- Did the compiler crash? If so, please provide a backtrace. --<!-- Include a backtrace in the code block by setting in your environment. E.g. . --<details<summaryBacktrace</summary<p</p</details<!-- If you know when this regression occurred, please add a line like below, replacing with one of stable, beta, or nightly. -- modify labels: +regression-from-stable-to-stable -regression-untriaged <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
WG-prioritization assigning priority (). cc since this regressed in the LLVM 15 update label -I-prioritize +P-medium +T-compiler
I've seen llvm doing these strange 1-byte-at-a-time "vectorizations" in other places too. This might be a more general problem. In this case we can probably paper over it by implementing TrustedRandomAccess for the array iter.
Unfortunately, the array iterator is fundamentally worse right now, because indexing into it -- a fundamental part of being a by-value array iterator -- keeps it from SRoAing and thus doesn't optimize well. This is why when I was making better I ended up making to not have to use . Sadly, for the foreseeable future you're better off using the "weaker" slice iterator when you can.
My guess is that the SROA is missing something in the opaque pointer mode.


claim
It's not about vectorization. This optimization can be restored by using . But highly unrecommended. Upstream issue:
The upstream issue is closed. claim


<!-- ICE: Rustc '-Zunstable-options --edition=2024 -ooutputfile -Zdump-mir-dir=dir' 'error: internal compiler error: impossible case reached', 'error: internal compiler error: impossible case reached' File: --auto-reduced (treereduce-rust): original: Version information ` Command: <!-- Include a backtrace in the code block by setting in your environment. E.g. . --<details<summary<strongProgram output</strong</summary<p</p</details<!-- query stack: [coroutinebymovebodydefid] looking up the coroutine by-move body for [analysis] running analysis passes on this crate -- label +F-asyncclosure
As a step of reducing your code examples, could you please ensure that is necessary to reproduce this ICE before mentioning it in the issue? This ICE reproduces on edition 2021, which is the current stable edition.
My project fails on nightly also while using edition 2021.
Yep, a fix is already up and it's waiting for approval. I recommend downgrading to a slightly older nightly until this is fixed.


we currently output The suggestion is incomplete and will not result in compilable code. Because the lifetime is coming from an argument of type , which is an unconstrained type parameter, itself will not have the needed lifetime and causes the obligation that we're trying to reverse by suggesting . The appropriate changes to the code would be either or , depending on whether appears in any other argument or not.
The suggested code .


I'm opening this up to serve as a tracking issue for enabling multiple codegen units in release mode by default. I've written up a before but the tl;dr; is that multiple codegen units enables us to run optimization/code generation in parallel, making use of all available computing resources often speeding up compilations by more than 2x. Historically this has not been done due to claims of a loss in performance, but the is intended to assuage such concerns. The most viable route forward seems to be to enable multiple CGUs and ThinLTO at the same time in release mode. Blocking issues: [x] Enable for libstd on all platforms - - - - Potential blockers/bugs: - -
cc
Presumably this will remain a stable compiler flag, but what else will change by default? Is the plan to make this only affect , or is the plan to also make this affect ? Do we want to make continue to use only a single CGU, to hedge against regressions for people who are already willing to trade off compiler time for runtime?
I would specifically propose that any opt level greater than 1 uses 16 codegen units and ThinLTO enabled by default for those 16 codegen units.
This is very interesting. One would think that ThinLTO-driven inlining should always have to do less work when our much more conservative pre-LLVM inlining. But that doesn't always seem to be the case, as in the . Most tests on the seem to profit though. Overall it's still not a clear picture to me.
was that comment meant for a different thread? I forget which one as well though, so I'll respond here! As a "quick benchmark" I compiled the regex test suite with 16 CGUs + ThinLTO and then toggled inlining in all CGUs on/off. Surprisingly inlining in all CGUs was 5s faster to compile, and additionally . In those timings is where inlining is only in one CGU, where is inlining in all CGUs. One benchmark, , got twice as slow!
Yeah, the comment was in response to (rust-doom) but since that was closed already, I put it here.


Regarding the compilation time difference between pre- and post-trans inlining, my hypothesis would be that sometimes pre-trans inlining will lead to more code being eliminated early on (as in the case of regex apparently) and sometimes it will have the opposite effect. I suspect that there's room for improvement by tuning which LLVM passes we run specifically for ThinLTO. Or do we do that already?
Heh it's true yeah, I'd imagine that there's always room for improvement in pass tuning in Rust :). Right now we perform (afaik) 0 customization of any pass manager in LLVM. All of the normal optimization passes, LTO optimization passes, and ThinLTO optimization passes are all the same as what's in LLVM itself.
I wanted to also take the time and tabulate all the results from the to make sure it's all visibile in one place. Note that all the timings below are comparing a release build to a release build with 16 CGUs and ThinLTO enabled Improvements All of the following compile times improved, sorted by most improved to least improved Regressions The following crates regressed in compile times, sorted from smallest regression to largest alexcrichton's attempt to reproduce the regressions Here I attempt to reproduce the regressions on my own machine with Unfortunately the only regression I was able to reproduce was the rust-belt regression. I'll be looking more into that.
Looking into , one interesting thing I've found is that the crate takes longer to compile with ThinLTO than it would otherwise. Looking at it appears that one codegen unit in this crate takes 99% of the time in LLVM. This codegen unit appears to be basically entirely dominated by . Almost all of the benefit of multiple codegen units is spreading out the work across all CPUs. Enabling ThinLTO to avoid losing any perf is fundamentally doing more work than what's already happening at , but we get speedups across the board in most cases. If we have one huge CGU, split it in two, and work on those in parallel then we've got 50% of the original time to run ThinLTO (in a perfect world). If ThinLTO takes more than 50% of the time then we'd have a build time regression, but that's almost never happening.


What's happening here is that we have one huge CGU, but when we split it up we still have one huge CGU. This means that the CGU which may take ~1% less time in LLVM only gives us a tiny sliver of a window to run ThinLTO passes. In the case of the crate this means that adding ThinLTO passes is an overall build time regression. So generalizing even further, I think that enabling ThinLTO and multiple CGUs by default is going to regress compile time performance in any crate where our paritioning implementation doesn't actually partition very well. In the case of we've got one huge function which hogs almost all the optimization time (I think) and the entire crate is basically dominated by that one function. I would be willing to conclude, however, that such a situation is likely quite rare. Almost all other crates in the ecosystem will benefit from the partitioning which should basically evenly split up a crate. maybe you have thoughts on this though?
Thank you so much for collecting and analyzing such a large amount of data, Your conclusions make sense to me. Unevenly distributed CGU sizes are also a problem for incremental compilation; e.g. the test sees 90% CGU re-use, yet compile time is almost the same as from-scratch. In the non-incremental case it might be an option to detect the problematic case right after partitioning and then switch to non-LTO mode? I'm not sure it's worth the extra complexity though. For cases where there is one big CGU but that CGU contains multiple functions, we should be able to rather easily redistribute functions to other CGUs. We'd only need a metric for the size of a . The number of MIR instructions might be a sufficient heuristic here. That would not help for but it might help for other crates. In conclusion, judging from the table above, I think we should make the default sooner rather than later. Open questions I see: What to do about ? I would have thought that it would always be a clear win to disable this when ThinLTO is enabled but that doesn't seem to be the case. Are there hardware configurations where this never is a win? E.g. should we default to traditional compilation if ?


FWIW, as the author of , which is a made-for-fun Piston game, I am more than happy to take a small compile regression when it seems like vast majority of crates get huge real-time improvements!
This seems like a good thing to have in our back pocket, but I'm also wary of trying to do this by default. For example the case is one where we may wish to disable ThinLTO but the one massive function could also critically rely on a function in a different CGU being inlined? That sort of case would be difficult for us to determine... In any case though I agree that we probably don't need the complexity just yet so I think we can defer this for later. Agreed! So far all the crate's I've seen the O(instructions) has been quite a good metric for "how long this takes in all LLVM-related passes", so counting MIR sounds reasonable to me as well. Again though I also feel like this is ok to have in our back pocket. I'd want dig more into the minor change example, I'm curious how awry the CGU distribution is there and whether a heuristic like this would help. Quite surprisingly I've yet to see any data that it's beneficial to compile time in release mode or doesn't hurt runtime. (all data is that it hurts both compile time and runtime performance!) That being said we're seeing such big wins from ThinLTO on big projects today that we can probably just save this as a possible optimization for the future. On the topic of inline functions I recently dug up again (later closed in favor of , but the latter may no longer be true today). I suspect that may "fix" quite a bit of the compile time issue here without coming at a loss of performance? In any case possibly lots of interesting things we could do there. Also a good question! I find this to be a difficult one, however, because the CGU number will affect the output artifact, which means that if we do this sort of probing it'll be beneficial for performance but come at the cost of more difficult deterministic builds. You'd have to specify the CGUs manually or build on the same-ish hardware to get a deterministic build I think? I think though that if you have 1 CPU then this is universaly a huge regression.


With one CPU we'd split the preexisting one huge CGU into N different ones, probably take roughly the same amount of time to opimize those, and then tack on ThinLTO and more optimization passes. My guess is that with one CPU we'd easily see 50% regressions. With 2+ CPUs however I'd probably expect to see benefits to compile time. Anything giving us twice the resources to churn the cgus more quickly should quickly start seeing wins in theory I think. For now though the deterministic builds wins me over in terms of leaving this as-is for all hardware configurations. That and I doubt anyone's compiling Rust on single-core machines nowadays!
One thing I think that's also worth pointing out is that up to this point we've mostly been measuring the runtime of an entire . That's actually, I believe, the absolute worst case scenario for where ThinLTO will provide benefit. Despite this, it's showing huge improvements for lots of projects! The benefit of ThinLTO and multiple CGUs is leveraging otherwise idle parallelism on the build machine. It's overall increasing the amount of work the compiler does. For a from scratch, though, you typically already have tons of crates compiling for the first half of the build in parallel. In that sense there's not actually any idle parallelism. Put another way, ThinLTO and multiple CGUs should only be beneficial for builds which dont have many crates compiling in parallel for long parts of the build. If a build is 100% parallel for the entire time then ThinLTO will likely regress compile time performance. Now you might realize, however, that one very common case where you're only building one crate is in an incremental build! Typically if you do an incremental build you're only building a handful of crates, often serially. In that sense I think that there's some massive wins of ThinLTO + multiple CGUs in incremental builds rather than entire crate builds. Although improving both is of course great as well :)
For deterministic builds you have to do some extra configuration anyway (e.g. path remapping) so I would not consider that a blocker. And I guess there are single core VMs around somewhere.