diff --git a/Cargo.lock b/Cargo.lock
index 686b98cf6128..3b56dd6bd9ce 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -649,11 +649,11 @@ checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d"
[[package]]
name = "clippy"
-version = "0.1.96"
+version = "0.1.97"
dependencies = [
"anstream",
"askama",
- "cargo_metadata 0.18.1",
+ "cargo_metadata 0.23.1",
"clippy_config",
"clippy_lints",
"clippy_lints_internal",
@@ -676,7 +676,7 @@ dependencies = [
[[package]]
name = "clippy_config"
-version = "0.1.96"
+version = "0.1.97"
dependencies = [
"clippy_utils",
"itertools",
@@ -700,10 +700,10 @@ dependencies = [
[[package]]
name = "clippy_lints"
-version = "0.1.96"
+version = "0.1.97"
dependencies = [
"arrayvec",
- "cargo_metadata 0.18.1",
+ "cargo_metadata 0.23.1",
"clippy_config",
"clippy_utils",
"declare_clippy_lint",
@@ -732,7 +732,7 @@ dependencies = [
[[package]]
name = "clippy_utils"
-version = "0.1.96"
+version = "0.1.97"
dependencies = [
"arrayvec",
"itertools",
@@ -1136,7 +1136,7 @@ dependencies = [
[[package]]
name = "declare_clippy_lint"
-version = "0.1.96"
+version = "0.1.97"
[[package]]
name = "derive-where"
@@ -1677,6 +1677,15 @@ dependencies = [
"serde_core",
]
+[[package]]
+name = "hashbrown"
+version = "0.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51"
+dependencies = [
+ "foldhash 0.2.0",
+]
+
[[package]]
name = "heck"
version = "0.4.1"
@@ -1953,12 +1962,12 @@ checksum = "964de6e86d545b246d84badc0fef527924ace5134f30641c203ef52ba83f58d5"
[[package]]
name = "indexmap"
-version = "2.13.0"
+version = "2.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
+checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
dependencies = [
"equivalent",
- "hashbrown 0.16.1",
+ "hashbrown 0.17.0",
"serde",
"serde_core",
]
@@ -3505,6 +3514,7 @@ dependencies = [
"rand_xoshiro",
"rustc_data_structures",
"rustc_error_messages",
+ "rustc_errors",
"rustc_hashes",
"rustc_index",
"rustc_macros",
@@ -3805,7 +3815,7 @@ dependencies = [
"either",
"elsa",
"ena",
- "hashbrown 0.16.1",
+ "hashbrown 0.17.0",
"indexmap",
"jobserver",
"libc",
@@ -3909,7 +3919,6 @@ dependencies = [
"anstream",
"anstyle",
"derive_setters",
- "rustc_abi",
"rustc_ast",
"rustc_data_structures",
"rustc_error_codes",
@@ -3995,6 +4004,7 @@ dependencies = [
"rustc_ast_pretty",
"rustc_data_structures",
"rustc_error_messages",
+ "rustc_errors",
"rustc_hashes",
"rustc_hir_id",
"rustc_index",
@@ -4224,6 +4234,7 @@ dependencies = [
name = "rustc_lint_defs"
version = "0.0.0"
dependencies = [
+ "rustc_ast",
"rustc_data_structures",
"rustc_error_messages",
"rustc_hir_id",
@@ -4568,7 +4579,6 @@ name = "rustc_query_impl"
version = "0.0.0"
dependencies = [
"measureme",
- "rustc_abi",
"rustc_data_structures",
"rustc_errors",
"rustc_hir",
@@ -4691,7 +4701,6 @@ dependencies = [
"rustc-demangle",
"rustc_abi",
"rustc_data_structures",
- "rustc_errors",
"rustc_hashes",
"rustc_hir",
"rustc_middle",
@@ -5540,9 +5549,9 @@ dependencies = [
[[package]]
name = "thin-vec"
-version = "0.2.14"
+version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "144f754d318415ac792f9d69fc87abbbfc043ce2ef041c60f16ad828f638717d"
+checksum = "da322882471314edc77fa5232c587bcb87c9df52bfd0d7d4826f8868ead61899"
[[package]]
name = "thiserror"
diff --git a/RELEASES.md b/RELEASES.md
index c396cd8069d6..87768b2f74e7 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,140 @@
+Version 1.95.0 (2026-04-16)
+===========================
+
+
+
+Language
+--------
+- [Stabilize `if let` guards on match arms](https://github.com/rust-lang/rust/pull/141295)
+- [`irrefutable_let_patterns` lint no longer lints on let chains](https://github.com/rust-lang/rust/pull/146832)
+- [Support importing path-segment keywords with renaming](https://github.com/rust-lang/rust/pull/146972)
+- [Stabilize inline assembly for PowerPC and PowerPC64](https://github.com/rust-lang/rust/pull/147996)
+- [const-eval: be more consistent in the behavior of padding during typed copies](https://github.com/rust-lang/rust/pull/148967)
+- [Const blocks are no longer evaluated to determine if expressions involving fallible operations can implicitly be constant-promoted.](https://github.com/rust-lang/rust/pull/150557). Expressions whose ability to implicitly be promoted would depend on the result of a const block are no longer implicitly promoted.
+- [Make operational semantics of pattern matching independent of crate and module](https://github.com/rust-lang/rust/pull/150681)
+
+
+
+
+Compiler
+--------
+
+- [Stabilize `--remap-path-scope` for controlling the scoping of how paths get remapped in the resulting binary](https://github.com/rust-lang/rust/pull/147611)
+- [Apply patches for CVE-2026-6042 and CVE-2026-40200 to vendored musl](https://github.com/rust-lang/rust/pull/155171)
+
+
+
+Platform Support
+----------------
+- [Promote `powerpc64-unknown-linux-musl` to Tier 2 with host tools](https://github.com/rust-lang/rust/pull/149962)
+- [Promote `aarch64-apple-tvos` to Tier 2](https://github.com/rust-lang/rust/pull/152021)
+- [Promote `aarch64-apple-tvos-sim` to Tier 2](https://github.com/rust-lang/rust/pull/152021)
+- [Promote `aarch64-apple-watchos` to Tier 2](https://github.com/rust-lang/rust/pull/152021)
+- [Promote `aarch64-apple-watchos-sim` to Tier 2](https://github.com/rust-lang/rust/pull/152021)
+- [Promote `aarch64-apple-visionos` to Tier 2](https://github.com/rust-lang/rust/pull/152021)
+- [Promote `aarch64-apple-visionos-sim` to Tier 2](https://github.com/rust-lang/rust/pull/152021)
+
+
+Refer to Rust's [platform support page][platform-support-doc]
+for more information on Rust's tiered platform support.
+
+[platform-support-doc]: https://doc.rust-lang.org/rustc/platform-support.html
+
+
+
+Libraries
+---------
+- [`thread::scope`: document how join interacts with TLS destructors](https://github.com/rust-lang/rust/pull/149482)
+- [Speed up `str::contains` on aarch64 targets with `neon` target feature enabled by default](https://github.com/rust-lang/rust/pull/152176)
+
+
+
+
+Stabilized APIs
+---------------
+
+- [`MaybeUninit<[T; N]>: From<[MaybeUninit; N]>`](https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#impl-From%3CMaybeUninit%3C%5BT;+N%5D%3E%3E-for-%5BMaybeUninit%3CT%3E;+N%5D)
+- [`MaybeUninit<[T; N]>: AsRef<[MaybeUninit; N]>`](https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#impl-AsRef%3C%5BMaybeUninit%3CT%3E;+N%5D%3E-for-MaybeUninit%3C%5BT;+N%5D%3E)
+- [`MaybeUninit<[T; N]>: AsRef<[MaybeUninit]>`](https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#impl-AsRef%3C%5BMaybeUninit%3CT%3E%5D%3E-for-MaybeUninit%3C%5BT;+N%5D%3E)
+- [`MaybeUninit<[T; N]>: AsMut<[MaybeUninit; N]>`](https://doc.rust-lang.org/beta/std/mem/union.MaybeUninit.html#impl-AsMut%3C%5BMaybeUninit%3CT%3E;+N%5D%3E-for-MaybeUninit%3C%5BT;+N%5D%3E)
+- [`MaybeUninit<[T; N]>: AsMut<[MaybeUninit]>`](https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#impl-AsMut%3C%5BMaybeUninit%3CT%3E%5D%3E-for-MaybeUninit%3C%5BT;+N%5D%3E)
+- [`[MaybeUninit; N]: From>`](https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#impl-From%3C%5BMaybeUninit%3CT%3E;+N%5D%3E-for-MaybeUninit%3C%5BT;+N%5D%3E)
+- [`Cell<[T; N]>: AsRef<[Cell; N]>`](https://doc.rust-lang.org/stable/std/cell/struct.Cell.html#impl-AsRef%3C%5BCell%3CT%3E;+N%5D%3E-for-Cell%3C%5BT;+N%5D%3E)
+- [`Cell<[T; N]>: AsRef<[Cell]>`](https://doc.rust-lang.org/stable/std/cell/struct.Cell.html#impl-AsRef%3C%5BCell%3CT%3E%5D%3E-for-Cell%3C%5BT;+N%5D%3E)
+- [`Cell<[T]>: AsRef<[Cell]>`](https://doc.rust-lang.org/stable/std/cell/struct.Cell.html#impl-AsRef%3C%5BCell%3CT%3E%5D%3E-for-Cell%3C%5BT%5D%3E)
+- [`bool: TryFrom<{integer}>`](https://doc.rust-lang.org/stable/std/primitive.bool.html#impl-TryFrom%3Cu128%3E-for-bool)
+- [`AtomicPtr::update`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicPtr.html#method.update)
+- [`AtomicPtr::try_update`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicPtr.html#method.try_update)
+- [`AtomicBool::update`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicBool.html#method.update)
+- [`AtomicBool::try_update`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicBool.html#method.try_update)
+- [`AtomicIn::update`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicIsize.html#method.update)
+- [`AtomicIn::try_update`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicIsize.html#method.try_update)
+- [`AtomicUn::update`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicUsize.html#method.update)
+- [`AtomicUn::try_update`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicUsize.html#method.try_update)
+- [`cfg_select!`](https://doc.rust-lang.org/stable/std/macro.cfg_select.html)
+- [`mod core::range`](https://doc.rust-lang.org/stable/core/range/index.html)
+- [`core::range::RangeInclusive`](https://doc.rust-lang.org/stable/core/range/struct.RangeInclusive.html)
+- [`core::range::RangeInclusiveIter`](https://doc.rust-lang.org/stable/core/range/struct.RangeInclusiveIter.html)
+- [`core::hint::cold_path`](https://doc.rust-lang.org/stable/core/hint/fn.cold_path.html)
+- [`<*const T>::as_ref_unchecked`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.as_ref_unchecked)
+- [`<*mut T>::as_ref_unchecked`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.as_ref_unchecked-1)
+- [`<*mut T>::as_mut_unchecked`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.as_mut_unchecked)
+- [`Vec::push_mut`](https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.push_mut)
+- [`Vec::insert_mut`](https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.insert_mut)
+- [`VecDeque::push_front_mut`](https://doc.rust-lang.org/stable/std/collections/struct.VecDeque.html#method.push_front_mut)
+- [`VecDeque::push_back_mut`](https://doc.rust-lang.org/stable/std/collections/struct.VecDeque.html#method.push_back_mut)
+- [`VecDeque::insert_mut`](https://doc.rust-lang.org/stable/std/collections/struct.VecDeque.html#method.insert_mut)
+- [`LinkedList::push_front_mut`](https://doc.rust-lang.org/stable/std/collections/struct.LinkedList.html#method.push_front_mut)
+- [`LinkedList::push_back_mut`](https://doc.rust-lang.org/stable/std/collections/struct.LinkedList.html#method.push_back_mut)
+- [`Layout::dangling_ptr`](https://doc.rust-lang.org/stable/std/alloc/struct.Layout.html#method.dangling_ptr)
+- [`Layout::repeat`](https://doc.rust-lang.org/stable/std/alloc/struct.Layout.html#method.repeat)
+- [`Layout::repeat_packed`](https://doc.rust-lang.org/stable/std/alloc/struct.Layout.html#method.repeat_packed)
+- [`Layout::extend_packed`](https://doc.rust-lang.org/stable/std/alloc/struct.Layout.html#method.extend_packed)
+
+These previously stable APIs are now stable in const contexts:
+
+- [`fmt::from_fn`](https://doc.rust-lang.org/stable/std/fmt/fn.from_fn.html)
+- [`ControlFlow::is_break`](https://doc.rust-lang.org/stable/core/ops/enum.ControlFlow.html#method.is_break)
+- [`ControlFlow::is_continue`](https://doc.rust-lang.org/stable/core/ops/enum.ControlFlow.html#method.is_continue)
+
+
+
+Rustdoc
+-----
+- [In search results, rank unstable items lower](https://github.com/rust-lang/rust/pull/149460)
+- [Add new "hide deprecated items" setting in rustdoc](https://github.com/rust-lang/rust/pull/151091)
+
+
+
+Compatibility Notes
+-------------------
+- [Array coercions may now result in less inference constraints than before](https://github.com/rust-lang/rust/pull/140283)
+- Importing `$crate` without renaming, i.e. `use $crate::{self};`, is now no longer permitted due to stricter error checking for `self` imports.
+- [const-eval: be more consistent in the behavior of padding during typed copies.](https://github.com/rust-lang/rust/pull/148967)
+ In very rare cases, this may cause compilation errors due to bytes from parts of a pointer ending up in the padding bytes of a `const` or `static`.
+- [A future-incompatibility warning lint `ambiguous_glob_imported_traits` is now reported when using an ambiguously glob imported trait](https://github.com/rust-lang/rust/pull/149058)
+- [Check lifetime bounds of types mentioning only type parameters](https://github.com/rust-lang/rust/pull/149389)
+- [Report more visibility-related ambiguous import errors](https://github.com/rust-lang/rust/pull/149596)
+- [Deprecate `Eq::assert_receiver_is_total_eq` and emit future compatibility warnings on manual impls](https://github.com/rust-lang/rust/pull/149978)
+- [powerpc64: Use the ELF ABI version set in target spec instead of guessing](https://github.com/rust-lang/rust/pull/150468) (fixes the ELF ABI used by the OpenBSD target)
+- Matching on a `#[non_exhaustive]` enum [now reads the discriminant, even if the enum has only one variant](https://github.com/rust-lang/rust/pull/150681). This can cause closures to capture values that they previously wouldn't.
+- `mut ref` and `mut ref mut` patterns, part of the unstable [Match Ergonomics 2024 RFC](https://github.com/rust-lang/rust/issues/123076), were accidentally allowed on stable within struct pattern field shorthand. These patterns are now correctly feature-gated as unstable in this position.
+- [Add future-compatibility warning for derive helper attributes which conflict with built-in attributes](https://github.com/rust-lang/rust/pull/151152)
+- [JSON target specs](https://doc.rust-lang.org/rustc/targets/custom.html) have been destabilized and now require `-Z unstable-options` to use. Previously, they could not be used without the standard library, which has no stable build mechanism. In preparation for the `build-std` project adding that support, JSON target specs are being proactively gated to ensure they remain unstable even if `build-std` is stabilized. Cargo now includes the `-Z json-target-spec` CLI flag to automatically pass `-Z unstable-options` to the compiler when needed. See [#150151](https://github.com/rust-lang/rust/pull/150151), [#151534](https://github.com/rust-lang/rust/pull/150151), and [rust-lang/cargo#16557](https://github.com/rust-lang/cargo/pull/16557).
+- [The arguments of `#[feature]` attributes on invalid targets are now checked](https://github.com/rust-lang/rust/issues/153764)
+
+
+
+Internal Changes
+----------------
+
+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.
+
+- [Update to LLVM 22](https://github.com/rust-lang/rust/pull/150722)
+
+
Version 1.94.1 (2026-03-26)
===========================
diff --git a/compiler/rustc_abi/Cargo.toml b/compiler/rustc_abi/Cargo.toml
index 83d96d8d04da..13e0bd8703d9 100644
--- a/compiler/rustc_abi/Cargo.toml
+++ b/compiler/rustc_abi/Cargo.toml
@@ -10,6 +10,7 @@ rand = { version = "0.9.0", default-features = false, optional = true }
rand_xoshiro = { version = "0.7.0", optional = true }
rustc_data_structures = { path = "../rustc_data_structures", optional = true }
rustc_error_messages = { path = "../rustc_error_messages", optional = true }
+rustc_errors = { path = "../rustc_errors", optional = true }
rustc_hashes = { path = "../rustc_hashes" }
rustc_index = { path = "../rustc_index", default-features = false }
rustc_macros = { path = "../rustc_macros", optional = true }
@@ -21,11 +22,12 @@ tracing = "0.1"
[features]
# tidy-alphabetical-start
default = ["nightly", "randomize"]
-# rust-analyzer depends on this crate and we therefore require it to built on a stable toolchain
-# without depending on rustc_data_structures, rustc_macros and rustc_serialize
+# rust-analyzer depends on this crate and we therefore require it to build on a stable toolchain
+# without depending on the rustc_* crates in the following list.
nightly = [
"dep:rustc_data_structures",
"dep:rustc_error_messages",
+ "dep:rustc_errors",
"dep:rustc_macros",
"dep:rustc_serialize",
"dep:rustc_span",
diff --git a/compiler/rustc_abi/src/callconv.rs b/compiler/rustc_abi/src/callconv.rs
index 7ad7088b3089..d6594e277f00 100644
--- a/compiler/rustc_abi/src/callconv.rs
+++ b/compiler/rustc_abi/src/callconv.rs
@@ -75,10 +75,11 @@ pub fn homogeneous_aggregate(&self, cx: &C) -> Result {
+ BackendRepr::SimdVector { element, count: _ } => {
assert!(!self.is_zst());
+
Ok(HomogeneousAggregate::Homogeneous(Reg {
- kind: RegKind::Vector,
+ kind: RegKind::Vector { hint_vector_elem: element.primitive() },
size: self.size,
}))
}
diff --git a/compiler/rustc_abi/src/callconv/reg.rs b/compiler/rustc_abi/src/callconv/reg.rs
index 66d4dca00726..c30425fb703a 100644
--- a/compiler/rustc_abi/src/callconv/reg.rs
+++ b/compiler/rustc_abi/src/callconv/reg.rs
@@ -1,14 +1,19 @@
#[cfg(feature = "nightly")]
use rustc_macros::HashStable_Generic;
-use crate::{Align, HasDataLayout, Size};
+use crate::{Align, HasDataLayout, Integer, Primitive, Size};
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum RegKind {
Integer,
Float,
- Vector,
+ Vector {
+ /// The `hint_vector_elem` is strictly for optimization purposes. E.g. it can be used by
+ /// a codegen backend to prevent extra bitcasts that obscure a pattern. Alternatively,
+ /// it can be safely ignored by always picking i8.
+ hint_vector_elem: Primitive,
+ },
}
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
@@ -36,6 +41,12 @@ impl Reg {
reg_ctor!(f32, Float, 32);
reg_ctor!(f64, Float, 64);
reg_ctor!(f128, Float, 128);
+
+ /// A vector of the given size with an unknown (and irrelevant) element type.
+ pub fn opaque_vector(size: Size) -> Reg {
+ // Default to an i8 vector of the given size.
+ Reg { kind: RegKind::Vector { hint_vector_elem: Primitive::Int(Integer::I8, true) }, size }
+ }
}
impl Reg {
@@ -58,7 +69,7 @@ pub fn align(&self, cx: &C) -> Align {
128 => dl.f128_align,
_ => panic!("unsupported float: {self:?}"),
},
- RegKind::Vector => dl.llvmlike_vector_align(self.size),
+ RegKind::Vector { .. } => dl.llvmlike_vector_align(self.size),
}
}
}
diff --git a/compiler/rustc_abi/src/extern_abi.rs b/compiler/rustc_abi/src/extern_abi.rs
index 9173245d8aa4..95ba2ee3b78f 100644
--- a/compiler/rustc_abi/src/extern_abi.rs
+++ b/compiler/rustc_abi/src/extern_abi.rs
@@ -131,6 +131,29 @@ pub const fn as_str(&self) -> &'static str {
$($e_name::$variant $( { unwind: $uw } )* => $tok,)*
}
}
+ // FIXME(FnSigKind): when PartialEq is stably const, use it instead
+ const fn internal_const_eq(&self, other: &Self) -> bool {
+ match (self, other) {
+ $( ( $e_name::$variant $( { unwind: $uw } )* , $e_name::$variant $( { unwind: $uw } )* ) => true,)*
+ _ => false,
+ }
+ }
+ // ALL_VARIANTS.iter().position(|v| v == self), but const
+ pub const fn as_packed(&self) -> u8 {
+ let mut index = 0;
+ while index < $e_name::ALL_VARIANTS.len() {
+ if self.internal_const_eq(&$e_name::ALL_VARIANTS[index]) {
+ return index as u8;
+ }
+ index += 1;
+ }
+ panic!("unreachable: invalid ExternAbi variant");
+ }
+ pub const fn from_packed(index: u8) -> Self {
+ let index = index as usize;
+ assert!(index < $e_name::ALL_VARIANTS.len(), "invalid ExternAbi index");
+ $e_name::ALL_VARIANTS[index]
+ }
}
impl ::core::str::FromStr for $e_name {
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index f148b776852a..450a93ee8481 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -46,10 +46,16 @@
use bitflags::bitflags;
#[cfg(feature = "nightly")]
use rustc_data_structures::stable_hasher::StableOrd;
+#[cfg(feature = "nightly")]
+use rustc_error_messages::{DiagArgValue, IntoDiagArg};
+#[cfg(feature = "nightly")]
+use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, msg};
use rustc_hashes::Hash64;
use rustc_index::{Idx, IndexSlice, IndexVec};
#[cfg(feature = "nightly")]
use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_Generic};
+#[cfg(feature = "nightly")]
+use rustc_span::{Symbol, sym};
mod callconv;
mod canon_abi;
@@ -332,7 +338,7 @@ fn default() -> TargetDataLayout {
}
}
-pub enum TargetDataLayoutErrors<'a> {
+pub enum TargetDataLayoutError<'a> {
InvalidAddressSpace { addr_space: &'a str, cause: &'a str, err: ParseIntError },
InvalidBits { kind: &'a str, bit: &'a str, cause: &'a str, err: ParseIntError },
MissingAlignment { cause: &'a str },
@@ -343,6 +349,51 @@ pub enum TargetDataLayoutErrors<'a> {
UnknownPointerSpecification { err: String },
}
+#[cfg(feature = "nightly")]
+impl Diagnostic<'_, G> for TargetDataLayoutError<'_> {
+ fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
+ match self {
+ TargetDataLayoutError::InvalidAddressSpace { addr_space, err, cause } => {
+ Diag::new(dcx, level, msg!("invalid address space `{$addr_space}` for `{$cause}` in \"data-layout\": {$err}"))
+ .with_arg("addr_space", addr_space)
+ .with_arg("cause", cause)
+ .with_arg("err", err)
+ }
+ TargetDataLayoutError::InvalidBits { kind, bit, cause, err } => {
+ Diag::new(dcx, level, msg!("invalid {$kind} `{$bit}` for `{$cause}` in \"data-layout\": {$err}"))
+ .with_arg("kind", kind)
+ .with_arg("bit", bit)
+ .with_arg("cause", cause)
+ .with_arg("err", err)
+ }
+ TargetDataLayoutError::MissingAlignment { cause } => {
+ Diag::new(dcx, level, msg!("missing alignment for `{$cause}` in \"data-layout\""))
+ .with_arg("cause", cause)
+ }
+ TargetDataLayoutError::InvalidAlignment { cause, err } => {
+ Diag::new(dcx, level, msg!("invalid alignment for `{$cause}` in \"data-layout\": {$err}"))
+ .with_arg("cause", cause)
+ .with_arg("err", err.to_string())
+ }
+ TargetDataLayoutError::InconsistentTargetArchitecture { dl, target } => {
+ Diag::new(dcx, level, msg!("inconsistent target specification: \"data-layout\" claims architecture is {$dl}-endian, while \"target-endian\" is `{$target}`"))
+ .with_arg("dl", dl).with_arg("target", target)
+ }
+ TargetDataLayoutError::InconsistentTargetPointerWidth { pointer_size, target } => {
+ Diag::new(dcx, level, msg!("inconsistent target specification: \"data-layout\" claims pointers are {$pointer_size}-bit, while \"target-pointer-width\" is `{$target}`"))
+ .with_arg("pointer_size", pointer_size).with_arg("target", target)
+ }
+ TargetDataLayoutError::InvalidBitsSize { err } => {
+ Diag::new(dcx, level, msg!("{$err}")).with_arg("err", err)
+ }
+ TargetDataLayoutError::UnknownPointerSpecification { err } => {
+ Diag::new(dcx, level, msg!("unknown pointer specification `{$err}` in datalayout string"))
+ .with_arg("err", err)
+ }
+ }
+ }
+}
+
impl TargetDataLayout {
/// Parse data layout from an
/// [llvm data layout string](https://llvm.org/docs/LangRef.html#data-layout)
@@ -352,17 +403,17 @@ impl TargetDataLayout {
pub fn parse_from_llvm_datalayout_string<'a>(
input: &'a str,
default_address_space: AddressSpace,
- ) -> Result> {
+ ) -> Result> {
// Parse an address space index from a string.
let parse_address_space = |s: &'a str, cause: &'a str| {
s.parse::().map(AddressSpace).map_err(|err| {
- TargetDataLayoutErrors::InvalidAddressSpace { addr_space: s, cause, err }
+ TargetDataLayoutError::InvalidAddressSpace { addr_space: s, cause, err }
})
};
// Parse a bit count from a string.
let parse_bits = |s: &'a str, kind: &'a str, cause: &'a str| {
- s.parse::().map_err(|err| TargetDataLayoutErrors::InvalidBits {
+ s.parse::().map_err(|err| TargetDataLayoutError::InvalidBits {
kind,
bit: s,
cause,
@@ -378,7 +429,7 @@ pub fn parse_from_llvm_datalayout_string<'a>(
let parse_align_str = |s: &'a str, cause: &'a str| {
let align_from_bits = |bits| {
Align::from_bits(bits)
- .map_err(|err| TargetDataLayoutErrors::InvalidAlignment { cause, err })
+ .map_err(|err| TargetDataLayoutError::InvalidAlignment { cause, err })
};
let abi = parse_bits(s, "alignment", cause)?;
Ok(align_from_bits(abi)?)
@@ -388,7 +439,7 @@ pub fn parse_from_llvm_datalayout_string<'a>(
// ignoring the secondary alignment specifications.
let parse_align_seq = |s: &[&'a str], cause: &'a str| {
if s.is_empty() {
- return Err(TargetDataLayoutErrors::MissingAlignment { cause });
+ return Err(TargetDataLayoutError::MissingAlignment { cause });
}
parse_align_str(s[0], cause)
};
@@ -426,7 +477,7 @@ pub fn parse_from_llvm_datalayout_string<'a>(
// However, we currently don't take into account further specifications:
// an error is emitted instead.
if p.starts_with(char::is_alphabetic) {
- return Err(TargetDataLayoutErrors::UnknownPointerSpecification {
+ return Err(TargetDataLayoutError::UnknownPointerSpecification {
err: p.to_string(),
});
}
@@ -471,7 +522,7 @@ pub fn parse_from_llvm_datalayout_string<'a>(
// However, we currently don't take into account further specifications:
// an error is emitted instead.
if p.starts_with(char::is_alphabetic) {
- return Err(TargetDataLayoutErrors::UnknownPointerSpecification {
+ return Err(TargetDataLayoutError::UnknownPointerSpecification {
err: p.to_string(),
});
}
@@ -723,6 +774,14 @@ pub fn as_str(&self) -> &'static str {
Self::Big => "big",
}
}
+
+ #[cfg(feature = "nightly")]
+ pub fn desc_symbol(&self) -> Symbol {
+ match self {
+ Self::Little => sym::little,
+ Self::Big => sym::big,
+ }
+ }
}
impl fmt::Debug for Endian {
@@ -1718,6 +1777,24 @@ pub fn from_field_count(count: usize) -> Option {
}
}
+#[cfg(feature = "nightly")]
+impl IntoDiagArg for NumScalableVectors {
+ fn into_diag_arg(self, _: &mut Option) -> DiagArgValue {
+ DiagArgValue::Str(std::borrow::Cow::Borrowed(match self.0 {
+ 0 => panic!("`NumScalableVectors(0)` is illformed"),
+ 1 => "one",
+ 2 => "two",
+ 3 => "three",
+ 4 => "four",
+ 5 => "five",
+ 6 => "six",
+ 7 => "seven",
+ 8 => "eight",
+ _ => panic!("`NumScalableVectors(N)` for N>8 is illformed"),
+ }))
+ }
+}
+
/// The way we represent values to the backend
///
/// Previously this was conflated with the "ABI" a type is given, as in the platform-specific ABI.
diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs
index 97dd21db07e7..24ade7300c33 100644
--- a/compiler/rustc_arena/src/lib.rs
+++ b/compiler/rustc_arena/src/lib.rs
@@ -140,25 +140,19 @@ impl TypedArena {
/// Allocates an object in the `TypedArena`, returning a reference to it.
#[inline]
pub fn alloc(&self, object: T) -> &mut T {
+ assert!(size_of::() != 0);
+
if self.ptr == self.end {
self.grow(1)
}
unsafe {
- if size_of::() == 0 {
- self.ptr.set(self.ptr.get().wrapping_byte_add(1));
- let ptr = ptr::NonNull::::dangling().as_ptr();
- // Don't drop the object. This `write` is equivalent to `forget`.
- ptr::write(ptr, object);
- &mut *ptr
- } else {
- let ptr = self.ptr.get();
- // Advance the pointer.
- self.ptr.set(self.ptr.get().add(1));
- // Write into uninitialized memory.
- ptr::write(ptr, object);
- &mut *ptr
- }
+ let ptr = self.ptr.get();
+ // Advance the pointer.
+ self.ptr.set(self.ptr.get().add(1));
+ // Write into uninitialized memory.
+ ptr::write(ptr, object);
+ &mut *ptr
}
}
@@ -287,10 +281,9 @@ fn grow(&self, additional: usize) {
// Also ensure that this chunk can fit `additional`.
new_cap = cmp::max(additional, new_cap);
- let mut chunk = ArenaChunk::::new(new_cap);
+ let chunk = chunks.push_mut(ArenaChunk::::new(new_cap));
self.ptr.set(chunk.start());
self.end.set(chunk.end());
- chunks.push(chunk);
}
}
@@ -303,16 +296,10 @@ fn clear_last_chunk(&self, last_chunk: &mut ArenaChunk) {
let end = self.ptr.get().addr();
// We then calculate the number of elements to be dropped in the last chunk,
// which is the filled area's length.
- let diff = if size_of::() == 0 {
- // `T` is ZST. It can't have a drop flag, so the value here doesn't matter. We get
- // the number of zero-sized values in the last and only chunk, just out of caution.
- // Recall that `end` was incremented for each allocated value.
- end - start
- } else {
- // FIXME: this should *likely* use `offset_from`, but more
- // investigation is needed (including running tests in miri).
- (end - start) / size_of::()
- };
+ assert_ne!(size_of::(), 0);
+ // FIXME: this should *likely* use `offset_from`, but more
+ // investigation is needed (including running tests in miri).
+ let diff = (end - start) / size_of::();
// Pass that to the `destroy` method.
unsafe {
last_chunk.destroy(diff);
@@ -419,7 +406,7 @@ fn grow(&self, layout: Layout) {
// Also ensure that this chunk can fit `additional`.
new_cap = cmp::max(additional, new_cap);
- let mut chunk = ArenaChunk::new(align_up(new_cap, PAGE));
+ let chunk = chunks.push_mut(ArenaChunk::new(align_up(new_cap, PAGE)));
self.start.set(chunk.start());
// Align the end to DROPLESS_ALIGNMENT.
@@ -430,8 +417,6 @@ fn grow(&self, layout: Layout) {
debug_assert!(chunk.start().addr() <= end);
self.end.set(chunk.end().with_addr(end));
-
- chunks.push(chunk);
}
}
diff --git a/compiler/rustc_arena/src/tests.rs b/compiler/rustc_arena/src/tests.rs
index eb9406d691b1..751ddd80408a 100644
--- a/compiler/rustc_arena/src/tests.rs
+++ b/compiler/rustc_arena/src/tests.rs
@@ -22,7 +22,6 @@ fn clear(&mut self) {
if let Some(last_chunk) = chunks_borrow.last_mut() {
self.clear_last_chunk(last_chunk);
let len = chunks_borrow.len();
- // If `T` is ZST, code below has no effect.
for mut chunk in chunks_borrow.drain(..len - 1) {
chunk.destroy(chunk.entries);
}
@@ -117,18 +116,6 @@ fn test_noncopy() {
}
}
-#[test]
-fn test_typed_arena_zero_sized() {
- let arena = TypedArena::default();
- #[cfg(not(miri))]
- const N: usize = 100000;
- #[cfg(miri)]
- const N: usize = 1000;
- for _ in 0..N {
- arena.alloc(());
- }
-}
-
#[test]
fn test_typed_arena_clear() {
let mut arena = TypedArena::default();
@@ -207,7 +194,8 @@ fn test_typed_arena_drop_on_clear() {
static DROP_COUNTER: Cell = Cell::new(0)
}
-struct SmallDroppable;
+#[allow(unused)]
+struct SmallDroppable(u8);
impl Drop for SmallDroppable {
fn drop(&mut self) {
@@ -222,7 +210,7 @@ fn test_typed_arena_drop_small_count() {
let arena: TypedArena = TypedArena::default();
for _ in 0..100 {
// Allocate something with drop glue to make sure it doesn't leak.
- arena.alloc(SmallDroppable);
+ arena.alloc(SmallDroppable(0));
}
// dropping
};
diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml
index 471a6bf1df13..97256963118f 100644
--- a/compiler/rustc_ast/Cargo.toml
+++ b/compiler/rustc_ast/Cargo.toml
@@ -15,6 +15,6 @@ rustc_macros = { path = "../rustc_macros" }
rustc_serialize = { path = "../rustc_serialize" }
rustc_span = { path = "../rustc_span" }
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
-thin-vec = "0.2.12"
+thin-vec = "0.2.15"
tracing = "0.1"
# tidy-alphabetical-end
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index ae4989fcbc6c..b2c573c23f89 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -3901,12 +3901,17 @@ pub struct Delegation {
pub from_glob: bool,
}
+#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
+pub enum DelegationSuffixes {
+ List(ThinVec<(Ident, Option)>),
+ Glob(Span),
+}
+
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
pub struct DelegationMac {
pub qself: Option>,
pub prefix: Path,
- // Some for list delegation, and None for glob delegation.
- pub suffixes: Option)>>,
+ pub suffixes: DelegationSuffixes,
pub body: Option>,
}
@@ -3918,6 +3923,13 @@ pub struct StaticItem {
pub mutability: Mutability,
pub expr: Option>,
pub define_opaque: Option>,
+
+ /// This static is an implementation of an externally implementable item (EII).
+ /// This means, there was an EII declared somewhere and this static is the
+ /// implementation that should be used for the declaration.
+ ///
+ /// For statics, there may be at most one `EiiImpl`, but this is a `ThinVec` to make usages of this field nicer.
+ pub eii_impls: ThinVec,
}
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 6aa8d5f38ad2..ee4b1d135430 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -430,6 +430,7 @@ pub fn ctxt(&self) -> Option {
Defaultness,
Delegation,
DelegationMac,
+ DelegationSuffixes,
DelimArgs,
DelimSpan,
EnumDef,
diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml
index c00bac5d3c5a..42befe958633 100644
--- a/compiler/rustc_ast_lowering/Cargo.toml
+++ b/compiler/rustc_ast_lowering/Cargo.toml
@@ -23,6 +23,6 @@ rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" }
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
-thin-vec = "0.2.12"
+thin-vec = "0.2.15"
tracing = "0.1"
# tidy-alphabetical-end
diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs
index ee4a52fb3863..01382a69f2ec 100644
--- a/compiler/rustc_ast_lowering/src/delegation.rs
+++ b/compiler/rustc_ast_lowering/src/delegation.rs
@@ -46,9 +46,9 @@
use rustc_ast::*;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::ErrorGuaranteed;
-use rustc_hir as hir;
use rustc_hir::attrs::{AttributeKind, InlineAttr};
use rustc_hir::def_id::DefId;
+use rustc_hir::{self as hir, FnDeclFlags};
use rustc_middle::span_bug;
use rustc_middle::ty::Asyncness;
use rustc_span::symbol::kw;
@@ -271,7 +271,7 @@ fn get_resolution_id(&self, node_id: NodeId) -> Option {
// Function parameter count, including C variadic `...` if present.
fn param_count(&self, def_id: DefId) -> (usize, bool /*c_variadic*/) {
let sig = self.tcx.fn_sig(def_id).skip_binder().skip_binder();
- (sig.inputs().len() + usize::from(sig.c_variadic), sig.c_variadic)
+ (sig.inputs().len() + usize::from(sig.c_variadic()), sig.c_variadic())
}
fn lower_delegation_decl(
@@ -309,9 +309,9 @@ fn lower_delegation_decl(
self.arena.alloc(hir::FnDecl {
inputs,
output: hir::FnRetTy::Return(output),
- c_variadic,
- lifetime_elision_allowed: true,
- implicit_self: hir::ImplicitSelfKind::None,
+ fn_decl_kind: FnDeclFlags::default()
+ .set_lifetime_elision_allowed(true)
+ .set_c_variadic(c_variadic),
})
}
@@ -331,11 +331,11 @@ fn lower_delegation_sig(
safety: if self.tcx.codegen_fn_attrs(sig_id).safe_target_features {
hir::HeaderSafety::SafeTargetFeatures
} else {
- hir::HeaderSafety::Normal(sig.safety)
+ hir::HeaderSafety::Normal(sig.safety())
},
constness: self.tcx.constness(sig_id),
asyncness,
- abi: sig.abi,
+ abi: sig.abi(),
};
hir::FnSig { decl, header, span }
@@ -603,13 +603,7 @@ fn generate_delegation_error(
span: Span,
delegation: &Delegation,
) -> DelegationResults<'hir> {
- let decl = self.arena.alloc(hir::FnDecl {
- inputs: &[],
- output: hir::FnRetTy::DefaultReturn(span),
- c_variadic: false,
- lifetime_elision_allowed: true,
- implicit_self: hir::ImplicitSelfKind::None,
- });
+ let decl = self.arena.alloc(hir::FnDecl::dummy(span));
let header = self.generate_header_error();
let sig = hir::FnSig { decl, header, span };
diff --git a/compiler/rustc_ast_lowering/src/delegation/generics.rs b/compiler/rustc_ast_lowering/src/delegation/generics.rs
index 4e960e3b9290..01b17438bc7f 100644
--- a/compiler/rustc_ast_lowering/src/delegation/generics.rs
+++ b/compiler/rustc_ast_lowering/src/delegation/generics.rs
@@ -10,18 +10,38 @@
use crate::{LoweringContext, ResolverAstLoweringExt};
-pub(super) enum DelegationGenerics {
+#[derive(Clone, Copy)]
+pub(super) enum DelegationGenericsKind {
/// User-specified args are present: `reuse foo::;`.
UserSpecified,
/// The default case when no user-specified args are present: `reuse Trait::foo;`.
- Default(T),
+ Default,
/// In free-to-trait reuse, when user specified args for trait `reuse Trait::::foo;`
/// in this case we need to both generate `Self` and process user args.
- SelfAndUserSpecified(T),
+ SelfAndUserSpecified,
/// In delegations from trait impl to other entities like free functions or trait functions,
/// we want to generate a function whose generics matches generics of signature function
/// in trait.
- TraitImpl(T, bool /* Has user-specified args */),
+ TraitImpl(bool /* Has user-specified args */),
+}
+
+pub(super) struct DelegationGenerics {
+ generics: T,
+ kind: DelegationGenericsKind,
+}
+
+impl<'hir> DelegationGenerics<&'hir [ty::GenericParamDef]> {
+ fn default(generics: &'hir [ty::GenericParamDef]) -> Self {
+ DelegationGenerics { generics, kind: DelegationGenericsKind::Default }
+ }
+
+ fn user_specified(generics: &'hir [ty::GenericParamDef]) -> Self {
+ DelegationGenerics { generics, kind: DelegationGenericsKind::UserSpecified }
+ }
+
+ fn trait_impl(generics: &'hir [ty::GenericParamDef], user_specified: bool) -> Self {
+ DelegationGenerics { generics, kind: DelegationGenericsKind::TraitImpl(user_specified) }
+ }
}
/// Used for storing either ty generics or their uplifted HIR version. First we obtain
@@ -54,20 +74,19 @@ pub(super) struct GenericArgsPropagationDetails {
pub(super) use_args_in_sig_inheritance: bool,
}
-impl DelegationGenerics {
- fn args_propagation_details(&self) -> GenericArgsPropagationDetails {
+impl DelegationGenericsKind {
+ fn args_propagation_details(self) -> GenericArgsPropagationDetails {
match self {
- DelegationGenerics::UserSpecified | DelegationGenerics::SelfAndUserSpecified { .. } => {
- GenericArgsPropagationDetails {
- should_propagate: false,
- use_args_in_sig_inheritance: true,
- }
- }
- DelegationGenerics::TraitImpl(_, user_specified) => GenericArgsPropagationDetails {
- should_propagate: !*user_specified,
+ DelegationGenericsKind::UserSpecified
+ | DelegationGenericsKind::SelfAndUserSpecified => GenericArgsPropagationDetails {
+ should_propagate: false,
+ use_args_in_sig_inheritance: true,
+ },
+ DelegationGenericsKind::TraitImpl(user_specified) => GenericArgsPropagationDetails {
+ should_propagate: !user_specified,
use_args_in_sig_inheritance: false,
},
- DelegationGenerics::Default(_) => GenericArgsPropagationDetails {
+ DelegationGenericsKind::Default => GenericArgsPropagationDetails {
should_propagate: true,
use_args_in_sig_inheritance: false,
},
@@ -81,25 +100,9 @@ pub(super) fn into_hir_generics(
ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
span: Span,
) -> &mut HirOrTyGenerics<'hir> {
- if let HirOrTyGenerics::Ty(params) = self {
- let mut uplift_params = |generics: &'hir [ty::GenericParamDef]| {
- ctx.uplift_delegation_generic_params(span, generics)
- };
-
- let hir_generics = match params {
- DelegationGenerics::UserSpecified => DelegationGenerics::UserSpecified,
- DelegationGenerics::Default(params) => {
- DelegationGenerics::Default(uplift_params(params))
- }
- DelegationGenerics::SelfAndUserSpecified(params) => {
- DelegationGenerics::SelfAndUserSpecified(uplift_params(params))
- }
- DelegationGenerics::TraitImpl(params, user_specified) => {
- DelegationGenerics::TraitImpl(uplift_params(params), *user_specified)
- }
- };
-
- *self = HirOrTyGenerics::Hir(hir_generics);
+ if let HirOrTyGenerics::Ty(ty) = self {
+ let params = ctx.uplift_delegation_generic_params(span, ty.generics);
+ *self = HirOrTyGenerics::Hir(DelegationGenerics { generics: params, kind: ty.kind });
}
self
@@ -108,12 +111,7 @@ pub(super) fn into_hir_generics(
fn hir_generics_or_empty(&self) -> &'hir hir::Generics<'hir> {
match self {
HirOrTyGenerics::Ty(_) => hir::Generics::empty(),
- HirOrTyGenerics::Hir(hir_generics) => match hir_generics {
- DelegationGenerics::UserSpecified => hir::Generics::empty(),
- DelegationGenerics::Default(generics)
- | DelegationGenerics::SelfAndUserSpecified(generics)
- | DelegationGenerics::TraitImpl(generics, _) => generics,
- },
+ HirOrTyGenerics::Hir(hir) => hir.generics,
}
}
@@ -127,21 +125,16 @@ pub(super) fn into_generic_args(
HirOrTyGenerics::Ty(_) => {
bug!("Attempting to get generic args before uplifting to HIR")
}
- HirOrTyGenerics::Hir(hir_generics) => match hir_generics {
- DelegationGenerics::UserSpecified => hir::GenericArgs::NONE,
- DelegationGenerics::Default(generics)
- | DelegationGenerics::SelfAndUserSpecified(generics)
- | DelegationGenerics::TraitImpl(generics, _) => {
- ctx.create_generics_args_from_params(generics.params, add_lifetimes, span)
- }
- },
+ HirOrTyGenerics::Hir(hir) => {
+ ctx.create_generics_args_from_params(hir.generics.params, add_lifetimes, span)
+ }
}
}
pub(super) fn args_propagation_details(&self) -> GenericArgsPropagationDetails {
match self {
- HirOrTyGenerics::Ty(ty_generics) => ty_generics.args_propagation_details(),
- HirOrTyGenerics::Hir(hir_generics) => hir_generics.args_propagation_details(),
+ HirOrTyGenerics::Ty(ty) => ty.kind.args_propagation_details(),
+ HirOrTyGenerics::Hir(hir) => hir.kind.args_propagation_details(),
}
}
}
@@ -231,9 +224,10 @@ pub(super) fn uplift_delegation_generics(
if matches!(delegation_parent_kind, DefKind::Impl { of_trait: true }) {
// Considering parent generics, during signature inheritance
// we will take those args that are in trait impl header trait ref.
- let parent = GenericsGenerationResult::new(DelegationGenerics::TraitImpl(&[], true));
+ let parent = DelegationGenerics::trait_impl(&[], true);
+ let parent = GenericsGenerationResult::new(parent);
- let child = DelegationGenerics::TraitImpl(sig_params, child_user_specified);
+ let child = DelegationGenerics::trait_impl(sig_params, child_user_specified);
let child = GenericsGenerationResult::new(child);
return GenericsGenerationResults { parent, child };
@@ -257,22 +251,28 @@ pub(super) fn uplift_delegation_generics(
if segments[len - 2].args.is_some() {
if generate_self {
// Take only first Self parameter, it is trait so Self must be present.
- DelegationGenerics::SelfAndUserSpecified(&sig_parent_params[..1])
+ DelegationGenerics {
+ kind: DelegationGenericsKind::SelfAndUserSpecified,
+ generics: &sig_parent_params[..1],
+ }
} else {
- DelegationGenerics::UserSpecified
+ DelegationGenerics::user_specified(&[])
}
} else {
let skip_self = usize::from(!generate_self);
- DelegationGenerics::Default(&sig_parent_params[skip_self..])
+ DelegationGenerics::default(&sig_parent_params[skip_self..])
}
} else {
- DelegationGenerics::<&'hir [ty::GenericParamDef]>::Default(&[])
+ DelegationGenerics::default(&[])
};
let child_generics = if child_user_specified {
- DelegationGenerics::UserSpecified
+ let synth_params_index =
+ sig_params.iter().position(|p| p.kind.is_synthetic()).unwrap_or(sig_params.len());
+
+ DelegationGenerics::user_specified(&sig_params[synth_params_index..])
} else {
- DelegationGenerics::Default(sig_params)
+ DelegationGenerics::default(sig_params)
};
GenericsGenerationResults {
@@ -295,10 +295,9 @@ fn uplift_delegation_generic_params(
let param_ident = Ident::new(p.name, span);
let def_name = Some(param_ident.name);
- let path_data = def_kind.def_path_data(def_name);
let node_id = self.next_node_id();
- let def_id = self.create_def(node_id, def_name, def_kind, path_data, span);
+ let def_id = self.create_def(node_id, def_name, def_kind, span);
let kind = match p.kind {
GenericParamDefKind::Lifetime => {
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index b6bc122051cb..aad838e9a172 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -8,7 +8,6 @@
use rustc_errors::msg;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
-use rustc_hir::definitions::DefPathData;
use rustc_hir::{HirId, Target, find_attr};
use rustc_middle::span_bug;
use rustc_middle::ty::TyCtxt;
@@ -29,7 +28,7 @@
use crate::errors::{InvalidLegacyConstGenericArg, UseConstGenericArg, YieldInClosure};
use crate::{AllowReturnTypeNotation, FnDeclKind, ImplTraitPosition, TryBlockScope};
-struct WillCreateDefIdsVisitor {}
+pub(super) struct WillCreateDefIdsVisitor;
impl<'v> rustc_ast::visit::Visitor<'v> for WillCreateDefIdsVisitor {
type Result = ControlFlow;
@@ -472,25 +471,19 @@ fn lower_legacy_const_generics(
for (idx, arg) in args.iter().cloned().enumerate() {
if legacy_args_idx.contains(&idx) {
let node_id = self.next_node_id();
- self.create_def(
- node_id,
- None,
- DefKind::AnonConst,
- DefPathData::LateAnonConst,
- f.span,
- );
- let mut visitor = WillCreateDefIdsVisitor {};
- let const_value = if let ControlFlow::Break(span) = visitor.visit_expr(&arg) {
- Box::new(Expr {
- id: self.next_node_id(),
- kind: ExprKind::Err(invalid_expr_error(self.tcx, span)),
- span: f.span,
- attrs: [].into(),
- tokens: None,
- })
- } else {
- arg
- };
+ self.create_def(node_id, None, DefKind::AnonConst, f.span);
+ let const_value =
+ if let ControlFlow::Break(span) = WillCreateDefIdsVisitor.visit_expr(&arg) {
+ Box::new(Expr {
+ id: self.next_node_id(),
+ kind: ExprKind::Err(invalid_expr_error(self.tcx, span)),
+ span: f.span,
+ attrs: [].into(),
+ tokens: None,
+ })
+ } else {
+ arg
+ };
let anon_const = AnonConst {
id: node_id,
@@ -762,9 +755,7 @@ pub(super) fn make_desugared_coroutine_expr(
let fn_decl = self.arena.alloc(hir::FnDecl {
inputs,
output,
- c_variadic: false,
- implicit_self: hir::ImplicitSelfKind::None,
- lifetime_elision_allowed: false,
+ fn_decl_kind: hir::FnDeclFlags::default(),
});
let body = self.lower_body(move |this| {
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 1c80c56f2693..239daecd3d1f 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -24,8 +24,8 @@
use super::errors::{InvalidAbi, InvalidAbiSuggestion, TupleStructWithDefault, UnionWithDefault};
use super::stability::{enabled_names, gate_unstable_abi};
use super::{
- AstOwner, FnDeclKind, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode,
- RelaxedBoundForbiddenReason, RelaxedBoundPolicy, ResolverAstLoweringExt,
+ AstOwner, FnDeclKind, GenericArgsMode, ImplTraitContext, ImplTraitPosition, LoweringContext,
+ ParamMode, RelaxedBoundForbiddenReason, RelaxedBoundPolicy, ResolverAstLoweringExt,
};
/// Wraps either IndexVec (during `hir_crate`), which acts like a primary
@@ -213,8 +213,14 @@ fn generate_extra_attrs_for_item_kind(
i: &ItemKind,
) -> Vec {
match i {
- ItemKind::Fn(box Fn { eii_impls, .. }) if eii_impls.is_empty() => Vec::new(),
- ItemKind::Fn(box Fn { eii_impls, .. }) => {
+ ItemKind::Fn(box Fn { eii_impls, .. })
+ | ItemKind::Static(box StaticItem { eii_impls, .. })
+ if eii_impls.is_empty() =>
+ {
+ Vec::new()
+ }
+ ItemKind::Fn(box Fn { eii_impls, .. })
+ | ItemKind::Static(box StaticItem { eii_impls, .. }) => {
vec![hir::Attribute::Parsed(AttributeKind::EiiImpls(
eii_impls.iter().map(|i| self.lower_eii_impl(i)).collect(),
))]
@@ -226,7 +232,6 @@ fn generate_extra_attrs_for_item_kind(
ItemKind::ExternCrate(..)
| ItemKind::Use(..)
- | ItemKind::Static(..)
| ItemKind::Const(..)
| ItemKind::ConstBlock(..)
| ItemKind::Mod(..)
@@ -302,6 +307,7 @@ fn lower_item_kind(
mutability: m,
expr: e,
define_opaque,
+ eii_impls: _,
}) => {
let ident = self.lower_ident(*ident);
let ty = self
@@ -540,14 +546,14 @@ fn lower_item_kind(
constness,
is_auto,
safety,
- // FIXME(impl_restrictions): lower to HIR
- impl_restriction: _,
+ impl_restriction,
ident,
generics,
bounds,
items,
}) => {
let constness = self.lower_constness(*constness);
+ let impl_restriction = self.lower_impl_restriction(impl_restriction);
let ident = self.lower_ident(*ident);
let (generics, (safety, items, bounds)) = self.lower_generics(
generics,
@@ -566,7 +572,16 @@ fn lower_item_kind(
(safety, items, bounds)
},
);
- hir::ItemKind::Trait(constness, *is_auto, safety, ident, generics, bounds, items)
+ hir::ItemKind::Trait(
+ constness,
+ *is_auto,
+ safety,
+ impl_restriction,
+ ident,
+ generics,
+ bounds,
+ items,
+ )
}
ItemKind::TraitAlias(box TraitAlias { constness, ident, generics, bounds }) => {
let constness = self.lower_constness(*constness);
@@ -817,6 +832,7 @@ fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir
expr: _,
safety,
define_opaque,
+ eii_impls: _,
}) => {
let ty = self
.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy));
@@ -1831,6 +1847,38 @@ pub(super) fn lower_safety(&self, s: Safety, default: hir::Safety) -> hir::Safet
}
}
+ pub(super) fn lower_impl_restriction(
+ &mut self,
+ r: &ImplRestriction,
+ ) -> &'hir hir::ImplRestriction<'hir> {
+ let kind = match &r.kind {
+ RestrictionKind::Unrestricted => hir::RestrictionKind::Unrestricted,
+ RestrictionKind::Restricted { path, id, shorthand: _ } => {
+ let res = self.resolver.get_partial_res(*id);
+ if let Some(did) = res.and_then(|res| res.expect_full_res().opt_def_id()) {
+ hir::RestrictionKind::Restricted(self.arena.alloc(hir::Path {
+ res: did,
+ segments: self.arena.alloc_from_iter(path.segments.iter().map(|segment| {
+ self.lower_path_segment(
+ path.span,
+ segment,
+ ParamMode::Explicit,
+ GenericArgsMode::Err,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ None,
+ )
+ })),
+ span: self.lower_span(path.span),
+ }))
+ } else {
+ self.dcx().span_delayed_bug(path.span, "should have errored in resolve");
+ hir::RestrictionKind::Unrestricted
+ }
+ }
+ };
+ self.arena.alloc(hir::ImplRestriction { kind, span: self.lower_span(r.span) })
+ }
+
/// Return the pair of the lowered `generics` as `hir::Generics` and the evaluation of `f` with
/// the carried impl trait definitions and bounds.
#[instrument(level = "debug", skip(self, f))]
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 0561490344d2..2ffb9c123b5f 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -39,8 +39,9 @@
use std::sync::Arc;
use rustc_ast::node_id::NodeMap;
+use rustc_ast::visit::Visitor;
use rustc_ast::{self as ast, *};
-use rustc_attr_parsing::{AttributeParser, Late, OmitDoc};
+use rustc_attr_parsing::{AttributeParser, EmitAttribute, Late, OmitDoc};
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::sorted_map::SortedMap;
@@ -50,8 +51,8 @@
use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle};
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId};
-use rustc_hir::definitions::{DefPathData, DisambiguatorState};
-use rustc_hir::lints::{AttributeLint, DelayedLint};
+use rustc_hir::definitions::PerParentDisambiguatorState;
+use rustc_hir::lints::{AttributeLint, DelayedLint, DynAttribute};
use rustc_hir::{
self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LifetimeSource,
LifetimeSyntax, ParamName, Target, TraitCandidate, find_attr,
@@ -93,7 +94,7 @@ macro_rules! arena_vec {
struct LoweringContext<'a, 'hir, R> {
tcx: TyCtxt<'hir>,
resolver: &'a mut R,
- disambiguator: DisambiguatorState,
+ disambiguator: PerParentDisambiguatorState,
/// Used to allocate HIR nodes.
arena: &'hir hir::Arena<'hir>,
@@ -154,11 +155,11 @@ struct LoweringContext<'a, 'hir, R> {
impl<'a, 'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'a, 'hir, R> {
fn new(tcx: TyCtxt<'hir>, resolver: &'a mut R) -> Self {
- let registered_tools = tcx.registered_tools(());
+ let registered_tools = tcx.registered_tools(()).iter().map(|x| x.name).collect();
Self {
tcx,
resolver,
- disambiguator: DisambiguatorState::new(),
+ disambiguator: Default::default(),
arena: tcx.hir_arena,
// HirId handling.
@@ -301,6 +302,10 @@ fn trait_candidates(&self, node_id: NodeId) -> Option<&'tcx [hir::TraitCandidate
fn next_node_id(&mut self) -> NodeId {
next_node_id(&mut self.next_node_id)
}
+
+ fn steal_or_create_disambiguator(&self, parent: LocalDefId) -> PerParentDisambiguatorState {
+ self.base.steal_or_create_disambiguator(parent)
+ }
}
fn next_node_id(current_id: &mut NodeId) -> NodeId {
@@ -403,6 +408,10 @@ fn trait_candidates(&self, node_id: NodeId) -> Option<&'tcx [hir::TraitCandidate
fn next_node_id(&mut self) -> NodeId {
next_node_id(&mut self.next_node_id)
}
+
+ fn steal_or_create_disambiguator(&self, parent: LocalDefId) -> PerParentDisambiguatorState {
+ self.per_parent_disambiguators.get(&parent).map(|s| s.steal()).unwrap_or_default()
+ }
}
/// How relaxed bounds `?Trait` should be treated.
@@ -716,7 +725,6 @@ fn create_def(
node_id: ast::NodeId,
name: Option,
def_kind: DefKind,
- def_path_data: DefPathData,
span: Span,
) -> LocalDefId {
let parent = self.current_hir_id_owner.def_id;
@@ -732,7 +740,7 @@ fn create_def(
let def_id = self
.tcx
.at(span)
- .create_def(parent, name, def_kind, Some(def_path_data), &mut self.disambiguator)
+ .create_def(parent, name, def_kind, None, &mut self.disambiguator)
.def_id();
debug!("create_def: def_id_to_node_id[{:?}] <-> {:?}", def_id, node_id);
@@ -773,6 +781,8 @@ fn with_hir_id_owner(
) {
let owner_id = self.owner_id(owner);
+ let new_disambig = self.resolver.steal_or_create_disambiguator(owner_id.def_id);
+ let disambiguator = std::mem::replace(&mut self.disambiguator, new_disambig);
let current_attrs = std::mem::take(&mut self.attrs);
let current_bodies = std::mem::take(&mut self.bodies);
let current_define_opaque = std::mem::take(&mut self.define_opaque);
@@ -807,6 +817,7 @@ fn with_hir_id_owner(
assert!(self.impl_trait_bounds.is_empty());
let info = self.make_owner_info(item);
+ self.disambiguator = disambiguator;
self.attrs = current_attrs;
self.bodies = current_bodies;
self.define_opaque = current_define_opaque;
@@ -846,14 +857,12 @@ fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> &'hir hir::OwnerInf
let bodies = SortedMap::from_presorted_elements(bodies);
// Don't hash unless necessary, because it's expensive.
- let rustc_middle::hir::Hashes { opt_hash_including_bodies, attrs_hash, delayed_lints_hash } =
- self.tcx.hash_owner_nodes(node, &bodies, &attrs, &delayed_lints, define_opaque);
+ let rustc_middle::hir::Hashes { opt_hash_including_bodies, attrs_hash } =
+ self.tcx.hash_owner_nodes(node, &bodies, &attrs, define_opaque);
let num_nodes = self.item_local_id_counter.as_usize();
let (nodes, parenting) = index::index_hir(self.tcx, node, &bodies, num_nodes);
let nodes = hir::OwnerNodes { opt_hash_including_bodies, nodes, bodies };
let attrs = hir::AttributeMap { map: attrs, opt_hash: attrs_hash, define_opaque };
- let delayed_lints =
- hir::lints::DelayedLints { lints: delayed_lints, opt_hash: delayed_lints_hash };
self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map, delayed_lints })
}
@@ -1014,7 +1023,6 @@ fn lifetime_res_to_generic_param(
param,
Some(kw::UnderscoreLifetime),
DefKind::LifetimeParam,
- DefPathData::DesugaredAnonymousLifetime,
ident.span,
);
debug!(?_def_id);
@@ -1166,13 +1174,23 @@ fn lower_attrs_vec(
target,
OmitDoc::Lower,
|s| l.lower(s),
- |lint_id, span, kind| {
- self.delayed_lints.push(DelayedLint::AttributeParsing(AttributeLint {
- lint_id,
- id: target_hir_id,
- span,
- kind,
- }));
+ |lint_id, span, kind| match kind {
+ EmitAttribute::Static(attr_kind) => {
+ self.delayed_lints.push(DelayedLint::AttributeParsing(AttributeLint {
+ lint_id,
+ id: target_hir_id,
+ span,
+ kind: attr_kind,
+ }));
+ }
+ EmitAttribute::Dynamic(callback) => {
+ self.delayed_lints.push(DelayedLint::Dynamic(DynAttribute {
+ lint_id,
+ id: target_hir_id,
+ span,
+ callback,
+ }));
+ }
},
)
}
@@ -1831,7 +1849,7 @@ fn lower_fn_decl(
// as they are not explicit in HIR/Ty function signatures.
// (instead, the `c_variadic` flag is set to `true`)
let mut inputs = &decl.inputs[..];
- if c_variadic {
+ if decl.c_variadic() {
inputs = &inputs[..inputs.len() - 1];
}
let inputs = self.arena.alloc_from_iter(inputs.iter().map(|param| {
@@ -1894,12 +1912,8 @@ fn lower_fn_decl(
},
};
- self.arena.alloc(hir::FnDecl {
- inputs,
- output,
- c_variadic,
- lifetime_elision_allowed: self.resolver.lifetime_elision_allowed(fn_node_id),
- implicit_self: decl.inputs.get(0).map_or(hir::ImplicitSelfKind::None, |arg| {
+ let fn_decl_kind = hir::FnDeclFlags::default()
+ .set_implicit_self(decl.inputs.get(0).map_or(hir::ImplicitSelfKind::None, |arg| {
let is_mutable_pat = matches!(
arg.pat.kind,
PatKind::Ident(hir::BindingMode(_, Mutability::Mut), ..)
@@ -1921,8 +1935,11 @@ fn lower_fn_decl(
}
_ => hir::ImplicitSelfKind::None,
}
- }),
- })
+ }))
+ .set_lifetime_elision_allowed(self.resolver.lifetime_elision_allowed(fn_node_id))
+ .set_c_variadic(c_variadic);
+
+ self.arena.alloc(hir::FnDecl { inputs, output, fn_decl_kind })
}
// Transforms `-> T` for `async fn` into `-> OpaqueTy { .. }`
@@ -2219,14 +2236,22 @@ fn lower_generic_param_kind(
// since later compiler stages cannot handle them (and shouldn't need to be able to).
let default = default
.as_ref()
- .filter(|_| match source {
+ .filter(|anon_const| match source {
hir::GenericParamSource::Generics => true,
hir::GenericParamSource::Binder => {
- self.dcx().emit_err(errors::GenericParamDefaultInBinder {
- span: param.span(),
- });
-
- false
+ let err = errors::GenericParamDefaultInBinder { span: param.span() };
+ if expr::WillCreateDefIdsVisitor
+ .visit_expr(&anon_const.value)
+ .is_break()
+ {
+ // FIXME(mgca): make this non-fatal once we have a better way
+ // to handle nested items in anno const from binder
+ // Issue: https://github.com/rust-lang/rust/issues/123629
+ self.dcx().emit_fatal(err)
+ } else {
+ self.dcx().emit_err(err);
+ false
+ }
}
})
.map(|def| self.lower_anon_const_to_const_arg_and_alloc(def));
@@ -2495,13 +2520,7 @@ fn lower_const_path_to_const_arg(
// We're lowering a const argument that was originally thought to be a type argument,
// so the def collector didn't create the def ahead of time. That's why we have to do
// it here.
- let def_id = self.create_def(
- node_id,
- None,
- DefKind::AnonConst,
- DefPathData::LateAnonConst,
- span,
- );
+ let def_id = self.create_def(node_id, None, DefKind::AnonConst, span);
let hir_id = self.lower_node_id(node_id);
let path_expr = Expr {
@@ -2563,12 +2582,17 @@ fn lower_expr_to_const_arg_direct(&mut self, expr: &Expr) -> hir::ConstArg<'hir>
let span = self.lower_span(expr.span);
let overly_complex_const = |this: &mut Self| {
- let e = this.dcx().struct_span_err(
- expr.span,
- "complex const arguments must be placed inside of a `const` block",
- );
+ let msg = "complex const arguments must be placed inside of a `const` block";
+ let e = if expr::WillCreateDefIdsVisitor.visit_expr(expr).is_break() {
+ // FIXME(mgca): make this non-fatal once we have a better way to handle
+ // nested items in const args
+ // Issue: https://github.com/rust-lang/rust/issues/154539
+ this.dcx().struct_span_fatal(expr.span, msg).emit()
+ } else {
+ this.dcx().struct_span_err(expr.span, msg).emit()
+ };
- ConstArg { hir_id: this.next_id(), kind: hir::ConstArgKind::Error(e.emit()), span }
+ ConstArg { hir_id: this.next_id(), kind: hir::ConstArgKind::Error(e), span }
};
match &expr.kind {
diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs
index 40d42ffb5f4f..88f038f11d3c 100644
--- a/compiler/rustc_ast_lowering/src/pat.rs
+++ b/compiler/rustc_ast_lowering/src/pat.rs
@@ -3,7 +3,6 @@
use rustc_ast::*;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir::def::{DefKind, Res};
-use rustc_hir::definitions::DefPathData;
use rustc_hir::{self as hir, LangItem, Target};
use rustc_middle::span_bug;
use rustc_span::{DesugaringKind, Ident, Span, Spanned, respan};
@@ -421,7 +420,11 @@ fn lower_expr_within_pat(
}
_ => {
let is_const_block = matches!(expr.kind, ExprKind::ConstBlock(_));
- let pattern_from_macro = expr.is_approximately_pattern();
+ let pattern_from_macro = expr.is_approximately_pattern()
+ || matches!(
+ expr.peel_parens().kind,
+ ExprKind::Binary(Spanned { node: BinOpKind::BitOr, .. }, ..)
+ );
let guar = self.dcx().emit_err(ArbitraryExpressionInPattern {
span,
pattern_from_macro_note: pattern_from_macro,
@@ -534,8 +537,7 @@ fn lower_ty_pat_range_end(
// We're generating a range end that didn't exist in the AST,
// so the def collector didn't create the def ahead of time. That's why we have to do
// it here.
- let def_id =
- self.create_def(node_id, None, DefKind::AnonConst, DefPathData::LateAnonConst, span);
+ let def_id = self.create_def(node_id, None, DefKind::AnonConst, span);
let hir_id = self.lower_node_id(node_id);
let unstable_span = self.mark_span_with_reason(
diff --git a/compiler/rustc_ast_passes/Cargo.toml b/compiler/rustc_ast_passes/Cargo.toml
index c9def6246d1b..42cbd7b3d362 100644
--- a/compiler/rustc_ast_passes/Cargo.toml
+++ b/compiler/rustc_ast_passes/Cargo.toml
@@ -18,5 +18,5 @@ rustc_macros = { path = "../rustc_macros" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" }
-thin-vec = "0.2.12"
+thin-vec = "0.2.15"
# tidy-alphabetical-end
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 1b615b611258..5831636a81b2 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -7,7 +7,7 @@
use rustc_hir::attrs::AttributeKind;
use rustc_session::Session;
use rustc_session::parse::{feature_err, feature_warn};
-use rustc_span::{DUMMY_SP, Span, Spanned, Symbol, sym};
+use rustc_span::{Span, Spanned, Symbol, sym};
use thin_vec::ThinVec;
use crate::errors;
@@ -646,14 +646,7 @@ fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate)
let mut errored = false;
if let Some(Attribute::Parsed(AttributeKind::Feature(feature_idents, first_span))) =
- AttributeParser::parse_limited(
- sess,
- &krate.attrs,
- sym::feature,
- DUMMY_SP,
- krate.id,
- Some(&features),
- )
+ AttributeParser::parse_limited(sess, &krate.attrs, &[sym::feature])
{
// `feature(...)` used on non-nightly. This is definitely an error.
let mut err = errors::FeatureOnNonNightly {
diff --git a/compiler/rustc_ast_pretty/Cargo.toml b/compiler/rustc_ast_pretty/Cargo.toml
index b704040be961..957fc1297c58 100644
--- a/compiler/rustc_ast_pretty/Cargo.toml
+++ b/compiler/rustc_ast_pretty/Cargo.toml
@@ -13,5 +13,5 @@ rustc_span = { path = "../rustc_span" }
[dev-dependencies]
# tidy-alphabetical-start
-thin-vec = "0.2.12"
+thin-vec = "0.2.15"
# tidy-alphabetical-end
diff --git a/compiler/rustc_ast_pretty/src/helpers.rs b/compiler/rustc_ast_pretty/src/helpers.rs
deleted file mode 100644
index 34641ea2f5ae..000000000000
--- a/compiler/rustc_ast_pretty/src/helpers.rs
+++ /dev/null
@@ -1,49 +0,0 @@
-use std::borrow::Cow;
-
-use crate::pp::Printer;
-
-impl Printer {
- pub fn word_space>>(&mut self, w: W) {
- self.word(w);
- self.space();
- }
-
- pub fn popen(&mut self) {
- self.word("(");
- }
-
- pub fn pclose(&mut self) {
- self.word(")");
- }
-
- pub fn hardbreak_if_not_bol(&mut self) {
- if !self.is_beginning_of_line() {
- self.hardbreak()
- }
- }
-
- pub fn space_if_not_bol(&mut self) {
- if !self.is_beginning_of_line() {
- self.space();
- }
- }
-
- pub fn nbsp(&mut self) {
- self.word(" ")
- }
-
- pub fn word_nbsp>>(&mut self, w: S) {
- self.word(w);
- self.nbsp()
- }
-
- /// Synthesizes a comment that was not textually present in the original
- /// source file.
- pub fn synth_comment(&mut self, text: impl Into>) {
- self.word("/*");
- self.space();
- self.word(text);
- self.space();
- self.word("*/")
- }
-}
diff --git a/compiler/rustc_ast_pretty/src/lib.rs b/compiler/rustc_ast_pretty/src/lib.rs
index a7d9f89fb3df..bfc1d387b700 100644
--- a/compiler/rustc_ast_pretty/src/lib.rs
+++ b/compiler/rustc_ast_pretty/src/lib.rs
@@ -3,6 +3,5 @@
#![feature(negative_impls)]
// tidy-alphabetical-end
-mod helpers;
pub mod pp;
pub mod pprust;
diff --git a/compiler/rustc_ast_pretty/src/pp.rs b/compiler/rustc_ast_pretty/src/pp.rs
index 4108671a3629..c7a38d981b89 100644
--- a/compiler/rustc_ast_pretty/src/pp.rs
+++ b/compiler/rustc_ast_pretty/src/pp.rs
@@ -132,7 +132,6 @@
//! methods called `Printer::scan_*`, and the 'PRINT' process is the
//! method called `Printer::print`.
-mod convenience;
mod ring;
use std::borrow::Cow;
@@ -188,6 +187,12 @@ pub(crate) enum Token {
End,
}
+impl Token {
+ pub(crate) fn is_hardbreak_tok(&self) -> bool {
+ *self == Printer::hardbreak_tok_offset(0)
+ }
+}
+
#[derive(Copy, Clone)]
enum PrintFrame {
Fits,
@@ -479,4 +484,132 @@ fn print_string(&mut self, string: &str) {
self.out.push_str(string);
self.space -= string.len() as isize;
}
+
+ /// Synthesizes a comment that was not textually present in the original
+ /// source file.
+ pub fn synth_comment(&mut self, text: impl Into>) {
+ self.word("/*");
+ self.space();
+ self.word(text);
+ self.space();
+ self.word("*/")
+ }
+
+ /// "raw box"
+ pub fn rbox(&mut self, indent: isize, breaks: Breaks) -> BoxMarker {
+ self.scan_begin(BeginToken { indent: IndentStyle::Block { offset: indent }, breaks })
+ }
+
+ /// Inconsistent breaking box
+ pub fn ibox(&mut self, indent: isize) -> BoxMarker {
+ self.rbox(indent, Breaks::Inconsistent)
+ }
+
+ /// Consistent breaking box
+ pub fn cbox(&mut self, indent: isize) -> BoxMarker {
+ self.rbox(indent, Breaks::Consistent)
+ }
+
+ pub fn visual_align(&mut self) -> BoxMarker {
+ self.scan_begin(BeginToken { indent: IndentStyle::Visual, breaks: Breaks::Consistent })
+ }
+
+ pub fn break_offset(&mut self, n: usize, off: isize) {
+ self.scan_break(BreakToken {
+ offset: off,
+ blank_space: n as isize,
+ ..BreakToken::default()
+ });
+ }
+
+ pub fn end(&mut self, b: BoxMarker) {
+ self.scan_end(b)
+ }
+
+ pub fn eof(mut self) -> String {
+ self.scan_eof();
+ self.out
+ }
+
+ pub fn word>>(&mut self, wrd: S) {
+ let string = wrd.into();
+ self.scan_string(string)
+ }
+
+ pub fn word_space>>(&mut self, w: W) {
+ self.word(w);
+ self.space();
+ }
+
+ pub fn nbsp(&mut self) {
+ self.word(" ")
+ }
+
+ pub fn word_nbsp>>(&mut self, w: S) {
+ self.word(w);
+ self.nbsp()
+ }
+
+ fn spaces(&mut self, n: usize) {
+ self.break_offset(n, 0)
+ }
+
+ pub fn zerobreak(&mut self) {
+ self.spaces(0)
+ }
+
+ pub fn space(&mut self) {
+ self.spaces(1)
+ }
+
+ pub fn popen(&mut self) {
+ self.word("(");
+ }
+
+ pub fn pclose(&mut self) {
+ self.word(")");
+ }
+
+ pub fn hardbreak(&mut self) {
+ self.spaces(SIZE_INFINITY as usize)
+ }
+
+ pub fn is_beginning_of_line(&self) -> bool {
+ match self.last_token() {
+ Some(last_token) => last_token.is_hardbreak_tok(),
+ None => true,
+ }
+ }
+
+ pub fn hardbreak_if_not_bol(&mut self) {
+ if !self.is_beginning_of_line() {
+ self.hardbreak()
+ }
+ }
+
+ pub fn space_if_not_bol(&mut self) {
+ if !self.is_beginning_of_line() {
+ self.space();
+ }
+ }
+
+ pub(crate) fn hardbreak_tok_offset(off: isize) -> Token {
+ Token::Break(BreakToken {
+ offset: off,
+ blank_space: SIZE_INFINITY,
+ ..BreakToken::default()
+ })
+ }
+
+ pub fn trailing_comma(&mut self) {
+ self.scan_break(BreakToken { pre_break: Some(','), ..BreakToken::default() });
+ }
+
+ pub fn trailing_comma_or_space(&mut self) {
+ self.scan_break(BreakToken {
+ blank_space: 1,
+ pre_break: Some(','),
+ ..BreakToken::default()
+ });
+ }
}
diff --git a/compiler/rustc_ast_pretty/src/pp/convenience.rs b/compiler/rustc_ast_pretty/src/pp/convenience.rs
deleted file mode 100644
index 9b902b38122c..000000000000
--- a/compiler/rustc_ast_pretty/src/pp/convenience.rs
+++ /dev/null
@@ -1,97 +0,0 @@
-use std::borrow::Cow;
-
-use crate::pp::{
- BeginToken, BoxMarker, BreakToken, Breaks, IndentStyle, Printer, SIZE_INFINITY, Token,
-};
-
-impl Printer {
- /// "raw box"
- pub fn rbox(&mut self, indent: isize, breaks: Breaks) -> BoxMarker {
- self.scan_begin(BeginToken { indent: IndentStyle::Block { offset: indent }, breaks })
- }
-
- /// Inconsistent breaking box
- pub fn ibox(&mut self, indent: isize) -> BoxMarker {
- self.rbox(indent, Breaks::Inconsistent)
- }
-
- /// Consistent breaking box
- pub fn cbox(&mut self, indent: isize) -> BoxMarker {
- self.rbox(indent, Breaks::Consistent)
- }
-
- pub fn visual_align(&mut self) -> BoxMarker {
- self.scan_begin(BeginToken { indent: IndentStyle::Visual, breaks: Breaks::Consistent })
- }
-
- pub fn break_offset(&mut self, n: usize, off: isize) {
- self.scan_break(BreakToken {
- offset: off,
- blank_space: n as isize,
- ..BreakToken::default()
- });
- }
-
- pub fn end(&mut self, b: BoxMarker) {
- self.scan_end(b)
- }
-
- pub fn eof(mut self) -> String {
- self.scan_eof();
- self.out
- }
-
- pub fn word>>(&mut self, wrd: S) {
- let string = wrd.into();
- self.scan_string(string)
- }
-
- fn spaces(&mut self, n: usize) {
- self.break_offset(n, 0)
- }
-
- pub fn zerobreak(&mut self) {
- self.spaces(0)
- }
-
- pub fn space(&mut self) {
- self.spaces(1)
- }
-
- pub fn hardbreak(&mut self) {
- self.spaces(SIZE_INFINITY as usize)
- }
-
- pub fn is_beginning_of_line(&self) -> bool {
- match self.last_token() {
- Some(last_token) => last_token.is_hardbreak_tok(),
- None => true,
- }
- }
-
- pub(crate) fn hardbreak_tok_offset(off: isize) -> Token {
- Token::Break(BreakToken {
- offset: off,
- blank_space: SIZE_INFINITY,
- ..BreakToken::default()
- })
- }
-
- pub fn trailing_comma(&mut self) {
- self.scan_break(BreakToken { pre_break: Some(','), ..BreakToken::default() });
- }
-
- pub fn trailing_comma_or_space(&mut self) {
- self.scan_break(BreakToken {
- blank_space: 1,
- pre_break: Some(','),
- ..BreakToken::default()
- });
- }
-}
-
-impl Token {
- pub(crate) fn is_hardbreak_tok(&self) -> bool {
- *self == Printer::hardbreak_tok_offset(0)
- }
-}
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index 3e9c59614834..cb9bbf014e01 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -43,6 +43,7 @@ pub(crate) fn print_foreign_item(&mut self, item: &ast::ForeignItem) {
expr,
safety,
define_opaque,
+ eii_impls,
}) => self.print_item_const(
*ident,
Some(*mutability),
@@ -53,6 +54,7 @@ pub(crate) fn print_foreign_item(&mut self, item: &ast::ForeignItem) {
*safety,
ast::Defaultness::Implicit,
define_opaque.as_deref(),
+ eii_impls,
),
ast::ForeignItemKind::TyAlias(box ast::TyAlias {
defaultness,
@@ -93,8 +95,12 @@ fn print_item_const(
safety: ast::Safety,
defaultness: ast::Defaultness,
define_opaque: Option<&[(ast::NodeId, ast::Path)]>,
+ eii_impls: &[EiiImpl],
) {
self.print_define_opaques(define_opaque);
+ for eii_impl in eii_impls {
+ self.print_eii_impl(eii_impl);
+ }
let (cb, ib) = self.head("");
self.print_visibility(vis);
self.print_safety(safety);
@@ -191,6 +197,7 @@ pub(crate) fn print_item(&mut self, item: &ast::Item) {
mutability: mutbl,
expr: body,
define_opaque,
+ eii_impls,
}) => {
self.print_safety(*safety);
self.print_item_const(
@@ -203,6 +210,7 @@ pub(crate) fn print_item(&mut self, item: &ast::Item) {
ast::Safety::Default,
ast::Defaultness::Implicit,
define_opaque.as_deref(),
+ eii_impls,
);
}
ast::ItemKind::ConstBlock(ast::ConstBlockItem { id: _, span: _, block }) => {
@@ -234,6 +242,7 @@ pub(crate) fn print_item(&mut self, item: &ast::Item) {
ast::Safety::Default,
*defaultness,
define_opaque.as_deref(),
+ &[],
);
}
ast::ItemKind::Fn(func) => {
@@ -435,7 +444,10 @@ pub(crate) fn print_item(&mut self, item: &ast::Item) {
&item.vis,
&deleg.qself,
&deleg.prefix,
- deleg.suffixes.as_ref().map_or(DelegationKind::Glob, |s| DelegationKind::List(s)),
+ match &deleg.suffixes {
+ ast::DelegationSuffixes::List(s) => DelegationKind::List(s),
+ ast::DelegationSuffixes::Glob(_) => DelegationKind::Glob,
+ },
&deleg.body,
),
}
@@ -602,6 +614,7 @@ pub(crate) fn print_assoc_item(&mut self, item: &ast::AssocItem) {
ast::Safety::Default,
*defaultness,
define_opaque.as_deref(),
+ &[],
);
}
ast::AssocItemKind::Type(box ast::TyAlias {
@@ -641,7 +654,10 @@ pub(crate) fn print_assoc_item(&mut self, item: &ast::AssocItem) {
vis,
&deleg.qself,
&deleg.prefix,
- deleg.suffixes.as_ref().map_or(DelegationKind::Glob, |s| DelegationKind::List(s)),
+ match &deleg.suffixes {
+ ast::DelegationSuffixes::List(s) => DelegationKind::List(s),
+ ast::DelegationSuffixes::Glob(_) => DelegationKind::Glob,
+ },
&deleg.body,
),
}
@@ -703,18 +719,8 @@ fn print_fn_full(&mut self, vis: &ast::Visibility, attrs: &[ast::Attribute], fun
self.print_define_opaques(define_opaque.as_deref());
- for EiiImpl { eii_macro_path, impl_safety, .. } in eii_impls {
- self.word("#[");
- if let Safety::Unsafe(..) = impl_safety {
- self.word("unsafe");
- self.popen();
- }
- self.print_path(eii_macro_path, false, 0);
- if let Safety::Unsafe(..) = impl_safety {
- self.pclose();
- }
- self.word("]");
- self.hardbreak();
+ for eii_impl in eii_impls {
+ self.print_eii_impl(eii_impl);
}
let body_cb_ib = body.as_ref().map(|body| (body, self.head("")));
@@ -741,6 +747,20 @@ fn print_fn_full(&mut self, vis: &ast::Visibility, attrs: &[ast::Attribute], fun
}
}
+ fn print_eii_impl(&mut self, eii: &ast::EiiImpl) {
+ self.word("#[");
+ if let Safety::Unsafe(..) = eii.impl_safety {
+ self.word("unsafe");
+ self.popen();
+ }
+ self.print_path(&eii.eii_macro_path, false, 0);
+ if let Safety::Unsafe(..) = eii.impl_safety {
+ self.pclose();
+ }
+ self.word("]");
+ self.hardbreak();
+ }
+
fn print_define_opaques(&mut self, define_opaque: Option<&[(ast::NodeId, ast::Path)]>) {
if let Some(define_opaque) = define_opaque {
self.word("#[define_opaque(");
diff --git a/compiler/rustc_attr_parsing/Cargo.toml b/compiler/rustc_attr_parsing/Cargo.toml
index 886df58e8d6f..fc83c3b6e9bc 100644
--- a/compiler/rustc_attr_parsing/Cargo.toml
+++ b/compiler/rustc_attr_parsing/Cargo.toml
@@ -19,5 +19,5 @@ rustc_parse_format = { path = "../rustc_parse_format" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" }
-thin-vec = "0.2.12"
+thin-vec = "0.2.15"
# tidy-alphabetical-end
diff --git a/compiler/rustc_attr_parsing/src/attributes/autodiff.rs b/compiler/rustc_attr_parsing/src/attributes/autodiff.rs
index 31e79e118bfa..1f8c5fe3d3e5 100644
--- a/compiler/rustc_attr_parsing/src/attributes/autodiff.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/autodiff.rs
@@ -8,8 +8,8 @@
use rustc_span::{Symbol, sym};
use thin_vec::ThinVec;
+use crate::attributes::SingleAttributeParser;
use crate::attributes::prelude::Allow;
-use crate::attributes::{OnDuplicate, SingleAttributeParser};
use crate::context::{AcceptContext, Stage};
use crate::parser::{ArgParser, MetaItemOrLitParser};
use crate::target_checking::AllowedTargets;
@@ -18,7 +18,6 @@
impl SingleAttributeParser for RustcAutodiffParser {
const PATH: &[Symbol] = &[sym::rustc_autodiff];
- const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::Inherent)),
diff --git a/compiler/rustc_attr_parsing/src/attributes/body.rs b/compiler/rustc_attr_parsing/src/attributes/body.rs
index a1492d761946..46285c2323b8 100644
--- a/compiler/rustc_attr_parsing/src/attributes/body.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/body.rs
@@ -6,7 +6,6 @@
impl NoArgsAttributeParser for CoroutineParser {
const PATH: &[Symbol] = &[sym::coroutine];
- const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Closure)]);
const CREATE: fn(rustc_span::Span) -> AttributeKind = |span| AttributeKind::Coroutine(span);
}
diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs
index ccc4a1a64c56..84c83be8b4a5 100644
--- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs
@@ -2,7 +2,7 @@
use rustc_ast::token::Delimiter;
use rustc_ast::tokenstream::DelimSpan;
-use rustc_ast::{AttrItem, Attribute, CRATE_NODE_ID, LitKind, ast, token};
+use rustc_ast::{AttrItem, Attribute, LitKind, ast, token};
use rustc_errors::{Applicability, PResult, msg};
use rustc_feature::{
AttrSuggestionStyle, AttributeTemplate, Features, GatedCfg, find_gated_cfg, template,
@@ -19,6 +19,7 @@
use rustc_span::{ErrorGuaranteed, Span, Symbol, sym};
use thin_vec::ThinVec;
+use crate::attributes::AttributeSafety;
use crate::context::{AcceptContext, ShouldEmit, Stage};
use crate::parser::{
AllowExprMetavar, ArgParser, MetaItemListParser, MetaItemOrLitParser, NameValueParser,
@@ -78,7 +79,7 @@ pub fn parse_cfg(
}
}
- adcx.expected_single_argument(list.span);
+ adcx.expected_single_argument(list.span, list.len());
return None;
};
parse_cfg_entry(cx, single).ok()
@@ -93,7 +94,7 @@ pub fn parse_cfg_entry(
ArgParser::List(list) => match meta.path().word_sym() {
Some(sym::not) => {
let Some(single) = list.single() else {
- return Err(cx.adcx().expected_single_argument(list.span));
+ return Err(cx.adcx().expected_single_argument(list.span, list.len()));
};
CfgEntry::Not(Box::new(parse_cfg_entry(cx, single)?), list.span)
}
@@ -324,12 +325,13 @@ pub fn parse_cfg_attr(
cfg_attr: &Attribute,
sess: &Session,
features: Option<&Features>,
+ lint_node_id: ast::NodeId,
) -> Option<(CfgEntry, Vec<(AttrItem, Span)>)> {
match cfg_attr.get_normal_item().args.unparsed_ref().unwrap() {
ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, tokens }) if !tokens.is_empty() => {
check_cfg_attr_bad_delim(&sess.psess, *dspan, *delim);
match parse_in(&sess.psess, tokens.clone(), "`cfg_attr` input", |p| {
- parse_cfg_attr_internal(p, sess, features, cfg_attr)
+ parse_cfg_attr_internal(p, sess, features, lint_node_id, cfg_attr)
}) {
Ok(r) => return Some(r),
Err(e) => {
@@ -390,6 +392,7 @@ fn parse_cfg_attr_internal<'a>(
parser: &mut Parser<'a>,
sess: &'a Session,
features: Option<&Features>,
+ lint_node_id: ast::NodeId,
attribute: &Attribute,
) -> PResult<'a, (CfgEntry, Vec<(ast::AttrItem, Span)>)> {
// Parse cfg predicate
@@ -408,9 +411,10 @@ fn parse_cfg_attr_internal<'a>(
attribute.style,
AttrPath { segments: attribute.path().into_boxed_slice(), span: attribute.span },
Some(attribute.get_normal_item().unsafety),
+ AttributeSafety::Normal,
ParsedDescription::Attribute,
pred_span,
- CRATE_NODE_ID,
+ lint_node_id,
Target::Crate,
features,
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs b/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs
index 4ff224006ca8..918fd0a4582b 100644
--- a/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs
@@ -12,6 +12,7 @@
use rustc_session::lint::builtin::UNREACHABLE_CFG_SELECT_PREDICATES;
use rustc_span::{ErrorGuaranteed, Span, Symbol, sym};
+use crate::attributes::AttributeSafety;
use crate::parser::{AllowExprMetavar, MetaItemOrLitParser};
use crate::{AttributeParser, ParsedDescription, ShouldEmit, errors, parse_cfg_entry};
@@ -105,6 +106,7 @@ pub fn parse_cfg_select(
AttrStyle::Inner,
AttrPath { segments: vec![sym::cfg_select].into_boxed_slice(), span: cfg_span },
None,
+ AttributeSafety::Normal,
ParsedDescription::Macro,
cfg_span,
lint_node_id,
diff --git a/compiler/rustc_attr_parsing/src/attributes/cfi_encoding.rs b/compiler/rustc_attr_parsing/src/attributes/cfi_encoding.rs
index 81d5c8f99f45..32ea506211c9 100644
--- a/compiler/rustc_attr_parsing/src/attributes/cfi_encoding.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/cfi_encoding.rs
@@ -8,7 +8,6 @@ impl SingleAttributeParser for CfiEncodingParser {
Allow(Target::Enum),
Allow(Target::Union),
]);
- const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "encoding");
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option {
diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
index 93664aff4915..357be2f48f85 100644
--- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
@@ -1,7 +1,9 @@
use rustc_hir::attrs::{CoverageAttrKind, OptimizeAttr, RtsanSetting, SanitizerSet, UsedBy};
use rustc_session::parse::feature_err;
+use rustc_span::edition::Edition::Edition2024;
use super::prelude::*;
+use crate::attributes::AttributeSafety;
use crate::session_diagnostics::{
NakedFunctionIncompatibleAttribute, NullOnExport, NullOnObjcClass, NullOnObjcSelector,
ObjcClassExpectedStringLiteral, ObjcSelectorExpectedStringLiteral,
@@ -12,7 +14,6 @@
impl SingleAttributeParser for OptimizeParser {
const PATH: &[Symbol] = &[sym::optimize];
- const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Closure),
@@ -23,16 +24,7 @@ impl SingleAttributeParser for OptimizeParser {
const TEMPLATE: AttributeTemplate = template!(List: &["size", "speed", "none"]);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option {
- let Some(list) = args.list() else {
- let attr_span = cx.attr_span;
- cx.adcx().expected_list(attr_span, args);
- return None;
- };
-
- let Some(single) = list.single() else {
- cx.adcx().expected_single_argument(list.span);
- return None;
- };
+ let single = cx.single_element_list(args, cx.attr_span)?;
let res = match single.meta_item().and_then(|i| i.path().word().map(|i| i.name)) {
Some(sym::size) => OptimizeAttr::Size,
@@ -69,7 +61,6 @@ impl NoArgsAttributeParser for ColdParser {
impl SingleAttributeParser for CoverageParser {
const PATH: &[Symbol] = &[sym::coverage];
- const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Closure),
@@ -84,22 +75,13 @@ impl SingleAttributeParser for CoverageParser {
const TEMPLATE: AttributeTemplate = template!(OneOf: &[sym::off, sym::on]);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option {
- let Some(args) = args.list() else {
- let attr_span = cx.attr_span;
- cx.adcx().expected_specific_argument_and_list(attr_span, &[sym::on, sym::off]);
- return None;
- };
-
- let Some(arg) = args.single() else {
- cx.adcx().expected_single_argument(args.span);
- return None;
- };
+ let arg = cx.single_element_list(args, cx.attr_span)?;
let mut fail_incorrect_argument =
|span| cx.adcx().expected_specific_argument(span, &[sym::on, sym::off]);
let Some(arg) = arg.meta_item() else {
- fail_incorrect_argument(args.span);
+ fail_incorrect_argument(arg.span());
return None;
};
@@ -121,6 +103,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option SingleAttributeParser for ExportNameParser {
const PATH: &[rustc_span::Symbol] = &[sym::export_name];
const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError;
+ const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: Some(Edition2024) };
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Static),
Allow(Target::Fn),
@@ -158,7 +141,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option SingleAttributeParser for RustcObjcClassParser {
const PATH: &[rustc_span::Symbol] = &[sym::rustc_objc_class];
- const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::ForeignStatic)]);
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "ClassName");
@@ -190,7 +172,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option SingleAttributeParser for RustcObjcSelectorParser {
const PATH: &[rustc_span::Symbol] = &[sym::rustc_objc_selector];
- const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::ForeignStatic)]);
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "methodName");
@@ -238,6 +219,7 @@ impl AttributeParser for NakedParser {
this.span = Some(cx.attr_span);
}
})];
+ const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::Inherent)),
@@ -295,15 +277,10 @@ fn finalize(self, cx: &FinalizeContext<'_, '_, S>) -> Option {
let span = self.span?;
- let Some(tools) = cx.tools else {
- unreachable!("tools required while parsing attributes");
- };
-
- let tools = tools.iter().map(|tool| tool.name).collect::>();
// only if we found a naked attribute do we do the somewhat expensive check
'outer: for other_attr in cx.all_attrs {
for allowed_attr in ALLOW_LIST {
- if other_attr.segments().next().is_some_and(|i| tools.contains(&i.name)) {
+ if other_attr.segments().next().is_some_and(|i| cx.tools.contains(&i.name)) {
// effectively skips the error message being emitted below
// if it's a tool attribute
continue 'outer;
@@ -363,6 +340,7 @@ impl NoArgsAttributeParser for TrackCallerParser {
impl NoArgsAttributeParser for NoMangleParser {
const PATH: &[Symbol] = &[sym::no_mangle];
const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn;
+ const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: Some(Edition2024) };
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
Allow(Target::Fn),
Allow(Target::Static),
@@ -394,7 +372,7 @@ impl AttributeParser for UsedParser {
ArgParser::NoArgs => UsedBy::Default,
ArgParser::List(list) => {
let Some(l) = list.single() else {
- cx.adcx().expected_single_argument(list.span);
+ cx.adcx().expected_single_argument(list.span, list.len());
return;
};
@@ -565,6 +543,7 @@ fn extend(
impl CombineAttributeParser for ForceTargetFeatureParser {
type Item = (Symbol, Span);
const PATH: &[Symbol] = &[sym::force_target_feature];
+ const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
const CONVERT: ConvertFn = |items, span| AttributeKind::TargetFeature {
features: items,
attr_span: span,
@@ -608,8 +587,6 @@ impl SingleAttributeParser for SanitizeParser {
r#"realtime = "nonblocking|blocking|caller""#,
]);
- const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
-
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option {
let Some(list) = args.list() else {
let attr_span = cx.attr_span;
@@ -712,7 +689,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option NoArgsAttributeParser for ThreadLocalParser {
const PATH: &[Symbol] = &[sym::thread_local];
- const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError;
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::Static), Allow(Target::ForeignStatic)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ThreadLocal;
@@ -722,7 +698,6 @@ impl NoArgsAttributeParser for ThreadLocalParser {
impl NoArgsAttributeParser for RustcPassIndirectlyInNonRusticAbisParser {
const PATH: &[Symbol] = &[sym::rustc_pass_indirectly_in_non_rustic_abis];
- const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPassIndirectlyInNonRusticAbis;
}
@@ -731,8 +706,8 @@ impl NoArgsAttributeParser for RustcPassIndirectlyInNonRusticAbisPa
impl NoArgsAttributeParser for RustcEiiForeignItemParser {
const PATH: &[Symbol] = &[sym::rustc_eii_foreign_item];
- const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
- const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
+ const ALLOWED_TARGETS: AllowedTargets =
+ AllowedTargets::AllowList(&[Allow(Target::ForeignFn), Allow(Target::ForeignStatic)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcEiiForeignItem;
}
@@ -740,7 +715,6 @@ impl NoArgsAttributeParser for RustcEiiForeignItemParser {
impl SingleAttributeParser for PatchableFunctionEntryParser {
const PATH: &[Symbol] = &[sym::patchable_function_entry];
- const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
const TEMPLATE: AttributeTemplate = template!(List: &["prefix_nops = m, entry_nops = n"]);
@@ -755,7 +729,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option) -> Option {
return None;
}
- Some(AttributeKind::RustcConfusables {
- symbols: self.confusables,
- first_span: self.first_span.unwrap(),
- })
+ Some(AttributeKind::RustcConfusables { confusables: self.confusables })
}
}
diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs
index 774fd0805a7a..fed4ca7e76ab 100644
--- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs
@@ -108,7 +108,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option SingleAttributeParser for MoveSizeLimitParser {
const PATH: &[Symbol] = &[sym::move_size_limit];
- const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
@@ -154,7 +153,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option SingleAttributeParser for PatternComplexityLimitParser {
const PATH: &[Symbol] = &[sym::pattern_complexity_limit];
- const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
@@ -177,7 +175,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option NoArgsAttributeParser for NoCoreParser {
const PATH: &[Symbol] = &[sym::no_core];
- const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoCore;
}
@@ -204,7 +201,6 @@ impl NoArgsAttributeParser for NoMainParser {
impl NoArgsAttributeParser for RustcCoherenceIsCoreParser {
const PATH: &[Symbol] = &[sym::rustc_coherence_is_core];
- const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcCoherenceIsCore;
}
@@ -247,7 +243,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option NoArgsAttributeParser for PanicRuntimeParser {
const PATH: &[Symbol] = &[sym::panic_runtime];
- const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::PanicRuntime;
}
@@ -256,7 +251,6 @@ impl NoArgsAttributeParser for PanicRuntimeParser {
impl NoArgsAttributeParser for NeedsPanicRuntimeParser {
const PATH: &[Symbol] = &[sym::needs_panic_runtime];
- const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NeedsPanicRuntime;
}
@@ -265,7 +259,6 @@ impl NoArgsAttributeParser for NeedsPanicRuntimeParser {
impl NoArgsAttributeParser for ProfilerRuntimeParser {
const PATH: &[Symbol] = &[sym::profiler_runtime];
- const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ProfilerRuntime;
}
@@ -283,7 +276,6 @@ impl NoArgsAttributeParser for NoBuiltinsParser {
impl NoArgsAttributeParser for RustcPreserveUbChecksParser {
const PATH: &[Symbol] = &[sym::rustc_preserve_ub_checks];
- const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcPreserveUbChecks;
}
@@ -292,7 +284,6 @@ impl NoArgsAttributeParser for RustcPreserveUbChecksParser {
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;
}
@@ -301,7 +292,6 @@ impl NoArgsAttributeParser for RustcNoImplicitBoundsParser {
impl NoArgsAttributeParser for DefaultLibAllocatorParser {
const PATH: &[Symbol] = &[sym::default_lib_allocator];
- const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::DefaultLibAllocator;
}
diff --git a/compiler/rustc_attr_parsing/src/attributes/debugger.rs b/compiler/rustc_attr_parsing/src/attributes/debugger.rs
index 3bde4949bce0..65e9b968e946 100644
--- a/compiler/rustc_attr_parsing/src/attributes/debugger.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/debugger.rs
@@ -20,15 +20,7 @@ fn extend(
cx: &mut AcceptContext<'_, '_, S>,
args: &ArgParser,
) -> impl IntoIterator- {
- let Some(l) = args.list() else {
- let attr_span = cx.attr_span;
- cx.adcx().expected_list(attr_span, args);
- return None;
- };
- let Some(single) = l.single() else {
- cx.adcx().expected_single_argument(l.span);
- return None;
- };
+ let single = cx.single_element_list(args, cx.attr_span)?;
let Some(mi) = single.meta_item() else {
cx.adcx().expected_name_value(single.span(), None);
return None;
diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
index 35996904e8c7..e948d120fafb 100644
--- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
@@ -34,7 +34,6 @@ fn get(
pub(crate) struct DeprecatedParser;
impl SingleAttributeParser
for DeprecatedParser {
const PATH: &[Symbol] = &[sym::deprecated];
- const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
Allow(Target::Fn),
Allow(Target::Mod),
diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs
index e63baf77c085..ea5e81c3db81 100644
--- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs
@@ -24,6 +24,7 @@
pub(crate) mod on_const;
pub(crate) mod on_move;
pub(crate) mod on_unimplemented;
+pub(crate) mod on_unknown;
#[derive(Copy, Clone)]
pub(crate) enum Mode {
@@ -35,6 +36,47 @@ pub(crate) enum Mode {
DiagnosticOnConst,
/// `#[diagnostic::on_move]`
DiagnosticOnMove,
+ /// `#[diagnostic::on_unknown]`
+ DiagnosticOnUnknown,
+}
+
+impl Mode {
+ fn as_str(&self) -> &'static str {
+ match self {
+ Self::RustcOnUnimplemented => "rustc_on_unimplemented",
+ Self::DiagnosticOnUnimplemented => "diagnostic::on_unimplemented",
+ Self::DiagnosticOnConst => "diagnostic::on_const",
+ Self::DiagnosticOnMove => "diagnostic::on_move",
+ Self::DiagnosticOnUnknown => "diagnostic::on_unknown",
+ }
+ }
+
+ fn expected_options(&self) -> &'static str {
+ const DEFAULT: &str =
+ "at least one of the `message`, `note` and `label` options are expected";
+ match self {
+ Self::RustcOnUnimplemented => {
+ "see "
+ }
+ Self::DiagnosticOnUnimplemented => DEFAULT,
+ Self::DiagnosticOnConst => DEFAULT,
+ Self::DiagnosticOnMove => DEFAULT,
+ Self::DiagnosticOnUnknown => DEFAULT,
+ }
+ }
+
+ fn allowed_options(&self) -> &'static str {
+ const DEFAULT: &str = "only `message`, `note` and `label` are allowed as options";
+ match self {
+ Self::RustcOnUnimplemented => {
+ "see "
+ }
+ Self::DiagnosticOnUnimplemented => DEFAULT,
+ Self::DiagnosticOnConst => DEFAULT,
+ Self::DiagnosticOnMove => DEFAULT,
+ Self::DiagnosticOnUnknown => DEFAULT,
+ }
+ }
}
fn merge_directives(
@@ -80,6 +122,49 @@ fn merge(
}
}
+fn parse_list<'p, S: Stage>(
+ cx: &mut AcceptContext<'_, '_, S>,
+ args: &'p ArgParser,
+ mode: Mode,
+) -> Option<&'p MetaItemListParser> {
+ let span = cx.attr_span;
+ match args {
+ ArgParser::List(items) if items.len() != 0 => return Some(items),
+ ArgParser::List(list) => {
+ // We're dealing with `#[diagnostic::attr()]`.
+ // This can be because that is what the user typed, but that's also what we'd see
+ // if the user used non-metaitem syntax. See `ArgParser::from_attr_args`.
+ cx.emit_lint(
+ MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+ AttributeLintKind::NonMetaItemDiagnosticAttribute,
+ list.span,
+ );
+ }
+ ArgParser::NoArgs => {
+ cx.emit_lint(
+ MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+ AttributeLintKind::MissingOptionsForDiagnosticAttribute {
+ attribute: mode.as_str(),
+ options: mode.expected_options(),
+ },
+ span,
+ );
+ }
+ ArgParser::NameValue(_) => {
+ cx.emit_lint(
+ MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+ AttributeLintKind::MalFormedDiagnosticAttribute {
+ attribute: mode.as_str(),
+ options: mode.allowed_options(),
+ span,
+ },
+ span,
+ );
+ }
+ }
+ None
+}
+
fn parse_directive_items<'p, S: Stage>(
cx: &mut AcceptContext<'_, '_, S>,
mode: Mode,
@@ -97,32 +182,15 @@ fn parse_directive_items<'p, S: Stage>(
let span = item.span();
macro malformed() {{
- match mode {
- Mode::RustcOnUnimplemented => {
- cx.emit_err(NoValueInOnUnimplemented { span: item.span() });
- }
- Mode::DiagnosticOnUnimplemented => {
- cx.emit_lint(
- MALFORMED_DIAGNOSTIC_ATTRIBUTES,
- AttributeLintKind::MalformedOnUnimplementedAttr { span },
- span,
- );
- }
- Mode::DiagnosticOnConst => {
- cx.emit_lint(
- MALFORMED_DIAGNOSTIC_ATTRIBUTES,
- AttributeLintKind::MalformedOnConstAttr { span },
- span,
- );
- }
- Mode::DiagnosticOnMove => {
- cx.emit_lint(
- MALFORMED_DIAGNOSTIC_ATTRIBUTES,
- AttributeLintKind::MalformedOnMoveAttr { span },
- span,
- );
- }
- }
+ cx.emit_lint(
+ MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+ AttributeLintKind::MalFormedDiagnosticAttribute {
+ attribute: mode.as_str(),
+ options: mode.allowed_options(),
+ span,
+ },
+ span,
+ );
continue;
}}
@@ -136,22 +204,15 @@ fn parse_directive_items<'p, S: Stage>(
}}
macro duplicate($name: ident, $($first_span:tt)*) {{
- match mode {
- Mode::RustcOnUnimplemented => {
- cx.emit_err(NoValueInOnUnimplemented { span: item.span() });
- }
- Mode::DiagnosticOnUnimplemented |Mode::DiagnosticOnConst | Mode::DiagnosticOnMove => {
- cx.emit_lint(
- MALFORMED_DIAGNOSTIC_ATTRIBUTES,
- AttributeLintKind::IgnoredDiagnosticOption {
- first_span: $($first_span)*,
- later_span: span,
- option_name: $name,
- },
- span,
- );
- }
- }
+ cx.emit_lint(
+ MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+ AttributeLintKind::IgnoredDiagnosticOption {
+ first_span: $($first_span)*,
+ later_span: span,
+ option_name: $name,
+ },
+ span,
+ );
}}
let item: &MetaItemParser = or_malformed!(item.meta_item()?);
@@ -176,7 +237,8 @@ fn parse_directive_items<'p, S: Stage>(
Ok((f, warnings)) => {
for warning in warnings {
let (FormatWarning::InvalidSpecifier { span, .. }
- | FormatWarning::PositionalArgument { span, .. }) = warning;
+ | FormatWarning::PositionalArgument { span, .. }
+ | FormatWarning::DisallowedPlaceholder { span }) = warning;
cx.emit_lint(
MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
AttributeLintKind::MalformedDiagnosticFormat { warning },
@@ -326,6 +388,10 @@ fn parse_arg(
is_source_literal: bool,
) -> FormatArg {
let span = slice_span(input_span, arg.position_span.clone(), is_source_literal);
+ if matches!(mode, Mode::DiagnosticOnUnknown) {
+ warnings.push(FormatWarning::DisallowedPlaceholder { span });
+ return FormatArg::AsIs(sym::empty_braces);
+ }
match arg.position {
// Something like "hello {name}"
@@ -525,15 +591,6 @@ pub(crate) enum InvalidOnClause {
},
}
-#[derive(Diagnostic)]
-#[diag("this attribute must have a value", code = E0232)]
-#[note("e.g. `#[rustc_on_unimplemented(message=\"foo\")]`")]
-pub(crate) struct NoValueInOnUnimplemented {
- #[primary_span]
- #[label("expected value here")]
- pub span: Span,
-}
-
#[derive(Diagnostic)]
#[diag(
"using multiple `rustc_on_unimplemented` (or mixing it with `diagnostic::on_unimplemented`) is not supported"
diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs
index def4069f6b47..1e62c03fc3b6 100644
--- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs
@@ -1,6 +1,4 @@
use rustc_hir::attrs::diagnostic::Directive;
-use rustc_hir::lints::AttributeLintKind;
-use rustc_session::lint::builtin::MALFORMED_DIAGNOSTIC_ATTRIBUTES;
use crate::attributes::diagnostic::*;
use crate::attributes::prelude::*;
@@ -17,35 +15,17 @@ impl AttributeParser for OnConstParser {
template!(List: &[r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#]),
|this, cx, args| {
if !cx.features().diagnostic_on_const() {
+ // `UnknownDiagnosticAttribute` is emitted in rustc_resolve/macros.rs
return;
}
let span = cx.attr_span;
this.span = Some(span);
+ let mode = Mode::DiagnosticOnConst;
- let items = match args {
- ArgParser::List(items) if items.len() != 0 => items,
- ArgParser::NoArgs | ArgParser::List(_) => {
- cx.emit_lint(
- MALFORMED_DIAGNOSTIC_ATTRIBUTES,
- AttributeLintKind::MissingOptionsForOnConst,
- span,
- );
- return;
- }
- ArgParser::NameValue(_) => {
- cx.emit_lint(
- MALFORMED_DIAGNOSTIC_ATTRIBUTES,
- AttributeLintKind::MalformedOnConstAttr { span },
- span,
- );
- return;
- }
- };
+ let Some(items) = parse_list(cx, args, mode) else { return };
- let Some(directive) =
- parse_directive_items(cx, Mode::DiagnosticOnConst, items.mixed(), true)
- else {
+ let Some(directive) = parse_directive_items(cx, mode, items.mixed(), true) else {
return;
};
merge_directives(cx, &mut this.directive, (span, directive));
diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs
index 006b3b66658e..2b62ab7f3d11 100644
--- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs
@@ -1,7 +1,5 @@
use rustc_feature::template;
use rustc_hir::attrs::AttributeKind;
-use rustc_hir::lints::AttributeLintKind;
-use rustc_session::lint::builtin::MALFORMED_DIAGNOSTIC_ATTRIBUTES;
use rustc_span::sym;
use crate::attributes::diagnostic::*;
@@ -24,30 +22,16 @@ fn parse<'sess, S: Stage>(
mode: Mode,
) {
if !cx.features().diagnostic_on_move() {
+ // `UnknownDiagnosticAttribute` is emitted in rustc_resolve/macros.rs
return;
}
let span = cx.attr_span;
self.span = Some(span);
- let Some(list) = args.list() else {
- cx.emit_lint(
- MALFORMED_DIAGNOSTIC_ATTRIBUTES,
- AttributeLintKind::MissingOptionsForOnMove,
- span,
- );
- return;
- };
- if list.is_empty() {
- cx.emit_lint(
- MALFORMED_DIAGNOSTIC_ATTRIBUTES,
- AttributeLintKind::OnMoveMalformedAttrExpectedLiteralOrDelimiter,
- list.span,
- );
- return;
- }
+ let Some(items) = parse_list(cx, args, mode) else { return };
- if let Some(directive) = parse_directive_items(cx, mode, list.mixed(), true) {
+ if let Some(directive) = parse_directive_items(cx, mode, items.mixed(), true) {
merge_directives(cx, &mut self.directive, (span, directive));
}
}
diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unimplemented.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unimplemented.rs
index 12028059b7d4..dce3226670a1 100644
--- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unimplemented.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unimplemented.rs
@@ -1,6 +1,4 @@
use rustc_hir::attrs::diagnostic::Directive;
-use rustc_hir::lints::AttributeLintKind;
-use rustc_session::lint::builtin::MALFORMED_DIAGNOSTIC_ATTRIBUTES;
use crate::attributes::diagnostic::*;
use crate::attributes::prelude::*;
@@ -29,25 +27,7 @@ fn parse<'sess, S: Stage>(
return;
}
- let items = match args {
- ArgParser::List(items) if items.len() != 0 => items,
- ArgParser::NoArgs | ArgParser::List(_) => {
- cx.emit_lint(
- MALFORMED_DIAGNOSTIC_ATTRIBUTES,
- AttributeLintKind::MissingOptionsForOnUnimplemented,
- span,
- );
- return;
- }
- ArgParser::NameValue(_) => {
- cx.emit_lint(
- MALFORMED_DIAGNOSTIC_ATTRIBUTES,
- AttributeLintKind::MalformedOnUnimplementedAttr { span },
- span,
- );
- return;
- }
- };
+ let Some(items) = parse_list(cx, args, mode) else { return };
if let Some(directive) = parse_directive_items(cx, mode, items.mixed(), true) {
merge_directives(cx, &mut self.directive, (span, directive));
diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs
new file mode 100644
index 000000000000..a5364f968b21
--- /dev/null
+++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs
@@ -0,0 +1,57 @@
+use rustc_hir::attrs::diagnostic::Directive;
+
+use crate::attributes::diagnostic::*;
+use crate::attributes::prelude::*;
+
+#[derive(Default)]
+pub(crate) struct OnUnknownParser {
+ span: Option,
+ directive: Option<(Span, Directive)>,
+}
+
+impl OnUnknownParser {
+ fn parse<'sess, S: Stage>(
+ &mut self,
+ cx: &mut AcceptContext<'_, 'sess, S>,
+ args: &ArgParser,
+ mode: Mode,
+ ) {
+ if let Some(features) = cx.features
+ && !features.diagnostic_on_unknown()
+ {
+ // `UnknownDiagnosticAttribute` is emitted in rustc_resolve/macros.rs
+ return;
+ }
+ let span = cx.attr_span;
+ self.span = Some(span);
+
+ let Some(items) = parse_list(cx, args, mode) else { return };
+
+ if let Some(directive) = parse_directive_items(cx, mode, items.mixed(), true) {
+ merge_directives(cx, &mut self.directive, (span, directive));
+ };
+ }
+}
+
+impl AttributeParser for OnUnknownParser {
+ const ATTRIBUTES: AcceptMapping = &[(
+ &[sym::diagnostic, sym::on_unknown],
+ template!(List: &[r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#]),
+ |this, cx, args| {
+ this.parse(cx, args, Mode::DiagnosticOnUnknown);
+ },
+ )];
+ //FIXME attribute is not parsed for non-use statements but diagnostics are issued in `check_attr.rs`
+ const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
+
+ fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option {
+ if let Some(span) = self.span {
+ Some(AttributeKind::OnUnknown {
+ span,
+ directive: self.directive.map(|d| Box::new(d.1)),
+ })
+ } else {
+ None
+ }
+ }
+}
diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs
index 99f856684abd..a5b8c0ebe25e 100644
--- a/compiler/rustc_attr_parsing/src/attributes/doc.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs
@@ -1,5 +1,5 @@
use rustc_ast::ast::{AttrStyle, LitKind, MetaItemLit};
-use rustc_errors::msg;
+use rustc_errors::{Diagnostic, msg};
use rustc_feature::template;
use rustc_hir::Target;
use rustc_hir::attrs::{
@@ -171,12 +171,15 @@ fn parse_single_test_doc_attr_item(
if let Some(used_span) = self.attribute.no_crate_inject {
let unused_span = path.span();
- cx.emit_lint(
+ cx.emit_dyn_lint(
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
- AttributeLintKind::UnusedDuplicate {
- this: unused_span,
- other: used_span,
- warning: true,
+ move |dcx, level| {
+ rustc_errors::lints::UnusedDuplicate {
+ this: unused_span,
+ other: used_span,
+ warning: true,
+ }
+ .into_diag(dcx, level)
},
unused_span,
);
diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs
index f34a776d9ae8..32f995753bad 100644
--- a/compiler/rustc_attr_parsing/src/attributes/inline.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs
@@ -38,7 +38,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option Some(AttributeKind::Inline(InlineAttr::Hint, cx.attr_span)),
ArgParser::List(list) => {
let Some(l) = list.single() else {
- cx.adcx().expected_single_argument(list.span);
+ cx.adcx().expected_single_argument(list.span, list.len());
return None;
};
@@ -67,7 +67,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option SingleAttributeParser for RustcForceInlineParser {
const PATH: &[Symbol] = &[sym::rustc_force_inline];
- const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::Inherent)),
@@ -80,7 +79,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option None,
ArgParser::List(list) => {
let Some(l) = list.single() else {
- cx.adcx().expected_single_argument(list.span);
+ cx.adcx().expected_single_argument(list.span, list.len());
return None;
};
diff --git a/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs b/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs
index 00e2241f2e70..36e45a763e17 100644
--- a/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs
@@ -15,16 +15,11 @@ impl SingleAttributeParser for InstructionSetParser {
Allow(Target::Method(MethodKind::Trait { body: true })),
]);
const TEMPLATE: AttributeTemplate = template!(List: &["set"], "https://doc.rust-lang.org/reference/attributes/codegen.html#the-instruction_set-attribute");
- const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option {
const POSSIBLE_SYMBOLS: &[Symbol] = &[sym::arm_a32, sym::arm_t32];
const POSSIBLE_ARM_SYMBOLS: &[Symbol] = &[sym::a32, sym::t32];
- let Some(maybe_meta_item) = args.list().and_then(MetaItemListParser::single) else {
- let attr_span = cx.attr_span;
- cx.adcx().expected_specific_argument(attr_span, POSSIBLE_SYMBOLS);
- return None;
- };
+ let maybe_meta_item = cx.single_element_list(args, cx.attr_span)?;
let Some(meta_item) = maybe_meta_item.meta_item() else {
cx.adcx().expected_specific_argument(maybe_meta_item.span(), POSSIBLE_SYMBOLS);
diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs
index 6ae4e31af9df..9f48f7f8ab55 100644
--- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs
@@ -5,11 +5,13 @@
use rustc_session::Session;
use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
use rustc_session::parse::feature_err;
+use rustc_span::edition::Edition::Edition2024;
use rustc_span::kw;
use rustc_target::spec::{Arch, BinaryFormat};
use super::prelude::*;
use super::util::parse_single_integer;
+use crate::attributes::AttributeSafety;
use crate::attributes::cfg::parse_cfg_entry;
use crate::session_diagnostics::{
AsNeededCompatibility, BundleNeedsStatic, EmptyLinkName, ExportSymbolsNeedsStatic,
@@ -388,12 +390,7 @@ fn parse_link_cfg(
cx.adcx().duplicate_key(item.span(), sym::cfg);
return true;
}
- let Some(link_cfg) = item.args().list() else {
- cx.adcx().expected_list(item.span(), item.args());
- return true;
- };
- let Some(link_cfg) = link_cfg.single() else {
- cx.adcx().expected_single_argument(item.span());
+ let Some(link_cfg) = cx.single_element_list(item.args(), item.span()) else {
return true;
};
if !features.link_cfg() {
@@ -468,6 +465,7 @@ fn parse_link_import_name_type(
impl SingleAttributeParser for LinkSectionParser {
const PATH: &[Symbol] = &[sym::link_section];
const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError;
+ const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: Some(Edition2024) };
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
Allow(Target::Static),
Allow(Target::Fn),
@@ -504,7 +502,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option NoArgsAttributeParser for ExportStableParser {
const PATH: &[Symbol] = &[sym::export_stable];
- const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); //FIXME Still checked fully in `check_attr.rs`
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ExportStable;
}
@@ -512,7 +509,7 @@ impl NoArgsAttributeParser for ExportStableParser {
pub(crate) struct FfiConstParser;
impl NoArgsAttributeParser for FfiConstParser {
const PATH: &[Symbol] = &[sym::ffi_const];
- const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn;
+ const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiConst;
}
@@ -520,7 +517,7 @@ impl NoArgsAttributeParser for FfiConstParser {
pub(crate) struct FfiPureParser;
impl NoArgsAttributeParser for FfiPureParser {
const PATH: &[Symbol] = &[sym::ffi_pure];
- const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn;
+ const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiPure;
}
@@ -528,7 +525,6 @@ impl NoArgsAttributeParser for FfiPureParser {
pub(crate) struct RustcStdInternalSymbolParser;
impl NoArgsAttributeParser for RustcStdInternalSymbolParser {
const PATH: &[Symbol] = &[sym::rustc_std_internal_symbol];
- const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::ForeignFn),
@@ -542,7 +538,6 @@ impl NoArgsAttributeParser for RustcStdInternalSymbolParser {
impl SingleAttributeParser for LinkOrdinalParser {
const PATH: &[Symbol] = &[sym::link_ordinal];
- const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::ForeignFn),
Allow(Target::ForeignStatic),
@@ -583,7 +578,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option SingleAttributeParser for LinkageParser {
const PATH: &[Symbol] = &[sym::linkage];
- const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::Inherent)),
@@ -666,7 +660,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option NoArgsAttributeParser for NeedsAllocatorParser {
const PATH: &[Symbol] = &[sym::needs_allocator];
- const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NeedsAllocator;
}
@@ -675,7 +668,6 @@ impl NoArgsAttributeParser for NeedsAllocatorParser {
impl NoArgsAttributeParser for CompilerBuiltinsParser {
const PATH: &[Symbol] = &[sym::compiler_builtins];
- const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::CompilerBuiltins;
}
diff --git a/compiler/rustc_attr_parsing/src/attributes/lint.rs b/compiler/rustc_attr_parsing/src/attributes/lint.rs
deleted file mode 100644
index f9c8ff6e6874..000000000000
--- a/compiler/rustc_attr_parsing/src/attributes/lint.rs
+++ /dev/null
@@ -1,371 +0,0 @@
-use rustc_ast::LitKind;
-use rustc_hir::HashIgnoredAttrId;
-use rustc_hir::attrs::{LintAttribute, LintAttributeKind, LintInstance};
-use rustc_hir::lints::AttributeLintKind;
-use rustc_hir::target::GenericParamKind;
-use rustc_session::DynLintStore;
-use rustc_session::lint::builtin::{RENAMED_AND_REMOVED_LINTS, UNKNOWN_LINTS, UNUSED_ATTRIBUTES};
-use rustc_session::lint::{CheckLintNameResult, LintId};
-
-use super::prelude::*;
-use crate::attributes::AcceptFn;
-use crate::session_diagnostics::UnknownToolInScopedLint;
-
-pub(crate) trait Lint {
- const KIND: LintAttributeKind;
- const ATTR_SYMBOL: Symbol = Self::KIND.symbol();
-}
-
-pub(crate) struct Allow;
-
-impl Lint for Allow {
- const KIND: LintAttributeKind = LintAttributeKind::Allow;
-}
-pub(crate) struct Deny;
-
-impl Lint for Deny {
- const KIND: LintAttributeKind = LintAttributeKind::Deny;
-}
-pub(crate) struct Expect;
-
-impl Lint for Expect {
- const KIND: LintAttributeKind = LintAttributeKind::Expect;
-}
-pub(crate) struct Forbid;
-
-impl Lint for Forbid {
- const KIND: LintAttributeKind = LintAttributeKind::Forbid;
-}
-pub(crate) struct Warn;
-
-impl Lint for Warn {
- const KIND: LintAttributeKind = LintAttributeKind::Warn;
-}
-
-#[derive(Default)]
-pub(crate) struct LintParser {
- lint_attrs: ThinVec,
-}
-
-trait Mapping {
- const MAPPING: (&'static [Symbol], AttributeTemplate, AcceptFn);
-}
-impl Mapping for T {
- const MAPPING: (&'static [Symbol], AttributeTemplate, AcceptFn) = (
- &[T::ATTR_SYMBOL],
- template!(
- List: &["lint1", "lint1, lint2, ...", r#"lint1, lint2, lint3, reason = "...""#],
- "https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
- ),
- |this, cx, args| {
- if let Some(lint_attr) = validate_lint_attr::(cx, args) {
- this.lint_attrs.push(lint_attr);
- }
- },
- );
-}
-
-impl AttributeParser for LintParser {
- const ATTRIBUTES: AcceptMapping =
- &[Allow::MAPPING, Deny::MAPPING, Expect::MAPPING, Forbid::MAPPING, Warn::MAPPING];
-
- const ALLOWED_TARGETS: AllowedTargets = {
- use super::prelude::{Allow, Warn};
- AllowedTargets::AllowList(&[
- Allow(Target::ExternCrate),
- Allow(Target::Use),
- Allow(Target::Static),
- Allow(Target::Const),
- Allow(Target::Fn),
- Allow(Target::Closure),
- Allow(Target::Mod),
- Allow(Target::ForeignMod),
- Allow(Target::GlobalAsm),
- 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::Expression),
- Allow(Target::Statement),
- Allow(Target::Arm),
- 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::Param),
- Allow(Target::PatField),
- Allow(Target::ExprField),
- Allow(Target::Crate),
- Allow(Target::Delegation { mac: false }),
- Allow(Target::Delegation { mac: true }),
- Allow(Target::GenericParam { kind: GenericParamKind::Type, has_default: false }),
- Allow(Target::GenericParam { kind: GenericParamKind::Lifetime, has_default: false }),
- Allow(Target::GenericParam { kind: GenericParamKind::Const, has_default: false }),
- Allow(Target::GenericParam { kind: GenericParamKind::Type, has_default: true }),
- Allow(Target::GenericParam { kind: GenericParamKind::Lifetime, has_default: true }),
- Allow(Target::GenericParam { kind: GenericParamKind::Const, has_default: true }),
- Warn(Target::MacroCall),
- ])
- };
-
- fn finalize(mut self, _cx: &FinalizeContext<'_, '_, S>) -> Option {
- if !self.lint_attrs.is_empty() {
- // Sort to ensure correct order operations later
- self.lint_attrs.sort_by(|a, b| a.attr_span.cmp(&b.attr_span));
- Some(AttributeKind::LintAttributes(self.lint_attrs))
- } else {
- None
- }
- }
-}
-
-#[inline(always)]
-fn validate_lint_attr(
- cx: &mut AcceptContext<'_, '_, S>,
- args: &ArgParser,
-) -> Option {
- let Some(lint_store) = cx.sess.lint_store.as_ref().map(|store| store.to_owned()) else {
- unreachable!("lint_store required while parsing attributes");
- };
- let lint_store = lint_store.as_ref();
- let Some(list) = args.list() else {
- let span = cx.inner_span;
- cx.adcx().expected_list(span, args);
- return None;
- };
- let mut list = list.mixed().peekable();
-
- let mut skip_unused_check = false;
- let mut errored = false;
- let mut reason = None;
- let mut lint_instances = ThinVec::new();
- let mut lint_index = 0;
- let targeting_crate = matches!(cx.target, Target::Crate);
- while let Some(item) = list.next() {
- let Some(meta_item) = item.meta_item() else {
- cx.adcx().expected_identifier(item.span());
- errored = true;
- continue;
- };
-
- match meta_item.args() {
- ArgParser::NameValue(nv_parser) if meta_item.path().word_is(sym::reason) => {
- //FIXME replace this with duplicate check?
- if list.peek().is_some() {
- cx.adcx().expected_nv_as_last_argument(meta_item.span(), sym::reason);
- errored = true;
- continue;
- }
-
- let val_lit = nv_parser.value_as_lit();
- let LitKind::Str(reason_sym, _) = val_lit.kind else {
- cx.adcx().expected_string_literal(nv_parser.value_span, Some(val_lit));
- errored = true;
- continue;
- };
- reason = Some(reason_sym);
- }
- ArgParser::NameValue(_) => {
- cx.adcx().expected_specific_argument(meta_item.span(), &[sym::reason]);
- errored = true;
- }
- ArgParser::List(list) => {
- cx.adcx().expected_no_args(list.span);
- errored = true;
- }
- ArgParser::NoArgs => {
- skip_unused_check = true;
- let mut segments = meta_item.path().segments();
-
- let Some(tool_or_name) = segments.next() else {
- unreachable!("first segment should always exist");
- };
-
- let rest = segments.collect::