Merge ref '6f109d8a2da2' from rust-lang/rust

Pull recent changes from https://github.com/rust-lang/rust via Josh.

Upstream ref: rust-lang/rust@6f109d8a2d
Filtered ref: rust-lang/miri@b3bc25a96b
Upstream diff: https://github.com/rust-lang/rust/compare/4c4205163abcbd08948b3efab796c543ba1ea687...6f109d8a2da2fe8d0fbfc52178300c033737b218

This merge was created using https://github.com/rust-lang/josh-sync.
This commit is contained in:
The Miri Cronjob Bot
2026-04-19 05:48:19 +00:00
2107 changed files with 357526 additions and 27886 deletions
+25 -16
View File
@@ -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"
+137
View File
@@ -1,3 +1,140 @@
Version 1.95.0 (2026-04-16)
===========================
<a id="1.95-Language"></a>
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)
<a id="1.95-Compiler"></a>
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)
<a id="1.95-Platform-Support"></a>
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
<a id="1.95-Libraries"></a>
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)
<a id="1.95-Stabilized-APIs"></a>
Stabilized APIs
---------------
- [`MaybeUninit<[T; N]>: From<[MaybeUninit<T>; 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<T>; 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<T>]>`](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<T>; 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<T>]>`](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<T>; N]: From<MaybeUninit<[T; N]>>`](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<T>; 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<T>]>`](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<T>]>`](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)
<a id="1.95-Rustdoc"></a>
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)
<a id="1.95-Compatibility-Notes"></a>
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)
<a id="1.95-Internal-Changes"></a>
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)
===========================
+4 -2
View File
@@ -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",
+3 -2
View File
@@ -75,10 +75,11 @@ pub fn homogeneous_aggregate<C>(&self, cx: &C) -> Result<HomogeneousAggregate, H
Ok(HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size }))
}
BackendRepr::SimdVector { .. } => {
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,
}))
}
+14 -3
View File
@@ -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<C: HasDataLayout>(&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),
}
}
}
+23
View File
@@ -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 {
+85 -8
View File
@@ -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<G: EmissionGuarantee> 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<TargetDataLayout, TargetDataLayoutErrors<'a>> {
) -> Result<TargetDataLayout, TargetDataLayoutError<'a>> {
// Parse an address space index from a string.
let parse_address_space = |s: &'a str, cause: &'a str| {
s.parse::<u32>().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::<u64>().map_err(|err| TargetDataLayoutErrors::InvalidBits {
s.parse::<u64>().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<Self> {
}
}
#[cfg(feature = "nightly")]
impl IntoDiagArg for NumScalableVectors {
fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> 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.
+14 -29
View File
@@ -140,25 +140,19 @@ impl<T> TypedArena<T> {
/// Allocates an object in the `TypedArena`, returning a reference to it.
#[inline]
pub fn alloc(&self, object: T) -> &mut T {
assert!(size_of::<T>() != 0);
if self.ptr == self.end {
self.grow(1)
}
unsafe {
if size_of::<T>() == 0 {
self.ptr.set(self.ptr.get().wrapping_byte_add(1));
let ptr = ptr::NonNull::<T>::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::<T>::new(new_cap);
let chunk = chunks.push_mut(ArenaChunk::<T>::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<T>) {
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::<T>() == 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::<T>()
};
assert_ne!(size_of::<T>(), 0);
// FIXME: this should *likely* use `offset_from`, but more
// investigation is needed (including running tests in miri).
let diff = (end - start) / size_of::<T>();
// 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);
}
}
+3 -15
View File
@@ -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<u32> = 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<SmallDroppable> = 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
};
+1 -1
View File
@@ -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
+14 -2
View File
@@ -3901,12 +3901,17 @@ pub struct Delegation {
pub from_glob: bool,
}
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
pub enum DelegationSuffixes {
List(ThinVec<(Ident, Option<Ident>)>),
Glob(Span),
}
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
pub struct DelegationMac {
pub qself: Option<Box<QSelf>>,
pub prefix: Path,
// Some for list delegation, and None for glob delegation.
pub suffixes: Option<ThinVec<(Ident, Option<Ident>)>>,
pub suffixes: DelegationSuffixes,
pub body: Option<Box<Block>>,
}
@@ -3918,6 +3923,13 @@ pub struct StaticItem {
pub mutability: Mutability,
pub expr: Option<Box<Expr>>,
pub define_opaque: Option<ThinVec<(NodeId, Path)>>,
/// 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<EiiImpl>,
}
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
+1
View File
@@ -430,6 +430,7 @@ pub fn ctxt(&self) -> Option<FnCtxt> {
Defaultness,
Delegation,
DelegationMac,
DelegationSuffixes,
DelimArgs,
DelimSpan,
EnumDef,
+1 -1
View File
@@ -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
+8 -14
View File
@@ -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<DefId> {
// 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 };
@@ -10,18 +10,38 @@
use crate::{LoweringContext, ResolverAstLoweringExt};
pub(super) enum DelegationGenerics<T> {
#[derive(Clone, Copy)]
pub(super) enum DelegationGenericsKind {
/// User-specified args are present: `reuse foo::<String>;`.
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::<i32>::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<T> {
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<T> DelegationGenerics<T> {
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 => {
+15 -24
View File
@@ -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<Span>;
@@ -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| {
+56 -8
View File
@@ -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<hir::Attribute> {
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))]
+71 -47
View File
@@ -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<Symbol>,
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 {
+6 -4
View File
@@ -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(
+1 -1
View File
@@ -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
@@ -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 {
+1 -1
View File
@@ -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
-49
View File
@@ -1,49 +0,0 @@
use std::borrow::Cow;
use crate::pp::Printer;
impl Printer {
pub fn word_space<W: Into<Cow<'static, str>>>(&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<S: Into<Cow<'static, str>>>(&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<Cow<'static, str>>) {
self.word("/*");
self.space();
self.word(text);
self.space();
self.word("*/")
}
}
-1
View File
@@ -3,6 +3,5 @@
#![feature(negative_impls)]
// tidy-alphabetical-end
mod helpers;
pub mod pp;
pub mod pprust;
+134 -1
View File
@@ -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<Cow<'static, str>>) {
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<S: Into<Cow<'static, str>>>(&mut self, wrd: S) {
let string = wrd.into();
self.scan_string(string)
}
pub fn word_space<W: Into<Cow<'static, str>>>(&mut self, w: W) {
self.word(w);
self.space();
}
pub fn nbsp(&mut self) {
self.word(" ")
}
pub fn word_nbsp<S: Into<Cow<'static, str>>>(&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()
});
}
}
@@ -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<S: Into<Cow<'static, str>>>(&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)
}
}
@@ -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(");
+1 -1
View File
@@ -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
@@ -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<S: Stage> SingleAttributeParser<S> for RustcAutodiffParser {
const PATH: &[Symbol] = &[sym::rustc_autodiff];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::Inherent)),
@@ -6,7 +6,6 @@
impl<S: Stage> NoArgsAttributeParser<S> for CoroutineParser {
const PATH: &[Symbol] = &[sym::coroutine];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Closure)]);
const CREATE: fn(rustc_span::Span) -> AttributeKind = |span| AttributeKind::Coroutine(span);
}
@@ -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<S: Stage>(
}
}
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<S: Stage>(
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 },
@@ -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,
@@ -8,7 +8,6 @@ impl<S: Stage> SingleAttributeParser<S> for CfiEncodingParser {
Allow(Target::Enum),
Allow(Target::Union),
]);
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "encoding");
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
@@ -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<S: Stage> SingleAttributeParser<S> for OptimizeParser {
const PATH: &[Symbol] = &[sym::optimize];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Closure),
@@ -23,16 +24,7 @@ impl<S: Stage> SingleAttributeParser<S> for OptimizeParser {
const TEMPLATE: AttributeTemplate = template!(List: &["size", "speed", "none"]);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
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<S: Stage> NoArgsAttributeParser<S> for ColdParser {
impl<S: Stage> SingleAttributeParser<S> for CoverageParser {
const PATH: &[Symbol] = &[sym::coverage];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Closure),
@@ -84,22 +75,13 @@ impl<S: Stage> SingleAttributeParser<S> for CoverageParser {
const TEMPLATE: AttributeTemplate = template!(OneOf: &[sym::off, sym::on]);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
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<Attrib
impl<S: Stage> SingleAttributeParser<S> for ExportNameParser {
const PATH: &[rustc_span::Symbol] = &[sym::export_name];
const ON_DUPLICATE: OnDuplicate<S> = 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<Attrib
impl<S: Stage> SingleAttributeParser<S> for RustcObjcClassParser {
const PATH: &[rustc_span::Symbol] = &[sym::rustc_objc_class];
const ON_DUPLICATE: OnDuplicate<S> = 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<Attrib
impl<S: Stage> SingleAttributeParser<S> for RustcObjcSelectorParser {
const PATH: &[rustc_span::Symbol] = &[sym::rustc_objc_selector];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::ForeignStatic)]);
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "methodName");
@@ -238,6 +219,7 @@ impl<S: Stage> AttributeParser<S> 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<AttributeKind> {
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::<Vec<_>>();
// 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<S: Stage> NoArgsAttributeParser<S> for TrackCallerParser {
impl<S: Stage> NoArgsAttributeParser<S> for NoMangleParser {
const PATH: &[Symbol] = &[sym::no_mangle];
const ON_DUPLICATE: OnDuplicate<S> = 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<S: Stage> AttributeParser<S> 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<S: Stage> CombineAttributeParser<S> for ForceTargetFeatureParser {
type Item = (Symbol, Span);
const PATH: &[Symbol] = &[sym::force_target_feature];
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature {
features: items,
attr_span: span,
@@ -608,8 +587,6 @@ impl<S: Stage> SingleAttributeParser<S> for SanitizeParser {
r#"realtime = "nonblocking|blocking|caller""#,
]);
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
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<Attrib
impl<S: Stage> NoArgsAttributeParser<S> for ThreadLocalParser {
const PATH: &[Symbol] = &[sym::thread_local];
const ON_DUPLICATE: OnDuplicate<S> = 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<S: Stage> NoArgsAttributeParser<S> for ThreadLocalParser {
impl<S: Stage> NoArgsAttributeParser<S> for RustcPassIndirectlyInNonRusticAbisParser {
const PATH: &[Symbol] = &[sym::rustc_pass_indirectly_in_non_rustic_abis];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPassIndirectlyInNonRusticAbis;
}
@@ -731,8 +706,8 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcPassIndirectlyInNonRusticAbisPa
impl<S: Stage> NoArgsAttributeParser<S> for RustcEiiForeignItemParser {
const PATH: &[Symbol] = &[sym::rustc_eii_foreign_item];
const ON_DUPLICATE: OnDuplicate<S> = 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<S: Stage> NoArgsAttributeParser<S> for RustcEiiForeignItemParser {
impl<S: Stage> SingleAttributeParser<S> for PatchableFunctionEntryParser {
const PATH: &[Symbol] = &[sym::patchable_function_entry];
const ON_DUPLICATE: OnDuplicate<S> = 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<Attrib
let mut entry = None;
if meta_item_list.len() == 0 {
cx.adcx().expected_list(meta_item_list.span, args);
cx.adcx().expected_at_least_one_argument(meta_item_list.span);
return None;
}
@@ -44,9 +44,6 @@ fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
return None;
}
Some(AttributeKind::RustcConfusables {
symbols: self.confusables,
first_span: self.first_span.unwrap(),
})
Some(AttributeKind::RustcConfusables { confusables: self.confusables })
}
}
@@ -108,7 +108,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
impl<S: Stage> SingleAttributeParser<S> for MoveSizeLimitParser {
const PATH: &[Symbol] = &[sym::move_size_limit];
const ON_DUPLICATE: OnDuplicate<S> = 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<Attrib
impl<S: Stage> SingleAttributeParser<S> for PatternComplexityLimitParser {
const PATH: &[Symbol] = &[sym::pattern_complexity_limit];
const ON_DUPLICATE: OnDuplicate<S> = 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<Attrib
impl<S: Stage> NoArgsAttributeParser<S> for NoCoreParser {
const PATH: &[Symbol] = &[sym::no_core];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoCore;
}
@@ -204,7 +201,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for NoMainParser {
impl<S: Stage> NoArgsAttributeParser<S> for RustcCoherenceIsCoreParser {
const PATH: &[Symbol] = &[sym::rustc_coherence_is_core];
const ON_DUPLICATE: OnDuplicate<S> = 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<Attrib
impl<S: Stage> NoArgsAttributeParser<S> for PanicRuntimeParser {
const PATH: &[Symbol] = &[sym::panic_runtime];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::PanicRuntime;
}
@@ -256,7 +251,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for PanicRuntimeParser {
impl<S: Stage> NoArgsAttributeParser<S> for NeedsPanicRuntimeParser {
const PATH: &[Symbol] = &[sym::needs_panic_runtime];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NeedsPanicRuntime;
}
@@ -265,7 +259,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for NeedsPanicRuntimeParser {
impl<S: Stage> NoArgsAttributeParser<S> for ProfilerRuntimeParser {
const PATH: &[Symbol] = &[sym::profiler_runtime];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ProfilerRuntime;
}
@@ -283,7 +276,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for NoBuiltinsParser {
impl<S: Stage> NoArgsAttributeParser<S> for RustcPreserveUbChecksParser {
const PATH: &[Symbol] = &[sym::rustc_preserve_ub_checks];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcPreserveUbChecks;
}
@@ -292,7 +284,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcPreserveUbChecksParser {
impl<S: Stage> NoArgsAttributeParser<S> for RustcNoImplicitBoundsParser {
const PATH: &[Symbol] = &[sym::rustc_no_implicit_bounds];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNoImplicitBounds;
}
@@ -301,7 +292,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcNoImplicitBoundsParser {
impl<S: Stage> NoArgsAttributeParser<S> for DefaultLibAllocatorParser {
const PATH: &[Symbol] = &[sym::default_lib_allocator];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::DefaultLibAllocator;
}
@@ -20,15 +20,7 @@ fn extend(
cx: &mut AcceptContext<'_, '_, S>,
args: &ArgParser,
) -> impl IntoIterator<Item = Self::Item> {
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;
@@ -34,7 +34,6 @@ fn get<S: Stage>(
pub(crate) struct DeprecatedParser;
impl<S: Stage> SingleAttributeParser<S> for DeprecatedParser {
const PATH: &[Symbol] = &[sym::deprecated];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
Allow(Target::Fn),
Allow(Target::Mod),
@@ -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 <https://rustc-dev-guide.rust-lang.org/diagnostics.html#rustc_on_unimplemented>"
}
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 <https://rustc-dev-guide.rust-lang.org/diagnostics.html#rustc_on_unimplemented>"
}
Self::DiagnosticOnUnimplemented => DEFAULT,
Self::DiagnosticOnConst => DEFAULT,
Self::DiagnosticOnMove => DEFAULT,
Self::DiagnosticOnUnknown => DEFAULT,
}
}
}
fn merge_directives<S: Stage>(
@@ -80,6 +122,49 @@ fn merge<T, S: Stage>(
}
}
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"
@@ -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<S: Stage> AttributeParser<S> 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));
@@ -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));
}
}
@@ -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));
@@ -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<Span>,
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<S: Stage> AttributeParser<S> for OnUnknownParser {
const ATTRIBUTES: AcceptMapping<Self, S> = &[(
&[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<AttributeKind> {
if let Some(span) = self.span {
Some(AttributeKind::OnUnknown {
span,
directive: self.directive.map(|d| Box::new(d.1)),
})
} else {
None
}
}
}
@@ -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<S: Stage>(
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,
);
@@ -38,7 +38,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
ArgParser::NoArgs => 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<Attrib
impl<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser {
const PATH: &[Symbol] = &[sym::rustc_force_inline];
const ON_DUPLICATE: OnDuplicate<S> = 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<Attrib
ArgParser::NoArgs => 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;
};
@@ -15,16 +15,11 @@ impl<S: Stage> SingleAttributeParser<S> 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<S> = OnDuplicate::Error;
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
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);
@@ -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<S: Stage>(
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<S: Stage>(
impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser {
const PATH: &[Symbol] = &[sym::link_section];
const ON_DUPLICATE: OnDuplicate<S> = 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<Attrib
pub(crate) struct ExportStableParser;
impl<S: Stage> NoArgsAttributeParser<S> for ExportStableParser {
const PATH: &[Symbol] = &[sym::export_stable];
const ON_DUPLICATE: OnDuplicate<S> = 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<S: Stage> NoArgsAttributeParser<S> for ExportStableParser {
pub(crate) struct FfiConstParser;
impl<S: Stage> NoArgsAttributeParser<S> for FfiConstParser {
const PATH: &[Symbol] = &[sym::ffi_const];
const ON_DUPLICATE: OnDuplicate<S> = 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<S: Stage> NoArgsAttributeParser<S> for FfiConstParser {
pub(crate) struct FfiPureParser;
impl<S: Stage> NoArgsAttributeParser<S> for FfiPureParser {
const PATH: &[Symbol] = &[sym::ffi_pure];
const ON_DUPLICATE: OnDuplicate<S> = 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<S: Stage> NoArgsAttributeParser<S> for FfiPureParser {
pub(crate) struct RustcStdInternalSymbolParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcStdInternalSymbolParser {
const PATH: &[Symbol] = &[sym::rustc_std_internal_symbol];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::ForeignFn),
@@ -542,7 +538,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcStdInternalSymbolParser {
impl<S: Stage> SingleAttributeParser<S> for LinkOrdinalParser {
const PATH: &[Symbol] = &[sym::link_ordinal];
const ON_DUPLICATE: OnDuplicate<S> = 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<Attrib
impl<S: Stage> SingleAttributeParser<S> for LinkageParser {
const PATH: &[Symbol] = &[sym::linkage];
const ON_DUPLICATE: OnDuplicate<S> = 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<Attrib
impl<S: Stage> NoArgsAttributeParser<S> for NeedsAllocatorParser {
const PATH: &[Symbol] = &[sym::needs_allocator];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NeedsAllocator;
}
@@ -675,7 +668,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for NeedsAllocatorParser {
impl<S: Stage> NoArgsAttributeParser<S> for CompilerBuiltinsParser {
const PATH: &[Symbol] = &[sym::compiler_builtins];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::CompilerBuiltins;
}
@@ -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<LintAttribute>,
}
trait Mapping<S: Stage> {
const MAPPING: (&'static [Symbol], AttributeTemplate, AcceptFn<LintParser, S>);
}
impl<S: Stage, T: Lint> Mapping<S> for T {
const MAPPING: (&'static [Symbol], AttributeTemplate, AcceptFn<LintParser, S>) = (
&[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::<T, S>(cx, args) {
this.lint_attrs.push(lint_attr);
}
},
);
}
impl<S: Stage> AttributeParser<S> for LintParser {
const ATTRIBUTES: AcceptMapping<Self, S> =
&[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<AttributeKind> {
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<T: Lint, S: Stage>(
cx: &mut AcceptContext<'_, '_, S>,
args: &ArgParser,
) -> Option<LintAttribute> {
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::<Vec<_>>();
let (tool_name, tool_span, name): (Option<Symbol>, Option<Span>, _) =
if rest.is_empty() {
let name = tool_or_name.name;
(None, None, name.to_string())
} else {
let tool = tool_or_name;
let name = rest
.into_iter()
.map(|ident| ident.to_string())
.collect::<Vec<_>>()
.join("::");
(Some(tool.name), Some(tool.span), name)
};
let meta_item_span = meta_item.span();
let original_name = Symbol::intern(&name);
let mut full_name = tool_name
.map(|tool| Symbol::intern(&format!("{tool}::{}", original_name)))
.unwrap_or(original_name);
if let Some(ids) = check_lint(
cx,
lint_store,
original_name,
&mut full_name,
tool_name,
tool_span,
meta_item_span,
) {
if !targeting_crate && ids.iter().any(|lint_id| lint_id.lint.crate_level_only) {
cx.emit_lint(
UNUSED_ATTRIBUTES,
AttributeLintKind::IgnoredUnlessCrateSpecified {
level: T::ATTR_SYMBOL,
name: original_name,
},
meta_item_span,
);
}
lint_instances.extend(ids.into_iter().map(|id| {
LintInstance::new(full_name, id.to_string(), meta_item_span, lint_index)
}));
}
lint_index += 1;
}
}
}
if !skip_unused_check && !errored && lint_instances.is_empty() {
let span = cx.attr_span;
cx.adcx().warn_empty_attribute(span);
}
(!errored).then_some(LintAttribute {
reason,
lint_instances,
attr_span: cx.attr_span,
attr_style: cx.attr_style,
attr_id: HashIgnoredAttrId { attr_id: cx.attr_id },
kind: T::KIND,
})
}
fn check_lint<'a, S: Stage>(
cx: &mut AcceptContext<'_, '_, S>,
lint_store: &'a dyn DynLintStore,
original_name: Symbol,
full_name: &mut Symbol,
tool_name: Option<Symbol>,
tool_span: Option<Span>,
span: Span,
) -> Option<&'a [LintId]> {
let Some(tools) = cx.tools else {
unreachable!("tools required while parsing attributes");
};
if tools.is_empty() {
unreachable!("tools should never be empty")
}
match lint_store.check_lint_name(original_name.as_str(), tool_name, tools) {
CheckLintNameResult::Ok(ids) => Some(ids),
CheckLintNameResult::Tool(ids, new_lint_name) => {
let _name = match new_lint_name {
None => original_name,
Some(new_lint_name) => {
let new_lint_name = Symbol::intern(&new_lint_name);
cx.emit_lint(
RENAMED_AND_REMOVED_LINTS,
AttributeLintKind::DeprecatedLintName {
name: *full_name,
suggestion: span,
replace: new_lint_name,
},
span,
);
new_lint_name
}
};
Some(ids)
}
CheckLintNameResult::MissingTool => {
// If `MissingTool` is returned, then either the lint does not
// exist in the tool or the code was not compiled with the tool and
// therefore the lint was never added to the `LintStore`. To detect
// this is the responsibility of the lint tool.
None
}
CheckLintNameResult::NoTool => {
cx.emit_err(UnknownToolInScopedLint {
span: tool_span,
tool_name: tool_name.unwrap(),
full_lint_name: *full_name,
is_nightly_build: cx.sess.is_nightly_build(),
});
None
}
CheckLintNameResult::Renamed(replace) => {
cx.emit_lint(
RENAMED_AND_REMOVED_LINTS,
AttributeLintKind::RenamedLint { name: *full_name, replace, suggestion: span },
span,
);
// Since it was renamed, and we have emitted the warning
// we replace the "full_name", to ensure we don't get notes with:
// `#[allow(NEW_NAME)]` implied by `#[allow(OLD_NAME)]`
// Other lints still have access to the original name as the user wrote it,
// through `original_name`
*full_name = replace;
// If this lint was renamed, apply the new lint instead of ignoring the
// attribute. Ignore any errors or warnings that happen because the new
// name is inaccurate.
// NOTE: `new_name` already includes the tool name, so we don't
// have to add it again.
match lint_store.check_lint_name(replace.as_str(), None, tools) {
CheckLintNameResult::Ok(ids) => Some(ids),
_ => panic!("renamed lint does not exist: {replace}"),
}
}
CheckLintNameResult::RenamedToolLint(new_name) => {
cx.emit_lint(
RENAMED_AND_REMOVED_LINTS,
AttributeLintKind::RenamedLint {
name: *full_name,
replace: new_name,
suggestion: span,
},
span,
);
None
}
CheckLintNameResult::Removed(reason) => {
cx.emit_lint(
RENAMED_AND_REMOVED_LINTS,
AttributeLintKind::RemovedLint { name: *full_name, reason },
span,
);
None
}
CheckLintNameResult::NoLint(suggestion) => {
cx.emit_lint(
UNKNOWN_LINTS,
AttributeLintKind::UnknownLint { name: *full_name, suggestion, span },
span,
);
None
}
}
}
@@ -3,7 +3,6 @@
pub(crate) struct RustcAsPtrParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcAsPtrParser {
const PATH: &[Symbol] = &[sym::rustc_as_ptr];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::Inherent)),
@@ -17,7 +16,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcAsPtrParser {
pub(crate) struct RustcPubTransparentParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcPubTransparentParser {
const PATH: &[Symbol] = &[sym::rustc_pub_transparent];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Struct),
Allow(Target::Enum),
@@ -29,7 +27,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcPubTransparentParser {
pub(crate) struct RustcPassByValueParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcPassByValueParser {
const PATH: &[Symbol] = &[sym::rustc_pass_by_value];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Struct),
Allow(Target::Enum),
@@ -41,7 +38,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcPassByValueParser {
pub(crate) struct RustcShouldNotBeCalledOnConstItemsParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcShouldNotBeCalledOnConstItemsParser {
const PATH: &[Symbol] = &[sym::rustc_should_not_be_called_on_const_items];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Method(MethodKind::Inherent)),
Allow(Target::Method(MethodKind::TraitImpl)),
@@ -3,7 +3,6 @@
pub(crate) struct LoopMatchParser;
impl<S: Stage> NoArgsAttributeParser<S> for LoopMatchParser {
const PATH: &[Symbol] = &[sym::loop_match];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Expression)]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::LoopMatch;
}
@@ -11,7 +10,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for LoopMatchParser {
pub(crate) struct ConstContinueParser;
impl<S: Stage> NoArgsAttributeParser<S> for ConstContinueParser {
const PATH: &[Symbol] = &[sym::const_continue];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Expression)]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::ConstContinue;
}
@@ -167,7 +167,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
impl<S: Stage> SingleAttributeParser<S> for CollapseDebugInfoParser {
const PATH: &[Symbol] = &[sym::collapse_debuginfo];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const TEMPLATE: AttributeTemplate = template!(
List: &["no", "external", "yes"],
"https://doc.rust-lang.org/reference/attributes/debugger.html#the-collapse_debuginfo-attribute"
@@ -175,15 +174,7 @@ impl<S: Stage> SingleAttributeParser<S> for CollapseDebugInfoParser {
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::MacroDef)]);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
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 Some(mi) = single.meta_item() else {
cx.adcx().expected_not_literal(single.span());
return None;
@@ -211,7 +202,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
impl<S: Stage> NoArgsAttributeParser<S> for RustcProcMacroDeclsParser {
const PATH: &[Symbol] = &[sym::rustc_proc_macro_decls];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Static)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcProcMacroDecls;
}
@@ -18,6 +18,7 @@
use rustc_feature::{AttributeTemplate, template};
use rustc_hir::attrs::AttributeKind;
use rustc_span::edition::Edition;
use rustc_span::{Span, Symbol};
use thin_vec::ThinVec;
@@ -46,7 +47,6 @@
pub(crate) mod inline;
pub(crate) mod instruction_set;
pub(crate) mod link_attrs;
pub(crate) mod lint;
pub(crate) mod lint_helpers;
pub(crate) mod loop_match;
pub(crate) mod macro_attrs;
@@ -98,6 +98,7 @@ pub(crate) trait AttributeParser<S: Stage>: Default + 'static {
/// If an attribute has this symbol, the `accept` function will be called on it.
const ATTRIBUTES: AcceptMapping<Self, S>;
const ALLOWED_TARGETS: AllowedTargets;
const SAFETY: AttributeSafety = AttributeSafety::Normal;
/// The parser has gotten a chance to accept the attributes on an item,
/// here it can produce an attribute.
@@ -127,7 +128,8 @@ pub(crate) trait SingleAttributeParser<S: Stage>: 'static {
/// Configures what to do when when the same attribute is
/// applied more than once on the same syntax node.
const ON_DUPLICATE: OnDuplicate<S>;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const SAFETY: AttributeSafety = AttributeSafety::Normal;
const ALLOWED_TARGETS: AllowedTargets;
@@ -159,13 +161,14 @@ impl<T: SingleAttributeParser<S>, S: Stage> AttributeParser<S> for Single<T, S>
if let Some(pa) = T::convert(cx, args) {
if let Some((_, used)) = group.1 {
T::ON_DUPLICATE.exec::<T>(cx, used, cx.attr_span);
} else {
group.1 = Some((pa, cx.attr_span));
}
group.1 = Some((pa, cx.attr_span));
}
},
)];
const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS;
const SAFETY: AttributeSafety = T::SAFETY;
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
Some(self.1?.0)
@@ -218,6 +221,18 @@ fn exec<P: SingleAttributeParser<S>>(
}
}
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum AttributeSafety {
/// Normal attribute that does not need `#[unsafe(...)]`
Normal,
/// Unsafe attribute that requires safety obligations to be discharged.
///
/// An error is emitted when `#[unsafe(...)]` is omitted, except when the attribute's edition
/// is less than the one stored in `unsafe_since`. This handles attributes that were safe in
/// earlier editions, but become unsafe in later ones.
Unsafe { unsafe_since: Option<Edition> },
}
/// An even simpler version of [`SingleAttributeParser`]:
/// now automatically check that there are no arguments provided to the attribute.
///
@@ -225,8 +240,9 @@ fn exec<P: SingleAttributeParser<S>>(
//
pub(crate) trait NoArgsAttributeParser<S: Stage>: 'static {
const PATH: &[Symbol];
const ON_DUPLICATE: OnDuplicate<S>;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets;
const SAFETY: AttributeSafety = AttributeSafety::Normal;
/// Create the [`AttributeKind`] given attribute's [`Span`].
const CREATE: fn(Span) -> AttributeKind;
@@ -243,6 +259,7 @@ fn default() -> Self {
impl<T: NoArgsAttributeParser<S>, S: Stage> SingleAttributeParser<S> for WithoutArgs<T, S> {
const PATH: &[Symbol] = T::PATH;
const ON_DUPLICATE: OnDuplicate<S> = T::ON_DUPLICATE;
const SAFETY: AttributeSafety = T::SAFETY;
const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS;
const TEMPLATE: AttributeTemplate = template!(Word);
@@ -272,6 +289,7 @@ pub(crate) trait CombineAttributeParser<S: Stage>: 'static {
/// For example, individual representations from `#[repr(...)]` attributes into an `AttributeKind::Repr(x)`,
/// where `x` is a vec of these individual reprs.
const CONVERT: ConvertFn<Self::Item>;
const SAFETY: AttributeSafety = AttributeSafety::Normal;
const ALLOWED_TARGETS: AllowedTargets;
@@ -313,6 +331,7 @@ impl<T: CombineAttributeParser<S>, S: Stage> AttributeParser<S> for Combine<T, S
group.items.extend(T::extend(cx, args))
})];
const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS;
const SAFETY: AttributeSafety = T::SAFETY;
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
if let Some(first_span) = self.first_span {
@@ -4,7 +4,6 @@
impl<S: Stage> SingleAttributeParser<S> for MustNotSuspendParser {
const PATH: &[rustc_span::Symbol] = &[sym::must_not_suspend];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Struct),
Allow(Target::Enum),
@@ -2,7 +2,7 @@
use rustc_hir::attrs::AttributeKind;
use rustc_span::{Span, Symbol, sym};
use crate::attributes::{NoArgsAttributeParser, OnDuplicate};
use crate::attributes::NoArgsAttributeParser;
use crate::context::Stage;
use crate::target_checking::AllowedTargets;
use crate::target_checking::Policy::Allow;
@@ -11,7 +11,6 @@
impl<S: Stage> NoArgsAttributeParser<S> for PinV2Parser {
const PATH: &[Symbol] = &[sym::pin_v2];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Enum),
Allow(Target::Struct),
@@ -9,7 +9,6 @@
pub(crate) struct ProcMacroParser;
impl<S: Stage> NoArgsAttributeParser<S> for ProcMacroParser {
const PATH: &[Symbol] = &[sym::proc_macro];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = PROC_MACRO_ALLOWED_TARGETS;
const CREATE: fn(Span) -> AttributeKind = AttributeKind::ProcMacro;
}
@@ -17,7 +16,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for ProcMacroParser {
pub(crate) struct ProcMacroAttributeParser;
impl<S: Stage> NoArgsAttributeParser<S> for ProcMacroAttributeParser {
const PATH: &[Symbol] = &[sym::proc_macro_attribute];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = PROC_MACRO_ALLOWED_TARGETS;
const CREATE: fn(Span) -> AttributeKind = AttributeKind::ProcMacroAttribute;
}
@@ -25,7 +23,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for ProcMacroAttributeParser {
pub(crate) struct ProcMacroDeriveParser;
impl<S: Stage> SingleAttributeParser<S> for ProcMacroDeriveParser {
const PATH: &[Symbol] = &[sym::proc_macro_derive];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = PROC_MACRO_ALLOWED_TARGETS;
const TEMPLATE: AttributeTemplate = template!(
List: &["TraitName", "TraitName, attributes(name1, name2, ...)"],
@@ -45,7 +42,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
pub(crate) struct RustcBuiltinMacroParser;
impl<S: Stage> SingleAttributeParser<S> for RustcBuiltinMacroParser {
const PATH: &[Symbol] = &[sym::rustc_builtin_macro];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::MacroDef)]);
const TEMPLATE: AttributeTemplate =
template!(List: &["TraitName", "TraitName, attributes(name1, name2, ...)"]);
@@ -5,7 +5,6 @@
use rustc_hir::attrs::{AttributeKind, MirDialect, MirPhase};
use rustc_span::{Span, Symbol, sym};
use super::OnDuplicate;
use crate::attributes::SingleAttributeParser;
use crate::context::{AcceptContext, Stage};
use crate::parser::ArgParser;
@@ -18,8 +17,6 @@
impl<S: Stage> SingleAttributeParser<S> for CustomMirParser {
const PATH: &[rustc_span::Symbol] = &[sym::custom_mir];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
const TEMPLATE: AttributeTemplate = template!(List: &[r#"dialect = "...", phase = "...""#]);
@@ -82,7 +79,7 @@ fn extract_value<S: Stage>(
}
let Some(val) = arg.name_value() else {
cx.adcx().expected_single_argument(arg.span().unwrap_or(span));
cx.adcx().expected_name_value(span, Some(key));
*failed = true;
return;
};
@@ -297,7 +297,7 @@ fn parse<S: Stage>(&mut self, cx: &mut AcceptContext<'_, '_, S>, args: &ArgParse
}
ArgParser::List(list) => {
let Some(align) = list.single() else {
cx.adcx().expected_single_argument(list.span);
cx.adcx().expected_single_argument(list.span, list.len());
return;
};
@@ -4,7 +4,6 @@
impl<S: Stage> NoArgsAttributeParser<S> for RustcAllocatorParser {
const PATH: &[Symbol] = &[sym::rustc_allocator];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcAllocator;
@@ -14,7 +13,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcAllocatorParser {
impl<S: Stage> NoArgsAttributeParser<S> for RustcAllocatorZeroedParser {
const PATH: &[Symbol] = &[sym::rustc_allocator_zeroed];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcAllocatorZeroed;
@@ -24,7 +22,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcAllocatorZeroedParser {
impl<S: Stage> SingleAttributeParser<S> for RustcAllocatorZeroedVariantParser {
const PATH: &[Symbol] = &[sym::rustc_allocator_zeroed_variant];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]);
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "function");
@@ -43,7 +40,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
impl<S: Stage> NoArgsAttributeParser<S> for RustcDeallocatorParser {
const PATH: &[Symbol] = &[sym::rustc_deallocator];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDeallocator;
@@ -53,7 +49,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcDeallocatorParser {
impl<S: Stage> NoArgsAttributeParser<S> for RustcReallocatorParser {
const PATH: &[Symbol] = &[sym::rustc_reallocator];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcReallocator;
@@ -1,9 +1,8 @@
use rustc_hir::attrs::AttributeKind;
use rustc_hir::attrs::{AttributeKind, RustcDumpLayoutKind};
use rustc_hir::{MethodKind, Target};
use rustc_span::{Span, Symbol, sym};
use crate::attributes::prelude::Allow;
use crate::attributes::{NoArgsAttributeParser, OnDuplicate};
use super::prelude::*;
use crate::context::Stage;
use crate::target_checking::AllowedTargets;
@@ -11,7 +10,6 @@
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpUserArgsParser {
const PATH: &[Symbol] = &[sym::rustc_dump_user_args];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpUserArgs;
}
@@ -20,16 +18,45 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpUserArgsParser {
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpDefParentsParser {
const PATH: &[Symbol] = &[sym::rustc_dump_def_parents];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpDefParents;
}
pub(crate) struct RustcDumpDefPathParser;
impl<S: Stage> SingleAttributeParser<S> for RustcDumpDefPathParser {
const PATH: &[Symbol] = &[sym::rustc_dump_def_path];
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::TraitImpl)),
Allow(Target::Method(MethodKind::Inherent)),
Allow(Target::Method(MethodKind::Trait { body: true })),
Allow(Target::ForeignFn),
Allow(Target::ForeignStatic),
Allow(Target::Impl { of_trait: false }),
]);
const TEMPLATE: AttributeTemplate = template!(Word);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
if let Err(span) = args.no_args() {
cx.adcx().expected_no_args(span);
return None;
}
Some(AttributeKind::RustcDumpDefPath(cx.attr_span))
}
}
pub(crate) struct RustcDumpHiddenTypeOfOpaquesParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpHiddenTypeOfOpaquesParser {
const PATH: &[Symbol] = &[sym::rustc_dump_hidden_type_of_opaques];
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpHiddenTypeOfOpaques;
}
pub(crate) struct RustcDumpInferredOutlivesParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpInferredOutlivesParser {
const PATH: &[Symbol] = &[sym::rustc_dump_inferred_outlives];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Struct),
Allow(Target::Enum),
@@ -43,16 +70,78 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpInferredOutlivesParser {
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpItemBoundsParser {
const PATH: &[Symbol] = &[sym::rustc_dump_item_bounds];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::AssocTy)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpItemBounds;
}
pub(crate) struct RustcDumpLayoutParser;
impl<S: Stage> CombineAttributeParser<S> for RustcDumpLayoutParser {
const PATH: &[Symbol] = &[sym::rustc_dump_layout];
type Item = RustcDumpLayoutKind;
const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::RustcDumpLayout(items);
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Struct),
Allow(Target::Enum),
Allow(Target::Union),
Allow(Target::TyAlias),
]);
const TEMPLATE: AttributeTemplate =
template!(List: &["abi", "align", "size", "homogenous_aggregate", "debug"]);
fn extend(
cx: &mut AcceptContext<'_, '_, S>,
args: &ArgParser,
) -> impl IntoIterator<Item = Self::Item> {
let ArgParser::List(items) = args else {
let attr_span = cx.attr_span;
cx.adcx().expected_list(attr_span, args);
return vec![];
};
let mut result = Vec::new();
for item in items.mixed() {
let Some(arg) = item.meta_item() else {
cx.adcx().expected_not_literal(item.span());
continue;
};
let Some(ident) = arg.ident() else {
cx.adcx().expected_identifier(arg.span());
return vec![];
};
let kind = match ident.name {
sym::align => RustcDumpLayoutKind::Align,
sym::backend_repr => RustcDumpLayoutKind::BackendRepr,
sym::debug => RustcDumpLayoutKind::Debug,
sym::homogeneous_aggregate => RustcDumpLayoutKind::HomogenousAggregate,
sym::size => RustcDumpLayoutKind::Size,
_ => {
cx.adcx().expected_specific_argument(
ident.span,
&[
sym::align,
sym::backend_repr,
sym::debug,
sym::homogeneous_aggregate,
sym::size,
],
);
continue;
}
};
result.push(kind);
}
result
}
}
pub(crate) struct RustcDumpObjectLifetimeDefaultsParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpObjectLifetimeDefaultsParser {
const PATH: &[Symbol] = &[sym::rustc_dump_object_lifetime_defaults];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::AssocConst),
Allow(Target::AssocTy),
@@ -79,7 +168,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpObjectLifetimeDefaultsParse
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpPredicatesParser {
const PATH: &[Symbol] = &[sym::rustc_dump_predicates];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::AssocConst),
Allow(Target::AssocTy),
@@ -103,11 +191,33 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpPredicatesParser {
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpPredicates;
}
pub(crate) struct RustcDumpSymbolNameParser;
impl<S: Stage> SingleAttributeParser<S> for RustcDumpSymbolNameParser {
const PATH: &[Symbol] = &[sym::rustc_dump_symbol_name];
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::TraitImpl)),
Allow(Target::Method(MethodKind::Inherent)),
Allow(Target::Method(MethodKind::Trait { body: true })),
Allow(Target::ForeignFn),
Allow(Target::ForeignStatic),
Allow(Target::Impl { of_trait: false }),
]);
const TEMPLATE: AttributeTemplate = template!(Word);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
if let Err(span) = args.no_args() {
cx.adcx().expected_no_args(span);
return None;
}
Some(AttributeKind::RustcDumpSymbolName(cx.attr_span))
}
}
pub(crate) struct RustcDumpVariancesParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpVariancesParser {
const PATH: &[Symbol] = &[sym::rustc_dump_variances];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Enum),
Allow(Target::Fn),
@@ -125,7 +235,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpVariancesParser {
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpVariancesOfOpaquesParser {
const PATH: &[Symbol] = &[sym::rustc_dump_variances_of_opaques];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpVariancesOfOpaques;
}
@@ -134,7 +243,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpVariancesOfOpaquesParser {
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpVtableParser {
const PATH: &[Symbol] = &[sym::rustc_dump_vtable];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Impl { of_trait: true }),
Allow(Target::TyAlias),
@@ -4,14 +4,13 @@
use rustc_hir::LangItem;
use rustc_hir::attrs::{
BorrowckGraphvizFormatKind, CguFields, CguKind, DivergingBlockBehavior,
DivergingFallbackBehavior, RustcCleanAttribute, RustcCleanQueries, RustcLayoutType,
RustcMirKind,
DivergingFallbackBehavior, RustcCleanAttribute, RustcCleanQueries, RustcMirKind,
};
use rustc_session::errors;
use rustc_span::Symbol;
use super::prelude::*;
use super::util::parse_single_integer;
use crate::errors;
use crate::session_diagnostics::{
AttributeRequiresOpt, CguFieldsMissing, RustcScalableVectorCountOutOfRange, UnknownLangItem,
};
@@ -20,7 +19,6 @@
impl<S: Stage> NoArgsAttributeParser<S> for RustcMainParser {
const PATH: &[Symbol] = &[sym::rustc_main];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcMain;
}
@@ -29,7 +27,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcMainParser {
impl<S: Stage> SingleAttributeParser<S> for RustcMustImplementOneOfParser {
const PATH: &[Symbol] = &[sym::rustc_must_implement_one_of];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
const TEMPLATE: AttributeTemplate = template!(List: &["function1, function2, ..."]);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
@@ -75,7 +72,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
impl<S: Stage> NoArgsAttributeParser<S> for RustcNeverReturnsNullPtrParser {
const PATH: &[Symbol] = &[sym::rustc_never_returns_null_ptr];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::Inherent)),
@@ -89,7 +85,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcNeverReturnsNullPtrParser {
impl<S: Stage> NoArgsAttributeParser<S> for RustcNoImplicitAutorefsParser {
const PATH: &[Symbol] = &[sym::rustc_no_implicit_autorefs];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::Inherent)),
@@ -105,7 +100,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcNoImplicitAutorefsParser {
impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeStartParser {
const PATH: &[Symbol] = &[sym::rustc_layout_scalar_valid_range_start];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
const TEMPLATE: AttributeTemplate = template!(List: &["start"]);
@@ -119,7 +113,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeEndParser {
const PATH: &[Symbol] = &[sym::rustc_layout_scalar_valid_range_end];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
const TEMPLATE: AttributeTemplate = template!(List: &["end"]);
@@ -133,7 +126,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
impl<S: Stage> SingleAttributeParser<S> for RustcLegacyConstGenericsParser {
const PATH: &[Symbol] = &[sym::rustc_legacy_const_generics];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
const TEMPLATE: AttributeTemplate = template!(List: &["N"]);
@@ -177,7 +169,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
impl<S: Stage> NoArgsAttributeParser<S> for RustcInheritOverflowChecksParser {
const PATH: &[Symbol] = &[sym::rustc_inherit_overflow_checks];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::Inherent)),
@@ -191,15 +182,10 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcInheritOverflowChecksParser {
impl<S: Stage> SingleAttributeParser<S> for RustcLintOptDenyFieldAccessParser {
const PATH: &[Symbol] = &[sym::rustc_lint_opt_deny_field_access];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Field)]);
const TEMPLATE: AttributeTemplate = template!(Word);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
let Some(arg) = args.list().and_then(MetaItemListParser::single) else {
let attr_span = cx.attr_span;
cx.adcx().expected_single_argument(attr_span);
return None;
};
let arg = cx.single_element_list(args, cx.attr_span)?;
let MetaItemOrLitParser::Lit(MetaItemLit { kind: LitKind::Str(lint_message, _), .. }) = arg
else {
@@ -215,7 +201,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
impl<S: Stage> NoArgsAttributeParser<S> for RustcLintOptTyParser {
const PATH: &[Symbol] = &[sym::rustc_lint_opt_ty];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcLintOptTy;
}
@@ -364,7 +349,6 @@ fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
impl<S: Stage> SingleAttributeParser<S> for RustcDeprecatedSafe2024Parser {
const PATH: &[Symbol] = &[sym::rustc_deprecated_safe_2024];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::Inherent)),
@@ -375,19 +359,10 @@ impl<S: Stage> SingleAttributeParser<S> for RustcDeprecatedSafe2024Parser {
const TEMPLATE: AttributeTemplate = template!(List: &[r#"audit_that = "...""#]);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
let Some(args) = args.list() else {
let attr_span = cx.attr_span;
cx.adcx().expected_list(attr_span, args);
return None;
};
let Some(single) = args.single() else {
cx.adcx().expected_single_argument(args.span);
return None;
};
let single = cx.single_element_list(args, cx.attr_span)?;
let Some(arg) = single.meta_item() else {
cx.adcx().expected_name_value(args.span, None);
cx.adcx().expected_name_value(single.span(), None);
return None;
};
@@ -414,7 +389,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
impl<S: Stage> NoArgsAttributeParser<S> for RustcConversionSuggestionParser {
const PATH: &[Symbol] = &[sym::rustc_conversion_suggestion];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::Inherent)),
@@ -429,7 +403,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcConversionSuggestionParser {
impl<S: Stage> NoArgsAttributeParser<S> for RustcCaptureAnalysisParser {
const PATH: &[Symbol] = &[sym::rustc_capture_analysis];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Closure)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcCaptureAnalysis;
}
@@ -438,7 +411,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcCaptureAnalysisParser {
impl<S: Stage> SingleAttributeParser<S> for RustcNeverTypeOptionsParser {
const PATH: &[Symbol] = &[sym::rustc_never_type_options];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const TEMPLATE: AttributeTemplate = template!(List: &[
r#"fallback = "unit", "never", "no""#,
@@ -521,7 +493,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
impl<S: Stage> NoArgsAttributeParser<S> for RustcTrivialFieldReadsParser {
const PATH: &[Symbol] = &[sym::rustc_trivial_field_reads];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcTrivialFieldReads;
}
@@ -530,7 +501,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcTrivialFieldReadsParser {
impl<S: Stage> NoArgsAttributeParser<S> for RustcNoMirInlineParser {
const PATH: &[Symbol] = &[sym::rustc_no_mir_inline];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::Inherent)),
@@ -541,11 +511,25 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcNoMirInlineParser {
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNoMirInline;
}
pub(crate) struct RustcNoWritableParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcNoWritableParser {
const PATH: &[Symbol] = &[sym::rustc_no_writable];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Closure),
Allow(Target::Method(MethodKind::Inherent)),
Allow(Target::Method(MethodKind::TraitImpl)),
Allow(Target::Method(MethodKind::Trait { body: true })),
]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNoWritable;
}
pub(crate) struct RustcLintQueryInstabilityParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcLintQueryInstabilityParser {
const PATH: &[Symbol] = &[sym::rustc_lint_query_instability];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::Inherent)),
@@ -560,7 +544,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcLintQueryInstabilityParser {
impl<S: Stage> NoArgsAttributeParser<S> for RustcRegionsParser {
const PATH: &[Symbol] = &[sym::rustc_regions];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::Inherent)),
@@ -576,7 +559,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcRegionsParser {
impl<S: Stage> NoArgsAttributeParser<S> for RustcLintUntrackedQueryInformationParser {
const PATH: &[Symbol] = &[sym::rustc_lint_untracked_query_information];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::Inherent)),
@@ -592,7 +574,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcLintUntrackedQueryInformationPa
impl<S: Stage> SingleAttributeParser<S> for RustcSimdMonomorphizeLaneLimitParser {
const PATH: &[Symbol] = &[sym::rustc_simd_monomorphize_lane_limit];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
@@ -610,7 +591,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
impl<S: Stage> SingleAttributeParser<S> for RustcScalableVectorParser {
const PATH: &[Symbol] = &[sym::rustc_scalable_vector];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
const TEMPLATE: AttributeTemplate = template!(Word, List: &["count"]);
@@ -635,7 +615,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
impl<S: Stage> SingleAttributeParser<S> for LangParser {
const PATH: &[Symbol] = &[sym::lang];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); // Targets are checked per lang item in `rustc_passes`
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
@@ -661,7 +640,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
impl<S: Stage> NoArgsAttributeParser<S> for RustcHasIncoherentInherentImplsParser {
const PATH: &[Symbol] = &[sym::rustc_has_incoherent_inherent_impls];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Trait),
Allow(Target::Struct),
@@ -676,24 +654,14 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcHasIncoherentInherentImplsParse
impl<S: Stage> NoArgsAttributeParser<S> for PanicHandlerParser {
const PATH: &[Symbol] = &[sym::panic_handler];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); // Targets are checked per lang item in `rustc_passes`
const CREATE: fn(Span) -> AttributeKind = |span| AttributeKind::Lang(LangItem::PanicImpl, span);
}
pub(crate) struct RustcHiddenTypeOfOpaquesParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcHiddenTypeOfOpaquesParser {
const PATH: &[Symbol] = &[sym::rustc_hidden_type_of_opaques];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcHiddenTypeOfOpaques;
}
pub(crate) struct RustcNounwindParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcNounwindParser {
const PATH: &[Symbol] = &[sym::rustc_nounwind];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::ForeignFn),
@@ -708,69 +676,10 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcNounwindParser {
impl<S: Stage> NoArgsAttributeParser<S> for RustcOffloadKernelParser {
const PATH: &[Symbol] = &[sym::rustc_offload_kernel];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcOffloadKernel;
}
pub(crate) struct RustcLayoutParser;
impl<S: Stage> CombineAttributeParser<S> for RustcLayoutParser {
const PATH: &[Symbol] = &[sym::rustc_layout];
type Item = RustcLayoutType;
const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::RustcLayout(items);
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Struct),
Allow(Target::Enum),
Allow(Target::Union),
Allow(Target::TyAlias),
]);
const TEMPLATE: AttributeTemplate =
template!(List: &["abi", "align", "size", "homogenous_aggregate", "debug"]);
fn extend(
cx: &mut AcceptContext<'_, '_, S>,
args: &ArgParser,
) -> impl IntoIterator<Item = Self::Item> {
let ArgParser::List(items) = args else {
let attr_span = cx.attr_span;
cx.adcx().expected_list(attr_span, args);
return vec![];
};
let mut result = Vec::new();
for item in items.mixed() {
let Some(arg) = item.meta_item() else {
cx.adcx().expected_not_literal(item.span());
continue;
};
let Some(ident) = arg.ident() else {
cx.adcx().expected_identifier(arg.span());
return vec![];
};
let ty = match ident.name {
sym::abi => RustcLayoutType::Abi,
sym::align => RustcLayoutType::Align,
sym::size => RustcLayoutType::Size,
sym::homogeneous_aggregate => RustcLayoutType::HomogenousAggregate,
sym::debug => RustcLayoutType::Debug,
_ => {
cx.adcx().expected_specific_argument(
ident.span,
&[sym::abi, sym::align, sym::size, sym::homogeneous_aggregate, sym::debug],
);
continue;
}
};
result.push(ty);
}
result
}
}
pub(crate) struct RustcMirParser;
impl<S: Stage> CombineAttributeParser<S> for RustcMirParser {
@@ -865,7 +774,6 @@ fn extend(
impl<S: Stage> NoArgsAttributeParser<S> for RustcNonConstTraitMethodParser {
const PATH: &[Symbol] = &[sym::rustc_non_const_trait_method];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Method(MethodKind::Trait { body: true })),
Allow(Target::Method(MethodKind::Trait { body: false })),
@@ -984,8 +892,6 @@ fn extend(
impl<S: Stage> SingleAttributeParser<S> for RustcIfThisChangedParser {
const PATH: &[Symbol] = &[sym::rustc_if_this_changed];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
// tidy-alphabetical-start
Allow(Target::AssocConst),
@@ -1022,7 +928,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
ArgParser::List(list) => {
let Some(item) = list.single() else {
let attr_span = cx.attr_span;
cx.adcx().expected_single_argument(attr_span);
cx.adcx().expected_single_argument(attr_span, list.len());
return None;
};
let Some(ident) = item.meta_item().and_then(|item| item.ident()) else {
@@ -1082,11 +988,7 @@ fn extend(
if !cx.cx.sess.opts.unstable_opts.query_dep_graph {
cx.emit_err(AttributeRequiresOpt { span: cx.attr_span, opt: "-Z query-dep-graph" });
}
let Some(item) = args.list().and_then(|l| l.single()) else {
let inner_span = cx.inner_span;
cx.adcx().expected_single_argument(inner_span);
return None;
};
let item = cx.single_element_list(args, cx.attr_span)?;
let Some(ident) = item.meta_item().and_then(|item| item.ident()) else {
cx.adcx().expected_identifier(item.span());
return None;
@@ -1099,7 +1001,6 @@ fn extend(
impl<S: Stage> NoArgsAttributeParser<S> for RustcInsignificantDtorParser {
const PATH: &[Symbol] = &[sym::rustc_insignificant_dtor];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Enum),
Allow(Target::Struct),
@@ -1112,7 +1013,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcInsignificantDtorParser {
impl<S: Stage> NoArgsAttributeParser<S> for RustcEffectiveVisibilityParser {
const PATH: &[Symbol] = &[sym::rustc_effective_visibility];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Use),
Allow(Target::Static),
@@ -1151,7 +1051,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcEffectiveVisibilityParser {
impl<S: Stage> SingleAttributeParser<S> for RustcDiagnosticItemParser {
const PATH: &[Symbol] = &[sym::rustc_diagnostic_item];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Trait),
Allow(Target::Struct),
@@ -1190,7 +1089,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
impl<S: Stage> NoArgsAttributeParser<S> for RustcDoNotConstCheckParser {
const PATH: &[Symbol] = &[sym::rustc_do_not_const_check];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::Inherent)),
@@ -1205,64 +1103,14 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcDoNotConstCheckParser {
impl<S: Stage> NoArgsAttributeParser<S> for RustcNonnullOptimizationGuaranteedParser {
const PATH: &[Symbol] = &[sym::rustc_nonnull_optimization_guaranteed];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNonnullOptimizationGuaranteed;
}
pub(crate) struct RustcSymbolNameParser;
impl<S: Stage> SingleAttributeParser<S> for RustcSymbolNameParser {
const PATH: &[Symbol] = &[sym::rustc_symbol_name];
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::TraitImpl)),
Allow(Target::Method(MethodKind::Inherent)),
Allow(Target::Method(MethodKind::Trait { body: true })),
Allow(Target::ForeignFn),
Allow(Target::ForeignStatic),
Allow(Target::Impl { of_trait: false }),
]);
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const TEMPLATE: AttributeTemplate = template!(Word);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
if let Err(span) = args.no_args() {
cx.adcx().expected_no_args(span);
return None;
}
Some(AttributeKind::RustcSymbolName(cx.attr_span))
}
}
pub(crate) struct RustcDefPathParser;
impl<S: Stage> SingleAttributeParser<S> for RustcDefPathParser {
const PATH: &[Symbol] = &[sym::rustc_def_path];
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::TraitImpl)),
Allow(Target::Method(MethodKind::Inherent)),
Allow(Target::Method(MethodKind::Trait { body: true })),
Allow(Target::ForeignFn),
Allow(Target::ForeignStatic),
Allow(Target::Impl { of_trait: false }),
]);
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const TEMPLATE: AttributeTemplate = template!(Word);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
if let Err(span) = args.no_args() {
cx.adcx().expected_no_args(span);
return None;
}
Some(AttributeKind::RustcDefPath(cx.attr_span))
}
}
pub(crate) struct RustcStrictCoherenceParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcStrictCoherenceParser {
const PATH: &[Symbol] = &[sym::rustc_strict_coherence];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Trait),
Allow(Target::Struct),
@@ -1277,7 +1125,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcStrictCoherenceParser {
impl<S: Stage> SingleAttributeParser<S> for RustcReservationImplParser {
const PATH: &[Symbol] = &[sym::rustc_reservation_impl];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::Impl { of_trait: true })]);
@@ -1303,7 +1150,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
impl<S: Stage> NoArgsAttributeParser<S> for PreludeImportParser {
const PATH: &[Symbol] = &[sym::prelude_import];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Use)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::PreludeImport;
}
@@ -1312,7 +1158,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for PreludeImportParser {
impl<S: Stage> SingleAttributeParser<S> for RustcDocPrimitiveParser {
const PATH: &[Symbol] = &[sym::rustc_doc_primitive];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Mod)]);
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "primitive name");
@@ -1336,7 +1181,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
impl<S: Stage> NoArgsAttributeParser<S> for RustcIntrinsicParser {
const PATH: &[Symbol] = &[sym::rustc_intrinsic];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcIntrinsic;
}
@@ -1345,7 +1189,14 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcIntrinsicParser {
impl<S: Stage> NoArgsAttributeParser<S> for RustcIntrinsicConstStableIndirectParser {
const PATH: &'static [Symbol] = &[sym::rustc_intrinsic_const_stable_indirect];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcIntrinsicConstStableIndirect;
}
pub(crate) struct RustcExhaustiveParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcExhaustiveParser {
const PATH: &'static [Symbol] = &[sym::rustc_must_match_exhaustively];
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Enum)]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcMustMatchExhaustively;
}
@@ -3,7 +3,6 @@
pub(crate) struct MayDangleParser;
impl<S: Stage> NoArgsAttributeParser<S> for MayDangleParser {
const PATH: &[Symbol] = &[sym::may_dangle];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); //FIXME Still checked fully in `check_attr.rs`
const CREATE: fn(span: Span) -> AttributeKind = AttributeKind::MayDangle;
}
@@ -2,6 +2,7 @@
use rustc_errors::ErrorGuaranteed;
use rustc_feature::ACCEPTED_LANG_FEATURES;
use rustc_hir::attrs::UnstableRemovedFeature;
use rustc_hir::target::GenericParamKind;
use rustc_hir::{
DefaultBodyStability, MethodKind, PartialConstStability, Stability, StabilityLevel,
@@ -476,3 +477,89 @@ pub(crate) fn parse_unstability<S: Stage>(
(Err(ErrorGuaranteed { .. }), _) | (_, Err(ErrorGuaranteed { .. })) => None,
}
}
pub(crate) struct UnstableRemovedParser;
impl<S: Stage> CombineAttributeParser<S> for UnstableRemovedParser {
type Item = UnstableRemovedFeature;
const PATH: &[Symbol] = &[sym::unstable_removed];
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const TEMPLATE: AttributeTemplate =
template!(List: &[r#"feature = "name", reason = "...", link = "...", since = "version""#]);
const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::UnstableRemoved(items);
fn extend(
cx: &mut AcceptContext<'_, '_, S>,
args: &ArgParser,
) -> impl IntoIterator<Item = Self::Item> {
let mut feature = None;
let mut reason = None;
let mut link = None;
let mut since = None;
if !cx.features().staged_api() {
cx.emit_err(session_diagnostics::StabilityOutsideStd { span: cx.attr_span });
return None;
}
let ArgParser::List(list) = args else {
let attr_span = cx.attr_span;
cx.adcx().expected_list(attr_span, args);
return None;
};
for param in list.mixed() {
let Some(param) = param.meta_item() else {
cx.adcx().expected_not_literal(param.span());
return None;
};
let Some(word) = param.path().word() else {
cx.adcx().expected_specific_argument(
param.span(),
&[sym::feature, sym::reason, sym::link, sym::since],
);
return None;
};
match word.name {
sym::feature => insert_value_into_option_or_error(cx, &param, &mut feature, word)?,
sym::since => insert_value_into_option_or_error(cx, &param, &mut since, word)?,
sym::reason => insert_value_into_option_or_error(cx, &param, &mut reason, word)?,
sym::link => insert_value_into_option_or_error(cx, &param, &mut link, word)?,
_ => {
cx.adcx().expected_specific_argument(
param.span(),
&[sym::feature, sym::reason, sym::link, sym::since],
);
return None;
}
}
}
// Check all the arguments are present
let Some(feature) = feature else {
cx.adcx().missing_name_value(list.span, sym::feature);
return None;
};
let Some(reason) = reason else {
cx.adcx().missing_name_value(list.span, sym::reason);
return None;
};
let Some(link) = link else {
cx.adcx().missing_name_value(list.span, sym::link);
return None;
};
let Some(since) = since else {
cx.adcx().missing_name_value(list.span, sym::since);
return None;
};
let Some(version) = parse_version(since) else {
cx.emit_err(session_diagnostics::InvalidSince { span: cx.attr_span });
return None;
};
Some(UnstableRemovedFeature { feature, reason, link, since: version })
}
}
@@ -72,7 +72,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
}
ArgParser::List(list) => {
let Some(single) = list.single() else {
cx.adcx().expected_single_argument(list.span);
cx.adcx().expected_single_argument(list.span, list.len());
return None;
};
let Some(single) = single.meta_item() else {
@@ -102,7 +102,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
impl<S: Stage> SingleAttributeParser<S> for ReexportTestHarnessMainParser {
const PATH: &[Symbol] = &[sym::reexport_test_harness_main];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
@@ -129,7 +128,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
impl<S: Stage> SingleAttributeParser<S> for RustcAbiParser {
const PATH: &[Symbol] = &[sym::rustc_abi];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const TEMPLATE: AttributeTemplate = template!(OneOf: &[sym::debug, sym::assert_eq]);
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::TyAlias),
@@ -150,7 +148,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
let Some(arg) = args.single() else {
let attr_span = cx.attr_span;
cx.adcx().expected_single_argument(attr_span);
cx.adcx().expected_single_argument(attr_span, args.len());
return None;
};
@@ -179,7 +177,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
impl<S: Stage> NoArgsAttributeParser<S> for RustcDelayedBugFromInsideQueryParser {
const PATH: &[Symbol] = &[sym::rustc_delayed_bug_from_inside_query];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDelayedBugFromInsideQuery;
}
@@ -188,7 +185,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcDelayedBugFromInsideQueryParser
impl<S: Stage> NoArgsAttributeParser<S> for RustcEvaluateWhereClausesParser {
const PATH: &[Symbol] = &[sym::rustc_evaluate_where_clauses];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::Inherent)),
@@ -203,21 +199,11 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcEvaluateWhereClausesParser {
impl<S: Stage> SingleAttributeParser<S> for TestRunnerParser {
const PATH: &[Symbol] = &[sym::test_runner];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const TEMPLATE: AttributeTemplate = template!(List: &["path"]);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
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 Some(meta) = single.meta_item() else {
cx.adcx().expected_not_literal(single.span());
@@ -232,7 +218,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
impl<S: Stage> SingleAttributeParser<S> for RustcTestMarkerParser {
const PATH: &[Symbol] = &[sym::rustc_test_marker];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Const),
Allow(Target::Fn),
@@ -1,16 +1,15 @@
use std::mem;
use super::prelude::*;
use crate::attributes::{NoArgsAttributeParser, OnDuplicate, SingleAttributeParser};
use crate::attributes::{NoArgsAttributeParser, SingleAttributeParser};
use crate::context::{AcceptContext, Stage};
use crate::parser::ArgParser;
use crate::target_checking::AllowedTargets;
use crate::target_checking::Policy::{Allow, Warn};
use crate::target_checking::{ALL_TARGETS, AllowedTargets};
pub(crate) struct RustcSkipDuringMethodDispatchParser;
impl<S: Stage> SingleAttributeParser<S> for RustcSkipDuringMethodDispatchParser {
const PATH: &[Symbol] = &[sym::rustc_skip_during_method_dispatch];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
const TEMPLATE: AttributeTemplate = template!(List: &["array, boxed_slice"]);
@@ -60,7 +59,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
pub(crate) struct RustcParenSugarParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcParenSugarParser {
const PATH: &[Symbol] = &[sym::rustc_paren_sugar];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcParenSugar;
}
@@ -70,7 +68,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcParenSugarParser {
pub(crate) struct MarkerParser;
impl<S: Stage> NoArgsAttributeParser<S> for MarkerParser {
const PATH: &[Symbol] = &[sym::marker];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Trait),
Warn(Target::Field),
@@ -83,7 +80,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for MarkerParser {
pub(crate) struct RustcDenyExplicitImplParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcDenyExplicitImplParser {
const PATH: &[Symbol] = &[sym::rustc_deny_explicit_impl];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcDenyExplicitImpl;
}
@@ -91,7 +87,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcDenyExplicitImplParser {
pub(crate) struct RustcDynIncompatibleTraitParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcDynIncompatibleTraitParser {
const PATH: &[Symbol] = &[sym::rustc_dyn_incompatible_trait];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcDynIncompatibleTrait;
}
@@ -101,7 +96,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcDynIncompatibleTraitParser {
pub(crate) struct RustcSpecializationTraitParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcSpecializationTraitParser {
const PATH: &[Symbol] = &[sym::rustc_specialization_trait];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcSpecializationTrait;
}
@@ -109,7 +103,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcSpecializationTraitParser {
pub(crate) struct RustcUnsafeSpecializationMarkerParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcUnsafeSpecializationMarkerParser {
const PATH: &[Symbol] = &[sym::rustc_unsafe_specialization_marker];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcUnsafeSpecializationMarker;
}
@@ -119,7 +112,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcUnsafeSpecializationMarkerParse
pub(crate) struct RustcCoinductiveParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcCoinductiveParser {
const PATH: &[Symbol] = &[sym::rustc_coinductive];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcCoinductive;
}
@@ -127,7 +119,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcCoinductiveParser {
pub(crate) struct RustcAllowIncoherentImplParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcAllowIncoherentImplParser {
const PATH: &[Symbol] = &[sym::rustc_allow_incoherent_impl];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::Method(MethodKind::Inherent))]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcAllowIncoherentImpl;
@@ -136,16 +127,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcAllowIncoherentImplParser {
pub(crate) struct FundamentalParser;
impl<S: Stage> NoArgsAttributeParser<S> for FundamentalParser {
const PATH: &[Symbol] = &[sym::fundamental];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::Struct), Allow(Target::Trait)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::Fundamental;
}
pub(crate) struct PointeeParser;
impl<S: Stage> NoArgsAttributeParser<S> for PointeeParser {
const PATH: &[Symbol] = &[sym::pointee];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); //FIXME Still checked fully in `check_attr.rs`
const CREATE: fn(Span) -> AttributeKind = AttributeKind::Pointee;
}
@@ -41,15 +41,7 @@ pub(crate) fn parse_single_integer<S: Stage>(
cx: &mut AcceptContext<'_, '_, S>,
args: &ArgParser,
) -> Option<u128> {
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 Some(lit) = single.lit() else {
cx.adcx().expected_integer_literal(single.span());
return None;
+118 -41
View File
@@ -7,7 +7,8 @@
use private::Sealed;
use rustc_ast::{AttrStyle, MetaItemLit, NodeId};
use rustc_errors::{Diag, Diagnostic, Level};
use rustc_data_structures::sync::{DynSend, DynSync};
use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level, MultiSpan};
use rustc_feature::{AttrSuggestionStyle, AttributeTemplate};
use rustc_hir::attrs::AttributeKind;
use rustc_hir::lints::AttributeLintKind;
@@ -15,9 +16,8 @@
use rustc_parse::parser::Recovery;
use rustc_session::Session;
use rustc_session::lint::{Lint, LintId};
use rustc_span::{AttrId, ErrorGuaranteed, Span, Symbol};
use rustc_span::{ErrorGuaranteed, Span, Symbol};
use crate::AttributeParser;
// Glob imports to avoid big, bitrotty import lists
use crate::attributes::allow_unstable::*;
use crate::attributes::autodiff::*;
@@ -32,12 +32,12 @@
use crate::attributes::diagnostic::on_const::*;
use crate::attributes::diagnostic::on_move::*;
use crate::attributes::diagnostic::on_unimplemented::*;
use crate::attributes::diagnostic::on_unknown::*;
use crate::attributes::doc::*;
use crate::attributes::dummy::*;
use crate::attributes::inline::*;
use crate::attributes::instruction_set::*;
use crate::attributes::link_attrs::*;
use crate::attributes::lint::*;
use crate::attributes::lint_helpers::*;
use crate::attributes::loop_match::*;
use crate::attributes::macro_attrs::*;
@@ -59,13 +59,14 @@
use crate::attributes::test_attrs::*;
use crate::attributes::traits::*;
use crate::attributes::transparency::*;
use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs};
use crate::parser::{ArgParser, RefPathParser};
use crate::attributes::{AttributeParser as _, AttributeSafety, Combine, Single, WithoutArgs};
use crate::parser::{ArgParser, MetaItemOrLitParser, RefPathParser};
use crate::session_diagnostics::{
AttributeParseError, AttributeParseErrorReason, AttributeParseErrorSuggestions,
ParsedDescription,
};
use crate::target_checking::AllowedTargets;
use crate::{AttributeParser, EmitAttribute};
type GroupType<S> = LazyLock<GroupTypeInner<S>>;
pub(super) struct GroupTypeInner<S: Stage> {
@@ -76,6 +77,7 @@ pub(super) struct GroupTypeInnerAccept<S: Stage> {
pub(super) template: AttributeTemplate,
pub(super) accept_fn: AcceptFn<S>,
pub(super) allowed_targets: AllowedTargets,
pub(super) safety: AttributeSafety,
pub(super) finalizer: FinalizeFn<S>,
}
@@ -126,6 +128,7 @@ mod late {
accept_fn(s, cx, args)
})
}),
safety: <$names as crate::attributes::AttributeParser<$stage>>::SAFETY,
allowed_targets: <$names as crate::attributes::AttributeParser<$stage>>::ALLOWED_TARGETS,
finalizer: Box::new(|cx| {
let state = STATE_OBJECT.take();
@@ -150,12 +153,12 @@ mod late {
ConfusablesParser,
ConstStabilityParser,
DocParser,
LintParser,
MacroUseParser,
NakedParser,
OnConstParser,
OnMoveParser,
OnUnimplementedParser,
OnUnknownParser,
RustcAlignParser,
RustcAlignStaticParser,
RustcCguTestAttributeParser,
@@ -174,11 +177,12 @@ mod late {
Combine<ReprParser>,
Combine<RustcAllowConstFnUnstableParser>,
Combine<RustcCleanParser>,
Combine<RustcLayoutParser>,
Combine<RustcDumpLayoutParser>,
Combine<RustcMirParser>,
Combine<RustcThenThisWouldNeedParser>,
Combine<TargetFeatureParser>,
Combine<UnstableFeatureBoundParser>,
Combine<UnstableRemovedParser>,
// tidy-alphabetical-end
// tidy-alphabetical-start
@@ -213,11 +217,12 @@ mod late {
Single<RustcAllocatorZeroedVariantParser>,
Single<RustcAutodiffParser>,
Single<RustcBuiltinMacroParser>,
Single<RustcDefPathParser>,
Single<RustcDeprecatedSafe2024Parser>,
Single<RustcDiagnosticItemParser>,
Single<RustcDocPrimitiveParser>,
Single<RustcDummyParser>,
Single<RustcDumpDefPathParser>,
Single<RustcDumpSymbolNameParser>,
Single<RustcForceInlineParser>,
Single<RustcIfThisChangedParser>,
Single<RustcLayoutScalarValidRangeEndParser>,
@@ -233,7 +238,6 @@ mod late {
Single<RustcScalableVectorParser>,
Single<RustcSimdMonomorphizeLaneLimitParser>,
Single<RustcSkipDuringMethodDispatchParser>,
Single<RustcSymbolNameParser>,
Single<RustcTestMarkerParser>,
Single<SanitizeParser>,
Single<ShouldPanicParser>,
@@ -268,7 +272,6 @@ mod late {
Single<WithoutArgs<PanicHandlerParser>>,
Single<WithoutArgs<PanicRuntimeParser>>,
Single<WithoutArgs<PinV2Parser>>,
Single<WithoutArgs<PointeeParser>>,
Single<WithoutArgs<PreludeImportParser>>,
Single<WithoutArgs<ProcMacroAttributeParser>>,
Single<WithoutArgs<ProcMacroParser>>,
@@ -287,6 +290,7 @@ mod late {
Single<WithoutArgs<RustcDenyExplicitImplParser>>,
Single<WithoutArgs<RustcDoNotConstCheckParser>>,
Single<WithoutArgs<RustcDumpDefParentsParser>>,
Single<WithoutArgs<RustcDumpHiddenTypeOfOpaquesParser>>,
Single<WithoutArgs<RustcDumpInferredOutlivesParser>>,
Single<WithoutArgs<RustcDumpItemBoundsParser>>,
Single<WithoutArgs<RustcDumpObjectLifetimeDefaultsParser>>,
@@ -299,8 +303,8 @@ mod late {
Single<WithoutArgs<RustcEffectiveVisibilityParser>>,
Single<WithoutArgs<RustcEiiForeignItemParser>>,
Single<WithoutArgs<RustcEvaluateWhereClausesParser>>,
Single<WithoutArgs<RustcExhaustiveParser>>,
Single<WithoutArgs<RustcHasIncoherentInherentImplsParser>>,
Single<WithoutArgs<RustcHiddenTypeOfOpaquesParser>>,
Single<WithoutArgs<RustcInheritOverflowChecksParser>>,
Single<WithoutArgs<RustcInsignificantDtorParser>>,
Single<WithoutArgs<RustcIntrinsicConstStableIndirectParser>>,
@@ -313,6 +317,7 @@ mod late {
Single<WithoutArgs<RustcNoImplicitAutorefsParser>>,
Single<WithoutArgs<RustcNoImplicitBoundsParser>>,
Single<WithoutArgs<RustcNoMirInlineParser>>,
Single<WithoutArgs<RustcNoWritableParser>>,
Single<WithoutArgs<RustcNonConstTraitMethodParser>>,
Single<WithoutArgs<RustcNonnullOptimizationGuaranteedParser>>,
Single<WithoutArgs<RustcNounwindParser>>,
@@ -447,8 +452,6 @@ pub struct AcceptContext<'f, 'sess, S: Stage> {
/// The name of the attribute we're currently accepting.
pub(crate) attr_path: AttrPath,
pub(crate) attr_id: AttrId,
}
impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
@@ -459,23 +462,54 @@ pub(crate) fn emit_err(&self, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuarant
/// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing
/// must be delayed until after HIR is built. This method will take care of the details of
/// that.
pub(crate) fn emit_lint(&mut self, lint: &'static Lint, kind: AttributeLintKind, span: Span) {
pub(crate) fn emit_lint(
&mut self,
lint: &'static Lint,
kind: AttributeLintKind,
span: impl Into<MultiSpan>,
) {
self.emit_lint_inner(lint, EmitAttribute::Static(kind), span);
}
/// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing
/// must be delayed until after HIR is built. This method will take care of the details of
/// that.
pub(crate) fn emit_dyn_lint<
F: for<'a> Fn(DiagCtxtHandle<'a>, Level) -> Diag<'a, ()> + DynSend + DynSync + 'static,
>(
&mut self,
lint: &'static Lint,
callback: F,
span: impl Into<MultiSpan>,
) {
self.emit_lint_inner(lint, EmitAttribute::Dynamic(Box::new(callback)), span);
}
fn emit_lint_inner(
&mut self,
lint: &'static Lint,
kind: EmitAttribute,
span: impl Into<MultiSpan>,
) {
if !matches!(
self.stage.should_emit(),
ShouldEmit::ErrorsAndLints { .. } | ShouldEmit::EarlyFatal { also_emit_lints: true }
) {
return;
}
(self.emit_lint)(LintId::of(lint), span, kind);
(self.emit_lint)(LintId::of(lint), span.into(), kind);
}
pub(crate) fn warn_unused_duplicate(&mut self, used_span: Span, unused_span: Span) {
self.emit_lint(
self.emit_dyn_lint(
rustc_session::lint::builtin::UNUSED_ATTRIBUTES,
AttributeLintKind::UnusedDuplicate {
this: unused_span,
other: used_span,
warning: false,
move |dcx, level| {
rustc_errors::lints::UnusedDuplicate {
this: unused_span,
other: used_span,
warning: false,
}
.into_diag(dcx, level)
},
unused_span,
)
@@ -486,12 +520,15 @@ pub(crate) fn warn_unused_duplicate_future_error(
used_span: Span,
unused_span: Span,
) {
self.emit_lint(
self.emit_dyn_lint(
rustc_session::lint::builtin::UNUSED_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,
)
@@ -502,6 +539,36 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
pub(crate) fn adcx(&mut self) -> AttributeDiagnosticContext<'_, 'f, 'sess, S> {
AttributeDiagnosticContext { ctx: self, custom_suggestions: Vec::new() }
}
/// Asserts that this MetaItem is a list that contains a single element. Emits an error and
/// returns `None` if it is not the case.
///
/// Some examples:
///
/// - In `#[allow(warnings)]`, `warnings` is returned
/// - In `#[cfg_attr(docsrs, doc = "foo")]`, `None` is returned, "expected a single argument
/// here" is emitted.
/// - In `#[cfg()]`, `None` is returned, "expected an argument here" is emitted.
///
/// The provided span is used as a fallback for diagnostic generation in case `arg` does not
/// contain any. It should be the span of the node that contains `arg`.
pub(crate) fn single_element_list<'arg>(
&mut self,
arg: &'arg ArgParser,
span: Span,
) -> Option<&'arg MetaItemOrLitParser> {
let ArgParser::List(l) = arg else {
self.adcx().expected_list(span, arg);
return None;
};
let Some(single) = l.single() else {
self.adcx().expected_single_argument(l.span, l.len());
return None;
};
Some(single)
}
}
impl<'f, 'sess, S: Stage> Deref for AcceptContext<'f, 'sess, S> {
@@ -532,7 +599,7 @@ pub struct SharedContext<'p, 'sess, S: Stage> {
/// The second argument of the closure is a [`NodeId`] if `S` is `Early` and a [`HirId`] if `S`
/// is `Late` and is the ID of the syntactical component this attribute was applied to.
pub(crate) emit_lint: &'p mut dyn FnMut(LintId, Span, AttributeLintKind),
pub(crate) emit_lint: &'p mut dyn FnMut(LintId, MultiSpan, EmitAttribute),
}
/// Context given to every attribute parser during finalization.
@@ -689,6 +756,8 @@ pub(crate) fn expected_integer_literal_in_range(
)
}
/// The provided span is used as a fallback in case `args` does not contain any. It should be
/// the span of the node that contains `args`.
pub(crate) fn expected_list(&mut self, span: Span, args: &ArgParser) -> ErrorGuaranteed {
let span = match args {
ArgParser::NoArgs => span,
@@ -740,19 +809,38 @@ pub(crate) fn expected_name_value(
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedNameValue(name))
}
/// Emit an error that a `name = value` argument is missing in a list of name-value pairs.
pub(crate) fn missing_name_value(&mut self, span: Span, name: Symbol) -> ErrorGuaranteed {
self.emit_parse_error(span, AttributeParseErrorReason::MissingNameValue(name))
}
/// Emit an error that a `name = value` pair was found where that name was already seen.
pub(crate) fn duplicate_key(&mut self, span: Span, key: Symbol) -> ErrorGuaranteed {
self.emit_parse_error(span, AttributeParseErrorReason::DuplicateKey(key))
}
/// An error that should be emitted when a [`MetaItemOrLitParser`](crate::parser::MetaItemOrLitParser)
/// An error that should be emitted when a [`MetaItemOrLitParser`]
/// was expected *not* to be a literal, but instead a meta item.
pub(crate) fn expected_not_literal(&mut self, span: Span) -> ErrorGuaranteed {
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedNotLiteral)
}
pub(crate) fn expected_single_argument(&mut self, span: Span) -> ErrorGuaranteed {
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedSingleArgument)
/// Signals that we expected exactly one argument and that we got either zero or two or more.
/// The `provided_arguments` argument allows distinguishing between "expected an argument here"
/// (when zero arguments are provided) and "expect a single argument here" (when two or more
/// arguments are provided).
pub(crate) fn expected_single_argument(
&mut self,
span: Span,
provided_arguments: usize,
) -> ErrorGuaranteed {
let reason = if provided_arguments == 0 {
AttributeParseErrorReason::ExpectedArgument
} else {
AttributeParseErrorReason::ExpectedSingleArgument
};
self.emit_parse_error(span, reason)
}
pub(crate) fn expected_at_least_one_argument(&mut self, span: Span) -> ErrorGuaranteed {
@@ -808,17 +896,6 @@ pub(crate) fn expected_specific_argument_strings(
)
}
pub(crate) fn expected_nv_as_last_argument(
&mut self,
span: Span,
name_value_key: Symbol,
) -> ErrorGuaranteed {
self.emit_parse_error(
span,
AttributeParseErrorReason::ExpectedNameValueAsLastArgument { span, name_value_key },
)
}
pub(crate) fn warn_empty_attribute(&mut self, span: Span) {
let attr_path = self.attr_path.clone().to_string();
let valid_without_list = self.template.word;
+16
View File
@@ -50,3 +50,19 @@ pub(crate) struct UnreachableCfgSelectPredicateWildcard {
#[label("always matches")]
pub wildcard_span: Span,
}
#[derive(Diagnostic)]
#[diag("must be a name of an associated function")]
pub(crate) struct MustBeNameOfAssociatedFunction {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag("unsafe attribute used without unsafe")]
pub(crate) struct UnsafeAttrOutsideUnsafeLint {
#[label("usage of unsafe attribute")]
pub span: Span,
#[subdiagnostic]
pub suggestion: Option<crate::session_diagnostics::UnsafeAttrOutsideUnsafeSuggestion>,
}
+89 -78
View File
@@ -2,27 +2,37 @@
use rustc_ast as ast;
use rustc_ast::token::DocFragmentKind;
use rustc_ast::{AttrItemKind, AttrStyle, NodeId, Safety};
use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::DiagCtxtHandle;
use rustc_ast::{AttrItemKind, AttrStyle, CRATE_NODE_ID, NodeId, Safety};
use rustc_data_structures::sync::{DynSend, DynSync};
use rustc_errors::{Diag, DiagCtxtHandle, Level, MultiSpan};
use rustc_feature::{AttributeTemplate, Features};
use rustc_hir::attrs::AttributeKind;
use rustc_hir::lints::AttributeLintKind;
use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, Target};
use rustc_session::Session;
use rustc_session::lint::LintId;
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym};
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
use crate::attributes::AttributeSafety;
use crate::context::{AcceptContext, FinalizeContext, FinalizeFn, SharedContext, Stage};
use crate::early_parsed::{EARLY_PARSED_ATTRIBUTES, EarlyParsedState};
use crate::parser::{AllowExprMetavar, ArgParser, PathParser, RefPathParser};
use crate::session_diagnostics::ParsedDescription;
use crate::{Early, Late, OmitDoc, ShouldEmit};
pub enum EmitAttribute {
Static(AttributeLintKind),
Dynamic(
Box<
dyn for<'a> Fn(DiagCtxtHandle<'a>, Level) -> Diag<'a, ()> + DynSend + DynSync + 'static,
>,
),
}
/// Context created once, for example as part of the ast lowering
/// context, through which all attributes can be lowered.
pub struct AttributeParser<'sess, S: Stage = Late> {
pub(crate) tools: Option<&'sess FxIndexSet<Ident>>,
pub(crate) tools: Vec<Symbol>,
pub(crate) features: Option<&'sess Features>,
pub(crate) sess: &'sess Session,
pub(crate) stage: S,
@@ -30,7 +40,7 @@ pub struct AttributeParser<'sess, S: Stage = Late> {
/// *Only* parse attributes with this symbol.
///
/// Used in cases where we want the lowering infrastructure for parse just a single attribute.
parse_only: Option<Symbol>,
parse_only: Option<&'static [Symbol]>,
}
impl<'sess> AttributeParser<'sess, Early> {
@@ -48,36 +58,30 @@ impl<'sess> AttributeParser<'sess, Early> {
/// No diagnostics will be emitted when parsing limited. Lints are not emitted at all, while
/// errors will be emitted as a delayed bugs. in other words, we *expect* attributes parsed
/// with `parse_limited` to be reparsed later during ast lowering where we *do* emit the errors
///
/// Due to this function not taking in RegisteredTools (`FxIndexSet<Ident>`), *do not* use this for parsing any lint attributes
pub fn parse_limited(
sess: &'sess Session,
attrs: &[ast::Attribute],
sym: Symbol,
target_span: Span,
target_node_id: NodeId,
features: Option<&'sess Features>,
sym: &'static [Symbol],
) -> Option<Attribute> {
Self::parse_limited_should_emit(
sess,
attrs,
sym,
target_span,
target_node_id,
Target::Crate, // Does not matter, we're not going to emit errors anyways
features,
// Because we're not emitting warnings/errors, the target should not matter
DUMMY_SP,
CRATE_NODE_ID,
Target::Crate,
None,
ShouldEmit::Nothing,
)
}
/// This does the same as `parse_limited`, except it has a `should_emit` parameter which allows it to emit errors.
/// Usually you want `parse_limited`, which emits no errors.
///
/// Due to this function not taking in RegisteredTools (`FxIndexSet<Ident>`), *do not* use this for parsing any lint attributes
pub fn parse_limited_should_emit(
sess: &'sess Session,
attrs: &[ast::Attribute],
sym: Symbol,
sym: &'static [Symbol],
target_span: Span,
target_node_id: NodeId,
target: Target,
@@ -93,7 +97,6 @@ pub fn parse_limited_should_emit(
target_node_id,
features,
should_emit,
None,
);
assert!(parsed.len() <= 1);
parsed.pop()
@@ -106,51 +109,32 @@ pub fn parse_limited_should_emit(
/// `rustc_ast_lowering`. Some attributes require access to features to parse, which would
/// crash if you tried to do so through [`parse_limited_all`](Self::parse_limited_all).
/// Therefore, if `parse_only` is None, then features *must* be provided.
pub fn parse_limited_all<'a>(
pub fn parse_limited_all(
sess: &'sess Session,
attrs: impl IntoIterator<Item = &'a ast::Attribute>,
parse_only: Option<Symbol>,
attrs: &[ast::Attribute],
parse_only: Option<&'static [Symbol]>,
target: Target,
target_span: Span,
target_node_id: NodeId,
features: Option<&'sess Features>,
emit_errors: ShouldEmit,
tools: Option<&'sess FxIndexSet<Ident>>,
) -> Vec<Attribute> {
let mut p = Self { features, tools, parse_only, sess, stage: Early { emit_errors } };
let mut p =
Self { features, tools: Vec::new(), parse_only, sess, stage: Early { emit_errors } };
p.parse_attribute_list(
attrs,
target_span,
target,
OmitDoc::Skip,
std::convert::identity,
|lint_id, span, kind| sess.psess.buffer_lint(lint_id.lint, span, target_node_id, kind),
)
}
/// This method provides the same functionality as [`parse_limited_all`](Self::parse_limited_all) except filtered,
/// making sure that only allow-listed symbols are parsed
pub fn parse_limited_all_filtered<'a>(
sess: &'sess Session,
attrs: impl IntoIterator<Item = &'a ast::Attribute>,
filter: &[Symbol],
target: Target,
target_span: Span,
target_node_id: NodeId,
features: Option<&'sess Features>,
emit_errors: ShouldEmit,
tools: &'sess FxIndexSet<Ident>,
) -> Vec<Attribute> {
Self::parse_limited_all(
sess,
attrs.into_iter().filter(|attr| attr.has_any_name(filter)),
None,
target,
target_span,
target_node_id,
features,
emit_errors,
Some(tools),
|lint_id, span, kind| match kind {
EmitAttribute::Static(kind) => {
sess.psess.buffer_lint(lint_id.lint, span, target_node_id, kind)
}
EmitAttribute::Dynamic(callback) => {
sess.psess.dyn_buffer_lint(lint_id.lint, span, target_node_id, callback)
}
},
)
}
@@ -167,6 +151,7 @@ pub fn parse_single<T>(
parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser) -> Option<T>,
template: &AttributeTemplate,
allow_expr_metavar: AllowExprMetavar,
expected_safety: AttributeSafety,
) -> Option<T> {
let ast::AttrKind::Normal(normal_attr) = &attr.kind else {
panic!("parse_single called on a doc attr")
@@ -189,6 +174,7 @@ pub fn parse_single<T>(
attr.style,
path,
Some(normal_attr.item.unsafety),
expected_safety,
ParsedDescription::Attribute,
target_span,
target_node_id,
@@ -210,6 +196,7 @@ pub fn parse_single_args<T, I>(
attr_style: AttrStyle,
attr_path: AttrPath,
attr_safety: Option<Safety>,
expected_safety: AttributeSafety,
parsed_description: ParsedDescription,
target_span: Span,
target_node_id: NodeId,
@@ -220,15 +207,30 @@ pub fn parse_single_args<T, I>(
parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &I) -> T,
template: &AttributeTemplate,
) -> T {
let mut parser =
Self { features, tools: None, parse_only: None, sess, stage: Early { emit_errors } };
let mut emit_lint = |lint_id: LintId, span: Span, kind: AttributeLintKind| {
sess.psess.buffer_lint(lint_id.lint, span, target_node_id, kind)
let mut parser = Self {
features,
tools: Vec::new(),
parse_only: None,
sess,
stage: Early { emit_errors },
};
let mut emit_lint = |lint_id: LintId, span: MultiSpan, kind: EmitAttribute| match kind {
EmitAttribute::Static(kind) => {
sess.psess.buffer_lint(lint_id.lint, span, target_node_id, kind)
}
EmitAttribute::Dynamic(callback) => {
sess.psess.dyn_buffer_lint(lint_id.lint, span, target_node_id, callback)
}
};
if let Some(safety) = attr_safety {
parser.check_attribute_safety(&attr_path, inner_span, safety, &mut emit_lint)
parser.check_attribute_safety(
&attr_path,
inner_span,
safety,
expected_safety,
&mut emit_lint,
);
}
let attr_id = sess.psess.attr_id_generator.mk_attr_id();
let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext {
shared: SharedContext {
cx: &mut parser,
@@ -242,7 +244,6 @@ pub fn parse_single_args<T, I>(
parsed_description,
template,
attr_path,
attr_id,
};
parse_fn(&mut cx, args)
}
@@ -252,10 +253,10 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
pub fn new(
sess: &'sess Session,
features: &'sess Features,
tools: &'sess FxIndexSet<Ident>,
tools: Vec<Symbol>,
stage: S,
) -> Self {
Self { features: Some(features), tools: Some(tools), parse_only: None, sess, stage }
Self { features: Some(features), tools, parse_only: None, sess, stage }
}
pub(crate) fn sess(&self) -> &'sess Session {
@@ -278,14 +279,14 @@ pub(crate) fn dcx(&self) -> DiagCtxtHandle<'sess> {
///
/// `target_span` is the span of the thing this list of attributes is applied to,
/// and when `omit_doc` is set, doc attributes are filtered out.
pub fn parse_attribute_list<'a>(
pub fn parse_attribute_list(
&mut self,
attrs: impl IntoIterator<Item = &'a ast::Attribute>,
attrs: &[ast::Attribute],
target_span: Span,
target: Target,
omit_doc: OmitDoc,
lower_span: impl Copy + Fn(Span) -> Span,
mut emit_lint: impl FnMut(LintId, Span, AttributeLintKind),
mut emit_lint: impl FnMut(LintId, MultiSpan, EmitAttribute),
) -> Vec<Attribute> {
let mut attributes = Vec::new();
// We store the attributes we intend to discard at the end of this function in order to
@@ -296,12 +297,12 @@ pub fn parse_attribute_list<'a>(
let mut attr_paths: Vec<RefPathParser<'_>> = Vec::new();
let mut early_parsed_state = EarlyParsedState::default();
let mut finalizers: Vec<&FinalizeFn<S>> = Vec::new();
let mut finalizers: Vec<&FinalizeFn<S>> = Vec::with_capacity(attrs.len());
for attr in attrs.into_iter() {
for attr in attrs {
// If we're only looking for a single attribute, skip all the ones we don't care about.
if let Some(expected) = self.parse_only {
if !attr.has_name(expected) {
if !attr.path_matches(expected) {
continue;
}
}
@@ -343,17 +344,18 @@ pub fn parse_attribute_list<'a>(
}
};
self.check_attribute_safety(
&attr_path,
lower_span(n.item.span()),
n.item.unsafety,
&mut emit_lint,
);
let parts =
n.item.path.segments.iter().map(|seg| seg.ident.name).collect::<Vec<_>>();
if let Some(accept) = S::parsers().accepters.get(parts.as_slice()) {
self.check_attribute_safety(
&attr_path,
lower_span(n.item.span()),
n.item.unsafety,
accept.safety,
&mut emit_lint,
);
let Some(args) = ArgParser::from_attr_args(
args,
&parts,
@@ -408,7 +410,6 @@ pub fn parse_attribute_list<'a>(
parsed_description: ParsedDescription::Attribute,
template: &accept.template,
attr_path: attr_path.clone(),
attr_id: attr.id,
};
(accept.accept_fn)(&mut cx, &args);
@@ -427,6 +428,14 @@ pub fn parse_attribute_list<'a>(
span: attr_span,
};
self.check_attribute_safety(
&attr_path,
lower_span(n.item.span()),
n.item.unsafety,
AttributeSafety::Normal,
&mut emit_lint,
);
if !matches!(self.stage.should_emit(), ShouldEmit::Nothing)
&& target == Target::Crate
{
@@ -435,9 +444,11 @@ pub fn parse_attribute_list<'a>(
let attr = Attribute::Unparsed(Box::new(attr));
if self
.tools
.is_some_and(|tools| tools.iter().any(|tool| tool.name == parts[0]))
if self.tools.contains(&parts[0])
// FIXME: this can be removed once #152369 has been merged.
// https://github.com/rust-lang/rust/pull/152369
|| [sym::allow, sym::deny, sym::expect, sym::forbid, sym::warn]
.contains(&parts[0])
{
attributes.push(attr);
} else {
+2 -1
View File
@@ -106,11 +106,12 @@
mod target_checking;
pub mod validate_attr;
pub use attributes::AttributeSafety;
pub use attributes::cfg::{
CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg, parse_cfg_attr, parse_cfg_entry,
};
pub use attributes::cfg_select::*;
pub use attributes::util::{is_builtin_attr, parse_version};
pub use context::{Early, Late, OmitDoc, ShouldEmit};
pub use interface::AttributeParser;
pub use interface::{AttributeParser, EmitAttribute};
pub use session_diagnostics::ParsedDescription;
+23 -25
View File
@@ -1,13 +1,13 @@
use rustc_ast::Safety;
use rustc_feature::{AttributeSafety, BUILTIN_ATTRIBUTE_MAP};
use rustc_errors::{Diagnostic, MultiSpan};
use rustc_hir::AttrPath;
use rustc_hir::lints::AttributeLintKind;
use rustc_session::lint::LintId;
use rustc_session::lint::builtin::UNSAFE_ATTR_OUTSIDE_UNSAFE;
use rustc_span::Span;
use crate::attributes::AttributeSafety;
use crate::context::Stage;
use crate::{AttributeParser, ShouldEmit};
use crate::{AttributeParser, EmitAttribute, ShouldEmit, errors};
impl<'sess, S: Stage> AttributeParser<'sess, S> {
pub fn check_attribute_safety(
@@ -15,28 +15,23 @@ pub fn check_attribute_safety(
attr_path: &AttrPath,
attr_span: Span,
attr_safety: Safety,
emit_lint: &mut impl FnMut(LintId, Span, AttributeLintKind),
expected_safety: AttributeSafety,
emit_lint: &mut impl FnMut(LintId, MultiSpan, EmitAttribute),
) {
if matches!(self.stage.should_emit(), ShouldEmit::Nothing) {
return;
}
let name = (attr_path.segments.len() == 1).then_some(attr_path.segments[0]);
// FIXME: We should retrieve this information from the attribute parsers instead of from `BUILTIN_ATTRIBUTE_MAP`
let builtin_attr_info = name.and_then(|name| BUILTIN_ATTRIBUTE_MAP.get(&name));
let builtin_attr_safety = builtin_attr_info.map(|x| x.safety);
match (builtin_attr_safety, attr_safety) {
match (expected_safety, attr_safety) {
// - Unsafe builtin attribute
// - User wrote `#[unsafe(..)]`, which is permitted on any edition
(Some(AttributeSafety::Unsafe { .. }), Safety::Unsafe(..)) => {
(AttributeSafety::Unsafe { .. }, Safety::Unsafe(..)) => {
// OK
}
// - Unsafe builtin attribute
// - User did not write `#[unsafe(..)]`
(Some(AttributeSafety::Unsafe { unsafe_since }), Safety::Default) => {
(AttributeSafety::Unsafe { unsafe_since }, Safety::Default) => {
let path_span = attr_path.span;
// If the `attr_item`'s span is not from a macro, then just suggest
@@ -83,19 +78,25 @@ pub fn check_attribute_safety(
} else {
emit_lint(
LintId::of(UNSAFE_ATTR_OUTSIDE_UNSAFE),
path_span,
AttributeLintKind::UnsafeAttrOutsideUnsafe {
attribute_name_span: path_span,
sugg_spans: not_from_proc_macro
.then(|| (diag_span.shrink_to_lo(), diag_span.shrink_to_hi())),
},
path_span.into(),
EmitAttribute::Dynamic(Box::new(move |dcx, level| {
errors::UnsafeAttrOutsideUnsafeLint {
span: path_span,
suggestion: not_from_proc_macro
.then(|| (diag_span.shrink_to_lo(), diag_span.shrink_to_hi()))
.map(|(left, right)| {
crate::session_diagnostics::UnsafeAttrOutsideUnsafeSuggestion { left, right }
}),
}
.into_diag(dcx, level)
})),
)
}
}
// - Normal builtin attribute
// - Writing `#[unsafe(..)]` is not permitted on normal builtin attributes
(None | Some(AttributeSafety::Normal), Safety::Unsafe(unsafe_span)) => {
(AttributeSafety::Normal, Safety::Unsafe(unsafe_span)) => {
self.stage.emit_err(
self.sess,
crate::session_diagnostics::InvalidAttrUnsafe {
@@ -107,14 +108,11 @@ pub fn check_attribute_safety(
// - Normal builtin attribute
// - No explicit `#[unsafe(..)]` written.
(None | Some(AttributeSafety::Normal), Safety::Default) => {
(AttributeSafety::Normal, Safety::Default) => {
// OK
}
(
Some(AttributeSafety::Unsafe { .. } | AttributeSafety::Normal) | None,
Safety::Safe(..),
) => {
(_, Safety::Safe(..)) => {
self.sess.dcx().span_delayed_bug(
attr_span,
"`check_attribute_safety` does not expect `Safety::Safe` on attributes",
@@ -557,6 +557,7 @@ pub(crate) enum AttributeParseErrorReason<'a> {
upper_bound: isize,
},
ExpectedAtLeastOneArgument,
ExpectedArgument,
ExpectedSingleArgument,
ExpectedList,
ExpectedListOrNoArgs,
@@ -567,6 +568,7 @@ pub(crate) enum AttributeParseErrorReason<'a> {
ExpectedNonEmptyStringLiteral,
ExpectedNotLiteral,
ExpectedNameValue(Option<Symbol>),
MissingNameValue(Symbol),
DuplicateKey(Symbol),
ExpectedSpecificArgument {
possibilities: &'a [Symbol],
@@ -575,10 +577,6 @@ pub(crate) enum AttributeParseErrorReason<'a> {
list: bool,
},
ExpectedIdentifier,
ExpectedNameValueAsLastArgument {
span: Span,
name_value_key: Symbol,
},
}
/// A description of a thing that can be parsed using an attribute parser.
@@ -777,6 +775,10 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
diag.span_label(self.span, "expected a single argument here");
diag.code(E0805);
}
AttributeParseErrorReason::ExpectedArgument => {
diag.span_label(self.span, "expected an argument here");
diag.code(E0805);
}
AttributeParseErrorReason::ExpectedAtLeastOneArgument => {
diag.span_label(self.span, "expected at least 1 argument here");
}
@@ -822,6 +824,9 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
format!("expected this to be of the form `{name} = \"...\"`"),
);
}
AttributeParseErrorReason::MissingNameValue(name) => {
diag.span_label(self.span, format!("missing argument `{name} = \"...\"`"));
}
AttributeParseErrorReason::ExpectedSpecificArgument {
possibilities,
strings,
@@ -839,12 +844,6 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
AttributeParseErrorReason::ExpectedIdentifier => {
diag.span_label(self.span, "expected a valid identifier here");
}
AttributeParseErrorReason::ExpectedNameValueAsLastArgument { span, name_value_key } => {
diag.span_label(
*span,
format!("expected {name_value_key} = \"...\" to be the last argument"),
);
}
}
if let Some(link) = self.template.docs {
@@ -1138,14 +1137,3 @@ pub(crate) struct UnstableAttrForAlreadyStableFeature {
#[label("the stability attribute annotates this item")]
pub item_span: Span,
}
#[derive(Diagnostic)]
#[diag("unknown tool name `{$tool_name}` found in scoped lint: `{$full_lint_name}`", code = E0710)]
pub(crate) struct UnknownToolInScopedLint {
#[primary_span]
pub span: Option<Span>,
pub tool_name: Symbol,
pub full_lint_name: Symbol,
#[help("add `#![register_tool({$tool_name})]` to the crate root")]
pub is_nightly_build: bool,
}
@@ -1,6 +1,7 @@
//! Meta-syntax validation logic of attributes for post-expansion.
use std::convert::identity;
use std::slice;
use rustc_ast::token::Delimiter;
use rustc_ast::tokenstream::DelimSpan;
@@ -8,7 +9,7 @@
self as ast, AttrArgs, Attribute, DelimArgs, MetaItem, MetaItemInner, MetaItemKind, Safety,
};
use rustc_errors::{Applicability, PResult};
use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP};
use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, template};
use rustc_hir::AttrPath;
use rustc_hir::lints::AttributeLintKind;
use rustc_parse::parse_in;
@@ -17,23 +18,50 @@
use rustc_session::parse::ParseSess;
use rustc_span::{Span, Symbol, sym};
use crate::session_diagnostics as errors;
use crate::{AttributeParser, Late, session_diagnostics as errors};
pub fn check_attr(psess: &ParseSess, attr: &Attribute) {
// Built-in attributes are parsed in their respective attribute parsers, so can be ignored here
if attr.is_doc_comment()
|| attr.name().is_some_and(|name| BUILTIN_ATTRIBUTE_MAP.contains_key(&name))
if attr.is_doc_comment() || attr.has_name(sym::cfg_trace) || attr.has_name(sym::cfg_attr_trace)
{
return;
}
let attr_item = attr.get_normal_item();
if let AttrArgs::Eq { .. } = attr_item.args.unparsed_ref().unwrap() {
// All key-value attributes are restricted to meta-item syntax.
match parse_meta(psess, attr) {
Ok(_) => {}
Err(err) => {
err.emit();
let builtin_attr_info = attr.name().and_then(|name| BUILTIN_ATTRIBUTE_MAP.get(&name));
// Check input tokens for built-in and key-value attributes.
match builtin_attr_info {
Some(BuiltinAttribute { name, .. }) => {
if AttributeParser::<Late>::is_parsed_attribute(slice::from_ref(&name)) {
return;
}
match parse_meta(psess, attr) {
// Don't check safety again, we just did that
Ok(meta) => {
// FIXME The only unparsed builtin attributes that are left are the lint attributes, so we can hardcode the template here
let lint_attrs = [sym::forbid, sym::allow, sym::warn, sym::deny, sym::expect];
assert!(lint_attrs.contains(name));
let template = template!(
List: &["lint1", "lint1, lint2, ...", r#"lint1, lint2, lint3, reason = "...""#],
"https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
);
check_builtin_meta_item(psess, &meta, attr.style, *name, template, false)
}
Err(err) => {
err.emit();
}
}
}
_ => {
let attr_item = attr.get_normal_item();
if let AttrArgs::Eq { .. } = attr_item.args.unparsed_ref().unwrap() {
// All key-value attributes are restricted to meta-item syntax.
match parse_meta(psess, attr) {
Ok(_) => {}
Err(err) => {
err.emit();
}
}
}
}
}
@@ -451,7 +451,7 @@ fn try_extract_error_from_region_constraints<'a, 'tcx>(
(RePlaceholder(a_p), RePlaceholder(b_p)) => a_p.bound == b_p.bound,
_ => a_region == b_region,
};
let mut check = |c: &Constraint<'tcx>, cause: &SubregionOrigin<'tcx>, exact| match c.kind {
let mut check = |c: Constraint<'tcx>, cause: &SubregionOrigin<'tcx>, exact| match c.kind {
ConstraintKind::RegSubReg
if ((exact && c.sup == placeholder_region)
|| (!exact && regions_the_same(c.sup, placeholder_region)))
@@ -467,13 +467,23 @@ fn try_extract_error_from_region_constraints<'a, 'tcx>(
{
Some((c.sub, cause.clone()))
}
_ => None,
ConstraintKind::VarSubVar
| ConstraintKind::RegSubVar
| ConstraintKind::VarSubReg
| ConstraintKind::RegSubReg => None,
ConstraintKind::VarEqVar | ConstraintKind::VarEqReg | ConstraintKind::RegEqReg => {
unreachable!()
}
};
let mut find_culprit = |exact_match: bool| {
region_constraints
.constraints
.iter()
.flat_map(|(constraint, cause)| {
constraint.iter_outlives().map(move |constraint| (constraint, cause))
})
.find_map(|(constraint, cause)| check(constraint, cause, exact_match))
};
@@ -3538,6 +3538,24 @@ fn try_report_cannot_return_reference_to_local(
Applicability::MaybeIncorrect,
);
}
if let Some(cow_did) = tcx.get_diagnostic_item(sym::Cow)
&& let ty::Adt(adt_def, _) = return_ty.kind()
&& adt_def.did() == cow_did
{
if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(return_span) {
if let Some(pos) = snippet.rfind(".to_owned") {
let byte_pos = BytePos(pos as u32 + 1u32);
let to_owned_span = return_span.with_hi(return_span.lo() + byte_pos);
err.span_suggestion_short(
to_owned_span.shrink_to_hi(),
"try using `.into_owned()` if you meant to convert a `Cow<'_, T>` to an owned `T`",
"in",
Applicability::MaybeIncorrect,
);
}
}
}
}
Err(err)
@@ -4022,23 +4040,74 @@ pub(crate) fn report_illegal_reassignment(
if let Some(decl) = local_decl
&& decl.can_be_made_mutable()
{
let is_for_loop = matches!(
decl.local_info(),
LocalInfo::User(BindingForm::Var(VarBindingForm {
opt_match_place: Some((_, match_span)),
..
})) if matches!(match_span.desugaring_kind(), Some(DesugaringKind::ForLoop))
);
let message = if is_for_loop
let mut is_for_loop = false;
let mut is_ref_pattern = false;
if let LocalInfo::User(BindingForm::Var(VarBindingForm {
opt_match_place: Some((_, match_span)),
..
})) = *decl.local_info()
{
if matches!(match_span.desugaring_kind(), Some(DesugaringKind::ForLoop)) {
is_for_loop = true;
if let Some(body) = self.infcx.tcx.hir_maybe_body_owned_by(self.mir_def_id()) {
struct RefPatternFinder<'tcx> {
tcx: TyCtxt<'tcx>,
binding_span: Span,
is_ref_pattern: bool,
}
impl<'tcx> Visitor<'tcx> for RefPatternFinder<'tcx> {
type NestedFilter = OnlyBodies;
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
self.tcx
}
fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) {
if !self.is_ref_pattern
&& let hir::PatKind::Binding(_, _, ident, _) = pat.kind
&& ident.span == self.binding_span
{
self.is_ref_pattern =
self.tcx.hir_parent_iter(pat.hir_id).any(|(_, node)| {
matches!(
node,
hir::Node::Pat(hir::Pat {
kind: hir::PatKind::Ref(..),
..
})
)
});
}
hir::intravisit::walk_pat(self, pat);
}
}
let mut finder = RefPatternFinder {
tcx: self.infcx.tcx,
binding_span: decl.source_info.span,
is_ref_pattern: false,
};
finder.visit_body(body);
is_ref_pattern = finder.is_ref_pattern;
}
}
}
let (span, message) = if is_for_loop
&& is_ref_pattern
&& let Ok(binding_name) =
self.infcx.tcx.sess.source_map().span_to_snippet(decl.source_info.span)
{
format!("(mut {}) ", binding_name)
(decl.source_info.span, format!("(mut {})", binding_name))
} else {
"mut ".to_string()
(decl.source_info.span.shrink_to_lo(), "mut ".to_string())
};
err.span_suggestion_verbose(
decl.source_info.span.shrink_to_lo(),
span,
"consider making this binding mutable",
message,
Applicability::MachineApplicable,
@@ -678,7 +678,7 @@ fn closure_clause_kind(
fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diag<'_>, span: Span) {
match error {
GroupedMoveError::MovesFromPlace { mut binds_to, move_from, .. } => {
self.add_borrow_suggestions(err, span);
self.add_borrow_suggestions(err, span, !binds_to.is_empty());
if binds_to.is_empty() {
let place_ty = move_from.ty(self.body, self.infcx.tcx).ty;
let place_desc = match self.describe_place(move_from.as_ref()) {
@@ -787,29 +787,67 @@ fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diag<'_>, span
}
}
fn add_borrow_suggestions(&self, err: &mut Diag<'_>, span: Span) {
fn add_borrow_suggestions(
&self,
err: &mut Diag<'_>,
span: Span,
is_destructuring_pattern_move: bool,
) {
match self.infcx.tcx.sess.source_map().span_to_snippet(span) {
Ok(snippet) if snippet.starts_with('*') => {
let sp = span.with_lo(span.lo() + BytePos(1));
let inner = self.find_expr(sp);
let mut is_raw_ptr = false;
let mut is_ref = false;
let mut is_destructuring_assignment = false;
let mut is_nested_deref = false;
if let Some(inner) = inner {
is_nested_deref =
matches!(inner.kind, hir::ExprKind::Unary(hir::UnOp::Deref, _));
let typck_result = self.infcx.tcx.typeck(self.mir_def_id());
if let Some(inner_type) = typck_result.node_type_opt(inner.hir_id) {
if matches!(inner_type.kind(), ty::RawPtr(..)) {
is_raw_ptr = true;
} else if matches!(inner_type.kind(), ty::Ref(..)) {
is_ref = true;
}
}
is_destructuring_assignment =
self.infcx.tcx.hir_parent_iter(inner.hir_id).any(|(_, node)| {
matches!(
node,
hir::Node::LetStmt(&hir::LetStmt {
source: hir::LocalSource::AssignDesugar,
..
})
)
});
}
// If the `inner` is a raw pointer, do not suggest removing the "*", see #126863
// FIXME: need to check whether the assigned object can be a raw pointer, see `tests/ui/borrowck/issue-20801.rs`.
if !is_raw_ptr {
if is_raw_ptr {
return;
}
if !is_destructuring_pattern_move || is_ref {
err.span_suggestion_verbose(
span.with_hi(span.lo() + BytePos(1)),
"consider removing the dereference here",
String::new(),
Applicability::MaybeIncorrect,
);
} else if !is_destructuring_assignment && !is_nested_deref {
err.span_suggestion_verbose(
span.shrink_to_lo(),
"consider borrowing here",
'&',
Applicability::MaybeIncorrect,
);
} else {
err.span_help(
span,
"destructuring assignment cannot borrow from this expression; consider using a `let` binding instead",
);
}
}
_ => {
@@ -493,7 +493,7 @@ pub(crate) fn report_mutability_error(
for (_, node) in self.infcx.tcx.hir_parent_iter(upvar_hir_id) {
if let Some(fn_decl) = node.fn_decl() {
if !matches!(
fn_decl.implicit_self,
fn_decl.implicit_self(),
hir::ImplicitSelfKind::RefImm | hir::ImplicitSelfKind::RefMut
) {
err.span_suggestion_verbose(
@@ -810,7 +810,7 @@ fn is_error_in_trait(&self, local: Local) -> (bool, bool, Option<Span>) {
&& let Some(ty) = sig.decl.inputs.get(local.index() - 1)
&& let hir::TyKind::Ref(_, mut_ty) = ty.kind
&& let hir::Mutability::Not = mut_ty.mutbl
&& sig.decl.implicit_self.has_implicit_self()
&& sig.decl.implicit_self().has_implicit_self()
{
Some(ty.span)
} else {
@@ -1147,7 +1147,7 @@ fn expected_fn_found_fn_mut_call(&self, err: &mut Diag<'_>, sp: Span, act: &str)
arg_pos
.and_then(|pos| {
sig.decl.inputs.get(
pos + if sig.decl.implicit_self.has_implicit_self() {
pos + if sig.decl.implicit_self().has_implicit_self() {
1
} else {
0
@@ -1410,9 +1410,20 @@ fn suggest_make_local_mut(&self, err: &mut Diag<'_>, local: Local, name: Symbol)
(span, " mut".to_owned(), true)
// If there is already a binding, we modify it to be `mut`.
} else if binding_exists {
// Shrink the span to just after the `&` in `&variable`.
let span = span.with_lo(span.lo() + BytePos(1)).shrink_to_lo();
(span, "mut ".to_owned(), true)
// Replace the sigil with the mutable version. We may be dealing
// with parser recovery here and cannot assume the user actually
// typed `&` or `*const`, so we compute the prefix from the snippet.
let Ok(src) = self.infcx.tcx.sess.source_map().span_to_snippet(span) else {
return;
};
let (prefix_len, replacement) = if local_decl.ty.is_ref() {
(src.chars().next().map_or(0, char::len_utf8), "&mut ")
} else {
(src.find("const").map_or(1, |i| i + "const".len()), "*mut ")
};
let ws_len = src[prefix_len..].len() - src[prefix_len..].trim_start().len();
let span = span.with_hi(span.lo() + BytePos((prefix_len + ws_len) as u32));
(span, replacement.to_owned(), true)
} else {
// Otherwise, suggest that the user annotates the binding; We provide the
// type of the local.
@@ -219,12 +219,12 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for FindOpaqueRegion<'_, 'tcx> {
fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
// If we find an opaque in a local ty, then for each of its captured regions,
// try to find a path between that captured regions and our borrow region...
if let ty::Alias(opaque @ ty::AliasTy { kind: ty::Opaque { def_id }, .. }) = *ty.kind()
if let ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) = *ty.kind()
&& let hir::OpaqueTyOrigin::FnReturn { parent, in_trait_or_impl: None } =
self.tcx.opaque_ty_origin(def_id)
{
let variances = self.tcx.variances_of(def_id);
for (idx, (arg, variance)) in std::iter::zip(opaque.args, variances).enumerate() {
for (idx, (arg, variance)) in std::iter::zip(args, variances).enumerate() {
// Skip uncaptured args.
if *variance == ty::Bivariant {
continue;
@@ -276,12 +276,12 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for CheckExplicitRegionMentionAndCollectGen
fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
match *ty.kind() {
ty::Alias(opaque @ ty::AliasTy { kind: ty::Opaque { def_id }, .. }) => {
ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) => {
if self.seen_opaques.insert(def_id) {
for (bound, _) in self
.tcx
.explicit_item_bounds(def_id)
.iter_instantiated_copied(self.tcx, opaque.args)
.iter_instantiated_copied(self.tcx, args)
{
bound.visit_with(self)?;
}
@@ -15,7 +15,8 @@
use rustc_middle::hir::place::PlaceBase;
use rustc_middle::mir::{AnnotationSource, ConstraintCategory, ReturnConstraint};
use rustc_middle::ty::{
self, GenericArgs, Region, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitor, fold_regions,
self, FnSigKind, GenericArgs, Region, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitor,
fold_regions,
};
use rustc_span::{Ident, Span, kw};
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
@@ -686,6 +687,8 @@ fn report_escaping_data_error(&self, errci: &ErrorConstraintInfo<'tcx>) -> Diag<
|| (*category == ConstraintCategory::Assignment
&& self.regioncx.universal_regions().defining_ty.is_fn_def())
|| self.regioncx.universal_regions().defining_ty.is_const()
|| (fr_name_and_span.is_none()
&& self.regioncx.universal_regions().defining_ty.is_fn_def())
{
return self.report_general_error(errci);
}
@@ -1081,14 +1084,14 @@ fn suggest_deref_closure_return(&self, diag: &mut Diag<'_>) {
}
// Build a new closure where the return type is an owned value, instead of a ref.
let fn_sig_kind =
FnSigKind::default().set_safe(true).set_c_variadic(liberated_sig.c_variadic());
let closure_sig_as_fn_ptr_ty = Ty::new_fn_ptr(
tcx,
ty::Binder::dummy(tcx.mk_fn_sig(
liberated_sig.inputs().iter().copied(),
peeled_ty,
liberated_sig.c_variadic,
hir::Safety::Safe,
rustc_abi::ExternAbi::Rust,
fn_sig_kind,
)),
);
let closure_ty = Ty::new_closure(
@@ -70,12 +70,14 @@ pub(crate) fn new(
#[instrument(skip(self), level = "debug")]
pub(super) fn convert_all(&mut self, query_constraints: &QueryRegionConstraints<'tcx>) {
let QueryRegionConstraints { outlives, assumptions } = query_constraints;
let QueryRegionConstraints { constraints, assumptions } = query_constraints;
let assumptions =
elaborate::elaborate_outlives_assumptions(self.infcx.tcx, assumptions.iter().copied());
for &(predicate, constraint_category) in outlives {
self.convert(predicate, constraint_category, &assumptions);
for &(constraint, constraint_category) in constraints {
constraint.iter_outlives().for_each(|predicate| {
self.convert(predicate, constraint_category, &assumptions);
});
}
}
@@ -292,8 +294,12 @@ fn normalize_and_add_type_outlives_constraints(
) {
Ok(TypeOpOutput { output: ty, constraints, .. }) => {
// FIXME(higher_ranked_auto): What should we do with the assumptions here?
if let Some(QueryRegionConstraints { outlives, assumptions: _ }) = constraints {
next_outlives_predicates.extend(outlives.iter().copied());
if let Some(QueryRegionConstraints { constraints, assumptions: _ }) = constraints {
next_outlives_predicates.extend(constraints.iter().flat_map(
|(constraint, category)| {
constraint.iter_outlives().map(|outlives| (outlives, *category))
},
));
}
ty
}
@@ -32,6 +32,15 @@ pub(super) fn check_signature_annotation(&mut self) {
return;
}
// If the MIR body was constructed via `construct_error` (because an
// earlier pass like match checking failed), its args may not match
// the user-provided signature (e.g. a coroutine with too many
// parameters). Bail out as this can cause panic,
// see <https://github.com/rust-lang/rust/issues/139570>.
if self.body.tainted_by_errors.is_some() {
return;
}
let user_provided_poly_sig = self.tcx().closure_user_provided_sig(mir_def_id);
// Instantiate the canonicalized variables from user-provided signature
@@ -94,9 +103,7 @@ pub(super) fn check_signature_annotation(&mut self) {
user_provided_sig = self.tcx().mk_fn_sig(
user_provided_sig.inputs().iter().copied(),
output_ty,
user_provided_sig.c_variadic,
user_provided_sig.safety,
user_provided_sig.abi,
user_provided_sig.fn_sig_kind,
);
}
@@ -1015,7 +1015,7 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
if let ty::FnDef(def_id, _) = *src_ty.kind()
&& let ty::FnPtr(_, target_hdr) = *ty.kind()
&& tcx.codegen_fn_attrs(def_id).safe_target_features
&& target_hdr.safety.is_safe()
&& target_hdr.safety().is_safe()
&& let Some(safe_sig) = tcx.adjust_target_feature_sig(
def_id,
src_sig,
@@ -1971,7 +1971,8 @@ fn check_call_inputs(
term_location: Location,
call_source: CallSource,
) {
if args.len() < sig.inputs().len() || (args.len() > sig.inputs().len() && !sig.c_variadic) {
if args.len() < sig.inputs().len() || (args.len() > sig.inputs().len() && !sig.c_variadic())
{
span_mirbug!(self, term, "call to {:?} with wrong # of args", sig);
}
+1 -1
View File
@@ -29,7 +29,7 @@ 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
+3 -1
View File
@@ -6,7 +6,8 @@
use rustc_ast::{AttrStyle, token};
use rustc_attr_parsing::parser::{AllowExprMetavar, MetaItemOrLitParser};
use rustc_attr_parsing::{
self as attr, AttributeParser, CFG_TEMPLATE, ParsedDescription, ShouldEmit, parse_cfg_entry,
self as attr, AttributeParser, AttributeSafety, CFG_TEMPLATE, ParsedDescription, ShouldEmit,
parse_cfg_entry,
};
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
use rustc_hir::attrs::CfgEntry;
@@ -53,6 +54,7 @@ fn parse_cfg(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream) -> Result<CfgEntry,
AttrStyle::Inner,
AttrPath { segments: vec![sym::cfg].into_boxed_slice(), span },
None,
AttributeSafety::Normal,
ParsedDescription::Macro,
span,
cx.current_expansion.lint_node_id,
@@ -493,7 +493,7 @@ pub(crate) fn expand_ext(
match item {
Annotatable::Item(item) => {
let is_packed = matches!(
AttributeParser::parse_limited(cx.sess, &item.attrs, sym::repr, item.span, item.id, None),
AttributeParser::parse_limited(cx.sess, &item.attrs, &[sym::repr]),
Some(Attribute::Parsed(AttributeKind::Repr { reprs, .. })) if reprs.iter().any(|(x, _)| matches!(x, ReprPacked(..)))
);
+119 -59
View File
@@ -1,7 +1,8 @@
use rustc_ast::token::{Delimiter, TokenKind};
use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
use rustc_ast::{
Attribute, DUMMY_NODE_ID, EiiDecl, EiiImpl, ItemKind, MetaItem, Path, StmtKind, Visibility, ast,
Attribute, DUMMY_NODE_ID, EiiDecl, EiiImpl, ItemKind, MetaItem, Mutability, Path, StmtKind,
Visibility, ast,
};
use rustc_ast_pretty::pprust::path_to_string;
use rustc_expand::base::{Annotatable, ExtCtxt};
@@ -10,8 +11,9 @@
use crate::errors::{
EiiExternTargetExpectedList, EiiExternTargetExpectedMacro, EiiExternTargetExpectedUnsafe,
EiiMacroExpectedMaxOneArgument, EiiOnlyOnce, EiiSharedMacroExpectedFunction,
EiiSharedMacroInStatementPosition,
EiiMacroExpectedMaxOneArgument, EiiOnlyOnce, EiiSharedMacroInStatementPosition,
EiiSharedMacroTarget, EiiStaticArgumentRequired, EiiStaticDefault,
EiiStaticMultipleImplementations, EiiStaticMutable,
};
/// ```rust
@@ -73,44 +75,72 @@ fn eii_(
});
return vec![orig_item];
} else {
ecx.dcx().emit_err(EiiSharedMacroExpectedFunction {
ecx.dcx().emit_err(EiiSharedMacroTarget {
span: eii_attr_span,
name: path_to_string(&meta_item.path),
});
return vec![orig_item];
};
let ast::Item { attrs, id: _, span: _, vis, kind: ItemKind::Fn(func), tokens: _ } =
item.as_ref()
else {
ecx.dcx().emit_err(EiiSharedMacroExpectedFunction {
span: eii_attr_span,
name: path_to_string(&meta_item.path),
});
return vec![Annotatable::Item(item)];
let ast::Item { attrs, id: _, span: _, vis, kind, tokens: _ } = item.as_ref();
let (item_span, foreign_item_name) = match kind {
ItemKind::Fn(func) => (func.sig.span, func.ident),
ItemKind::Static(stat) => {
// Statics with a default are not supported yet
if let Some(stat_body) = &stat.expr {
ecx.dcx().emit_err(EiiStaticDefault {
span: stat_body.span,
name: path_to_string(&meta_item.path),
});
return vec![];
}
// Statics must have an explicit name for the eii
if meta_item.is_word() {
ecx.dcx().emit_err(EiiStaticArgumentRequired {
span: eii_attr_span,
name: path_to_string(&meta_item.path),
});
return vec![];
}
// Mut statics are currently not supported
if stat.mutability == Mutability::Mut {
ecx.dcx().emit_err(EiiStaticMutable {
span: eii_attr_span,
name: path_to_string(&meta_item.path),
});
}
(item.span, stat.ident)
}
_ => {
ecx.dcx().emit_err(EiiSharedMacroTarget {
span: eii_attr_span,
name: path_to_string(&meta_item.path),
});
return vec![Annotatable::Item(item)];
}
};
// only clone what we need
let attrs = attrs.clone();
let func = (**func).clone();
let vis = vis.clone();
let attrs_from_decl =
filter_attrs_for_multiple_eii_attr(ecx, attrs, eii_attr_span, &meta_item.path);
let Ok(macro_name) = name_for_impl_macro(ecx, &func, &meta_item) else {
let Ok(macro_name) = name_for_impl_macro(ecx, foreign_item_name, &meta_item) else {
// we don't need to wrap in Annotatable::Stmt conditionally since
// EII can't be used on items in statement position
return vec![Annotatable::Item(item)];
};
// span of the declaring item without attributes
let item_span = func.sig.span;
let foreign_item_name = func.ident;
let mut module_items = Vec::new();
if func.body.is_some() {
module_items.push(generate_default_impl(
if let ItemKind::Fn(func) = kind
&& func.body.is_some()
{
module_items.push(generate_default_func_impl(
ecx,
&func,
impl_unsafe,
@@ -125,7 +155,7 @@ fn eii_(
ecx,
eii_attr_span,
item_span,
func,
kind,
vis,
&attrs_from_decl,
));
@@ -148,11 +178,11 @@ fn eii_(
/// declaration of the EII.
fn name_for_impl_macro(
ecx: &mut ExtCtxt<'_>,
func: &ast::Fn,
item_ident: Ident,
meta_item: &MetaItem,
) -> Result<Ident, ErrorGuaranteed> {
if meta_item.is_word() {
Ok(func.ident)
Ok(item_ident)
} else if let Some([first]) = meta_item.meta_item_list()
&& let Some(m) = first.meta_item()
&& m.path.segments.len() == 1
@@ -190,7 +220,7 @@ fn filter_attrs_for_multiple_eii_attr(
.collect()
}
fn generate_default_impl(
fn generate_default_func_impl(
ecx: &mut ExtCtxt<'_>,
func: &ast::Fn,
impl_unsafe: bool,
@@ -257,7 +287,7 @@ fn generate_foreign_item(
ecx: &mut ExtCtxt<'_>,
eii_attr_span: Span,
item_span: Span,
mut func: ast::Fn,
item_kind: &ItemKind,
vis: Visibility,
attrs_from_decl: &[Attribute],
) -> Box<ast::Item> {
@@ -268,30 +298,21 @@ fn generate_foreign_item(
// This attribute makes sure that we later know that this foreign item's symbol should not be.
foreign_item_attrs.push(ecx.attr_word(sym::rustc_eii_foreign_item, eii_attr_span));
let abi = match func.sig.header.ext {
// extern "X" fn => extern "X" {}
ast::Extern::Explicit(lit, _) => Some(lit),
// extern fn => extern {}
ast::Extern::Implicit(_) => None,
// fn => extern "Rust" {}
ast::Extern::None => Some(ast::StrLit {
symbol: sym::Rust,
suffix: None,
symbol_unescaped: sym::Rust,
style: ast::StrStyle::Cooked,
span: eii_attr_span,
}),
// We set the abi to the default "rust" abi, which can be overridden by `generate_foreign_func`,
// if a specific abi was specified on the EII function
let mut abi = Some(ast::StrLit {
symbol: sym::Rust,
suffix: None,
symbol_unescaped: sym::Rust,
style: ast::StrStyle::Cooked,
span: eii_attr_span,
});
let foreign_kind = match item_kind {
ItemKind::Fn(func) => generate_foreign_func(func.clone(), &mut abi),
ItemKind::Static(stat) => generate_foreign_static(stat.clone()),
_ => unreachable!("Target was checked earlier"),
};
// ABI has been moved to the extern {} block, so we remove it from the fn item.
func.sig.header.ext = ast::Extern::None;
func.body = None;
// And mark safe functions explicitly as `safe fn`.
if func.sig.header.safety == ast::Safety::Default {
func.sig.header.safety = ast::Safety::Safe(func.sig.span);
}
ecx.item(
eii_attr_span,
ThinVec::new(),
@@ -304,13 +325,46 @@ fn generate_foreign_item(
id: ast::DUMMY_NODE_ID,
span: item_span,
vis,
kind: ast::ForeignItemKind::Fn(Box::new(func.clone())),
kind: foreign_kind,
tokens: None,
})]),
}),
)
}
fn generate_foreign_func(
mut func: Box<ast::Fn>,
abi: &mut Option<ast::StrLit>,
) -> ast::ForeignItemKind {
match func.sig.header.ext {
// extern "X" fn => extern "X" {}
ast::Extern::Explicit(lit, _) => *abi = Some(lit),
// extern fn => extern {}
ast::Extern::Implicit(_) => *abi = None,
// no abi was specified, so we keep the default
ast::Extern::None => {}
};
// ABI has been moved to the extern {} block, so we remove it from the fn item.
func.sig.header.ext = ast::Extern::None;
func.body = None;
// And mark safe functions explicitly as `safe fn`.
if func.sig.header.safety == ast::Safety::Default {
func.sig.header.safety = ast::Safety::Safe(func.sig.span);
}
ast::ForeignItemKind::Fn(func)
}
fn generate_foreign_static(mut stat: Box<ast::StaticItem>) -> ast::ForeignItemKind {
if stat.safety == ast::Safety::Default {
stat.safety = ast::Safety::Safe(stat.ident.span);
}
ast::ForeignItemKind::Static(stat)
}
/// Generate a stub macro (a bit like in core) that will roughly look like:
///
/// ```rust, ignore, example
@@ -453,19 +507,25 @@ pub(crate) fn eii_shared_macro(
{
item
} else {
ecx.dcx().emit_err(EiiSharedMacroExpectedFunction {
span,
name: path_to_string(&meta_item.path),
});
ecx.dcx().emit_err(EiiSharedMacroTarget { span, name: path_to_string(&meta_item.path) });
return vec![item];
};
let ItemKind::Fn(f) = &mut i.kind else {
ecx.dcx().emit_err(EiiSharedMacroExpectedFunction {
span,
name: path_to_string(&meta_item.path),
});
return vec![item];
let eii_impls = match &mut i.kind {
ItemKind::Fn(func) => &mut func.eii_impls,
ItemKind::Static(stat) => {
if !stat.eii_impls.is_empty() {
// Reject multiple implementations on one static item
// because it might be unintuitive for libraries defining statics the defined statics may alias
ecx.dcx().emit_err(EiiStaticMultipleImplementations { span });
}
&mut stat.eii_impls
}
_ => {
ecx.dcx()
.emit_err(EiiSharedMacroTarget { span, name: path_to_string(&meta_item.path) });
return vec![item];
}
};
let is_default = if meta_item.is_word() {
@@ -483,7 +543,7 @@ pub(crate) fn eii_shared_macro(
return vec![item];
};
f.eii_impls.push(EiiImpl {
eii_impls.push(EiiImpl {
node_id: DUMMY_NODE_ID,
inner_span: meta_item.path.span,
eii_macro_path: meta_item.path.clone(),
+46 -2
View File
@@ -158,6 +158,16 @@ pub(crate) struct AllocMustStatics {
pub(crate) span: Span,
}
#[derive(Diagnostic)]
#[diag("allocators cannot be `#[thread_local]`")]
pub(crate) struct AllocCannotThreadLocal {
#[primary_span]
pub(crate) span: Span,
#[label("marked `#[thread_local]` here")]
#[suggestion("remove this attribute", code = "", applicability = "maybe-incorrect")]
pub(crate) attr: Span,
}
pub(crate) use autodiff::*;
mod autodiff {
@@ -1107,8 +1117,42 @@ pub(crate) struct EiiExternTargetExpectedUnsafe {
}
#[derive(Diagnostic)]
#[diag("`#[{$name}]` is only valid on functions")]
pub(crate) struct EiiSharedMacroExpectedFunction {
#[diag("`#[{$name}]` is only valid on functions and statics")]
pub(crate) struct EiiSharedMacroTarget {
#[primary_span]
pub span: Span,
pub name: String,
}
#[derive(Diagnostic)]
#[diag("static cannot implement multiple EIIs")]
#[note(
"this is not allowed because multiple externally implementable statics that alias may be unintuitive"
)]
pub(crate) struct EiiStaticMultipleImplementations {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag("`#[{$name}]` cannot be used on statics with a value")]
pub(crate) struct EiiStaticDefault {
#[primary_span]
pub span: Span,
pub name: String,
}
#[derive(Diagnostic)]
#[diag("`#[{$name}]` requires the name as an explicit argument when used on a static")]
pub(crate) struct EiiStaticArgumentRequired {
#[primary_span]
pub span: Span,
pub name: String,
}
#[derive(Diagnostic)]
#[diag("`#[{$name}]` cannot be used on mutable statics")]
pub(crate) struct EiiStaticMutable {
#[primary_span]
pub span: Span,
pub name: String,
@@ -38,6 +38,12 @@ pub(crate) fn expand(
return vec![orig_item];
};
// Forbid `#[thread_local]` attributes on the item
if let Some(attr) = item.attrs.iter().find(|x| x.has_name(sym::thread_local)) {
ecx.dcx().emit_err(errors::AllocCannotThreadLocal { span: item.span, attr: attr.span });
return vec![orig_item];
}
// Generate a bunch of new items using the AllocFnFactory
let span = ecx.with_def_site_ctxt(item.span);
let f = AllocFnFactory { span, ty_span, global: ident, cx: ecx };
@@ -80,6 +80,7 @@ fn pat_to_ty_pat(cx: &mut ExtCtxt<'_>, pat: ast::Pat) -> TyPat {
TyPatKind::Or(variants.into_iter().map(|pat| pat_to_ty_pat(cx, pat)).collect())
}
ast::PatKind::Err(guar) => TyPatKind::Err(guar),
ast::PatKind::Paren(p) => pat_to_ty_pat(cx, *p).kind,
_ => TyPatKind::Err(cx.dcx().span_err(pat.span, "pattern not supported in pattern types")),
};
ty_pat(kind, pat.span)
@@ -1,7 +1,7 @@
use std::{mem, slice};
use rustc_ast::visit::{self, Visitor};
use rustc_ast::{self as ast, HasNodeId, NodeId, attr};
use rustc_ast::{self as ast, NodeId, attr};
use rustc_ast_pretty::pprust;
use rustc_attr_parsing::AttributeParser;
use rustc_errors::DiagCtxtHandle;
@@ -108,10 +108,7 @@ fn collect_custom_derive(
})) = AttributeParser::parse_limited(
self.session,
slice::from_ref(attr),
sym::proc_macro_derive,
item.span,
item.node_id(),
None,
&[sym::proc_macro_derive],
)
else {
return;
+2 -9
View File
@@ -3,7 +3,7 @@
use std::{assert_matches, iter};
use rustc_ast::{self as ast, GenericParamKind, HasNodeId, attr, join_path_idents};
use rustc_ast::{self as ast, GenericParamKind, attr, join_path_idents};
use rustc_ast_pretty::pprust;
use rustc_attr_parsing::AttributeParser;
use rustc_errors::{Applicability, Diag, Level};
@@ -480,14 +480,7 @@ fn should_ignore_message(i: &ast::Item) -> Option<Symbol> {
fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic {
if let Some(Attribute::Parsed(AttributeKind::ShouldPanic { reason, .. })) =
AttributeParser::parse_limited(
cx.sess,
&i.attrs,
sym::should_panic,
i.span,
i.node_id(),
None,
)
AttributeParser::parse_limited(cx.sess, &i.attrs, &[sym::should_panic])
{
ShouldPanic::Yes(reason)
} else {
@@ -61,7 +61,7 @@ pub fn inject(
// Do this here so that the test_runner crate attribute gets marked as used
// even in non-test builds
let test_runner = get_test_runner(sess, features, krate);
let test_runner = get_test_runner(sess, krate);
if sess.is_test_crate() {
let panic_strategy = match (panic_strategy, sess.opts.unstable_opts.panic_abort_tests) {
@@ -387,15 +387,8 @@ fn get_test_name(i: &ast::Item) -> Option<Symbol> {
attr::first_attr_value_str_by_name(&i.attrs, sym::rustc_test_marker)
}
fn get_test_runner(sess: &Session, features: &Features, krate: &ast::Crate) -> Option<ast::Path> {
match AttributeParser::parse_limited(
sess,
&krate.attrs,
sym::test_runner,
krate.spans.inner_span,
krate.id,
Some(features),
) {
fn get_test_runner(sess: &Session, krate: &ast::Crate) -> Option<ast::Path> {
match AttributeParser::parse_limited(sess, &krate.attrs, &[sym::test_runner]) {
Some(rustc_hir::Attribute::Parsed(AttributeKind::TestRunner(path))) => Some(path),
_ => None,
}
@@ -8,6 +8,7 @@
rustc_attrs,
rustc_private,
transparent_unions,
pattern_types,
auto_traits,
freeze_impls
)]
@@ -15,6 +16,30 @@
#![no_core]
#![allow(dead_code, internal_features, ambiguous_wide_pointer_comparisons)]
#[lang = "pointee_trait"]
pub trait Pointee: PointeeSized {
#[lang = "metadata_type"]
// needed so that layout_of will return `TooGeneric` instead of `Unknown`
// when asked for the layout of `*const T`. Which is important for making
// transmutes between raw pointers (and especially pattern types of raw pointers)
// work.
type Metadata: Copy + Sync + Unpin + Freeze;
}
#[lang = "dyn_metadata"]
pub struct DynMetadata<Dyn: PointeeSized> {
_vtable_ptr: NonNull<VTable>,
_phantom: PhantomData<Dyn>,
}
unsafe extern "C" {
/// Opaque type for accessing vtables.
///
/// Private implementation detail of `DynMetadata::size_of` etc.
/// There is conceptually not actually any Abstract Machine memory behind this pointer.
type VTable;
}
#[lang = "pointee_sized"]
pub trait PointeeSized {}
@@ -105,7 +130,7 @@ unsafe impl<'a, T: PointeeSized> Sync for &'a T {}
unsafe impl<T: Sync, const N: usize> Sync for [T; N] {}
#[lang = "freeze"]
unsafe auto trait Freeze {}
pub unsafe auto trait Freeze {}
unsafe impl<T: PointeeSized> Freeze for PhantomData<T> {}
unsafe impl<T: PointeeSized> Freeze for *const T {}
@@ -570,10 +595,24 @@ pub trait Deref {
fn deref(&self) -> &Self::Target;
}
#[rustc_builtin_macro(pattern_type)]
#[macro_export]
macro_rules! pattern_type {
($($arg:tt)*) => {
/* compiler built-in */
};
}
impl<T: PointeeSized, U: PointeeSized> CoerceUnsized<pattern_type!(*const U is !null)> for pattern_type!(*const T is !null) where
T: Unsize<U>
{
}
impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<pattern_type!(U is !null)> for pattern_type!(T is !null) {}
#[repr(transparent)]
#[rustc_layout_scalar_valid_range_start(1)]
#[rustc_nonnull_optimization_guaranteed]
pub struct NonNull<T: PointeeSized>(pub *const T);
pub struct NonNull<T: PointeeSized>(pub pattern_type!(*const T is !null));
impl<T: PointeeSized, U: PointeeSized> CoerceUnsized<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
impl<T: PointeeSized, U: PointeeSized> DispatchFromDyn<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
@@ -600,7 +639,16 @@ pub fn new(val: T) -> Box<T> {
let size = size_of::<T>();
let ptr = libc::malloc(size);
intrinsics::copy(&val as *const T as *const u8, ptr, size);
Box(Unique { pointer: NonNull(ptr as *const T), _marker: PhantomData }, Global)
Box(
Unique {
pointer: NonNull(intrinsics::transmute::<
*mut u8,
pattern_type!(*const T is !null),
>(ptr)),
_marker: PhantomData,
},
Global,
)
}
}
}
@@ -609,7 +657,9 @@ impl<T: ?Sized, A> Drop for Box<T, A> {
fn drop(&mut self) {
// inner value is dropped by compiler
unsafe {
libc::free(self.0.pointer.0 as *mut u8);
libc::free(intrinsics::transmute::<pattern_type!(*const T is !null), *const T>(
self.0.pointer.0,
) as *mut u8);
}
}
}
@@ -1,4 +1,13 @@
#![feature(no_core, lang_items, never_type, extern_types, thread_local, repr_simd, rustc_private)]
#![feature(
no_core,
lang_items,
never_type,
extern_types,
thread_local,
repr_simd,
pattern_types,
rustc_private
)]
#![cfg_attr(not(any(jit, target_vendor = "apple", windows)), feature(linkage))]
#![no_core]
#![allow(dead_code, non_camel_case_types, internal_features)]
@@ -153,7 +162,10 @@ extern "C" fn bool_struct_in_11(_arg0: bool_11) {}
#[allow(unreachable_code)] // FIXME false positive
fn main() {
take_unique(Unique { pointer: unsafe { NonNull(1 as *mut ()) }, _marker: PhantomData });
take_unique(Unique {
pointer: unsafe { NonNull(intrinsics::transmute(1 as *mut ())) },
_marker: PhantomData,
});
take_f32(0.1);
call_return_u128_pair();
@@ -219,7 +231,12 @@ fn main() {
let noisy_unsized_drop = const { intrinsics::needs_drop::<NoisyDropUnsized>() };
assert!(noisy_unsized_drop);
Unique { pointer: NonNull(1 as *mut &str), _marker: PhantomData } as Unique<dyn SomeTrait>;
Unique {
pointer: NonNull(intrinsics::transmute::<_, pattern_type!(*const &str is !null)>(
1 as *mut &str,
)),
_marker: PhantomData,
} as Unique<dyn SomeTrait>;
struct MyDst<T: ?Sized>(T);
@@ -26,7 +26,9 @@ fn reg_to_abi_param(reg: Reg) -> AbiParam {
(RegKind::Float, 4) => types::F32,
(RegKind::Float, 8) => types::F64,
(RegKind::Float, 16) => types::F128,
(RegKind::Vector, size) => types::I8.by(u32::try_from(size).unwrap()).unwrap(),
(RegKind::Vector { hint_vector_elem: _ }, size) => {
types::I8.by(u32::try_from(size).unwrap()).unwrap()
}
_ => unreachable!("{:?}", reg),
};
AbiParam::new(clif_ty)
@@ -380,11 +380,9 @@ fn codegen_cgu_content(
fn module_codegen(
tcx: TyCtxt<'_>,
(global_asm_config, cgu_name, token): (
Arc<GlobalAsmConfig>,
rustc_span::Symbol,
ConcurrencyLimiterToken,
),
global_asm_config: Arc<GlobalAsmConfig>,
cgu_name: rustc_span::Symbol,
token: ConcurrencyLimiterToken,
) -> OngoingModuleCodegen {
let mut module = make_module(tcx.sess, cgu_name.as_str().to_string());
@@ -513,8 +511,14 @@ pub(crate) fn run_aot(tcx: TyCtxt<'_>) -> Box<OngoingCodegen> {
let (module, _) = tcx.dep_graph.with_task(
dep_node,
tcx,
(global_asm_config.clone(), cgu.name(), concurrency_limiter.acquire(tcx.dcx())),
module_codegen,
|| {
module_codegen(
tcx,
global_asm_config.clone(),
cgu.name(),
concurrency_limiter.acquire(tcx.dcx()),
)
},
Some(rustc_middle::dep_graph::hash_result),
);
IntoDynSyncSend(module)
@@ -98,7 +98,7 @@ pub(crate) fn by_val_pair(
/// Create an instance of a ZST
///
/// The is represented by a dangling pointer of suitable alignment.
/// The ZST is represented by a dangling pointer of suitable alignment.
pub(crate) fn zst(layout: TyAndLayout<'tcx>) -> CValue<'tcx> {
assert!(layout.is_zst());
CValue::by_ref(crate::Pointer::dangling(layout.align.abi), layout)
@@ -870,20 +870,10 @@ pub(crate) fn assert_assignable<'tcx>(
let from_sig = fx
.tcx
.normalize_erasing_late_bound_regions(fx.typing_env(), from_ty.fn_sig(fx.tcx));
let FnSig {
inputs_and_output: types_from,
c_variadic: c_variadic_from,
safety: unsafety_from,
abi: abi_from,
} = from_sig;
let FnSig { inputs_and_output: types_from, fn_sig_kind: fn_sig_kind_from } = from_sig;
let to_sig =
fx.tcx.normalize_erasing_late_bound_regions(fx.typing_env(), to_ty.fn_sig(fx.tcx));
let FnSig {
inputs_and_output: types_to,
c_variadic: c_variadic_to,
safety: unsafety_to,
abi: abi_to,
} = to_sig;
let FnSig { inputs_and_output: types_to, fn_sig_kind: fn_sig_kind_to } = to_sig;
let mut types_from = types_from.iter();
let mut types_to = types_to.iter();
loop {
@@ -894,17 +884,7 @@ pub(crate) fn assert_assignable<'tcx>(
}
}
assert_eq!(
c_variadic_from, c_variadic_to,
"Can't write fn ptr with incompatible sig {:?} to place with sig {:?}\n\n{:#?}",
from_sig, to_sig, fx,
);
assert_eq!(
unsafety_from, unsafety_to,
"Can't write fn ptr with incompatible sig {:?} to place with sig {:?}\n\n{:#?}",
from_sig, to_sig, fx,
);
assert_eq!(
abi_from, abi_to,
fn_sig_kind_from, fn_sig_kind_to,
"Can't write fn ptr with incompatible sig {:?} to place with sig {:?}\n\n{:#?}",
from_sig, to_sig, fx,
);
@@ -9,6 +9,7 @@
transparent_unions,
auto_traits,
freeze_impls,
pattern_types,
thread_local
)]
#![no_core]
@@ -580,9 +581,16 @@ impl Allocator for () {}
impl Allocator for Global {}
#[repr(transparent)]
#[rustc_layout_scalar_valid_range_start(1)]
#[rustc_nonnull_optimization_guaranteed]
pub struct NonNull<T: PointeeSized>(pub *const T);
pub struct NonNull<T: PointeeSized>(pub pattern_type!(*const T is !null));
#[rustc_builtin_macro(pattern_type)]
#[macro_export]
macro_rules! pattern_type {
($($arg:tt)*) => {
/* compiler built-in */
};
}
impl<T: PointeeSized, U: PointeeSized> CoerceUnsized<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
impl<T: PointeeSized, U: PointeeSized> DispatchFromDyn<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
+3 -1
View File
@@ -90,7 +90,9 @@ fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, '_>) -> Type<'gcc> {
64 => cx.type_f64(),
_ => bug!("unsupported float: {:?}", self),
},
RegKind::Vector => cx.type_vector(cx.type_i8(), self.size.bytes()),
RegKind::Vector { hint_vector_elem: _ } => {
cx.type_vector(cx.type_i8(), self.size.bytes())
}
}
}
}
+4 -3
View File
@@ -83,8 +83,7 @@ pub fn compile_codegen_unit(
let (module, _) = tcx.dep_graph.with_task(
dep_node,
tcx,
(cgu_name, target_info, lto_supported),
module_codegen,
|| module_codegen(tcx, cgu_name, target_info, lto_supported),
Some(dep_graph::hash_result),
);
let time_to_codegen = start_time.elapsed();
@@ -96,7 +95,9 @@ pub fn compile_codegen_unit(
fn module_codegen(
tcx: TyCtxt<'_>,
(cgu_name, target_info, lto_supported): (Symbol, LockedTargetInfo, bool),
cgu_name: Symbol,
target_info: LockedTargetInfo,
lto_supported: bool,
) -> ModuleCodegen<GccContext> {
let cgu = tcx.codegen_unit(cgu_name);
// Instantiate monomorphizations without filling out definitions yet...
@@ -7,8 +7,6 @@
#[cfg(feature = "master")]
use gccjit::Type;
use gccjit::{ComparisonOp, Function, FunctionType, RValue, ToRValue, UnaryOp};
#[cfg(feature = "master")]
use rustc_abi::ExternAbi;
use rustc_abi::{BackendRepr, HasDataLayout, WrappingRange};
use rustc_codegen_ssa::MemFlags;
use rustc_codegen_ssa::base::wants_msvc_seh;
@@ -1483,32 +1481,26 @@ fn get_rust_try_fn<'a, 'gcc, 'tcx>(
// `unsafe fn(*mut i8) -> ()`
let try_fn_ty = Ty::new_fn_ptr(
tcx,
ty::Binder::dummy(tcx.mk_fn_sig(
ty::Binder::dummy(tcx.mk_fn_sig_rust_abi(
iter::once(i8p),
tcx.types.unit,
false,
rustc_hir::Safety::Unsafe,
ExternAbi::Rust,
)),
);
// `unsafe fn(*mut i8, *mut i8) -> ()`
let catch_fn_ty = Ty::new_fn_ptr(
tcx,
ty::Binder::dummy(tcx.mk_fn_sig(
ty::Binder::dummy(tcx.mk_fn_sig_rust_abi(
[i8p, i8p].iter().cloned(),
tcx.types.unit,
false,
rustc_hir::Safety::Unsafe,
ExternAbi::Rust,
)),
);
// `unsafe fn(unsafe fn(*mut i8) -> (), *mut i8, unsafe fn(*mut i8, *mut i8) -> ()) -> i32`
let rust_fn_sig = ty::Binder::dummy(cx.tcx.mk_fn_sig(
let rust_fn_sig = ty::Binder::dummy(cx.tcx.mk_fn_sig_rust_abi(
[try_fn_ty, i8p, catch_fn_ty],
tcx.types.i32,
false,
rustc_hir::Safety::Unsafe,
ExternAbi::Rust,
));
let rust_try = gen_fn(cx, "__rust_try", rust_fn_sig, codegen);
cx.rust_try_fn.set(Some(rust_try));

Some files were not shown because too many files have changed in this diff Show More