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 { }| if ast::attr::contains_name(&item.attrs, sym::rustc_edition_redirect) | ||
| && let Some(Attribute::Parsed(AttributeKind::RustcEditionRedirect(mut redirects))) = |
There was a problem hiding this comment.
| if ast::attr::contains_name(&item.attrs, sym::rustc_edition_redirect) | |
| && let Some(Attribute::Parsed(AttributeKind::RustcEditionRedirect(mut redirects))) = | |
| if let Some(Attribute::Parsed(AttributeKind::RustcEditionRedirect(mut redirects))) = |
No need for this check, the attribute parser already does it.
| if edition_redirects | ||
| .last() | ||
| .is_some_and(|existing| existing.before == redirect.before) | ||
| { | ||
| self.r.dcx().span_err( | ||
| redirect.span, | ||
| format!("multiple edition redirects before edition {}", redirect.before), | ||
| ); | ||
| continue; | ||
| } |
There was a problem hiding this comment.
This check should be in attribute parsing, not here. CombineParser::finalize_check can be overridden to do this. If you implement AttributeParser you can store state in your attribute parser instead, if that makes things easier.
| let before = match before.as_str().parse::<Edition>() { | ||
| Ok(before) => before, | ||
| Err(()) => { | ||
| cx.dcx().span_err(cx.attr_span, "invalid edition in edition redirect"); | ||
| return None; | ||
| } | ||
| }; |
There was a problem hiding this comment.
What is the behavior of before = "future"? Should it be supported or be an error? Either way it looks like there are no tests for it.
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
const,static,fn,struct,enum,union,mod,type, etc) and on single-itemusere-exports.targetfield of the attribute is resolved in the local scope of the item it is on. Crate metadata directly encodes a resolved target rather than a path.beforekeys. The oldest one that applies is selected.usere-export. It has the same rules regarding visibility, stability, etc. Notably this means that the target of the redirect should also be marked as stable.#[rustc_edition_redirect]marker within the standard library retain the edition redirect (e.g. re-exports ofcorefromstd). Re-exports of such items outside the standard library are resolved using the edition of the re-exporting crate. This also applies to glob re-exports.Implementation
EditionRedirectwhich records the edition and target path.ModChildin crate metadata.Decloutside the standard library,edition_adjusted_declis used to apply the appropriate edition redirect depending on the span of the identifier being resolved.Decl:Declhas no edition redirects.Open questions
edition_redirectwithout a tracking issue. Does this need a separate tracking issue?#[stable]. This can be awkward if we don't want to expose a redirect target in the latest edition, we would have to wrap it in a private module to prevent it from being accessible.r? petrochenkov