diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 2b5699dcd098..3f052eca48e6 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -10,7 +10,7 @@ the Zulip stream is the best place to *ask* for help.
Documentation for contributing to the compiler or tooling is located in the [Guide to Rustc
Development][rustc-dev-guide], commonly known as the [rustc-dev-guide]. Documentation for the
-standard library in the [Standard library developers Guide][std-dev-guide], commonly known as the [std-dev-guide].
+standard library is in the [Standard library developers Guide][std-dev-guide], commonly known as the [std-dev-guide].
## Making changes to subtrees and submodules
diff --git a/Cargo.lock b/Cargo.lock
index 23abc6626aab..4f98a3facf9b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3539,6 +3539,7 @@ dependencies = [
"rustc_abi",
"rustc_ast",
"rustc_ast_pretty",
+ "rustc_data_structures",
"rustc_errors",
"rustc_feature",
"rustc_hir",
@@ -3571,7 +3572,6 @@ dependencies = [
"rustc_abi",
"rustc_data_structures",
"rustc_errors",
- "rustc_fluent_macro",
"rustc_graphviz",
"rustc_hir",
"rustc_index",
@@ -3687,7 +3687,6 @@ dependencies = [
"serde_json",
"smallvec",
"tempfile",
- "thin-vec",
"thorin-dwp",
"tracing",
"wasm-encoder 0.219.2",
@@ -3704,7 +3703,6 @@ dependencies = [
"rustc_ast",
"rustc_data_structures",
"rustc_errors",
- "rustc_fluent_macro",
"rustc_hir",
"rustc_index",
"rustc_infer",
@@ -3771,7 +3769,6 @@ dependencies = [
"rustc_abi",
"rustc_ast",
"rustc_ast_pretty",
- "rustc_borrowck",
"rustc_codegen_ssa",
"rustc_const_eval",
"rustc_data_structures",
@@ -3791,13 +3788,11 @@ dependencies = [
"rustc_mir_build",
"rustc_mir_transform",
"rustc_parse",
- "rustc_passes",
"rustc_public",
"rustc_resolve",
"rustc_session",
"rustc_span",
"rustc_target",
- "rustc_trait_selection",
"serde_json",
"shlex",
"tracing",
@@ -3892,19 +3887,6 @@ dependencies = [
"serde_json",
]
-[[package]]
-name = "rustc_fluent_macro"
-version = "0.0.0"
-dependencies = [
- "annotate-snippets 0.11.5",
- "fluent-bundle",
- "fluent-syntax",
- "proc-macro2",
- "quote",
- "syn 2.0.110",
- "unic-langid",
-]
-
[[package]]
name = "rustc_fs_util"
version = "0.0.0"
@@ -3959,7 +3941,6 @@ dependencies = [
"rustc_data_structures",
"rustc_errors",
"rustc_feature",
- "rustc_fluent_macro",
"rustc_hir",
"rustc_index",
"rustc_infer",
@@ -4148,7 +4129,6 @@ dependencies = [
"rustc_data_structures",
"rustc_errors",
"rustc_feature",
- "rustc_fluent_macro",
"rustc_hir",
"rustc_index",
"rustc_infer",
@@ -4286,7 +4266,6 @@ dependencies = [
"rustc_ast",
"rustc_data_structures",
"rustc_errors",
- "rustc_fluent_macro",
"rustc_hir",
"rustc_index",
"rustc_infer",
@@ -4388,7 +4367,6 @@ dependencies = [
"rustc_data_structures",
"rustc_errors",
"rustc_feature",
- "rustc_fluent_macro",
"rustc_index",
"rustc_lexer",
"rustc_macros",
@@ -4421,7 +4399,6 @@ dependencies = [
"rustc_errors",
"rustc_expand",
"rustc_feature",
- "rustc_fluent_macro",
"rustc_hir",
"rustc_index",
"rustc_macros",
@@ -4515,6 +4492,7 @@ name = "rustc_query_impl"
version = "0.0.0"
dependencies = [
"measureme",
+ "rustc_abi",
"rustc_data_structures",
"rustc_errors",
"rustc_hashes",
@@ -4524,7 +4502,9 @@ dependencies = [
"rustc_middle",
"rustc_query_system",
"rustc_serialize",
+ "rustc_session",
"rustc_span",
+ "rustc_thread_pool",
"tracing",
]
@@ -4570,7 +4550,6 @@ dependencies = [
"rustc_macros",
"rustc_metadata",
"rustc_middle",
- "rustc_query_system",
"rustc_session",
"rustc_span",
"smallvec",
@@ -4724,7 +4703,6 @@ dependencies = [
"rustc_ast",
"rustc_data_structures",
"rustc_errors",
- "rustc_fluent_macro",
"rustc_hir",
"rustc_infer",
"rustc_macros",
@@ -5586,7 +5564,6 @@ dependencies = [
"build_helper",
"cargo_metadata 0.21.0",
"clap",
- "fluent-syntax",
"globset",
"ignore",
"miropt-test-tools",
diff --git a/INSTALL.md b/INSTALL.md
index dd6c64b3df5f..0e998101fcd1 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -233,7 +233,7 @@ itself back on after some time).
### MSVC
-MSVC builds of Rust additionally requires an installation of:
+MSVC builds of Rust additionally require an installation of:
- Visual Studio 2022 (or later) build tools so `rustc` can use its linker. Older
Visual Studio versions such as 2019 *may* work but aren't actively tested.
diff --git a/RELEASES.md b/RELEASES.md
index 424e12ceec05..29c787f4e14c 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,12 @@
+Version 1.93.1 (2026-02-12)
+===========================
+
+
+
+- [Don't try to recover keyword as non-keyword identifier](https://github.com/rust-lang/rust/pull/150590), fixing an ICE that especially [affected rustfmt](https://github.com/rust-lang/rustfmt/issues/6739).
+- [Fix `clippy::panicking_unwrap` false-positive on field access with implicit deref](https://github.com/rust-lang/rust-clippy/pull/16196).
+- [Revert "Update wasm-related dependencies in CI"](https://github.com/rust-lang/rust/pull/152259), fixing file descriptor leaks on the `wasm32-wasip2` target.
+
Version 1.93.0 (2026-01-22)
==========================
@@ -1546,7 +1555,7 @@ Compatibility Notes
- [Check well-formedness of the source type's signature in fn pointer casts.](https://github.com/rust-lang/rust/pull/129021) This partly closes a soundness hole that comes when casting a function item to function pointer
- [Use equality instead of subtyping when resolving type dependent paths.](https://github.com/rust-lang/rust/pull/129073)
- Linking on macOS now correctly includes Rust's default deployment target. Due to a linker bug, you might have to pass `MACOSX_DEPLOYMENT_TARGET` or fix your `#[link]` attributes to point to the correct frameworks. See .
-- [Rust will now correctly raise an error for `repr(Rust)` written on non-`struct`/`enum`/`union` items, since it previous did not have any effect.](https://github.com/rust-lang/rust/pull/129422)
+- [Rust will now correctly raise an error for `repr(Rust)` written on non-`struct`/`enum`/`union` items, since it previously did not have any effect.](https://github.com/rust-lang/rust/pull/129422)
- The future incompatibility lint `deprecated_cfg_attr_crate_type_name` [has been made into a hard error](https://github.com/rust-lang/rust/pull/129670). It was used to deny usage of `#![crate_type]` and `#![crate_name]` attributes in `#![cfg_attr]`, which required a hack in the compiler to be able to change the used crate type and crate name after cfg expansion.
Users can use `--crate-type` instead of `#![cfg_attr(..., crate_type = "...")]` and `--crate-name` instead of `#![cfg_attr(..., crate_name = "...")]` when running `rustc`/`cargo rustc` on the command line.
Use of those two attributes outside of `#![cfg_attr]` continue to be fully supported.
@@ -1722,7 +1731,7 @@ Cargo
Compatibility Notes
-------------------
- We now [disallow setting some built-in cfgs via the command-line](https://github.com/rust-lang/rust/pull/126158) with the newly added [`explicit_builtin_cfgs_in_flags`](https://doc.rust-lang.org/rustc/lints/listing/deny-by-default.html#explicit-builtin-cfgs-in-flags) lint in order to prevent incoherent state, eg. `windows` cfg active but target is Linux based. The appropriate [`rustc` flag](https://doc.rust-lang.org/rustc/command-line-arguments.html) should be used instead.
-- The standard library has a new implementation of `binary_search` which is significantly improves performance ([#128254](https://github.com/rust-lang/rust/pull/128254)). However when a sorted slice has multiple values which compare equal, the new implementation may select a different value among the equal ones than the old implementation.
+- The standard library has a new implementation of `binary_search` which significantly improves performance ([#128254](https://github.com/rust-lang/rust/pull/128254)). However when a sorted slice has multiple values which compare equal, the new implementation may select a different value among the equal ones than the old implementation.
- [illumos/Solaris now sets `MSG_NOSIGNAL` when writing to sockets](https://github.com/rust-lang/rust/pull/128259). This avoids killing the process with SIGPIPE when writing to a closed socket, which matches the existing behavior on other UNIX targets.
- [Removes a problematic hack that always passed the --whole-archive linker flag for tests, which may cause linker errors for code accidentally relying on it.](https://github.com/rust-lang/rust/pull/128400)
- The WebAssembly target features `multivalue` and `reference-types` are now
@@ -1872,7 +1881,7 @@ These changes do not affect any public interfaces of Rust, but they represent
significant improvements to the performance or internals of rustc and related
tools.
-- [Add a Rust-for Linux `auto` CI job to check kernel builds.](https://github.com/rust-lang/rust/pull/125209/)
+- [Add a Rust-for-Linux `auto` CI job to check kernel builds.](https://github.com/rust-lang/rust/pull/125209/)
Version 1.80.1 (2024-08-08)
===========================
@@ -4510,7 +4519,7 @@ Compatibility Notes
saturating to `0` instead][89926]. In the real world the panic happened mostly
on platforms with buggy monotonic clock implementations rather than catching
programming errors like reversing the start and end times. Such programming
- errors will now results in `0` rather than a panic.
+ errors will now result in `0` rather than a panic.
- In a future release we're planning to increase the baseline requirements for
the Linux kernel to version 3.2, and for glibc to version 2.17. We'd love
your feedback in [PR #95026][95026].
diff --git a/compiler/rustc_abi/src/callconv/reg.rs b/compiler/rustc_abi/src/callconv/reg.rs
index 66c8056d0c2a..66d4dca00726 100644
--- a/compiler/rustc_abi/src/callconv/reg.rs
+++ b/compiler/rustc_abi/src/callconv/reg.rs
@@ -35,6 +35,7 @@ impl Reg {
reg_ctor!(f32, Float, 32);
reg_ctor!(f64, Float, 64);
+ reg_ctor!(f128, Float, 128);
}
impl Reg {
diff --git a/compiler/rustc_abi/src/layout/ty.rs b/compiler/rustc_abi/src/layout/ty.rs
index 41ad14f550ab..aafb124986e1 100644
--- a/compiler/rustc_abi/src/layout/ty.rs
+++ b/compiler/rustc_abi/src/layout/ty.rs
@@ -290,7 +290,19 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
/// function call isn't allowed (a.k.a. `va_list`).
///
/// This function handles transparent types automatically.
- pub fn pass_indirectly_in_non_rustic_abis(mut self, cx: &C) -> bool
+ pub fn pass_indirectly_in_non_rustic_abis(self, cx: &C) -> bool
+ where
+ Ty: TyAbiInterface<'a, C> + Copy,
+ {
+ let base = self.peel_transparent_wrappers(cx);
+ Ty::is_pass_indirectly_in_non_rustic_abis_flag_set(base)
+ }
+
+ /// Recursively peel away transparent wrappers, returning the inner value.
+ ///
+ /// The return value is not `repr(transparent)` and/or does
+ /// not have a non-1zst field.
+ pub fn peel_transparent_wrappers(mut self, cx: &C) -> Self
where
Ty: TyAbiInterface<'a, C> + Copy,
{
@@ -300,7 +312,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
self = field;
}
- Ty::is_pass_indirectly_in_non_rustic_abis_flag_set(self)
+ self
}
/// Finds the one field that is not a 1-ZST.
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index 061ad8617893..85f31b75e240 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -1,6 +1,6 @@
// tidy-alphabetical-start
+#![cfg_attr(all(feature = "nightly", bootstrap), feature(assert_matches))]
#![cfg_attr(feature = "nightly", allow(internal_features))]
-#![cfg_attr(feature = "nightly", feature(assert_matches))]
#![cfg_attr(feature = "nightly", feature(rustc_attrs))]
#![cfg_attr(feature = "nightly", feature(step_trait))]
// tidy-alphabetical-end
diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs
index 6217bf46a942..97dd21db07e7 100644
--- a/compiler/rustc_arena/src/lib.rs
+++ b/compiler/rustc_arena/src/lib.rs
@@ -13,7 +13,6 @@
#![cfg_attr(test, feature(test))]
#![deny(unsafe_op_in_unsafe_fn)]
#![doc(test(no_crate_inject, attr(deny(warnings), allow(internal_features))))]
-#![feature(core_intrinsics)]
#![feature(decl_macro)]
#![feature(dropck_eyepatch)]
#![feature(never_type)]
@@ -26,7 +25,7 @@ use std::cell::{Cell, RefCell};
use std::marker::PhantomData;
use std::mem::{self, MaybeUninit};
use std::ptr::{self, NonNull};
-use std::{cmp, intrinsics, slice};
+use std::{cmp, hint, slice};
use smallvec::SmallVec;
@@ -452,7 +451,7 @@ impl DroplessArena {
let bytes = align_up(layout.size(), DROPLESS_ALIGNMENT);
// Tell LLVM that `end` is aligned to DROPLESS_ALIGNMENT.
- unsafe { intrinsics::assume(end == align_down(end, DROPLESS_ALIGNMENT)) };
+ unsafe { hint::assert_unchecked(end == align_down(end, DROPLESS_ALIGNMENT)) };
if let Some(sub) = end.checked_sub(bytes) {
let new_end = align_down(sub, layout.align());
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 591abdaa2683..fa323b7cf581 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -656,11 +656,7 @@ impl Pat {
// A tuple pattern `(P0, .., Pn)` can be reparsed as `(T0, .., Tn)`
// assuming `T0` to `Tn` are all syntactically valid as types.
PatKind::Tuple(pats) => {
- let mut tys = ThinVec::with_capacity(pats.len());
- // FIXME(#48994) - could just be collected into an Option
- for pat in pats {
- tys.push(pat.to_ty()?);
- }
+ let tys = pats.iter().map(|pat| pat.to_ty()).collect::>>()?;
TyKind::Tup(tys)
}
_ => return None,
@@ -3873,27 +3869,44 @@ pub struct ConstItem {
pub ident: Ident,
pub generics: Generics,
pub ty: Box,
- pub rhs: Option,
+ pub rhs_kind: ConstItemRhsKind,
pub define_opaque: Option>,
}
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
-pub enum ConstItemRhs {
- TypeConst(AnonConst),
- Body(Box),
+pub enum ConstItemRhsKind {
+ Body { rhs: Option> },
+ TypeConst { rhs: Option },
}
-impl ConstItemRhs {
- pub fn span(&self) -> Span {
- self.expr().span
+impl ConstItemRhsKind {
+ pub fn new_body(rhs: Box) -> Self {
+ Self::Body { rhs: Some(rhs) }
}
- pub fn expr(&self) -> &Expr {
+ pub fn span(&self) -> Option {
+ Some(self.expr()?.span)
+ }
+
+ pub fn expr(&self) -> Option<&Expr> {
match self {
- ConstItemRhs::TypeConst(anon_const) => &anon_const.value,
- ConstItemRhs::Body(expr) => expr,
+ Self::Body { rhs: Some(body) } => Some(&body),
+ Self::TypeConst { rhs: Some(anon) } => Some(&anon.value),
+ _ => None,
}
}
+
+ pub fn has_expr(&self) -> bool {
+ match self {
+ Self::Body { rhs: Some(_) } => true,
+ Self::TypeConst { rhs: Some(_) } => true,
+ _ => false,
+ }
+ }
+
+ pub fn is_type_const(&self) -> bool {
+ matches!(self, &Self::TypeConst { .. })
+ }
}
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 51614460d3c4..8556e8288670 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -427,7 +427,7 @@ macro_rules! common_visitor_and_walkers {
Const,
ConstBlockItem,
ConstItem,
- ConstItemRhs,
+ ConstItemRhsKind,
Defaultness,
Delegation,
DelegationMac,
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 051bebfbec00..d9bf6b52f31f 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -966,14 +966,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr));
this.arena.alloc(this.expr(gen_future_span, expr_break))
});
- self.arm(ready_pat, break_x)
+ self.arm(ready_pat, break_x, span)
};
// `::std::task::Poll::Pending => {}`
let pending_arm = {
let pending_pat = self.pat_lang_item_variant(span, hir::LangItem::PollPending, &[]);
let empty_block = self.expr_block_empty(span);
- self.arm(pending_pat, empty_block)
+ self.arm(pending_pat, empty_block, span)
};
let inner_match_stmt = {
@@ -1027,7 +1027,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
});
// mut __awaitee => loop { ... }
- let awaitee_arm = self.arm(awaitee_pat, loop_expr);
+ let awaitee_arm = self.arm(awaitee_pat, loop_expr, span);
// `match ::std::future::IntoFuture::into_future() { ... }`
let into_future_expr = match await_kind {
@@ -1817,7 +1817,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let break_expr =
self.with_loop_scope(loop_hir_id, |this| this.expr_break_alloc(for_span));
let pat = self.pat_none(for_span);
- self.arm(pat, break_expr)
+ self.arm(pat, break_expr, for_span)
};
// Some() => ,
@@ -1826,7 +1826,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let body_block =
self.with_loop_scope(loop_hir_id, |this| this.lower_block(body, false));
let body_expr = self.arena.alloc(self.expr_block(body_block));
- self.arm(some_pat, body_expr)
+ self.arm(some_pat, body_expr, for_span)
};
// `mut iter`
@@ -1885,7 +1885,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let loop_expr = self.arena.alloc(hir::Expr { hir_id: loop_hir_id, kind, span: for_span });
// `mut iter => { ... }`
- let iter_arm = self.arm(iter_pat, loop_expr);
+ let iter_arm = self.arm(iter_pat, loop_expr, for_span);
let match_expr = match loop_kind {
ForLoopKind::For => {
@@ -1930,7 +1930,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir::LangItem::IntoAsyncIterIntoIter,
arena_vec![self; head],
);
- let iter_arm = self.arm(async_iter_pat, inner_match_expr);
+ let iter_arm = self.arm(async_iter_pat, inner_match_expr, for_span);
self.arena.alloc(self.expr_match(
for_span,
iter,
@@ -1997,7 +1997,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let val_expr = self.expr_ident(span, val_ident, val_pat_nid);
self.lower_attrs(val_expr.hir_id, &attrs, span, Target::Expression);
let continue_pat = self.pat_cf_continue(unstable_span, val_pat);
- self.arm(continue_pat, val_expr)
+ self.arm(continue_pat, val_expr, try_span)
};
// `ControlFlow::Break(residual) =>
@@ -2040,7 +2040,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.lower_attrs(ret_expr.hir_id, &attrs, span, Target::Expression);
let break_pat = self.pat_cf_break(try_span, residual_local);
- self.arm(break_pat, ret_expr)
+ self.arm(break_pat, ret_expr, try_span)
};
hir::ExprKind::Match(
@@ -2368,12 +2368,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
&mut self,
pat: &'hir hir::Pat<'hir>,
expr: &'hir hir::Expr<'hir>,
+ span: Span,
) -> hir::Arm<'hir> {
hir::Arm {
hir_id: self.next_id(),
pat,
guard: None,
- span: self.lower_span(expr.span),
+ span: self.lower_span(span),
body: expr,
}
}
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index b497c6beeb98..9922ed8a5c58 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -288,7 +288,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ident,
generics,
ty,
- rhs,
+ rhs_kind,
define_opaque,
}) => {
let ident = self.lower_ident(*ident);
@@ -301,7 +301,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ty,
ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
);
- let rhs = this.lower_const_item_rhs(attrs, rhs.as_ref(), span);
+ let rhs = this.lower_const_item_rhs(rhs_kind, span);
(ty, rhs)
},
);
@@ -827,7 +827,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir_id,
def_id: self.local_def_id(v.id),
data: self.lower_variant_data(hir_id, item_kind, &v.data),
- disr_expr: v.disr_expr.as_ref().map(|e| self.lower_anon_const_to_anon_const(e)),
+ disr_expr: v
+ .disr_expr
+ .as_ref()
+ .map(|e| self.lower_anon_const_to_anon_const(e, e.value.span)),
ident: self.lower_ident(v.ident),
span: self.lower_span(v.span),
}
@@ -917,7 +920,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
None => Ident::new(sym::integer(index), self.lower_span(f.span)),
},
vis_span: self.lower_span(f.vis.span),
- default: f.default.as_ref().map(|v| self.lower_anon_const_to_anon_const(v)),
+ default: f
+ .default
+ .as_ref()
+ .map(|v| self.lower_anon_const_to_anon_const(v, v.value.span)),
ty,
safety: self.lower_safety(f.safety, hir::Safety::Safe),
}
@@ -935,7 +941,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (ident, generics, kind, has_default) = match &i.kind {
AssocItemKind::Const(box ConstItem {
- ident, generics, ty, rhs, define_opaque, ..
+ ident,
+ generics,
+ ty,
+ rhs_kind,
+ define_opaque,
+ ..
}) => {
let (generics, kind) = self.lower_generics(
generics,
@@ -946,15 +957,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
ty,
ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
);
- let rhs = rhs
- .as_ref()
- .map(|rhs| this.lower_const_item_rhs(attrs, Some(rhs), i.span));
- hir::TraitItemKind::Const(ty, rhs)
+ // Trait associated consts don't need an expression/body.
+ let rhs = if rhs_kind.has_expr() {
+ Some(this.lower_const_item_rhs(rhs_kind, i.span))
+ } else {
+ None
+ };
+ hir::TraitItemKind::Const(ty, rhs, rhs_kind.is_type_const().into())
},
);
if define_opaque.is_some() {
- if rhs.is_some() {
+ if rhs_kind.has_expr() {
self.lower_define_opaque(hir_id, &define_opaque);
} else {
self.dcx().span_err(
@@ -964,7 +978,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
}
- (*ident, generics, kind, rhs.is_some())
+ (*ident, generics, kind, rhs_kind.has_expr())
}
AssocItemKind::Fn(box Fn {
sig, ident, generics, body: None, define_opaque, ..
@@ -1148,7 +1162,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (ident, (generics, kind)) = match &i.kind {
AssocItemKind::Const(box ConstItem {
- ident, generics, ty, rhs, define_opaque, ..
+ ident,
+ generics,
+ ty,
+ rhs_kind,
+ define_opaque,
+ ..
}) => (
*ident,
self.lower_generics(
@@ -1161,7 +1180,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
);
this.lower_define_opaque(hir_id, &define_opaque);
- let rhs = this.lower_const_item_rhs(attrs, rhs.as_ref(), i.span);
+ let rhs = this.lower_const_item_rhs(rhs_kind, i.span);
hir::ImplItemKind::Const(ty, rhs)
},
),
@@ -1391,7 +1410,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
// create a fake body so that the entire rest of the compiler doesn't have to deal with
// this as a special case.
return self.lower_fn_body(decl, contract, |this| {
- if attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic))
+ if find_attr!(attrs, AttributeKind::RustcIntrinsic)
|| this.tcx.is_sdylib_interface_build()
{
let span = this.lower_span(span);
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index e4f431fd2431..ff5edfc79943 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -2374,15 +2374,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn lower_const_item_rhs(
&mut self,
- attrs: &[hir::Attribute],
- rhs: Option<&ConstItemRhs>,
+ rhs_kind: &ConstItemRhsKind,
span: Span,
) -> hir::ConstItemRhs<'hir> {
- match rhs {
- Some(ConstItemRhs::TypeConst(anon)) => {
+ match rhs_kind {
+ ConstItemRhsKind::Body { rhs: Some(body) } => {
+ hir::ConstItemRhs::Body(self.lower_const_body(span, Some(body)))
+ }
+ ConstItemRhsKind::Body { rhs: None } => {
+ hir::ConstItemRhs::Body(self.lower_const_body(span, None))
+ }
+ ConstItemRhsKind::TypeConst { rhs: Some(anon) } => {
hir::ConstItemRhs::TypeConst(self.lower_anon_const_to_const_arg_and_alloc(anon))
}
- None if find_attr!(attrs, AttributeKind::TypeConst(_)) => {
+ ConstItemRhsKind::TypeConst { rhs: None } => {
let const_arg = ConstArg {
hir_id: self.next_id(),
kind: hir::ConstArgKind::Error(
@@ -2392,10 +2397,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
};
hir::ConstItemRhs::TypeConst(self.arena.alloc(const_arg))
}
- Some(ConstItemRhs::Body(body)) => {
- hir::ConstItemRhs::Body(self.lower_const_body(span, Some(body)))
- }
- None => hir::ConstItemRhs::Body(self.lower_const_body(span, None)),
}
}
@@ -2425,15 +2426,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
);
let lowered_args = self.arena.alloc_from_iter(args.iter().map(|arg| {
- let const_arg = if let ExprKind::ConstBlock(anon_const) = &arg.kind {
- let def_id = self.local_def_id(anon_const.id);
- let def_kind = self.tcx.def_kind(def_id);
- assert_eq!(DefKind::AnonConst, def_kind);
- self.lower_anon_const_to_const_arg(anon_const)
- } else {
- self.lower_expr_to_const_arg_direct(arg)
- };
-
+ let const_arg = self.lower_expr_to_const_arg_direct(arg);
&*self.arena.alloc(const_arg)
}));
@@ -2445,16 +2438,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
ExprKind::Tup(exprs) => {
let exprs = self.arena.alloc_from_iter(exprs.iter().map(|expr| {
- let expr = if let ExprKind::ConstBlock(anon_const) = &expr.kind {
- let def_id = self.local_def_id(anon_const.id);
- let def_kind = self.tcx.def_kind(def_id);
- assert_eq!(DefKind::AnonConst, def_kind);
-
- self.lower_anon_const_to_const_arg(anon_const)
- } else {
- self.lower_expr_to_const_arg_direct(&expr)
- };
-
+ let expr = self.lower_expr_to_const_arg_direct(&expr);
&*self.arena.alloc(expr)
}));
@@ -2494,16 +2478,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// then go unused as the `Target::ExprField` is not actually
// corresponding to `Node::ExprField`.
self.lower_attrs(hir_id, &f.attrs, f.span, Target::ExprField);
-
- let expr = if let ExprKind::ConstBlock(anon_const) = &f.expr.kind {
- let def_id = self.local_def_id(anon_const.id);
- let def_kind = self.tcx.def_kind(def_id);
- assert_eq!(DefKind::AnonConst, def_kind);
-
- self.lower_anon_const_to_const_arg(anon_const)
- } else {
- self.lower_expr_to_const_arg_direct(&f.expr)
- };
+ let expr = self.lower_expr_to_const_arg_direct(&f.expr);
&*self.arena.alloc(hir::ConstArgExprField {
hir_id,
@@ -2521,13 +2496,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
ExprKind::Array(elements) => {
let lowered_elems = self.arena.alloc_from_iter(elements.iter().map(|element| {
- let const_arg = if let ExprKind::ConstBlock(anon_const) = &element.kind {
- let def_id = self.local_def_id(anon_const.id);
- assert_eq!(DefKind::AnonConst, self.tcx.def_kind(def_id));
- self.lower_anon_const_to_const_arg(anon_const)
- } else {
- self.lower_expr_to_const_arg_direct(element)
- };
+ let const_arg = self.lower_expr_to_const_arg_direct(element);
&*self.arena.alloc(const_arg)
}));
let array_expr = self.arena.alloc(hir::ConstArgArrayExpr {
@@ -2557,6 +2526,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
| ExprKind::Call(..)
| ExprKind::Tup(..)
| ExprKind::Array(..)
+ | ExprKind::ConstBlock(..)
)
{
return self.lower_expr_to_const_arg_direct(expr);
@@ -2570,10 +2540,27 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
ConstArg {
hir_id: self.lower_node_id(expr.id),
- kind: hir::ConstArgKind::Literal(literal.node),
+ kind: hir::ConstArgKind::Literal { lit: literal.node, negated: false },
span,
}
}
+ ExprKind::Unary(UnOp::Neg, inner_expr)
+ if let ExprKind::Lit(literal) = &inner_expr.kind =>
+ {
+ let span = expr.span;
+ let literal = self.lower_lit(literal, span);
+
+ ConstArg {
+ hir_id: self.lower_node_id(expr.id),
+ kind: hir::ConstArgKind::Literal { lit: literal.node, negated: true },
+ span,
+ }
+ }
+ ExprKind::ConstBlock(anon_const) => {
+ let def_id = self.local_def_id(anon_const.id);
+ assert_eq!(DefKind::AnonConst, self.tcx.def_kind(def_id));
+ self.lower_anon_const_to_const_arg(anon_const, span)
+ }
_ => overly_complex_const(self),
}
}
@@ -2584,11 +2571,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
&mut self,
anon: &AnonConst,
) -> &'hir hir::ConstArg<'hir> {
- self.arena.alloc(self.lower_anon_const_to_const_arg(anon))
+ self.arena.alloc(self.lower_anon_const_to_const_arg(anon, anon.value.span))
}
#[instrument(level = "debug", skip(self))]
- fn lower_anon_const_to_const_arg(&mut self, anon: &AnonConst) -> hir::ConstArg<'hir> {
+ fn lower_anon_const_to_const_arg(
+ &mut self,
+ anon: &AnonConst,
+ span: Span,
+ ) -> hir::ConstArg<'hir> {
let tcx = self.tcx;
// We cannot change parsing depending on feature gates available,
@@ -2599,7 +2590,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
if tcx.features().min_generic_const_args() {
return match anon.mgca_disambiguation {
MgcaDisambiguation::AnonConst => {
- let lowered_anon = self.lower_anon_const_to_anon_const(anon);
+ let lowered_anon = self.lower_anon_const_to_anon_const(anon, span);
ConstArg {
hir_id: self.next_id(),
kind: hir::ConstArgKind::Anon(lowered_anon),
@@ -2645,7 +2636,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
};
}
- let lowered_anon = self.lower_anon_const_to_anon_const(anon);
+ let lowered_anon = self.lower_anon_const_to_anon_const(anon, anon.value.span);
ConstArg {
hir_id: self.next_id(),
kind: hir::ConstArgKind::Anon(lowered_anon),
@@ -2655,7 +2646,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
/// See [`hir::ConstArg`] for when to use this function vs
/// [`Self::lower_anon_const_to_const_arg`].
- fn lower_anon_const_to_anon_const(&mut self, c: &AnonConst) -> &'hir hir::AnonConst {
+ fn lower_anon_const_to_anon_const(
+ &mut self,
+ c: &AnonConst,
+ span: Span,
+ ) -> &'hir hir::AnonConst {
self.arena.alloc(self.with_new_scopes(c.value.span, |this| {
let def_id = this.local_def_id(c.id);
let hir_id = this.lower_node_id(c.id);
@@ -2663,7 +2658,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
def_id,
hir_id,
body: this.lower_const_body(c.value.span, Some(&c.value)),
- span: this.lower_span(c.value.span),
+ span: this.lower_span(span),
}
}))
}
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 2457e0a777e4..b9fb20b68971 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -1361,9 +1361,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
});
}
- ItemKind::Const(box ConstItem { defaultness, ident, rhs, .. }) => {
+ ItemKind::Const(box ConstItem { defaultness, ident, rhs_kind, .. }) => {
self.check_defaultness(item.span, *defaultness);
- if rhs.is_none() {
+ if !rhs_kind.has_expr() {
self.dcx().emit_err(errors::ConstWithoutBody {
span: item.span,
replace_span: self.ending_semi_or_hi(item.span),
@@ -1715,11 +1715,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
if let AssocCtxt::Impl { .. } = ctxt {
match &item.kind {
- AssocItemKind::Const(box ConstItem { rhs: None, .. }) => {
- self.dcx().emit_err(errors::AssocConstWithoutBody {
- span: item.span,
- replace_span: self.ending_semi_or_hi(item.span),
- });
+ AssocItemKind::Const(box ConstItem { rhs_kind, .. }) => {
+ if !rhs_kind.has_expr() {
+ self.dcx().emit_err(errors::AssocConstWithoutBody {
+ span: item.span,
+ replace_span: self.ending_semi_or_hi(item.span),
+ });
+ }
}
AssocItemKind::Fn(box Fn { body, .. }) => {
if body.is_none() && !self.is_sdylib_interface {
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index baf6f6beaeed..dd260aede489 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -3,7 +3,7 @@
use rustc_abi::ExternAbi;
use rustc_ast::ParamKindOrd;
use rustc_errors::codes::*;
-use rustc_errors::{Applicability, Diag, EmissionGuarantee, Subdiagnostic, inline_fluent};
+use rustc_errors::{Applicability, Diag, EmissionGuarantee, Subdiagnostic};
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_span::{Ident, Span, Symbol};
@@ -503,7 +503,7 @@ pub(crate) struct AutoTraitItems {
#[primary_span]
pub spans: Vec,
#[suggestion(
- "remove the super traits or lifetime bounds",
+ "remove the associated items",
code = "",
applicability = "machine-applicable",
style = "tool-only"
@@ -927,19 +927,15 @@ pub(crate) struct FeatureOnNonNightly {
pub sugg: Option,
}
+#[derive(Subdiagnostic)]
+#[help(
+ "the feature `{$name}` has been stable since `{$since}` and no longer requires an attribute to enable"
+)]
pub(crate) struct StableFeature {
pub name: Symbol,
pub since: Symbol,
}
-impl Subdiagnostic for StableFeature {
- fn add_to_diag(self, diag: &mut Diag<'_, G>) {
- diag.arg("name", self.name);
- diag.arg("since", self.since);
- diag.help(inline_fluent!("the feature `{$name}` has been stable since `{$since}` and no longer requires an attribute to enable"));
- }
-}
-
#[derive(Diagnostic)]
#[diag("`{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed")]
#[help("remove one of these features")]
@@ -950,6 +946,16 @@ pub(crate) struct IncompatibleFeatures {
pub f2: Symbol,
}
+#[derive(Diagnostic)]
+#[diag("`{$parent}` requires {$missing} to be enabled")]
+#[help("enable all of these features")]
+pub(crate) struct MissingDependentFeatures {
+ #[primary_span]
+ pub parent_span: Span,
+ pub parent: Symbol,
+ pub missing: String,
+}
+
#[derive(Diagnostic)]
#[diag("negative bounds are not supported")]
pub(crate) struct NegativeBoundUnsupported {
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 1b1bbb1564c4..34c73b545df8 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -249,6 +249,14 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
ast::ItemKind::TyAlias(box ast::TyAlias { ty: Some(ty), .. }) => {
self.check_impl_trait(ty, false)
}
+ ast::ItemKind::Const(box ast::ConstItem {
+ rhs_kind: ast::ConstItemRhsKind::TypeConst { .. },
+ ..
+ }) => {
+ // Make sure this is only allowed if the feature gate is enabled.
+ // #![feature(min_generic_const_args)]
+ gate!(&self, min_generic_const_args, i.span, "top-level `type const` are unstable");
+ }
_ => {}
}
@@ -330,15 +338,11 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
fn visit_expr(&mut self, e: &'a ast::Expr) {
match e.kind {
ast::ExprKind::TryBlock(_, None) => {
+ // `try { ... }` is old and is only gated post-expansion here.
gate!(&self, try_blocks, e.span, "`try` expression is experimental");
}
ast::ExprKind::TryBlock(_, Some(_)) => {
- gate!(
- &self,
- try_blocks_heterogeneous,
- e.span,
- "`try bikeshed` expression is experimental"
- );
+ // `try_blocks_heterogeneous` is new, and gated pre-expansion instead.
}
ast::ExprKind::Lit(token::Lit {
kind: token::LitKind::Float | token::LitKind::Integer,
@@ -422,6 +426,20 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
}
false
}
+ ast::AssocItemKind::Const(box ast::ConstItem {
+ rhs_kind: ast::ConstItemRhsKind::TypeConst { .. },
+ ..
+ }) => {
+ // Make sure this is only allowed if the feature gate is enabled.
+ // #![feature(min_generic_const_args)]
+ gate!(
+ &self,
+ min_generic_const_args,
+ i.span,
+ "associated `type const` are unstable"
+ );
+ false
+ }
_ => false,
};
if let ast::Defaultness::Default(_) = i.kind.defaultness() {
@@ -441,6 +459,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
maybe_stage_features(sess, features, krate);
check_incompatible_features(sess, features);
+ check_dependent_features(sess, features);
check_new_solver_banned_features(sess, features);
let mut visitor = PostExpansionVisitor { sess, features };
@@ -499,6 +518,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
half_open_range_patterns_in_slices,
"half-open range patterns in slices are unstable"
);
+ gate_all!(try_blocks_heterogeneous, "`try bikeshed` expression is experimental");
gate_all!(yeet_expr, "`do yeet` expression is experimental");
gate_all!(const_closures, "const closures are experimental");
gate_all!(builtin_syntax, "`builtin #` syntax is unstable");
@@ -527,6 +547,27 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
}
}
}
+ // `mgca_type_const_syntax` is part of `min_generic_const_args` so either
+ // or both are enabled we don't need to emit a feature error.
+ if let Some(spans) = spans.get(&sym::mgca_type_const_syntax) {
+ for span in spans {
+ if visitor.features.min_generic_const_args()
+ || visitor.features.mgca_type_const_syntax()
+ || span.allows_unstable(sym::min_generic_const_args)
+ || span.allows_unstable(sym::mgca_type_const_syntax)
+ {
+ continue;
+ }
+ feature_err(
+ &visitor.sess,
+ sym::min_generic_const_args,
+ *span,
+ "`type const` syntax is experimental",
+ )
+ .emit();
+ }
+ }
+
gate_all!(global_registration, "global registration is experimental");
gate_all!(return_type_notation, "return type notation is experimental");
gate_all!(pin_ergonomics, "pinned reference syntax is experimental");
@@ -649,6 +690,27 @@ fn check_incompatible_features(sess: &Session, features: &Features) {
}
}
+fn check_dependent_features(sess: &Session, features: &Features) {
+ for &(parent, children) in
+ rustc_feature::DEPENDENT_FEATURES.iter().filter(|(parent, _)| features.enabled(*parent))
+ {
+ if children.iter().any(|f| !features.enabled(*f)) {
+ let parent_span = features
+ .enabled_features_iter_stable_order()
+ .find_map(|(name, span)| (name == parent).then_some(span))
+ .unwrap();
+ // FIXME: should probably format this in fluent instead of here
+ let missing = children
+ .iter()
+ .filter(|f| !features.enabled(**f))
+ .map(|s| format!("`{}`", s.as_str()))
+ .intersperse(String::from(", "))
+ .collect();
+ sess.dcx().emit_err(errors::MissingDependentFeatures { parent_span, parent, missing });
+ }
+ }
+}
+
fn check_new_solver_banned_features(sess: &Session, features: &Features) {
if !sess.opts.unstable_opts.next_solver.globally {
return;
diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs
index 2630348c49c1..7793f786cefe 100644
--- a/compiler/rustc_ast_passes/src/lib.rs
+++ b/compiler/rustc_ast_passes/src/lib.rs
@@ -5,6 +5,7 @@
// tidy-alphabetical-start
#![feature(box_patterns)]
#![feature(if_let_guard)]
+#![feature(iter_intersperse)]
#![feature(iter_is_partitioned)]
// tidy-alphabetical-end
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index 68054b06e39f..c7f110a2e003 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -221,7 +221,7 @@ impl<'a> State<'a> {
ident,
generics,
ty,
- rhs,
+ rhs_kind,
define_opaque,
}) => {
self.print_item_const(
@@ -229,7 +229,7 @@ impl<'a> State<'a> {
None,
generics,
ty,
- rhs.as_ref().map(|ct| ct.expr()),
+ rhs_kind.expr(),
&item.vis,
ast::Safety::Default,
*defaultness,
@@ -573,7 +573,7 @@ impl<'a> State<'a> {
ident,
generics,
ty,
- rhs,
+ rhs_kind,
define_opaque,
}) => {
self.print_item_const(
@@ -581,7 +581,7 @@ impl<'a> State<'a> {
None,
generics,
ty,
- rhs.as_ref().map(|ct| ct.expr()),
+ rhs_kind.expr(),
vis,
ast::Safety::Default,
*defaultness,
diff --git a/compiler/rustc_attr_parsing/Cargo.toml b/compiler/rustc_attr_parsing/Cargo.toml
index 411f3f5ccbd1..0a11a2da0dcf 100644
--- a/compiler/rustc_attr_parsing/Cargo.toml
+++ b/compiler/rustc_attr_parsing/Cargo.toml
@@ -8,6 +8,7 @@ edition = "2024"
rustc_abi = { path = "../rustc_abi" }
rustc_ast = { path = "../rustc_ast" }
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
+rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_feature = { path = "../rustc_feature" }
rustc_hir = { path = "../rustc_hir" }
diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
index d825d770fa35..4f1a8cd8b403 100644
--- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
@@ -29,7 +29,7 @@ impl CombineAttributeParser for AllowInternalUnstableParser {
pub(crate) struct UnstableFeatureBoundParser;
impl CombineAttributeParser for UnstableFeatureBoundParser {
- const PATH: &'static [rustc_span::Symbol] = &[sym::unstable_feature_bound];
+ const PATH: &[rustc_span::Symbol] = &[sym::unstable_feature_bound];
type Item = (Symbol, Span);
const CONVERT: ConvertFn = |items, _| AttributeKind::UnstableFeatureBound(items);
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs b/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs
index 4005ad2cba11..b6cb5b4504ee 100644
--- a/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs
@@ -1,22 +1,35 @@
use rustc_ast::token::Token;
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::{AttrStyle, NodeId, token};
+use rustc_data_structures::fx::FxHashMap;
use rustc_feature::{AttributeTemplate, Features};
use rustc_hir::attrs::CfgEntry;
use rustc_hir::{AttrPath, Target};
use rustc_parse::exp;
use rustc_parse::parser::{Parser, Recovery};
use rustc_session::Session;
-use rustc_span::{ErrorGuaranteed, Span, sym};
+use rustc_session::lint::BuiltinLintDiag;
+use rustc_session::lint::builtin::UNREACHABLE_CFG_SELECT_PREDICATES;
+use rustc_span::{ErrorGuaranteed, Span, Symbol, sym};
use crate::parser::MetaItemOrLitParser;
use crate::{AttributeParser, ParsedDescription, ShouldEmit, parse_cfg_entry};
+#[derive(Clone)]
pub enum CfgSelectPredicate {
Cfg(CfgEntry),
Wildcard(Token),
}
+impl CfgSelectPredicate {
+ fn span(&self) -> Span {
+ match self {
+ CfgSelectPredicate::Cfg(cfg_entry) => cfg_entry.span(),
+ CfgSelectPredicate::Wildcard(token) => token.span,
+ }
+ }
+}
+
#[derive(Default)]
pub struct CfgSelectBranches {
/// All the conditional branches.
@@ -115,5 +128,102 @@ pub fn parse_cfg_select(
}
}
+ if let Some(features) = features
+ && features.enabled(sym::cfg_select)
+ {
+ let it = branches
+ .reachable
+ .iter()
+ .map(|(entry, _, _)| CfgSelectPredicate::Cfg(entry.clone()))
+ .chain(branches.wildcard.as_ref().map(|(t, _, _)| CfgSelectPredicate::Wildcard(*t)))
+ .chain(
+ branches.unreachable.iter().map(|(entry, _, _)| CfgSelectPredicate::clone(entry)),
+ );
+
+ lint_unreachable(p, it, lint_node_id);
+ }
+
Ok(branches)
}
+
+fn lint_unreachable(
+ p: &mut Parser<'_>,
+ predicates: impl Iterator- ,
+ lint_node_id: NodeId,
+) {
+ // Symbols that have a known value.
+ let mut known = FxHashMap::
::default();
+ let mut wildcard_span = None;
+ let mut it = predicates;
+
+ let branch_is_unreachable = |predicate: CfgSelectPredicate, wildcard_span| {
+ let span = predicate.span();
+ p.psess.buffer_lint(
+ UNREACHABLE_CFG_SELECT_PREDICATES,
+ span,
+ lint_node_id,
+ BuiltinLintDiag::UnreachableCfg { span, wildcard_span },
+ );
+ };
+
+ for predicate in &mut it {
+ let CfgSelectPredicate::Cfg(ref cfg_entry) = predicate else {
+ wildcard_span = Some(predicate.span());
+ break;
+ };
+
+ match cfg_entry {
+ CfgEntry::Bool(true, _) => {
+ wildcard_span = Some(predicate.span());
+ break;
+ }
+ CfgEntry::Bool(false, _) => continue,
+ CfgEntry::NameValue { name, value, .. } => match value {
+ None => {
+ // `name` will be false in all subsequent branches.
+ let current = known.insert(*name, false);
+
+ match current {
+ None => continue,
+ Some(false) => {
+ branch_is_unreachable(predicate, None);
+ break;
+ }
+ Some(true) => {
+ // this branch will be taken, so all subsequent branches are unreachable.
+ break;
+ }
+ }
+ }
+ Some(_) => { /* for now we don't bother solving these */ }
+ },
+ CfgEntry::Not(inner, _) => match &**inner {
+ CfgEntry::NameValue { name, value: None, .. } => {
+ // `name` will be true in all subsequent branches.
+ let current = known.insert(*name, true);
+
+ match current {
+ None => continue,
+ Some(true) => {
+ branch_is_unreachable(predicate, None);
+ break;
+ }
+ Some(false) => {
+ // this branch will be taken, so all subsequent branches are unreachable.
+ break;
+ }
+ }
+ }
+ _ => { /* for now we don't bother solving these */ }
+ },
+ CfgEntry::All(_, _) | CfgEntry::Any(_, _) => {
+ /* for now we don't bother solving these */
+ }
+ CfgEntry::Version(..) => { /* don't bother solving these */ }
+ }
+ }
+
+ for predicate in it {
+ branch_is_unreachable(predicate, wildcard_span)
+ }
+}
diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs
index 557dfe09853b..bdfe7bfb8f1f 100644
--- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs
@@ -283,3 +283,12 @@ impl NoArgsAttributeParser for RustcPreserveUbChecksParser {
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcPreserveUbChecks;
}
+
+pub(crate) struct RustcNoImplicitBoundsParser;
+
+impl NoArgsAttributeParser for RustcNoImplicitBoundsParser {
+ const PATH: &[Symbol] = &[sym::rustc_no_implicit_bounds];
+ const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn;
+ const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
+ const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNoImplicitBounds;
+}
diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
index e01377d247bb..c055c2936e95 100644
--- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
@@ -1,4 +1,5 @@
use rustc_hir::attrs::{DeprecatedSince, Deprecation};
+use rustc_hir::{RustcVersion, VERSION_PLACEHOLDER};
use super::prelude::*;
use super::util::parse_version;
@@ -143,6 +144,8 @@ impl SingleAttributeParser for DeprecationParser {
DeprecatedSince::Future
} else if !is_rustc {
DeprecatedSince::NonStandard(since)
+ } else if since.as_str() == VERSION_PLACEHOLDER {
+ DeprecatedSince::RustcVersion(RustcVersion::CURRENT)
} else if let Some(version) = parse_version(since) {
DeprecatedSince::RustcVersion(version)
} else {
diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs
index f6aab9ea0ee2..767200bfa9bf 100644
--- a/compiler/rustc_attr_parsing/src/attributes/inline.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs
@@ -10,7 +10,7 @@ use super::prelude::*;
pub(crate) struct InlineParser;
impl SingleAttributeParser for InlineParser {
- const PATH: &'static [Symbol] = &[sym::inline];
+ const PATH: &[Symbol] = &[sym::inline];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
@@ -67,7 +67,7 @@ impl SingleAttributeParser for InlineParser {
pub(crate) struct RustcForceInlineParser;
impl SingleAttributeParser for RustcForceInlineParser {
- const PATH: &'static [Symbol] = &[sym::rustc_force_inline];
+ const PATH: &[Symbol] = &[sym::rustc_force_inline];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
diff --git a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs
index 3674aa7124ab..f9ace7e25d1b 100644
--- a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs
@@ -1,3 +1,6 @@
+use rustc_hir::lints::AttributeLintKind;
+use rustc_session::lint::builtin::AMBIGUOUS_DERIVE_HELPERS;
+
use super::prelude::*;
const PROC_MACRO_ALLOWED_TARGETS: AllowedTargets =
@@ -126,6 +129,13 @@ fn parse_derive_like(
cx.expected_identifier(ident.span);
return None;
}
+ if rustc_feature::is_builtin_attr_name(ident.name) {
+ cx.emit_lint(
+ AMBIGUOUS_DERIVE_HELPERS,
+ AttributeLintKind::AmbiguousDeriveHelpers,
+ ident.span,
+ );
+ }
attributes.push(ident.name);
}
}
diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs
index 34d4957edc70..fb0b8df65284 100644
--- a/compiler/rustc_attr_parsing/src/attributes/repr.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs
@@ -272,7 +272,7 @@ fn parse_alignment(node: &LitKind) -> Result {
pub(crate) struct AlignParser(Option<(Align, Span)>);
impl AlignParser {
- const PATH: &'static [Symbol] = &[sym::rustc_align];
+ const PATH: &[Symbol] = &[sym::rustc_align];
const TEMPLATE: AttributeTemplate = template!(List: &[""]);
fn parse(&mut self, cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) {
@@ -329,7 +329,7 @@ impl AttributeParser for AlignParser {
pub(crate) struct AlignStaticParser(AlignParser);
impl AlignStaticParser {
- const PATH: &'static [Symbol] = &[sym::rustc_align_static];
+ const PATH: &[Symbol] = &[sym::rustc_align_static];
const TEMPLATE: AttributeTemplate = AlignParser::TEMPLATE;
fn parse(&mut self, cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) {
diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
index 348882dc59fc..f1b31365013e 100644
--- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
@@ -2,7 +2,8 @@ use std::path::PathBuf;
use rustc_ast::{LitIntType, LitKind, MetaItemLit};
use rustc_hir::attrs::{
- BorrowckGraphvizFormatKind, RustcCleanAttribute, RustcCleanQueries, RustcLayoutType,
+ BorrowckGraphvizFormatKind, CguFields, CguKind, DivergingBlockBehavior,
+ DivergingFallbackBehavior, RustcCleanAttribute, RustcCleanQueries, RustcLayoutType,
RustcMirKind,
};
use rustc_session::errors;
@@ -10,12 +11,14 @@ use rustc_span::Symbol;
use super::prelude::*;
use super::util::parse_single_integer;
-use crate::session_diagnostics::{AttributeRequiresOpt, RustcScalableVectorCountOutOfRange};
+use crate::session_diagnostics::{
+ AttributeRequiresOpt, CguFieldsMissing, RustcScalableVectorCountOutOfRange,
+};
pub(crate) struct RustcMainParser;
impl NoArgsAttributeParser for RustcMainParser {
- const PATH: &'static [Symbol] = &[sym::rustc_main];
+ const PATH: &[Symbol] = &[sym::rustc_main];
const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcMain;
@@ -100,7 +103,7 @@ impl NoArgsAttributeParser for RustcNoImplicitAutorefsParser {
pub(crate) struct RustcLayoutScalarValidRangeStartParser;
impl SingleAttributeParser for RustcLayoutScalarValidRangeStartParser {
- const PATH: &'static [Symbol] = &[sym::rustc_layout_scalar_valid_range_start];
+ const PATH: &[Symbol] = &[sym::rustc_layout_scalar_valid_range_start];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
@@ -115,7 +118,7 @@ impl SingleAttributeParser for RustcLayoutScalarValidRangeStartPars
pub(crate) struct RustcLayoutScalarValidRangeEndParser;
impl SingleAttributeParser for RustcLayoutScalarValidRangeEndParser {
- const PATH: &'static [Symbol] = &[sym::rustc_layout_scalar_valid_range_end];
+ const PATH: &[Symbol] = &[sym::rustc_layout_scalar_valid_range_end];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
@@ -204,6 +207,325 @@ impl NoArgsAttributeParser for RustcLintOptTyParser {
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcLintOptTy;
}
+fn parse_cgu_fields(
+ cx: &mut AcceptContext<'_, '_, S>,
+ args: &ArgParser,
+ accepts_kind: bool,
+) -> Option<(Symbol, Symbol, Option)> {
+ let Some(args) = args.list() else {
+ cx.expected_list(cx.attr_span, args);
+ return None;
+ };
+
+ let mut cfg = None::<(Symbol, Span)>;
+ let mut module = None::<(Symbol, Span)>;
+ let mut kind = None::<(Symbol, Span)>;
+
+ for arg in args.mixed() {
+ let Some(arg) = arg.meta_item() else {
+ cx.expected_name_value(args.span, None);
+ continue;
+ };
+
+ let res = match arg.ident().map(|i| i.name) {
+ Some(sym::cfg) => &mut cfg,
+ Some(sym::module) => &mut module,
+ Some(sym::kind) if accepts_kind => &mut kind,
+ _ => {
+ cx.expected_specific_argument(
+ arg.path().span(),
+ if accepts_kind {
+ &[sym::cfg, sym::module, sym::kind]
+ } else {
+ &[sym::cfg, sym::module]
+ },
+ );
+ continue;
+ }
+ };
+
+ let Some(i) = arg.args().name_value() else {
+ cx.expected_name_value(arg.span(), None);
+ continue;
+ };
+
+ let Some(str) = i.value_as_str() else {
+ cx.expected_string_literal(i.value_span, Some(i.value_as_lit()));
+ continue;
+ };
+
+ if res.is_some() {
+ cx.duplicate_key(arg.span(), arg.ident().unwrap().name);
+ continue;
+ }
+
+ *res = Some((str, i.value_span));
+ }
+
+ let Some((cfg, _)) = cfg else {
+ cx.emit_err(CguFieldsMissing { span: args.span, name: &cx.attr_path, field: sym::cfg });
+ return None;
+ };
+ let Some((module, _)) = module else {
+ cx.emit_err(CguFieldsMissing { span: args.span, name: &cx.attr_path, field: sym::module });
+ return None;
+ };
+ let kind = if let Some((kind, span)) = kind {
+ Some(match kind {
+ sym::no => CguKind::No,
+ sym::pre_dash_lto => CguKind::PreDashLto,
+ sym::post_dash_lto => CguKind::PostDashLto,
+ sym::any => CguKind::Any,
+ _ => {
+ cx.expected_specific_argument_strings(
+ span,
+ &[sym::no, sym::pre_dash_lto, sym::post_dash_lto, sym::any],
+ );
+ return None;
+ }
+ })
+ } else {
+ // return None so that an unwrap for the attributes that need it is ok.
+ if accepts_kind {
+ cx.emit_err(CguFieldsMissing {
+ span: args.span,
+ name: &cx.attr_path,
+ field: sym::kind,
+ });
+ return None;
+ };
+
+ None
+ };
+
+ Some((cfg, module, kind))
+}
+
+#[derive(Default)]
+pub(crate) struct RustcCguTestAttributeParser {
+ items: ThinVec<(Span, CguFields)>,
+}
+
+impl AttributeParser for RustcCguTestAttributeParser {
+ const ATTRIBUTES: AcceptMapping = &[
+ (
+ &[sym::rustc_partition_reused],
+ template!(List: &[r#"cfg = "...", module = "...""#]),
+ |this, cx, args| {
+ this.items.extend(parse_cgu_fields(cx, args, false).map(|(cfg, module, _)| {
+ (cx.attr_span, CguFields::PartitionReused { cfg, module })
+ }));
+ },
+ ),
+ (
+ &[sym::rustc_partition_codegened],
+ template!(List: &[r#"cfg = "...", module = "...""#]),
+ |this, cx, args| {
+ this.items.extend(parse_cgu_fields(cx, args, false).map(|(cfg, module, _)| {
+ (cx.attr_span, CguFields::PartitionCodegened { cfg, module })
+ }));
+ },
+ ),
+ (
+ &[sym::rustc_expected_cgu_reuse],
+ template!(List: &[r#"cfg = "...", module = "...", kind = "...""#]),
+ |this, cx, args| {
+ this.items.extend(parse_cgu_fields(cx, args, true).map(|(cfg, module, kind)| {
+ // unwrap ok because if not given, we return None in `parse_cgu_fields`.
+ (cx.attr_span, CguFields::ExpectedCguReuse { cfg, module, kind: kind.unwrap() })
+ }));
+ },
+ ),
+ ];
+
+ const ALLOWED_TARGETS: AllowedTargets =
+ AllowedTargets::AllowList(&[Allow(Target::Mod), Allow(Target::Crate)]);
+
+ fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option {
+ Some(AttributeKind::RustcCguTestAttr(self.items))
+ }
+}
+
+pub(crate) struct RustcDeprecatedSafe2024Parser;
+
+impl SingleAttributeParser for RustcDeprecatedSafe2024Parser {
+ const PATH: &[Symbol] = &[sym::rustc_deprecated_safe_2024];
+ const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
+ const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+ Allow(Target::Fn),
+ Allow(Target::Method(MethodKind::Inherent)),
+ Allow(Target::Method(MethodKind::Trait { body: false })),
+ Allow(Target::Method(MethodKind::Trait { body: true })),
+ Allow(Target::Method(MethodKind::TraitImpl)),
+ ]);
+ const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
+ const TEMPLATE: AttributeTemplate = template!(List: &[r#"audit_that = "...""#]);
+
+ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option {
+ let Some(args) = args.list() else {
+ cx.expected_list(cx.attr_span, args);
+ return None;
+ };
+
+ let Some(single) = args.single() else {
+ cx.expected_single_argument(args.span);
+ return None;
+ };
+
+ let Some(arg) = single.meta_item() else {
+ cx.expected_name_value(args.span, None);
+ return None;
+ };
+
+ let Some(args) = arg.word_is(sym::audit_that) else {
+ cx.expected_specific_argument(arg.span(), &[sym::audit_that]);
+ return None;
+ };
+
+ let Some(nv) = args.name_value() else {
+ cx.expected_name_value(arg.span(), Some(sym::audit_that));
+ return None;
+ };
+
+ let Some(suggestion) = nv.value_as_str() else {
+ cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
+ return None;
+ };
+
+ Some(AttributeKind::RustcDeprecatedSafe2024 { suggestion })
+ }
+}
+
+pub(crate) struct RustcConversionSuggestionParser;
+
+impl NoArgsAttributeParser for RustcConversionSuggestionParser {
+ const PATH: &[Symbol] = &[sym::rustc_conversion_suggestion];
+ const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
+ const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+ Allow(Target::Fn),
+ Allow(Target::Method(MethodKind::Inherent)),
+ Allow(Target::Method(MethodKind::Trait { body: false })),
+ Allow(Target::Method(MethodKind::Trait { body: true })),
+ Allow(Target::Method(MethodKind::TraitImpl)),
+ ]);
+ const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcConversionSuggestion;
+}
+
+pub(crate) struct RustcCaptureAnalysisParser;
+
+impl NoArgsAttributeParser for RustcCaptureAnalysisParser {
+ const PATH: &[Symbol] = &[sym::rustc_capture_analysis];
+ const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
+ const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Closure)]);
+ const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcCaptureAnalysis;
+}
+
+pub(crate) struct RustcNeverTypeOptionsParser;
+
+impl SingleAttributeParser for RustcNeverTypeOptionsParser {
+ const PATH: &[Symbol] = &[sym::rustc_never_type_options];
+ const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
+ const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
+ const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
+ const TEMPLATE: AttributeTemplate = template!(List: &[
+ r#"fallback = "unit", "never", "no""#,
+ r#"diverging_block_default = "unit", "never""#,
+ ]);
+
+ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option {
+ let Some(list) = args.list() else {
+ cx.expected_list(cx.attr_span, args);
+ return None;
+ };
+
+ let mut fallback = None::;
+ let mut diverging_block_default = None::;
+
+ for arg in list.mixed() {
+ let Some(meta) = arg.meta_item() else {
+ cx.expected_name_value(arg.span(), None);
+ continue;
+ };
+
+ let res = match meta.ident().map(|i| i.name) {
+ Some(sym::fallback) => &mut fallback,
+ Some(sym::diverging_block_default) => &mut diverging_block_default,
+ _ => {
+ cx.expected_specific_argument(
+ meta.path().span(),
+ &[sym::fallback, sym::diverging_block_default],
+ );
+ continue;
+ }
+ };
+
+ let Some(nv) = meta.args().name_value() else {
+ cx.expected_name_value(meta.span(), None);
+ continue;
+ };
+
+ let Some(field) = nv.value_as_str() else {
+ cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
+ continue;
+ };
+
+ if res.is_some() {
+ cx.duplicate_key(meta.span(), meta.ident().unwrap().name);
+ continue;
+ }
+
+ *res = Some(Ident { name: field, span: nv.value_span });
+ }
+
+ let fallback = match fallback {
+ None => None,
+ Some(Ident { name: sym::unit, .. }) => Some(DivergingFallbackBehavior::ToUnit),
+ Some(Ident { name: sym::never, .. }) => Some(DivergingFallbackBehavior::ToNever),
+ Some(Ident { name: sym::no, .. }) => Some(DivergingFallbackBehavior::NoFallback),
+ Some(Ident { span, .. }) => {
+ cx.expected_specific_argument_strings(span, &[sym::unit, sym::never, sym::no]);
+ return None;
+ }
+ };
+
+ let diverging_block_default = match diverging_block_default {
+ None => None,
+ Some(Ident { name: sym::unit, .. }) => Some(DivergingBlockBehavior::Unit),
+ Some(Ident { name: sym::never, .. }) => Some(DivergingBlockBehavior::Never),
+ Some(Ident { span, .. }) => {
+ cx.expected_specific_argument_strings(span, &[sym::unit, sym::no]);
+ return None;
+ }
+ };
+
+ Some(AttributeKind::RustcNeverTypeOptions { fallback, diverging_block_default })
+ }
+}
+
+pub(crate) struct RustcTrivialFieldReadsParser;
+
+impl NoArgsAttributeParser for RustcTrivialFieldReadsParser {
+ const PATH: &[Symbol] = &[sym::rustc_trivial_field_reads];
+ const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
+ const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
+ const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcTrivialFieldReads;
+}
+
+pub(crate) struct RustcNoMirInlineParser;
+
+impl NoArgsAttributeParser for RustcNoMirInlineParser {
+ const PATH: &[Symbol] = &[sym::rustc_no_mir_inline];
+ const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
+ const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+ Allow(Target::Fn),
+ Allow(Target::Method(MethodKind::Inherent)),
+ Allow(Target::Method(MethodKind::Trait { body: false })),
+ Allow(Target::Method(MethodKind::Trait { body: true })),
+ Allow(Target::Method(MethodKind::TraitImpl)),
+ ]);
+ const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNoMirInline;
+}
+
pub(crate) struct RustcLintQueryInstabilityParser;
impl NoArgsAttributeParser for RustcLintQueryInstabilityParser {
@@ -219,6 +541,22 @@ impl NoArgsAttributeParser for RustcLintQueryInstabilityParser {
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcLintQueryInstability;
}
+pub(crate) struct RustcRegionsParser;
+
+impl NoArgsAttributeParser for RustcRegionsParser {
+ const PATH: &[Symbol] = &[sym::rustc_regions];
+ const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
+ const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+ Allow(Target::Fn),
+ Allow(Target::Method(MethodKind::Inherent)),
+ Allow(Target::Method(MethodKind::Trait { body: false })),
+ Allow(Target::Method(MethodKind::Trait { body: true })),
+ Allow(Target::Method(MethodKind::TraitImpl)),
+ ]);
+
+ const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcRegions;
+}
+
pub(crate) struct RustcLintUntrackedQueryInformationParser;
impl NoArgsAttributeParser for RustcLintUntrackedQueryInformationParser {
@@ -237,21 +575,11 @@ impl NoArgsAttributeParser for RustcLintUntrackedQueryInformationPa
pub(crate) struct RustcObjectLifetimeDefaultParser;
-impl SingleAttributeParser for RustcObjectLifetimeDefaultParser {
+impl NoArgsAttributeParser for RustcObjectLifetimeDefaultParser {
const PATH: &[Symbol] = &[sym::rustc_object_lifetime_default];
- const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
- const TEMPLATE: AttributeTemplate = template!(Word);
-
- fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option {
- if let Err(span) = args.no_args() {
- cx.expected_no_args(span);
- return None;
- }
-
- Some(AttributeKind::RustcObjectLifetimeDefault)
- }
+ const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcObjectLifetimeDefault;
}
pub(crate) struct RustcSimdMonomorphizeLaneLimitParser;
@@ -490,10 +818,11 @@ impl CombineAttributeParser for RustcMirParser {
.collect()
}
}
+
pub(crate) struct RustcNonConstTraitMethodParser;
impl NoArgsAttributeParser for RustcNonConstTraitMethodParser {
- const PATH: &'static [Symbol] = &[sym::rustc_non_const_trait_method];
+ const PATH: &[Symbol] = &[sym::rustc_non_const_trait_method];
const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Method(MethodKind::Trait { body: true })),
@@ -721,3 +1050,173 @@ impl CombineAttributeParser for RustcThenThisWouldNeedParser {
Some(ident)
}
}
+
+pub(crate) struct RustcInsignificantDtorParser;
+
+impl NoArgsAttributeParser for RustcInsignificantDtorParser {
+ const PATH: &[Symbol] = &[sym::rustc_insignificant_dtor];
+ const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
+ const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+ Allow(Target::Enum),
+ Allow(Target::Struct),
+ Allow(Target::ForeignTy),
+ ]);
+ const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcInsignificantDtor;
+}
+
+pub(crate) struct RustcEffectiveVisibilityParser;
+
+impl NoArgsAttributeParser for RustcEffectiveVisibilityParser {
+ const PATH: &[Symbol] = &[sym::rustc_effective_visibility];
+ const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
+ const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+ Allow(Target::Use),
+ Allow(Target::Static),
+ Allow(Target::Const),
+ Allow(Target::Fn),
+ Allow(Target::Closure),
+ Allow(Target::Mod),
+ Allow(Target::ForeignMod),
+ Allow(Target::TyAlias),
+ Allow(Target::Enum),
+ Allow(Target::Variant),
+ Allow(Target::Struct),
+ Allow(Target::Field),
+ Allow(Target::Union),
+ Allow(Target::Trait),
+ Allow(Target::TraitAlias),
+ Allow(Target::Impl { of_trait: false }),
+ Allow(Target::Impl { of_trait: true }),
+ Allow(Target::AssocConst),
+ Allow(Target::Method(MethodKind::Inherent)),
+ Allow(Target::Method(MethodKind::Trait { body: false })),
+ Allow(Target::Method(MethodKind::Trait { body: true })),
+ Allow(Target::Method(MethodKind::TraitImpl)),
+ Allow(Target::AssocTy),
+ Allow(Target::ForeignFn),
+ Allow(Target::ForeignStatic),
+ Allow(Target::ForeignTy),
+ Allow(Target::MacroDef),
+ Allow(Target::PatField),
+ Allow(Target::Crate),
+ ]);
+ const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcEffectiveVisibility;
+}
+
+pub(crate) struct RustcSymbolName;
+
+impl SingleAttributeParser for RustcSymbolName {
+ const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+ Allow(Target::Fn),
+ Allow(Target::Method(MethodKind::TraitImpl)),
+ Allow(Target::Method(MethodKind::Inherent)),
+ Allow(Target::Method(MethodKind::Trait { body: true })),
+ Allow(Target::ForeignFn),
+ Allow(Target::ForeignStatic),
+ Allow(Target::Impl { of_trait: false }),
+ ]);
+ const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
+ const PATH: &[Symbol] = &[sym::rustc_symbol_name];
+ const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
+ const TEMPLATE: AttributeTemplate = template!(Word);
+ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option {
+ if let Err(span) = args.no_args() {
+ cx.expected_no_args(span);
+ return None;
+ }
+ Some(AttributeKind::RustcSymbolName(cx.attr_span))
+ }
+}
+
+pub(crate) struct RustcDefPath;
+
+impl SingleAttributeParser for RustcDefPath {
+ const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+ Allow(Target::Fn),
+ Allow(Target::Method(MethodKind::TraitImpl)),
+ Allow(Target::Method(MethodKind::Inherent)),
+ Allow(Target::Method(MethodKind::Trait { body: true })),
+ Allow(Target::ForeignFn),
+ Allow(Target::ForeignStatic),
+ Allow(Target::Impl { of_trait: false }),
+ ]);
+ const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
+ const PATH: &[Symbol] = &[sym::rustc_def_path];
+ const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
+ const TEMPLATE: AttributeTemplate = template!(Word);
+ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option {
+ if let Err(span) = args.no_args() {
+ cx.expected_no_args(span);
+ return None;
+ }
+ Some(AttributeKind::RustcDefPath(cx.attr_span))
+ }
+}
+
+pub(crate) struct RustcIntrinsicParser;
+
+impl NoArgsAttributeParser for RustcIntrinsicParser {
+ const PATH: &[Symbol] = &[sym::rustc_intrinsic];
+ const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
+ const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
+ const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcIntrinsic;
+}
+
+pub(crate) struct RustcIntrinsicConstStableIndirectParser;
+
+impl NoArgsAttributeParser for RustcIntrinsicConstStableIndirectParser {
+ const PATH: &'static [Symbol] = &[sym::rustc_intrinsic_const_stable_indirect];
+ const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
+ const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
+ const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcIntrinsicConstStableIndirect;
+}
+
+pub(crate) struct RustcStrictCoherenceParser;
+
+impl NoArgsAttributeParser for RustcStrictCoherenceParser {
+ const PATH: &[Symbol] = &[sym::rustc_strict_coherence];
+ const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
+ const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+ Allow(Target::Trait),
+ Allow(Target::Struct),
+ Allow(Target::Enum),
+ Allow(Target::Union),
+ Allow(Target::ForeignTy),
+ ]);
+ const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcStrictCoherence;
+}
+
+pub(crate) struct RustcReservationImplParser;
+
+impl SingleAttributeParser for RustcReservationImplParser {
+ const PATH: &[Symbol] = &[sym::rustc_reservation_impl];
+ const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
+ const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
+ const ALLOWED_TARGETS: AllowedTargets =
+ AllowedTargets::AllowList(&[Allow(Target::Impl { of_trait: true })]);
+
+ const TEMPLATE: AttributeTemplate = template!(NameValueStr: "reservation message");
+
+ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option {
+ let Some(nv) = args.name_value() else {
+ cx.expected_name_value(args.span().unwrap_or(cx.attr_span), None);
+ return None;
+ };
+
+ let Some(value_str) = nv.value_as_str() else {
+ cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
+ return None;
+ };
+
+ Some(AttributeKind::RustcReservationImpl(cx.attr_span, value_str))
+ }
+}
+
+pub(crate) struct PreludeImportParser;
+
+impl NoArgsAttributeParser for PreludeImportParser {
+ const PATH: &[Symbol] = &[sym::prelude_import];
+ const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn;
+ const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Use)]);
+ const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::PreludeImport;
+}
diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs
index 1f01cadcb43e..a2be2d42b3e1 100644
--- a/compiler/rustc_attr_parsing/src/attributes/stability.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs
@@ -244,7 +244,20 @@ impl AttributeParser for ConstStabilityParser {
this.promotable = true;
}),
];
- const ALLOWED_TARGETS: AllowedTargets = ALLOWED_TARGETS;
+ const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+ Allow(Target::Fn),
+ Allow(Target::Method(MethodKind::Inherent)),
+ Allow(Target::Method(MethodKind::TraitImpl)),
+ Allow(Target::Method(MethodKind::Trait { body: true })),
+ Allow(Target::Impl { of_trait: false }),
+ Allow(Target::Impl { of_trait: true }),
+ Allow(Target::Use), // FIXME I don't think this does anything?
+ Allow(Target::Const),
+ Allow(Target::AssocConst),
+ Allow(Target::Trait),
+ Allow(Target::Static),
+ Allow(Target::Crate),
+ ]);
fn finalize(mut self, cx: &FinalizeContext<'_, '_, S>) -> Option {
if self.promotable {
diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs
index 236d10d77b92..41b1836588de 100644
--- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs
@@ -1,3 +1,4 @@
+use rustc_hir::attrs::RustcAbiAttrKind;
use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
use super::prelude::*;
@@ -140,3 +141,119 @@ impl SingleAttributeParser for ReexportTestHarnessMainParser {
Some(AttributeKind::ReexportTestHarnessMain(name))
}
}
+
+pub(crate) struct RustcAbiParser;
+
+impl SingleAttributeParser for RustcAbiParser {
+ const PATH: &[Symbol] = &[sym::rustc_abi];
+ const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn;
+ const TEMPLATE: AttributeTemplate = template!(OneOf: &[sym::debug, sym::assert_eq]);
+ const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
+ const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+ Allow(Target::TyAlias),
+ Allow(Target::Fn),
+ Allow(Target::ForeignFn),
+ Allow(Target::Method(MethodKind::Inherent)),
+ Allow(Target::Method(MethodKind::Trait { body: true })),
+ Allow(Target::Method(MethodKind::Trait { body: false })),
+ Allow(Target::Method(MethodKind::TraitImpl)),
+ ]);
+
+ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option {
+ let Some(args) = args.list() else {
+ cx.expected_specific_argument_and_list(cx.attr_span, &[sym::assert_eq, sym::debug]);
+ return None;
+ };
+
+ let Some(arg) = args.single() else {
+ cx.expected_single_argument(cx.attr_span);
+ return None;
+ };
+
+ let fail_incorrect_argument =
+ |span| cx.expected_specific_argument(span, &[sym::assert_eq, sym::debug]);
+
+ let Some(arg) = arg.meta_item() else {
+ fail_incorrect_argument(args.span);
+ return None;
+ };
+
+ let kind: RustcAbiAttrKind = match arg.path().word_sym() {
+ Some(sym::assert_eq) => RustcAbiAttrKind::AssertEq,
+ Some(sym::debug) => RustcAbiAttrKind::Debug,
+ None | Some(_) => {
+ fail_incorrect_argument(arg.span());
+ return None;
+ }
+ };
+
+ Some(AttributeKind::RustcAbi { attr_span: cx.attr_span, kind })
+ }
+}
+
+pub(crate) struct RustcDelayedBugFromInsideQueryParser;
+
+impl NoArgsAttributeParser for RustcDelayedBugFromInsideQueryParser {
+ const PATH: &[Symbol] = &[sym::rustc_delayed_bug_from_inside_query];
+ const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn;
+ const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
+ const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDelayedBugFromInsideQuery;
+}
+
+pub(crate) struct RustcEvaluateWhereClausesParser;
+
+impl NoArgsAttributeParser for RustcEvaluateWhereClausesParser {
+ const PATH: &[Symbol] = &[sym::rustc_evaluate_where_clauses];
+ const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn;
+ const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+ Allow(Target::Fn),
+ Allow(Target::Method(MethodKind::Inherent)),
+ Allow(Target::Method(MethodKind::Trait { body: true })),
+ Allow(Target::Method(MethodKind::TraitImpl)),
+ Allow(Target::Method(MethodKind::Trait { body: false })),
+ ]);
+ const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcEvaluateWhereClauses;
+}
+
+pub(crate) struct RustcOutlivesParser;
+
+impl NoArgsAttributeParser for RustcOutlivesParser {
+ const PATH: &[Symbol] = &[sym::rustc_outlives];
+ const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn;
+ const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+ Allow(Target::Struct),
+ Allow(Target::Enum),
+ Allow(Target::Union),
+ Allow(Target::TyAlias),
+ ]);
+ const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcOutlives;
+}
+
+pub(crate) struct TestRunnerParser;
+
+impl SingleAttributeParser for TestRunnerParser {
+ const PATH: &[Symbol] = &[sym::test_runner];
+ const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
+ const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
+ const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
+ const TEMPLATE: AttributeTemplate = template!(List: &["path"]);
+
+ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option {
+ let Some(list) = args.list() else {
+ cx.expected_list(cx.attr_span, args);
+ return None;
+ };
+
+ let Some(single) = list.single() else {
+ cx.expected_single_argument(list.span);
+ return None;
+ };
+
+ let Some(meta) = single.meta_item() else {
+ cx.unexpected_literal(single.span());
+ return None;
+ };
+
+ Some(AttributeKind::TestRunner(meta.path().0.clone()))
+ }
+}
diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs
index bfea02e789a0..ceaa43948d67 100644
--- a/compiler/rustc_attr_parsing/src/attributes/traits.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs
@@ -66,15 +66,6 @@ impl NoArgsAttributeParser for ParenSugarParser {
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcParenSugar;
}
-pub(crate) struct TypeConstParser;
-impl NoArgsAttributeParser for TypeConstParser {
- const PATH: &[Symbol] = &[sym::type_const];
- const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
- const ALLOWED_TARGETS: AllowedTargets =
- AllowedTargets::AllowList(&[Allow(Target::Const), Allow(Target::AssocConst)]);
- const CREATE: fn(Span) -> AttributeKind = AttributeKind::TypeConst;
-}
-
// Markers
pub(crate) struct MarkerParser;
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index 5abf299ec618..c6f0914bfbda 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -1,5 +1,6 @@
use std::cell::RefCell;
use std::collections::BTreeMap;
+use std::collections::btree_map::Entry;
use std::ops::{Deref, DerefMut};
use std::sync::LazyLock;
@@ -61,7 +62,7 @@ use crate::target_checking::AllowedTargets;
type GroupType = LazyLock>;
pub(super) struct GroupTypeInner {
- pub(super) accepters: BTreeMap<&'static [Symbol], Vec>>,
+ pub(super) accepters: BTreeMap<&'static [Symbol], GroupTypeInnerAccept>,
}
pub(super) struct GroupTypeInnerAccept {
@@ -101,7 +102,7 @@ macro_rules! attribute_parsers {
@[$stage: ty] pub(crate) static $name: ident = [$($names: ty),* $(,)?];
) => {
pub(crate) static $name: GroupType<$stage> = LazyLock::new(|| {
- let mut accepters = BTreeMap::<_, Vec>>::new();
+ let mut accepters = BTreeMap::<_, GroupTypeInnerAccept<$stage>>::new();
$(
{
thread_local! {
@@ -109,19 +110,24 @@ macro_rules! attribute_parsers {
};
for (path, template, accept_fn) in <$names>::ATTRIBUTES {
- accepters.entry(*path).or_default().push(GroupTypeInnerAccept {
- template: *template,
- accept_fn: Box::new(|cx, args| {
- STATE_OBJECT.with_borrow_mut(|s| {
- accept_fn(s, cx, args)
- })
- }),
- allowed_targets: <$names as crate::attributes::AttributeParser<$stage>>::ALLOWED_TARGETS,
- finalizer: Box::new(|cx| {
- let state = STATE_OBJECT.take();
- state.finalize(cx)
- }),
- });
+ match accepters.entry(*path) {
+ Entry::Vacant(e) => {
+ e.insert(GroupTypeInnerAccept {
+ template: *template,
+ accept_fn: Box::new(|cx, args| {
+ STATE_OBJECT.with_borrow_mut(|s| {
+ accept_fn(s, cx, args)
+ })
+ }),
+ allowed_targets: <$names as crate::attributes::AttributeParser<$stage>>::ALLOWED_TARGETS,
+ finalizer: Box::new(|cx| {
+ let state = STATE_OBJECT.take();
+ state.finalize(cx)
+ })
+ });
+ }
+ Entry::Occupied(_) => panic!("Attribute {path:?} has multiple accepters"),
+ }
}
}
)*
@@ -141,6 +147,7 @@ attribute_parsers!(
DocParser,
MacroUseParser,
NakedParser,
+ RustcCguTestAttributeParser,
StabilityParser,
UsedParser,
// tidy-alphabetical-end
@@ -191,8 +198,11 @@ attribute_parsers!(
Single,
Single,
Single,
+ Single,
Single,
Single,
+ Single,
+ Single,
Single,
Single,
Single,
@@ -200,12 +210,15 @@ attribute_parsers!(
Single,
Single,
Single,
- Single,
+ Single,
+ Single,
Single,
Single,
+ Single,
Single,
Single,
Single,
+ Single,
Single,
Single,
Single,
@@ -245,41 +258,56 @@ attribute_parsers!(
Single>,
Single>,
Single>,
+ Single>,
Single>,
Single>,
Single>,
Single>,
Single>,
Single>,
+ Single>,
Single>,
+ Single>,
Single>,
+ Single>,
Single>,
Single>,
Single>,
Single>,
Single>,
+ Single>,
+ Single>,
Single>,
Single>,
+ Single>,
+ Single>,
+ Single>,
Single>,
Single>,
Single>,
Single>,
Single>,
Single>,
+ Single>,
+ Single>,
Single>,
Single>,
+ Single>,
Single>,
+ Single>,
Single>,
Single>,
Single>,
+ Single>,
Single>,
+ Single>,
+ Single>,
Single>,
Single