Add #[rustc_edition_redirect] - #160227
Conversation
|
Some changes occurred in compiler/rustc_passes/src/check_attr.rs cc @jdonszelmann, @JonathanBrouwer Some changes occurred in compiler/rustc_attr_parsing cc @jdonszelmann, @JonathanBrouwer Some changes occurred in compiler/rustc_hir/src/attrs |
There was a problem hiding this comment.
I can review the attribute portion of this.
- Multiple attributes are allowed with different
beforekeys. The oldest one that applies is selected.
Given that it's an internal attribute it's not so important, but another option is a range syntax to force unambiguity (error on overlapping ranges):
#[rustc_edition_redirect(during = "..=2018", target(oldest_module))]
#[rustc_edition_redirect(during = "2021..=2024", target(middle_module))]
pub mod redirected_module { }|
@bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Add #[rustc_edition_redirect]
|
Given that this is a major expansion to name resolution, it's not surprising that I don't like it :) Some initial ideas:
I'll need to think about this more in the background for some time. |
This comment has been minimized.
This comment has been minimized.
|
Finished benchmarking commit (1b93257): comparison URL. Overall result: ❌✅ regressions and improvements - please read:Benchmarking means the PR may be perf-sensitive. It's automatically marked not fit for rolling up. Overriding is possible but disadvised: it risks changing compiler perf. Next, please: If you can, justify the regressions found in this try perf run in writing along with @bors rollup=never rustc-perf Instruction countOur most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.
Max RSS (memory usage)Results (primary 0.8%, secondary 1.5%)A less reliable metric. May be of interest, but not used to determine the overall result above.
CyclesResults (primary 0.1%, secondary -0.1%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Binary sizeResults (primary 0.3%, secondary 0.1%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Bootstrap: 490.333s -> 491.013s (0.14%) |
|
@petrochenkov Can you give more concrete examples of what you are proposing? You seem to be saying that we should just have multiple items with the same name in the same namespace with a different edition filter on them. I think that would be more complex and intrusive than the current solution. #[rustc_edition_redirect = "2024"]
use RedirectTarget2024 as Name;
#[rustc_edition_redirect = "2021"]
use RedirectTarget2021 as Name;
#[rustc_edition_redirect = "2018"]
use RedirectTarget2018 as Name;The current system is much simpler: there is only one name per namespace and you can attach any number of edition redirects on that name: #[rustc_edition_redirect(before = "2024", target(RedirectTarget2024)]
#[rustc_edition_redirect(before = "2021", target(RedirectTarget2021)]
#[rustc_edition_redirect(before = "2018", target(RedirectTarget2018)]
struct Name;That way all the redirection metadata for one name is available on the single
In theory yes, we could manually add edition redirect attributes on every re-export of an item that has redirects. But that would just end up being completely equivalent to what the current implementation is doing, while being more error-prone since we may accidentally forget redirects in some places.
There's quite a few places in the compiler where we change global behavior depending on whether a feature is enabled. For example |
This comment has been minimized.
This comment has been minimized.
ba14d93 to
457c443
Compare
This comment has been minimized.
This comment has been minimized.
|
Here's some minimized version that I came up with today - petrochenkov@2659b90. Initially I wanted to limit all the edition-based dispatch to one place in But then I realized that one place in So I hid the // tests\ui\edition-redirect\basic.rs
let _: ExpectedScopedRedirected = edition_redirect::ScopedRedirected;
let _: edition_redirect::same_redirects::Item = ExpectedRedirectedUse;
// tests\ui\edition-redirect\reexport.rs
let _: reexport_preserving::Item = reexport_source::current();
let _: reexport_preserving::Child = reexport_source::current_child();All the other things work correctly because the correct redirects are fetched in |
This comment has been minimized.
This comment has been minimized.
0ce7bfd to
08d99f8
Compare
|
Some changes occurred in compiler/rustc_attr_ir |
This comment has been minimized.
This comment has been minimized.
|
@petrochenkov I applied your changes on top of mine and then had an LLM audit every single code path that ends up calling
Tests were added for all of these issues. However I'm not 100% confident about these, so another round of review is probably necessary. |
This comment has been minimized.
This comment has been minimized.
|
cc @rust-lang/edition for awareness. |
08d99f8 to
9af5b03
Compare
|
This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
Yeah, I only did bare minimum for the test suite to pass, but anything not correctly updated will result in a panic rather than a silent bug, so it's not a big problem. |
| const PATH: &[Symbol] = &[sym::rustc_edition_redirect]; | ||
| const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Use)]); | ||
| const TEMPLATE: AttributeTemplate = template!(NameValueStr: "2024"); | ||
| const STABILITY: AttributeStability = unstable!(edition_redirect); |
There was a problem hiding this comment.
| const STABILITY: AttributeStability = unstable!(edition_redirect); | |
| const STABILITY: AttributeStability = unstable!(rustc_attrs); |
The feature no longer does anything besides gating the attribute itself, I'd rather avoid introducing more entities and reuse feature(rustc_attrs) which is used for other attributes in this file.
| pub struct Oldest; | ||
| pub struct Middle; | ||
|
|
||
| #[rustc_edition_redirect = "2021"] |
There was a problem hiding this comment.
| #[rustc_edition_redirect = "2021"] | |
| #[rustc_edition_redirect = "..=2021"] |
Similarly to @mejrs I'd personally prefer to use ranges and prohibit overlaps instead of relying on overlaps to determine which edition the reexport actually uses.
Also, it's not very obvious from the current syntax that "2021" actually means "not later than 2021".
This is not very related to name resolution though, so I'll leave this for lang team to decide.
| await_macro, | ||
| backchain, | ||
| backend_repr, | ||
| before, |
There was a problem hiding this comment.
This symbol is no longer used.
| ambiguity_vis_min: CmCell<Option<Decl<'ra>>>, | ||
| parent_module: Option<Module<'ra>>, | ||
| /// Fully resolved cross-crate redirects attached to this declaration. | ||
| edition_redirects: &'ra [EditionRedirectDecl<'ra>], |
There was a problem hiding this comment.
This can be moved to struct NameResolution since only non_glob_decl declarations in NameResolutions can have redirects.
Also, allocating on the arena may be unnecessary from the lifetime point of view.
But it is probably still slightly useful for performance.
| } | ||
|
|
||
| impl<'ra> Module<'ra> { | ||
| /// Visits children without applying edition redirects. |
There was a problem hiding this comment.
| /// Visits children without applying edition redirects. | |
| /// Visits children and panic if any edition redirects are encountered. |
|
|
||
| self.add_import(module_path, kind, use_tree.span(), item, root_span, item.id, vis); | ||
| let edition_redirect = if !nested | ||
| && ast::attr::contains_name(&item.attrs, sym::rustc_edition_redirect) |
There was a problem hiding this comment.
| && ast::attr::contains_name(&item.attrs, sym::rustc_edition_redirect) | |
| && attr::contains_name(&item.attrs, sym::rustc_edition_redirect) |
| /// The glob declaration for this name, if it is known to exist. | ||
| pub glob_decl: Option<Decl<'ra>> = None, | ||
| pub orig_ident_span: Span, | ||
| mod name_resolution { |
There was a problem hiding this comment.
Could you add a comment telling why this module exists?
| pub(crate) fn determined_decl(&self) -> Option<Decl<'ra>> { | ||
| if self.non_glob_decl.is_some() { | ||
| self.non_glob_decl | ||
| if self.non_glob_decl().is_some() { |
There was a problem hiding this comment.
| if self.non_glob_decl().is_some() { | |
| if let non_glob_decl @ Some(..) = self.non_glob_decl() { |
To avoid the second call.
And the same below for consistency.
| return; // Has resolution, do not create the dummy binding | ||
| } | ||
| if import.edition_redirect.is_some() { | ||
| let dummy_decl = self.new_import_decl(self.dummy_decl, import); |
There was a problem hiding this comment.
Is this necessary?
I remember removing it in my commit without consequences.
| let mut ambig_module_children = Default::default(); | ||
| for module in &self.local_modules { | ||
| self.finalize_resolutions_in(*module, &mut module_children, &mut ambig_module_children); | ||
| for index in 0..self.local_modules.len() { |
There was a problem hiding this comment.
Why was this change necessary?
View all comments
This implements the compiler portion of the library API evolution project goal by adding the
#[rustc_edition_redirect]attribute. This attribute allows an item path in the standard library to be redirected to a different item when used from a crate with an older edition.This PR only implements the compiler portion and doesn't make any use of this in the standard library. However I do have a POC branch which replaces the edition-specific
panic!dispatching with this.Example
Semantics
#[rustc_edition_redirect = "EDITION"]is only allowed on a single-item use.Implementation
ModChildin crate metadata.Open questions
edition_redirectwithout a tracking issue. Does this need a separate tracking issue?r? petrochenkov