Skip to content

Commit 95ae99b

Browse files
committed
Auto merge of #160227 - Amanieu:edition-redirects, r=<try>
Add #[rustc_edition_redirect]
2 parents 7c329d6 + 457c443 commit 95ae99b

38 files changed

Lines changed: 1122 additions & 32 deletions

compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs

Lines changed: 116 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ use std::path::PathBuf;
22

33
use rustc_ast::{LitIntType, LitKind, MetaItemLit};
44
use rustc_feature::AttributeStability;
5-
use rustc_hir::LangItem;
65
use rustc_hir::attrs::{
76
BorrowckGraphvizFormatKind, CguFields, CguKind, DivergingBlockBehavior,
8-
DivergingFallbackBehavior, RustcCleanAttribute, RustcCleanQueries, RustcMirKind,
7+
DivergingFallbackBehavior, EditionRedirect, RustcCleanAttribute, RustcCleanQueries,
8+
RustcMirKind,
99
};
1010
use rustc_hir::target::GenericParamKind;
11+
use rustc_hir::{LangItem, find_attr};
1112
use rustc_span::Symbol;
13+
use rustc_span::edition::Edition;
1214

1315
use super::prelude::*;
1416
use super::util::parse_single_integer;
@@ -329,6 +331,118 @@ impl AttributeParser for RustcCguTestAttributeParser {
329331
}
330332
}
331333

334+
pub(crate) struct RustcEditionRedirectParser;
335+
336+
impl CombineAttributeParser for RustcEditionRedirectParser {
337+
const PATH: &[Symbol] = &[sym::rustc_edition_redirect];
338+
type Item = EditionRedirect;
339+
const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::RustcEditionRedirect(items);
340+
const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
341+
Allow(Target::Const),
342+
Allow(Target::Enum),
343+
Allow(Target::ExternCrate),
344+
Allow(Target::Fn),
345+
Allow(Target::MacroDef),
346+
Allow(Target::Mod),
347+
Allow(Target::Static),
348+
Allow(Target::Struct),
349+
Allow(Target::Trait),
350+
Allow(Target::TraitAlias),
351+
Allow(Target::TyAlias),
352+
Allow(Target::Union),
353+
Allow(Target::Use),
354+
]);
355+
const TEMPLATE: AttributeTemplate =
356+
template!(List: &[r#"before = "2024", target(path::to::item)"#]);
357+
const STABILITY: AttributeStability = unstable!(edition_redirect);
358+
359+
fn extend(
360+
cx: &mut AcceptContext<'_, '_>,
361+
args: &ArgParser,
362+
) -> impl IntoIterator<Item = Self::Item> {
363+
let list = cx.expect_list(args, cx.attr_span)?;
364+
let mut before = None;
365+
let mut target = None;
366+
367+
for item in list.mixed() {
368+
let Some(meta) = item.meta_item() else {
369+
cx.adcx().expected_identifier(item.span());
370+
return None;
371+
};
372+
let Some(name) = meta.path().word() else {
373+
cx.adcx()
374+
.expected_specific_argument(meta.path().span(), &[sym::before, sym::target]);
375+
return None;
376+
};
377+
match name.name {
378+
sym::before if before.is_none() => {
379+
let Some(value) =
380+
cx.expect_name_value(meta.args(), item.span(), Some(sym::before))
381+
else {
382+
return None;
383+
};
384+
let Some(value) = cx.expect_string_literal(value) else { return None };
385+
before = Some(value);
386+
}
387+
sym::target if target.is_none() => {
388+
let Some(single) = cx.expect_single_element_list(meta.args(), item.span())
389+
else {
390+
return None;
391+
};
392+
let Some(target_path) = single.meta_item_no_args() else {
393+
cx.adcx().expected_not_literal(single.span());
394+
return None;
395+
};
396+
target = Some(target_path.path().0.clone());
397+
}
398+
sym::before | sym::target => {
399+
cx.adcx().duplicate_key(item.span(), name.name);
400+
return None;
401+
}
402+
_ => {
403+
cx.adcx().expected_specific_argument(item.span(), &[sym::before, sym::target]);
404+
return None;
405+
}
406+
}
407+
}
408+
409+
let Some(before) = before else {
410+
cx.dcx().span_err(cx.attr_span, "missing `before` argument");
411+
return None;
412+
};
413+
let Some(target) = target else {
414+
cx.dcx().span_err(cx.attr_span, "missing `target` argument");
415+
return None;
416+
};
417+
let before = match before.as_str().parse::<Edition>() {
418+
Ok(before) => before,
419+
Err(()) => {
420+
cx.dcx().span_err(cx.attr_span, "invalid edition in edition redirect");
421+
return None;
422+
}
423+
};
424+
425+
Some(EditionRedirect { before, target, span: cx.attr_span })
426+
}
427+
428+
fn finalize_check(cx: &FinalizeCheckContext<'_, '_>, _attr_span: Span) {
429+
let redirects = find_attr!(
430+
cx.parsed_attrs,
431+
RustcEditionRedirect(redirects) => redirects
432+
)
433+
.unwrap();
434+
435+
for (index, redirect) in redirects.iter().enumerate() {
436+
if redirects[..index].iter().any(|existing| existing.before == redirect.before) {
437+
cx.emit_err(diagnostics::MultipleEditionRedirects {
438+
span: redirect.span,
439+
edition: redirect.before.to_string(),
440+
});
441+
}
442+
}
443+
}
444+
}
445+
332446
pub(crate) struct RustcDeprecatedSafe2024Parser;
333447

334448
impl SingleAttributeParser for RustcDeprecatedSafe2024Parser {

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ attribute_parsers!(
193193
Combine<RustcAllowConstFnUnstableParser>,
194194
Combine<RustcCleanParser>,
195195
Combine<RustcDumpLayoutParser>,
196+
Combine<RustcEditionRedirectParser>,
196197
Combine<RustcMirParser>,
197198
Combine<RustcThenThisWouldNeedParser>,
198199
Combine<TargetFeatureParser>,

compiler/rustc_attr_parsing/src/diagnostics.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,14 @@ pub(crate) struct UnreachableCfgSelectPredicateWildcard {
5252
pub wildcard_span: Span,
5353
}
5454

55+
#[derive(Diagnostic)]
56+
#[diag("multiple edition redirects before edition {$edition}")]
57+
pub(crate) struct MultipleEditionRedirects {
58+
#[primary_span]
59+
pub span: Span,
60+
pub edition: String,
61+
}
62+
5563
#[derive(Diagnostic)]
5664
#[diag("must be a name of an associated function")]
5765
pub(crate) struct MustBeNameOfAssociatedFunction {

compiler/rustc_feature/src/builtin_attrs.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ pub static BUILTIN_ATTRIBUTES: &[Symbol] = &[
246246
sym::rustc_eii_foreign_item,
247247
sym::rustc_allowed_through_unstable_modules,
248248
sym::rustc_deprecated_safe_2024,
249+
sym::rustc_edition_redirect,
249250
sym::rustc_pub_transparent,
250251

251252
// ==========================================================================

compiler/rustc_feature/src/unstable.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,8 @@ declare_features! (
262262
(internal, const_param_ty_unchecked, "1.97.0", None),
263263
/// Allows writing custom MIR
264264
(internal, custom_mir, "1.65.0", None),
265+
/// Allows defining edition redirects and preserving redirects on re-exports.
266+
(internal, edition_redirect, "CURRENT_RUSTC_VERSION", None),
265267
/// Implementation details of externally implementable items
266268
(internal, eii_internals, "1.94.0", None),
267269
/// Implementation details of field representing types.

compiler/rustc_hir/src/attrs/data_structures.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use rustc_data_structures::fx::FxIndexMap;
1515
use rustc_error_messages::{DiagArgValue, IntoDiagArg};
1616
use rustc_macros::{Decodable, Encodable, PrintAttribute, StableHash};
1717
use rustc_span::def_id::DefId;
18+
use rustc_span::edition::Edition;
1819
use rustc_span::hygiene::Transparency;
1920
use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol};
2021
pub use rustc_target::spec::SanitizerSet;
@@ -152,6 +153,13 @@ pub enum InstrumentFnAttr {
152153
Off,
153154
}
154155

156+
#[derive(Clone, Debug, StableHash, Encodable, Decodable, PrintAttribute)]
157+
pub struct EditionRedirect {
158+
pub before: Edition,
159+
pub target: Path,
160+
pub span: Span,
161+
}
162+
155163
#[derive(Copy, Clone, Debug, PartialEq, Eq, Default, PrintAttribute)]
156164
#[derive(Encodable, Decodable, StableHash)]
157165
pub enum OptimizeAttr {
@@ -1477,6 +1485,9 @@ pub enum AttributeKind {
14771485
/// Represents `#[rustc_dyn_incompatible_trait]`.
14781486
RustcDynIncompatibleTrait(Span),
14791487

1488+
/// Represents `#[rustc_edition_redirect(before = "...", target(...))]`.
1489+
RustcEditionRedirect(ThinVec<EditionRedirect>),
1490+
14801491
/// Represents `#[rustc_effective_visibility]`.
14811492
RustcEffectiveVisibility,
14821493

compiler/rustc_hir/src/attrs/encode_cross_crate.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ impl AttributeKind {
144144
RustcDumpVariancesOfOpaques => No,
145145
RustcDumpVtable(..) => No,
146146
RustcDynIncompatibleTrait(..) => No,
147+
RustcEditionRedirect(..) => No,
147148
RustcEffectiveVisibility => Yes,
148149
RustcEiiForeignItem => No,
149150
RustcEvaluateWhereClauses => Yes,

compiler/rustc_hir/src/attrs/pretty_printing.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use rustc_ast_pretty::pp::Printer;
1313
use rustc_data_structures::Limit;
1414
use rustc_data_structures::fx::FxIndexMap;
1515
use rustc_span::def_id::DefId;
16+
use rustc_span::edition::Edition;
1617
use rustc_span::hygiene::Transparency;
1718
use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol};
1819
use rustc_target::spec::SanitizerSet;
@@ -191,7 +192,7 @@ macro_rules! print_tup {
191192

192193
print_tup!(A B C D E F G H);
193194
print_skip!(Span, (), ErrorGuaranteed, AttrId);
194-
print_disp!(u8, u16, u32, u128, usize, bool, NonZero<u32>, Limit);
195+
print_disp!(u8, u16, u32, u128, usize, bool, NonZero<u32>, Edition, Limit);
195196
print_debug!(
196197
Symbol,
197198
Ident,

compiler/rustc_metadata/src/rmeta/decoder.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1313,7 +1313,14 @@ impl CrateMetadata {
13131313
let res = Res::Def(self.def_kind(id), self.local_def_id(id));
13141314
let vis = self.get_visibility(tcx, id);
13151315

1316-
ModChild { ident, res, vis, reexport_chain: Default::default() }
1316+
ModChild {
1317+
ident,
1318+
res,
1319+
vis,
1320+
reexport_chain: Default::default(),
1321+
// Children with redirects are encoded as full `ModChild`s.
1322+
edition_redirects: Default::default(),
1323+
}
13171324
}
13181325

13191326
/// Iterates over all named children of the given module,

compiler/rustc_metadata/src/rmeta/encoder.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1736,11 +1736,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
17361736
let module_children = tcx.module_children_local(local_def_id);
17371737

17381738
record_array!(self.tables.module_children_non_reexports[def_id] <-
1739-
module_children.iter().filter(|child| child.reexport_chain.is_empty())
1739+
module_children.iter().filter(|child| child.reexport_chain.is_empty()
1740+
&& child.edition_redirects.is_empty())
17401741
.map(|child| child.res.def_id().index));
17411742

17421743
record_defaulted_array!(self.tables.module_children_reexports[def_id] <-
1743-
module_children.iter().filter(|child| !child.reexport_chain.is_empty()));
1744+
module_children.iter().filter(|child| !child.reexport_chain.is_empty()
1745+
|| !child.edition_redirects.is_empty()));
17441746

17451747
let ambig_module_children = tcx
17461748
.resolutions(())

0 commit comments

Comments
 (0)