mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
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:
+25
-16
@@ -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
@@ -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)
|
||||
===========================
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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,
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -430,6 +430,7 @@ pub fn ctxt(&self) -> Option<FnCtxt> {
|
||||
Defaultness,
|
||||
Delegation,
|
||||
DelegationMac,
|
||||
DelegationSuffixes,
|
||||
DelimArgs,
|
||||
DelimSpan,
|
||||
EnumDef,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 => {
|
||||
|
||||
@@ -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| {
|
||||
|
||||
@@ -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))]
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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("*/")
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,5 @@
|
||||
#![feature(negative_impls)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
mod helpers;
|
||||
pub mod pp;
|
||||
pub mod pprust;
|
||||
|
||||
@@ -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(");
|
||||
|
||||
@@ -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, ¶m, &mut feature, word)?,
|
||||
sym::since => insert_value_into_option_or_error(cx, ¶m, &mut since, word)?,
|
||||
sym::reason => insert_value_into_option_or_error(cx, ¶m, &mut reason, word)?,
|
||||
sym::link => insert_value_into_option_or_error(cx, ¶m, &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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>,
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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(..)))
|
||||
);
|
||||
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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> {}
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user