Merge pull request #4814 from rust-lang/rustup-2026-01-12
Automatic Rustup
This commit is contained in:
commit
c947436dfd
1983 changed files with 15273 additions and 7279 deletions
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
|
|
@ -289,7 +289,7 @@ jobs:
|
|||
fi
|
||||
|
||||
# Get closest bors merge commit
|
||||
PARENT_COMMIT=`git rev-list --author='bors <bors@rust-lang.org>' -n1 --first-parent HEAD^1`
|
||||
PARENT_COMMIT=`git rev-list --author='122020455+rust-bors\[bot\]@users.noreply.github.com' -n1 --first-parent HEAD^1`
|
||||
|
||||
./build/citool/debug/citool postprocess-metrics \
|
||||
--job-name ${CI_JOB_NAME} \
|
||||
|
|
|
|||
2
.github/workflows/post-merge.yml
vendored
2
.github/workflows/post-merge.yml
vendored
|
|
@ -29,7 +29,7 @@ jobs:
|
|||
sleep 60
|
||||
|
||||
# Get closest bors merge commit
|
||||
PARENT_COMMIT=`git rev-list --author='bors <bors@rust-lang.org>' -n1 --first-parent HEAD^1`
|
||||
PARENT_COMMIT=`git rev-list --author='122020455+rust-bors\[bot\]@users.noreply.github.com' -n1 --first-parent HEAD^1`
|
||||
echo "Parent: ${PARENT_COMMIT}"
|
||||
|
||||
# Find PR for the current commit
|
||||
|
|
|
|||
111
Cargo.lock
111
Cargo.lock
|
|
@ -182,19 +182,6 @@ version = "0.7.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
||||
|
||||
[[package]]
|
||||
name = "askama"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4"
|
||||
dependencies = [
|
||||
"askama_derive 0.14.0",
|
||||
"itoa",
|
||||
"percent-encoding",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama"
|
||||
version = "0.15.1"
|
||||
|
|
@ -208,30 +195,13 @@ dependencies = [
|
|||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama_derive"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f"
|
||||
dependencies = [
|
||||
"askama_parser 0.14.0",
|
||||
"basic-toml",
|
||||
"memchr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustc-hash 2.1.1",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama_derive"
|
||||
version = "0.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ba5e7259a1580c61571e3116ebaaa01e3c001b2132b17c4cc5c70780ca3e994"
|
||||
dependencies = [
|
||||
"askama_parser 0.15.1",
|
||||
"askama_parser",
|
||||
"basic-toml",
|
||||
"memchr",
|
||||
"proc-macro2",
|
||||
|
|
@ -248,19 +218,7 @@ version = "0.15.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "236ce20b77cb13506eaf5024899f4af6e12e8825f390bd943c4c37fd8f322e46"
|
||||
dependencies = [
|
||||
"askama_derive 0.15.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama_parser"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"winnow 0.7.13",
|
||||
"askama_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -675,7 +633,7 @@ name = "clippy"
|
|||
version = "0.1.94"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"askama 0.14.0",
|
||||
"askama",
|
||||
"cargo_metadata 0.18.1",
|
||||
"clippy_config",
|
||||
"clippy_lints",
|
||||
|
|
@ -1566,7 +1524,7 @@ name = "generate-copyright"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"askama 0.15.1",
|
||||
"askama",
|
||||
"cargo_metadata 0.21.0",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
@ -3412,9 +3370,9 @@ checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
|
|||
|
||||
[[package]]
|
||||
name = "rustc-literal-escaper"
|
||||
version = "0.0.5"
|
||||
version = "0.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4ee29da77c5a54f42697493cd4c9b9f31b74df666a6c04dfc4fde77abe0438b"
|
||||
checksum = "8be87abb9e40db7466e0681dc8ecd9dcfd40360cb10b4c8fe24a7c4c3669b198"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-main"
|
||||
|
|
@ -4421,6 +4379,7 @@ dependencies = [
|
|||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_macros",
|
||||
"rustc_middle",
|
||||
"rustc_session",
|
||||
|
|
@ -4912,7 +4871,7 @@ name = "rustdoc"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"askama 0.15.1",
|
||||
"askama",
|
||||
"base64",
|
||||
"expect-test",
|
||||
"indexmap",
|
||||
|
|
@ -5658,6 +5617,7 @@ dependencies = [
|
|||
"build_helper",
|
||||
"cargo_metadata 0.21.0",
|
||||
"fluent-syntax",
|
||||
"globset",
|
||||
"ignore",
|
||||
"miropt-test-tools",
|
||||
"regex",
|
||||
|
|
@ -6221,9 +6181,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasi-preview1-component-adapter-provider"
|
||||
version = "38.0.4"
|
||||
version = "40.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ec3ef3783e18f2457796ed91b1e6c2adc46f2905f740d1527ab3053fe8e5682"
|
||||
checksum = "bb5e2b9858989c3a257de4ca169977f4f79897b64e4f482f188f4fcf8ac557d1"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
|
|
@ -6272,17 +6232,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-component-ld"
|
||||
version = "0.5.19"
|
||||
version = "0.5.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4bfc50dd0b883d841bc1dba5ff7020ca52fa7b2c3bb1266d8bf6a09dd032e115"
|
||||
checksum = "846d20ed66ae37b7a237e36dfcd2fdc979eae82a46cdb0586f9bba80782fd789"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"clap_lex",
|
||||
"lexopt",
|
||||
"libc",
|
||||
"tempfile",
|
||||
"wasi-preview1-component-adapter-provider",
|
||||
"wasmparser 0.241.2",
|
||||
"wasmparser 0.243.0",
|
||||
"wat",
|
||||
"windows-sys 0.61.2",
|
||||
"winsplit",
|
||||
|
|
@ -6309,24 +6270,24 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-encoder"
|
||||
version = "0.241.2"
|
||||
version = "0.243.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e01164c9dda68301e34fdae536c23ed6fe90ce6d97213ccc171eebbd3d02d6b8"
|
||||
checksum = "c55db9c896d70bd9fa535ce83cd4e1f2ec3726b0edd2142079f594fc3be1cb35"
|
||||
dependencies = [
|
||||
"leb128fmt",
|
||||
"wasmparser 0.241.2",
|
||||
"wasmparser 0.243.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-metadata"
|
||||
version = "0.241.2"
|
||||
version = "0.243.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "876fe286f2fa416386deedebe8407e6f19e0b5aeaef3d03161e77a15fa80f167"
|
||||
checksum = "eae05bf9579f45a62e8d0a4e3f52eaa8da518883ac5afa482ec8256c329ecd56"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"indexmap",
|
||||
"wasm-encoder 0.241.2",
|
||||
"wasmparser 0.241.2",
|
||||
"wasm-encoder 0.243.0",
|
||||
"wasmparser 0.243.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6351,9 +6312,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.241.2"
|
||||
version = "0.243.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46d90019b1afd4b808c263e428de644f3003691f243387d30d673211ee0cb8e8"
|
||||
checksum = "f6d8db401b0528ec316dfbe579e6ab4152d61739cfe076706d2009127970159d"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"hashbrown 0.15.5",
|
||||
|
|
@ -6364,22 +6325,22 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wast"
|
||||
version = "241.0.2"
|
||||
version = "243.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "63f66e07e2ddf531fef6344dbf94d112df7c2f23ed6ffb10962e711500b8d816"
|
||||
checksum = "df21d01c2d91e46cb7a221d79e58a2d210ea02020d57c092e79255cc2999ca7f"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"leb128fmt",
|
||||
"memchr",
|
||||
"unicode-width 0.2.2",
|
||||
"wasm-encoder 0.241.2",
|
||||
"wasm-encoder 0.243.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wat"
|
||||
version = "1.241.2"
|
||||
version = "1.243.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "45f923705c40830af909c5dec2352ec2821202e4a66008194585e1917458a26d"
|
||||
checksum = "226a9a91cd80a50449312fef0c75c23478fcecfcc4092bdebe1dc8e760ef521b"
|
||||
dependencies = [
|
||||
"wast",
|
||||
]
|
||||
|
|
@ -6775,9 +6736,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wit-component"
|
||||
version = "0.241.2"
|
||||
version = "0.243.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0c57df25e7ee612d946d3b7646c1ddb2310f8280aa2c17e543b66e0812241"
|
||||
checksum = "36f9fc53513e461ce51dcf17a3e331752cb829f1d187069e54af5608fc998fe4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags",
|
||||
|
|
@ -6786,17 +6747,17 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"wasm-encoder 0.241.2",
|
||||
"wasm-encoder 0.243.0",
|
||||
"wasm-metadata",
|
||||
"wasmparser 0.241.2",
|
||||
"wasmparser 0.243.0",
|
||||
"wit-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-parser"
|
||||
version = "0.241.2"
|
||||
version = "0.243.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ef1c6ad67f35c831abd4039c02894de97034100899614d1c44e2268ad01c91"
|
||||
checksum = "df983a8608e513d8997f435bb74207bf0933d0e49ca97aa9d8a6157164b9b7fc"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"id-arena",
|
||||
|
|
@ -6807,7 +6768,7 @@ dependencies = [
|
|||
"serde_derive",
|
||||
"serde_json",
|
||||
"unicode-xid",
|
||||
"wasmparser 0.241.2",
|
||||
"wasmparser 0.243.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
|
|
@ -618,7 +618,7 @@ impl DroplessArena {
|
|||
/// - Types that are `!Copy` and `Drop`: these must be specified in the
|
||||
/// arguments. The `TypedArena` will be used for them.
|
||||
///
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[rustc_macro_transparency = "semiopaque"]
|
||||
pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
|
||||
#[derive(Default)]
|
||||
pub struct Arena<'tcx> {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ edition = "2024"
|
|||
# tidy-alphabetical-start
|
||||
bitflags = "2.4.1"
|
||||
memchr = "2.7.6"
|
||||
rustc-literal-escaper = "0.0.5"
|
||||
rustc-literal-escaper = "0.0.7"
|
||||
rustc_ast_ir = { path = "../rustc_ast_ir" }
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_index = { path = "../rustc_index" }
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ use rustc_span::source_map::{Spanned, respan};
|
|||
use rustc_span::{ByteSymbol, DUMMY_SP, ErrorGuaranteed, Ident, Span, Symbol, kw, sym};
|
||||
use thin_vec::{ThinVec, thin_vec};
|
||||
|
||||
use crate::attr::data_structures::CfgEntry;
|
||||
pub use crate::format::*;
|
||||
use crate::token::{self, CommentKind, Delimiter};
|
||||
use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, TokenStream};
|
||||
|
|
@ -2116,10 +2117,9 @@ pub struct MacroDef {
|
|||
|
||||
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic, Walkable)]
|
||||
pub struct EiiExternTarget {
|
||||
/// path to the extern item we're targetting
|
||||
/// path to the extern item we're targeting
|
||||
pub extern_item_path: Path,
|
||||
pub impl_unsafe: bool,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug, Copy, Hash, Eq, PartialEq)]
|
||||
|
|
@ -3390,7 +3390,7 @@ impl NormalAttr {
|
|||
item: AttrItem {
|
||||
unsafety: Safety::Default,
|
||||
path: Path::from_ident(ident),
|
||||
args: AttrArgs::Empty,
|
||||
args: AttrItemKind::Unparsed(AttrArgs::Empty),
|
||||
tokens: None,
|
||||
},
|
||||
tokens: None,
|
||||
|
|
@ -3402,11 +3402,53 @@ impl NormalAttr {
|
|||
pub struct AttrItem {
|
||||
pub unsafety: Safety,
|
||||
pub path: Path,
|
||||
pub args: AttrArgs,
|
||||
pub args: AttrItemKind,
|
||||
// Tokens for the meta item, e.g. just the `foo` within `#[foo]` or `#![foo]`.
|
||||
pub tokens: Option<LazyAttrTokenStream>,
|
||||
}
|
||||
|
||||
/// Some attributes are stored in a parsed form, for performance reasons.
|
||||
/// Their arguments don't have to be reparsed everytime they're used
|
||||
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
|
||||
pub enum AttrItemKind {
|
||||
Parsed(EarlyParsedAttribute),
|
||||
Unparsed(AttrArgs),
|
||||
}
|
||||
|
||||
impl AttrItemKind {
|
||||
pub fn unparsed(self) -> Option<AttrArgs> {
|
||||
match self {
|
||||
AttrItemKind::Unparsed(args) => Some(args),
|
||||
AttrItemKind::Parsed(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unparsed_ref(&self) -> Option<&AttrArgs> {
|
||||
match self {
|
||||
AttrItemKind::Unparsed(args) => Some(args),
|
||||
AttrItemKind::Parsed(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn span(&self) -> Option<Span> {
|
||||
match self {
|
||||
AttrItemKind::Unparsed(args) => args.span(),
|
||||
AttrItemKind::Parsed(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Some attributes are stored in parsed form in the AST.
|
||||
/// This is done for performance reasons, so the attributes don't need to be reparsed on every use.
|
||||
///
|
||||
/// Currently all early parsed attributes are excluded from pretty printing at rustc_ast_pretty::pprust::state::print_attribute_inline.
|
||||
/// When adding new early parsed attributes, consider whether they should be pretty printed.
|
||||
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
pub enum EarlyParsedAttribute {
|
||||
CfgTrace(CfgEntry),
|
||||
CfgAttrTrace,
|
||||
}
|
||||
|
||||
impl AttrItem {
|
||||
pub fn is_valid_for_outer_style(&self) -> bool {
|
||||
self.path == sym::cfg_attr
|
||||
|
|
@ -3770,6 +3812,19 @@ pub struct Fn {
|
|||
pub struct EiiImpl {
|
||||
pub node_id: NodeId,
|
||||
pub eii_macro_path: Path,
|
||||
/// This field is an implementation detail that prevents a lot of bugs.
|
||||
/// See <https://github.com/rust-lang/rust/issues/149981> for an example.
|
||||
///
|
||||
/// The problem is, that if we generate a declaration *together* with its default,
|
||||
/// we generate both a declaration and an implementation. The generated implementation
|
||||
/// uses the same mechanism to register itself as a user-defined implementation would,
|
||||
/// despite being invisible to users. What does happen is a name resolution step.
|
||||
/// The invisible default implementation has to find the declaration.
|
||||
/// Both are generated at the same time, so we can skip that name resolution step.
|
||||
///
|
||||
/// This field is that shortcut: we prefill the extern target to skip a name resolution step,
|
||||
/// making sure it never fails. It'd be awful UX if we fail name resolution in code invisible to the user.
|
||||
pub known_eii_macro_resolution: Option<EiiExternTarget>,
|
||||
pub impl_safety: Safety,
|
||||
pub span: Span,
|
||||
pub inner_span: Span,
|
||||
|
|
|
|||
101
compiler/rustc_ast/src/attr/data_structures.rs
Normal file
101
compiler/rustc_ast/src/attr/data_structures.rs
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
use std::fmt;
|
||||
|
||||
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
|
||||
use rustc_span::{Span, Symbol};
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
use crate::attr::version::RustcVersion;
|
||||
|
||||
#[derive(Encodable, Decodable, Clone, Debug, PartialEq, Eq, Hash, HashStable_Generic)]
|
||||
pub enum CfgEntry {
|
||||
All(ThinVec<CfgEntry>, Span),
|
||||
Any(ThinVec<CfgEntry>, Span),
|
||||
Not(Box<CfgEntry>, Span),
|
||||
Bool(bool, Span),
|
||||
NameValue { name: Symbol, value: Option<Symbol>, span: Span },
|
||||
Version(Option<RustcVersion>, Span),
|
||||
}
|
||||
|
||||
impl CfgEntry {
|
||||
pub fn lower_spans(&mut self, lower_span: impl Copy + Fn(Span) -> Span) {
|
||||
match self {
|
||||
CfgEntry::All(subs, span) | CfgEntry::Any(subs, span) => {
|
||||
*span = lower_span(*span);
|
||||
subs.iter_mut().for_each(|sub| sub.lower_spans(lower_span));
|
||||
}
|
||||
CfgEntry::Not(sub, span) => {
|
||||
*span = lower_span(*span);
|
||||
sub.lower_spans(lower_span);
|
||||
}
|
||||
CfgEntry::Bool(_, span)
|
||||
| CfgEntry::NameValue { span, .. }
|
||||
| CfgEntry::Version(_, span) => {
|
||||
*span = lower_span(*span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn span(&self) -> Span {
|
||||
let (Self::All(_, span)
|
||||
| Self::Any(_, span)
|
||||
| Self::Not(_, span)
|
||||
| Self::Bool(_, span)
|
||||
| Self::NameValue { span, .. }
|
||||
| Self::Version(_, span)) = self;
|
||||
*span
|
||||
}
|
||||
|
||||
/// Same as `PartialEq` but doesn't check spans and ignore order of cfgs.
|
||||
pub fn is_equivalent_to(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::All(a, _), Self::All(b, _)) | (Self::Any(a, _), Self::Any(b, _)) => {
|
||||
a.len() == b.len() && a.iter().all(|a| b.iter().any(|b| a.is_equivalent_to(b)))
|
||||
}
|
||||
(Self::Not(a, _), Self::Not(b, _)) => a.is_equivalent_to(b),
|
||||
(Self::Bool(a, _), Self::Bool(b, _)) => a == b,
|
||||
(
|
||||
Self::NameValue { name: name1, value: value1, .. },
|
||||
Self::NameValue { name: name2, value: value2, .. },
|
||||
) => name1 == name2 && value1 == value2,
|
||||
(Self::Version(a, _), Self::Version(b, _)) => a == b,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CfgEntry {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fn write_entries(
|
||||
name: &str,
|
||||
entries: &[CfgEntry],
|
||||
f: &mut fmt::Formatter<'_>,
|
||||
) -> fmt::Result {
|
||||
write!(f, "{name}(")?;
|
||||
for (nb, entry) in entries.iter().enumerate() {
|
||||
if nb != 0 {
|
||||
f.write_str(", ")?;
|
||||
}
|
||||
entry.fmt(f)?;
|
||||
}
|
||||
f.write_str(")")
|
||||
}
|
||||
match self {
|
||||
Self::All(entries, _) => write_entries("all", entries, f),
|
||||
Self::Any(entries, _) => write_entries("any", entries, f),
|
||||
Self::Not(entry, _) => write!(f, "not({entry})"),
|
||||
Self::Bool(value, _) => write!(f, "{value}"),
|
||||
Self::NameValue { name, value, .. } => {
|
||||
match value {
|
||||
// We use `as_str` and debug display to have characters escaped and `"`
|
||||
// characters surrounding the string.
|
||||
Some(value) => write!(f, "{name} = {:?}", value.as_str()),
|
||||
None => write!(f, "{name}"),
|
||||
}
|
||||
}
|
||||
Self::Version(version, _) => match version {
|
||||
Some(version) => write!(f, "{version}"),
|
||||
None => Ok(()),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,8 @@
|
|||
//! Functions dealing with attributes and meta items.
|
||||
|
||||
pub mod data_structures;
|
||||
pub mod version;
|
||||
|
||||
use std::fmt::Debug;
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
|
||||
|
|
@ -8,6 +11,7 @@ use rustc_span::{Ident, Span, Symbol, sym};
|
|||
use smallvec::{SmallVec, smallvec};
|
||||
use thin_vec::{ThinVec, thin_vec};
|
||||
|
||||
use crate::AttrItemKind;
|
||||
use crate::ast::{
|
||||
AttrArgs, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute, DUMMY_NODE_ID, DelimArgs,
|
||||
Expr, ExprKind, LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NormalAttr, Path,
|
||||
|
|
@ -62,6 +66,15 @@ impl Attribute {
|
|||
}
|
||||
}
|
||||
|
||||
/// Replaces the arguments of this attribute with new arguments `AttrItemKind`.
|
||||
/// This is useful for making this attribute into a trace attribute, and should otherwise be avoided.
|
||||
pub fn replace_args(&mut self, new_args: AttrItemKind) {
|
||||
match &mut self.kind {
|
||||
AttrKind::Normal(normal) => normal.item.args = new_args,
|
||||
AttrKind::DocComment(..) => panic!("unexpected doc comment"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unwrap_normal_item(self) -> AttrItem {
|
||||
match self.kind {
|
||||
AttrKind::Normal(normal) => normal.item,
|
||||
|
|
@ -77,7 +90,7 @@ impl AttributeExt for Attribute {
|
|||
|
||||
fn value_span(&self) -> Option<Span> {
|
||||
match &self.kind {
|
||||
AttrKind::Normal(normal) => match &normal.item.args {
|
||||
AttrKind::Normal(normal) => match &normal.item.args.unparsed_ref()? {
|
||||
AttrArgs::Eq { expr, .. } => Some(expr.span),
|
||||
_ => None,
|
||||
},
|
||||
|
|
@ -96,11 +109,11 @@ impl AttributeExt for Attribute {
|
|||
}
|
||||
|
||||
/// For a single-segment attribute, returns its name; otherwise, returns `None`.
|
||||
fn ident(&self) -> Option<Ident> {
|
||||
fn name(&self) -> Option<Symbol> {
|
||||
match &self.kind {
|
||||
AttrKind::Normal(normal) => {
|
||||
if let [ident] = &*normal.item.path.segments {
|
||||
Some(ident.ident)
|
||||
Some(ident.ident.name)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
@ -109,9 +122,18 @@ impl AttributeExt for Attribute {
|
|||
}
|
||||
}
|
||||
|
||||
fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>> {
|
||||
fn symbol_path(&self) -> Option<SmallVec<[Symbol; 1]>> {
|
||||
match &self.kind {
|
||||
AttrKind::Normal(p) => Some(p.item.path.segments.iter().map(|i| i.ident).collect()),
|
||||
AttrKind::Normal(p) => {
|
||||
Some(p.item.path.segments.iter().map(|i| i.ident.name).collect())
|
||||
}
|
||||
AttrKind::DocComment(_, _) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn path_span(&self) -> Option<Span> {
|
||||
match &self.kind {
|
||||
AttrKind::Normal(attr) => Some(attr.item.path.span),
|
||||
AttrKind::DocComment(_, _) => None,
|
||||
}
|
||||
}
|
||||
|
|
@ -138,7 +160,7 @@ impl AttributeExt for Attribute {
|
|||
|
||||
fn is_word(&self) -> bool {
|
||||
if let AttrKind::Normal(normal) = &self.kind {
|
||||
matches!(normal.item.args, AttrArgs::Empty)
|
||||
matches!(normal.item.args, AttrItemKind::Unparsed(AttrArgs::Empty))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
|
@ -213,6 +235,34 @@ impl AttributeExt for Attribute {
|
|||
}
|
||||
}
|
||||
|
||||
fn deprecation_note(&self) -> Option<Symbol> {
|
||||
match &self.kind {
|
||||
AttrKind::Normal(normal) if normal.item.path == sym::deprecated => {
|
||||
let meta = &normal.item;
|
||||
|
||||
// #[deprecated = "..."]
|
||||
if let Some(s) = meta.value_str() {
|
||||
return Some(s);
|
||||
}
|
||||
|
||||
// #[deprecated(note = "...")]
|
||||
if let Some(list) = meta.meta_item_list() {
|
||||
for nested in list {
|
||||
if let Some(mi) = nested.meta_item()
|
||||
&& mi.path == sym::note
|
||||
&& let Some(s) = mi.value_str()
|
||||
{
|
||||
return Some(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn doc_resolution_scope(&self) -> Option<AttrStyle> {
|
||||
match &self.kind {
|
||||
AttrKind::DocComment(..) => Some(self.style),
|
||||
|
|
@ -255,6 +305,7 @@ impl Attribute {
|
|||
|
||||
pub fn may_have_doc_links(&self) -> bool {
|
||||
self.doc_str().is_some_and(|s| comments::may_have_doc_links(s.as_str()))
|
||||
|| self.deprecation_note().is_some_and(|s| comments::may_have_doc_links(s.as_str()))
|
||||
}
|
||||
|
||||
/// Extracts the MetaItem from inside this Attribute.
|
||||
|
|
@ -294,7 +345,7 @@ impl AttrItem {
|
|||
}
|
||||
|
||||
pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
|
||||
match &self.args {
|
||||
match &self.args.unparsed_ref()? {
|
||||
AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => {
|
||||
MetaItemKind::list_from_tokens(args.tokens.clone())
|
||||
}
|
||||
|
|
@ -315,7 +366,7 @@ impl AttrItem {
|
|||
/// #[attr("value")]
|
||||
/// ```
|
||||
fn value_str(&self) -> Option<Symbol> {
|
||||
match &self.args {
|
||||
match &self.args.unparsed_ref()? {
|
||||
AttrArgs::Eq { expr, .. } => match expr.kind {
|
||||
ExprKind::Lit(token_lit) => {
|
||||
LitKind::from_token_lit(token_lit).ok().and_then(|lit| lit.str())
|
||||
|
|
@ -339,7 +390,7 @@ impl AttrItem {
|
|||
/// #[attr("value")]
|
||||
/// ```
|
||||
fn value_span(&self) -> Option<Span> {
|
||||
match &self.args {
|
||||
match &self.args.unparsed_ref()? {
|
||||
AttrArgs::Eq { expr, .. } => Some(expr.span),
|
||||
AttrArgs::Delimited(_) | AttrArgs::Empty => None,
|
||||
}
|
||||
|
|
@ -355,7 +406,7 @@ impl AttrItem {
|
|||
}
|
||||
|
||||
pub fn meta_kind(&self) -> Option<MetaItemKind> {
|
||||
MetaItemKind::from_attr_args(&self.args)
|
||||
MetaItemKind::from_attr_args(self.args.unparsed_ref()?)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -690,7 +741,13 @@ fn mk_attr(
|
|||
args: AttrArgs,
|
||||
span: Span,
|
||||
) -> Attribute {
|
||||
mk_attr_from_item(g, AttrItem { unsafety, path, args, tokens: None }, None, style, span)
|
||||
mk_attr_from_item(
|
||||
g,
|
||||
AttrItem { unsafety, path, args: AttrItemKind::Unparsed(args), tokens: None },
|
||||
None,
|
||||
style,
|
||||
span,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn mk_attr_from_item(
|
||||
|
|
@ -794,9 +851,7 @@ pub trait AttributeExt: Debug {
|
|||
|
||||
/// For a single-segment attribute (i.e., `#[attr]` and not `#[path::atrr]`),
|
||||
/// return the name of the attribute; otherwise, returns `None`.
|
||||
fn name(&self) -> Option<Symbol> {
|
||||
self.ident().map(|ident| ident.name)
|
||||
}
|
||||
fn name(&self) -> Option<Symbol>;
|
||||
|
||||
/// Get the meta item list, `#[attr(meta item list)]`
|
||||
fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>>;
|
||||
|
|
@ -807,9 +862,6 @@ pub trait AttributeExt: Debug {
|
|||
/// Gets the span of the value literal, as string, when using `#[attr = value]`
|
||||
fn value_span(&self) -> Option<Span>;
|
||||
|
||||
/// For a single-segment attribute, returns its ident; otherwise, returns `None`.
|
||||
fn ident(&self) -> Option<Ident>;
|
||||
|
||||
/// Checks whether the path of this attribute matches the name.
|
||||
///
|
||||
/// Matches one segment of the path to each element in `name`
|
||||
|
|
@ -822,7 +874,7 @@ pub trait AttributeExt: Debug {
|
|||
|
||||
#[inline]
|
||||
fn has_name(&self, name: Symbol) -> bool {
|
||||
self.ident().map(|x| x.name == name).unwrap_or(false)
|
||||
self.name().map(|x| x == name).unwrap_or(false)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -836,13 +888,13 @@ pub trait AttributeExt: Debug {
|
|||
fn is_word(&self) -> bool;
|
||||
|
||||
fn path(&self) -> SmallVec<[Symbol; 1]> {
|
||||
self.ident_path()
|
||||
.map(|i| i.into_iter().map(|i| i.name).collect())
|
||||
.unwrap_or(smallvec![sym::doc])
|
||||
self.symbol_path().unwrap_or(smallvec![sym::doc])
|
||||
}
|
||||
|
||||
fn path_span(&self) -> Option<Span>;
|
||||
|
||||
/// Returns None for doc comments
|
||||
fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>>;
|
||||
fn symbol_path(&self) -> Option<SmallVec<[Symbol; 1]>>;
|
||||
|
||||
/// Returns the documentation if this is a doc comment or a sugared doc comment.
|
||||
/// * `///doc` returns `Some("doc")`.
|
||||
|
|
@ -850,6 +902,11 @@ pub trait AttributeExt: Debug {
|
|||
/// * `#[doc(...)]` returns `None`.
|
||||
fn doc_str(&self) -> Option<Symbol>;
|
||||
|
||||
/// Returns the deprecation note if this is deprecation attribute.
|
||||
/// * `#[deprecated = "note"]` returns `Some("note")`.
|
||||
/// * `#[deprecated(note = "note", ...)]` returns `Some("note")`.
|
||||
fn deprecation_note(&self) -> Option<Symbol>;
|
||||
|
||||
fn is_proc_macro_attr(&self) -> bool {
|
||||
[sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
|
||||
.iter()
|
||||
|
|
@ -903,10 +960,6 @@ impl Attribute {
|
|||
AttributeExt::value_span(self)
|
||||
}
|
||||
|
||||
pub fn ident(&self) -> Option<Ident> {
|
||||
AttributeExt::ident(self)
|
||||
}
|
||||
|
||||
pub fn path_matches(&self, name: &[Symbol]) -> bool {
|
||||
AttributeExt::path_matches(self, name)
|
||||
}
|
||||
|
|
@ -938,10 +991,6 @@ impl Attribute {
|
|||
AttributeExt::path(self)
|
||||
}
|
||||
|
||||
pub fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>> {
|
||||
AttributeExt::ident_path(self)
|
||||
}
|
||||
|
||||
pub fn doc_str(&self) -> Option<Symbol> {
|
||||
AttributeExt::doc_str(self)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,10 @@
|
|||
use std::borrow::Cow;
|
||||
use std::fmt::{self, Display};
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use rustc_error_messages::{DiagArgValue, IntoDiagArg};
|
||||
use rustc_macros::{
|
||||
BlobDecodable, Encodable, HashStable_Generic, PrintAttribute, current_rustc_version,
|
||||
};
|
||||
|
||||
use crate::attrs::PrintAttribute;
|
||||
use rustc_macros::{BlobDecodable, Encodable, HashStable_Generic, current_rustc_version};
|
||||
|
||||
#[derive(Encodable, BlobDecodable, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[derive(HashStable_Generic, PrintAttribute)]
|
||||
#[derive(HashStable_Generic)]
|
||||
pub struct RustcVersion {
|
||||
pub major: u16,
|
||||
pub minor: u16,
|
||||
|
|
@ -47,9 +41,3 @@ impl Display for RustcVersion {
|
|||
write!(formatter, "{}.{}.{}", self.major, self.minor, self.patch)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoDiagArg for RustcVersion {
|
||||
fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
|
||||
DiagArgValue::Str(Cow::Owned(self.to_string()))
|
||||
}
|
||||
}
|
||||
|
|
@ -366,6 +366,7 @@ macro_rules! common_visitor_and_walkers {
|
|||
crate::token::LitKind,
|
||||
crate::tokenstream::LazyAttrTokenStream,
|
||||
crate::tokenstream::TokenStream,
|
||||
EarlyParsedAttribute,
|
||||
Movability,
|
||||
Mutability,
|
||||
Pinnedness,
|
||||
|
|
@ -457,6 +458,7 @@ macro_rules! common_visitor_and_walkers {
|
|||
ModSpans,
|
||||
MutTy,
|
||||
NormalAttr,
|
||||
AttrItemKind,
|
||||
Parens,
|
||||
ParenthesizedArgs,
|
||||
PatFieldsRest,
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// Let statements are allowed to have impl trait in bindings.
|
||||
let super_ = l.super_.map(|span| self.lower_span(span));
|
||||
let ty = l.ty.as_ref().map(|t| {
|
||||
self.lower_ty(t, self.impl_trait_in_bindings_ctxt(ImplTraitPosition::Variable))
|
||||
self.lower_ty_alloc(t, self.impl_trait_in_bindings_ctxt(ImplTraitPosition::Variable))
|
||||
});
|
||||
let init = l.kind.init().map(|init| self.lower_expr(init));
|
||||
let hir_id = self.lower_node_id(l.id);
|
||||
|
|
|
|||
|
|
@ -158,14 +158,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
ExprKind::Cast(expr, ty) => {
|
||||
let expr = self.lower_expr(expr);
|
||||
let ty =
|
||||
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast));
|
||||
let ty = self
|
||||
.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast));
|
||||
hir::ExprKind::Cast(expr, ty)
|
||||
}
|
||||
ExprKind::Type(expr, ty) => {
|
||||
let expr = self.lower_expr(expr);
|
||||
let ty =
|
||||
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast));
|
||||
let ty = self
|
||||
.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast));
|
||||
hir::ExprKind::Type(expr, ty)
|
||||
}
|
||||
ExprKind::AddrOf(k, m, ohs) => {
|
||||
|
|
@ -335,7 +335,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
ExprKind::FormatArgs(fmt) => self.lower_format_args(e.span, fmt),
|
||||
ExprKind::OffsetOf(container, fields) => hir::ExprKind::OffsetOf(
|
||||
self.lower_ty(
|
||||
self.lower_ty_alloc(
|
||||
container,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::OffsetOf),
|
||||
),
|
||||
|
|
@ -371,7 +371,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
*kind,
|
||||
self.lower_expr(expr),
|
||||
ty.as_ref().map(|ty| {
|
||||
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast))
|
||||
self.lower_ty_alloc(
|
||||
ty,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Cast),
|
||||
)
|
||||
}),
|
||||
),
|
||||
|
||||
|
|
@ -617,7 +620,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
});
|
||||
|
||||
if let Some(ty) = opt_ty {
|
||||
let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path));
|
||||
let ty = self.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path));
|
||||
let block_expr = self.arena.alloc(self.expr_block(whole_block));
|
||||
hir::ExprKind::Type(block_expr, ty)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -312,7 +312,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
|||
|
||||
fn visit_const_arg(&mut self, const_arg: &'hir ConstArg<'hir, AmbigArg>) {
|
||||
self.insert(
|
||||
const_arg.as_unambig_ct().span(),
|
||||
const_arg.as_unambig_ct().span,
|
||||
const_arg.hir_id,
|
||||
Node::ConstArg(const_arg.as_unambig_ct()),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use rustc_abi::ExternAbi;
|
|||
use rustc_ast::visit::AssocCtxt;
|
||||
use rustc_ast::*;
|
||||
use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err};
|
||||
use rustc_hir::attrs::{AttributeKind, EiiDecl};
|
||||
use rustc_hir::attrs::{AttributeKind, EiiDecl, EiiImplResolution};
|
||||
use rustc_hir::def::{DefKind, PerNS, Res};
|
||||
use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
|
||||
use rustc_hir::{
|
||||
|
|
@ -134,6 +134,56 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
fn lower_eii_extern_target(
|
||||
&mut self,
|
||||
id: NodeId,
|
||||
eii_name: Ident,
|
||||
EiiExternTarget { extern_item_path, impl_unsafe }: &EiiExternTarget,
|
||||
) -> Option<EiiDecl> {
|
||||
self.lower_path_simple_eii(id, extern_item_path).map(|did| EiiDecl {
|
||||
eii_extern_target: did,
|
||||
impl_unsafe: *impl_unsafe,
|
||||
name: eii_name,
|
||||
})
|
||||
}
|
||||
|
||||
fn lower_eii_impl(
|
||||
&mut self,
|
||||
EiiImpl {
|
||||
node_id,
|
||||
eii_macro_path,
|
||||
impl_safety,
|
||||
span,
|
||||
inner_span,
|
||||
is_default,
|
||||
known_eii_macro_resolution,
|
||||
}: &EiiImpl,
|
||||
) -> hir::attrs::EiiImpl {
|
||||
let resolution = if let Some(target) = known_eii_macro_resolution
|
||||
&& let Some(decl) = self.lower_eii_extern_target(
|
||||
*node_id,
|
||||
// the expect is ok here since we always generate this path in the eii macro.
|
||||
eii_macro_path.segments.last().expect("at least one segment").ident,
|
||||
target,
|
||||
) {
|
||||
EiiImplResolution::Known(decl)
|
||||
} else if let Some(macro_did) = self.lower_path_simple_eii(*node_id, eii_macro_path) {
|
||||
EiiImplResolution::Macro(macro_did)
|
||||
} else {
|
||||
EiiImplResolution::Error(
|
||||
self.dcx().span_delayed_bug(*span, "eii never resolved without errors given"),
|
||||
)
|
||||
};
|
||||
|
||||
hir::attrs::EiiImpl {
|
||||
span: self.lower_span(*span),
|
||||
inner_span: self.lower_span(*inner_span),
|
||||
impl_marked_unsafe: self.lower_safety(*impl_safety, hir::Safety::Safe).is_unsafe(),
|
||||
is_default: *is_default,
|
||||
resolution,
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_extra_attrs_for_item_kind(
|
||||
&mut self,
|
||||
id: NodeId,
|
||||
|
|
@ -143,49 +193,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ItemKind::Fn(box Fn { eii_impls, .. }) if eii_impls.is_empty() => Vec::new(),
|
||||
ItemKind::Fn(box Fn { eii_impls, .. }) => {
|
||||
vec![hir::Attribute::Parsed(AttributeKind::EiiImpls(
|
||||
eii_impls
|
||||
.iter()
|
||||
.flat_map(
|
||||
|EiiImpl {
|
||||
node_id,
|
||||
eii_macro_path,
|
||||
impl_safety,
|
||||
span,
|
||||
inner_span,
|
||||
is_default,
|
||||
}| {
|
||||
self.lower_path_simple_eii(*node_id, eii_macro_path).map(|did| {
|
||||
hir::attrs::EiiImpl {
|
||||
eii_macro: did,
|
||||
span: self.lower_span(*span),
|
||||
inner_span: self.lower_span(*inner_span),
|
||||
impl_marked_unsafe: self
|
||||
.lower_safety(*impl_safety, hir::Safety::Safe)
|
||||
.is_unsafe(),
|
||||
is_default: *is_default,
|
||||
}
|
||||
})
|
||||
},
|
||||
)
|
||||
.collect(),
|
||||
eii_impls.iter().map(|i| self.lower_eii_impl(i)).collect(),
|
||||
))]
|
||||
}
|
||||
ItemKind::MacroDef(
|
||||
_,
|
||||
MacroDef {
|
||||
eii_extern_target: Some(EiiExternTarget { extern_item_path, impl_unsafe, span }),
|
||||
..
|
||||
},
|
||||
) => self
|
||||
.lower_path_simple_eii(id, extern_item_path)
|
||||
.map(|did| {
|
||||
vec![hir::Attribute::Parsed(AttributeKind::EiiExternTarget(EiiDecl {
|
||||
eii_extern_target: did,
|
||||
impl_unsafe: *impl_unsafe,
|
||||
span: self.lower_span(*span),
|
||||
}))]
|
||||
})
|
||||
ItemKind::MacroDef(name, MacroDef { eii_extern_target: Some(target), .. }) => self
|
||||
.lower_eii_extern_target(id, *name, target)
|
||||
.map(|decl| vec![hir::Attribute::Parsed(AttributeKind::EiiExternTarget(decl))])
|
||||
.unwrap_or_default(),
|
||||
|
||||
ItemKind::ExternCrate(..)
|
||||
| ItemKind::Use(..)
|
||||
| ItemKind::Static(..)
|
||||
|
|
@ -264,8 +279,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
define_opaque,
|
||||
}) => {
|
||||
let ident = self.lower_ident(*ident);
|
||||
let ty =
|
||||
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy));
|
||||
let ty = self
|
||||
.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy));
|
||||
let body_id = self.lower_const_body(span, e.as_deref());
|
||||
self.lower_define_opaque(hir_id, define_opaque);
|
||||
hir::ItemKind::Static(*m, ident, ty, body_id)
|
||||
|
|
@ -279,8 +294,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
id,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| {
|
||||
let ty = this
|
||||
.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
|
||||
let ty = this.lower_ty_alloc(
|
||||
ty,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
|
||||
);
|
||||
let rhs = this.lower_const_item_rhs(attrs, rhs.as_ref(), span);
|
||||
(ty, rhs)
|
||||
},
|
||||
|
|
@ -379,7 +396,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
);
|
||||
this.arena.alloc(this.ty(span, hir::TyKind::Err(guar)))
|
||||
}
|
||||
Some(ty) => this.lower_ty(
|
||||
Some(ty) => this.lower_ty_alloc(
|
||||
ty,
|
||||
ImplTraitContext::OpaqueTy {
|
||||
origin: hir::OpaqueTyOrigin::TyAlias {
|
||||
|
|
@ -453,7 +470,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
.as_deref()
|
||||
.map(|of_trait| this.lower_trait_impl_header(of_trait));
|
||||
|
||||
let lowered_ty = this.lower_ty(
|
||||
let lowered_ty = this.lower_ty_alloc(
|
||||
ty,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::ImplSelf),
|
||||
);
|
||||
|
|
@ -758,8 +775,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
safety,
|
||||
define_opaque,
|
||||
}) => {
|
||||
let ty =
|
||||
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy));
|
||||
let ty = self
|
||||
.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy));
|
||||
let safety = self.lower_safety(*safety, hir::Safety::Unsafe);
|
||||
if define_opaque.is_some() {
|
||||
self.dcx().span_err(i.span, "foreign statics cannot define opaque types");
|
||||
|
|
@ -870,7 +887,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
&mut self,
|
||||
(index, f): (usize, &FieldDef),
|
||||
) -> hir::FieldDef<'hir> {
|
||||
let ty = self.lower_ty(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy));
|
||||
let ty =
|
||||
self.lower_ty_alloc(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy));
|
||||
let hir_id = self.lower_node_id(f.id);
|
||||
self.lower_attrs(hir_id, &f.attrs, f.span, Target::Field);
|
||||
hir::FieldDef {
|
||||
|
|
@ -908,8 +926,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
i.id,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| {
|
||||
let ty = this
|
||||
.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
|
||||
let ty = this.lower_ty_alloc(
|
||||
ty,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
|
||||
);
|
||||
let rhs = rhs
|
||||
.as_ref()
|
||||
.map(|rhs| this.lower_const_item_rhs(attrs, Some(rhs), i.span));
|
||||
|
|
@ -1008,7 +1028,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| {
|
||||
let ty = ty.as_ref().map(|x| {
|
||||
this.lower_ty(
|
||||
this.lower_ty_alloc(
|
||||
x,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::AssocTy),
|
||||
)
|
||||
|
|
@ -1120,8 +1140,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
i.id,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| {
|
||||
let ty = this
|
||||
.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
|
||||
let ty = this.lower_ty_alloc(
|
||||
ty,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
|
||||
);
|
||||
this.lower_define_opaque(hir_id, &define_opaque);
|
||||
let rhs = this.lower_const_item_rhs(attrs, rhs.as_ref(), i.span);
|
||||
hir::ImplItemKind::Const(ty, rhs)
|
||||
|
|
@ -1180,7 +1202,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
hir::ImplItemKind::Type(ty)
|
||||
}
|
||||
Some(ty) => {
|
||||
let ty = this.lower_ty(
|
||||
let ty = this.lower_ty_alloc(
|
||||
ty,
|
||||
ImplTraitContext::OpaqueTy {
|
||||
origin: hir::OpaqueTyOrigin::TyAlias {
|
||||
|
|
@ -1916,7 +1938,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
bound_generic_params,
|
||||
hir::GenericParamSource::Binder,
|
||||
),
|
||||
bounded_ty: self.lower_ty(
|
||||
bounded_ty: self.lower_ty_alloc(
|
||||
bounded_ty,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||
),
|
||||
|
|
@ -1945,10 +1967,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
WherePredicateKind::EqPredicate(WhereEqPredicate { lhs_ty, rhs_ty }) => {
|
||||
hir::WherePredicateKind::EqPredicate(hir::WhereEqPredicate {
|
||||
lhs_ty: self
|
||||
.lower_ty(lhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound)),
|
||||
rhs_ty: self
|
||||
.lower_ty(rhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound)),
|
||||
lhs_ty: self.lower_ty_alloc(
|
||||
lhs_ty,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||
),
|
||||
rhs_ty: self.lower_ty_alloc(
|
||||
rhs_ty,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||
),
|
||||
})
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1125,8 +1125,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let kind = match &constraint.kind {
|
||||
AssocItemConstraintKind::Equality { term } => {
|
||||
let term = match term {
|
||||
Term::Ty(ty) => self.lower_ty(ty, itctx).into(),
|
||||
Term::Const(c) => self.lower_anon_const_to_const_arg(c).into(),
|
||||
Term::Ty(ty) => self.lower_ty_alloc(ty, itctx).into(),
|
||||
Term::Const(c) => self.lower_anon_const_to_const_arg_and_alloc(c).into(),
|
||||
};
|
||||
hir::AssocItemConstraintKind::Equality { term }
|
||||
}
|
||||
|
|
@ -1250,17 +1250,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
_ => {}
|
||||
}
|
||||
GenericArg::Type(self.lower_ty(ty, itctx).try_as_ambig_ty().unwrap())
|
||||
}
|
||||
ast::GenericArg::Const(ct) => {
|
||||
GenericArg::Const(self.lower_anon_const_to_const_arg(ct).try_as_ambig_ct().unwrap())
|
||||
GenericArg::Type(self.lower_ty_alloc(ty, itctx).try_as_ambig_ty().unwrap())
|
||||
}
|
||||
ast::GenericArg::Const(ct) => GenericArg::Const(
|
||||
self.lower_anon_const_to_const_arg_and_alloc(ct).try_as_ambig_ct().unwrap(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> &'hir hir::Ty<'hir> {
|
||||
self.arena.alloc(self.lower_ty_direct(t, itctx))
|
||||
fn lower_ty_alloc(&mut self, t: &Ty, itctx: ImplTraitContext) -> &'hir hir::Ty<'hir> {
|
||||
self.arena.alloc(self.lower_ty(t, itctx))
|
||||
}
|
||||
|
||||
fn lower_path_ty(
|
||||
|
|
@ -1324,11 +1324,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
self.ty(span, hir::TyKind::Tup(tys))
|
||||
}
|
||||
|
||||
fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> {
|
||||
fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> {
|
||||
let kind = match &t.kind {
|
||||
TyKind::Infer => hir::TyKind::Infer(()),
|
||||
TyKind::Err(guar) => hir::TyKind::Err(*guar),
|
||||
TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
|
||||
TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty_alloc(ty, itctx)),
|
||||
TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
|
||||
TyKind::Ref(region, mt) => {
|
||||
let lifetime = self.lower_ty_direct_lifetime(t, *region);
|
||||
|
|
@ -1362,15 +1362,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params);
|
||||
hir::TyKind::UnsafeBinder(self.arena.alloc(hir::UnsafeBinderTy {
|
||||
generic_params,
|
||||
inner_ty: self.lower_ty(&f.inner_ty, itctx),
|
||||
inner_ty: self.lower_ty_alloc(&f.inner_ty, itctx),
|
||||
}))
|
||||
}
|
||||
TyKind::Never => hir::TyKind::Never,
|
||||
TyKind::Tup(tys) => hir::TyKind::Tup(
|
||||
self.arena.alloc_from_iter(tys.iter().map(|ty| self.lower_ty_direct(ty, itctx))),
|
||||
self.arena.alloc_from_iter(tys.iter().map(|ty| self.lower_ty(ty, itctx))),
|
||||
),
|
||||
TyKind::Paren(ty) => {
|
||||
return self.lower_ty_direct(ty, itctx);
|
||||
return self.lower_ty(ty, itctx);
|
||||
}
|
||||
TyKind::Path(qself, path) => {
|
||||
return self.lower_path_ty(t, qself, path, ParamMode::Explicit, itctx);
|
||||
|
|
@ -1393,7 +1393,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
))
|
||||
}
|
||||
TyKind::Array(ty, length) => hir::TyKind::Array(
|
||||
self.lower_ty(ty, itctx),
|
||||
self.lower_ty_alloc(ty, itctx),
|
||||
self.lower_array_length_to_const_arg(length),
|
||||
),
|
||||
TyKind::TraitObject(bounds, kind) => {
|
||||
|
|
@ -1493,7 +1493,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
}
|
||||
TyKind::Pat(ty, pat) => {
|
||||
hir::TyKind::Pat(self.lower_ty(ty, itctx), self.lower_ty_pat(pat, ty.span))
|
||||
hir::TyKind::Pat(self.lower_ty_alloc(ty, itctx), self.lower_ty_pat(pat, ty.span))
|
||||
}
|
||||
TyKind::MacCall(_) => {
|
||||
span_bug!(t.span, "`TyKind::MacCall` should have been expanded by now")
|
||||
|
|
@ -1693,7 +1693,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
ImplTraitContext::Disallowed(ImplTraitPosition::PointerParam)
|
||||
}
|
||||
};
|
||||
self.lower_ty_direct(¶m.ty, itctx)
|
||||
self.lower_ty(¶m.ty, itctx)
|
||||
}));
|
||||
|
||||
let output = match coro {
|
||||
|
|
@ -1732,7 +1732,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
ImplTraitContext::Disallowed(ImplTraitPosition::PointerReturn)
|
||||
}
|
||||
};
|
||||
hir::FnRetTy::Return(self.lower_ty(ty, itctx))
|
||||
hir::FnRetTy::Return(self.lower_ty_alloc(ty, itctx))
|
||||
}
|
||||
FnRetTy::Default(span) => hir::FnRetTy::DefaultReturn(self.lower_span(*span)),
|
||||
},
|
||||
|
|
@ -1843,7 +1843,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// Not `OpaqueTyOrigin::AsyncFn`: that's only used for the
|
||||
// `impl Future` opaque type that `async fn` implicitly
|
||||
// generates.
|
||||
self.lower_ty(ty, itctx)
|
||||
self.lower_ty_alloc(ty, itctx)
|
||||
}
|
||||
FnRetTy::Default(ret_ty_span) => self.arena.alloc(self.ty_tup(*ret_ty_span, &[])),
|
||||
};
|
||||
|
|
@ -1986,8 +1986,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let (name, kind) = self.lower_generic_param_kind(param, source);
|
||||
|
||||
let hir_id = self.lower_node_id(param.id);
|
||||
self.lower_attrs(hir_id, ¶m.attrs, param.span(), Target::Param);
|
||||
hir::GenericParam {
|
||||
let param_attrs = ¶m.attrs;
|
||||
let param_span = param.span();
|
||||
let param = hir::GenericParam {
|
||||
hir_id,
|
||||
def_id: self.local_def_id(param.id),
|
||||
name,
|
||||
|
|
@ -1996,7 +1997,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
kind,
|
||||
colon_span: param.colon_span.map(|s| self.lower_span(s)),
|
||||
source,
|
||||
}
|
||||
};
|
||||
self.lower_attrs(hir_id, param_attrs, param_span, Target::from_generic_param(¶m));
|
||||
param
|
||||
}
|
||||
|
||||
fn lower_generic_param_kind(
|
||||
|
|
@ -2036,7 +2039,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
})
|
||||
.map(|def| {
|
||||
self.lower_ty(
|
||||
self.lower_ty_alloc(
|
||||
def,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault),
|
||||
)
|
||||
|
|
@ -2047,8 +2050,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
(hir::ParamName::Plain(self.lower_ident(param.ident)), kind)
|
||||
}
|
||||
GenericParamKind::Const { ty, span: _, default } => {
|
||||
let ty = self
|
||||
.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault));
|
||||
let ty = self.lower_ty_alloc(
|
||||
ty,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault),
|
||||
);
|
||||
|
||||
// Not only do we deny const param defaults in binders but we also map them to `None`
|
||||
// since later compiler stages cannot handle them (and shouldn't need to be able to).
|
||||
|
|
@ -2064,7 +2069,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
false
|
||||
}
|
||||
})
|
||||
.map(|def| self.lower_anon_const_to_const_arg(def));
|
||||
.map(|def| self.lower_anon_const_to_const_arg_and_alloc(def));
|
||||
|
||||
(
|
||||
hir::ParamName::Plain(self.lower_ident(param.ident)),
|
||||
|
|
@ -2198,7 +2203,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
|
||||
fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> {
|
||||
hir::MutTy { ty: self.lower_ty(&mt.ty, itctx), mutbl: mt.mutbl }
|
||||
hir::MutTy { ty: self.lower_ty_alloc(&mt.ty, itctx), mutbl: mt.mutbl }
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
|
|
@ -2283,10 +2288,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// `ExprKind::Paren(ExprKind::Underscore)` and should also be lowered to `GenericArg::Infer`
|
||||
match c.value.peel_parens().kind {
|
||||
ExprKind::Underscore => {
|
||||
let ct_kind = hir::ConstArgKind::Infer(self.lower_span(c.value.span), ());
|
||||
self.arena.alloc(hir::ConstArg { hir_id: self.lower_node_id(c.id), kind: ct_kind })
|
||||
let ct_kind = hir::ConstArgKind::Infer(());
|
||||
self.arena.alloc(hir::ConstArg {
|
||||
hir_id: self.lower_node_id(c.id),
|
||||
kind: ct_kind,
|
||||
span: self.lower_span(c.value.span),
|
||||
})
|
||||
}
|
||||
_ => self.lower_anon_const_to_const_arg(c),
|
||||
_ => self.lower_anon_const_to_const_arg_and_alloc(c),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2354,7 +2363,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
hir::ConstArgKind::Anon(ct)
|
||||
};
|
||||
|
||||
self.arena.alloc(hir::ConstArg { hir_id: self.next_id(), kind: ct_kind })
|
||||
self.arena.alloc(hir::ConstArg {
|
||||
hir_id: self.next_id(),
|
||||
kind: ct_kind,
|
||||
span: self.lower_span(span),
|
||||
})
|
||||
}
|
||||
|
||||
fn lower_const_item_rhs(
|
||||
|
|
@ -2365,15 +2378,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
) -> hir::ConstItemRhs<'hir> {
|
||||
match rhs {
|
||||
Some(ConstItemRhs::TypeConst(anon)) => {
|
||||
hir::ConstItemRhs::TypeConst(self.lower_anon_const_to_const_arg(anon))
|
||||
hir::ConstItemRhs::TypeConst(self.lower_anon_const_to_const_arg_and_alloc(anon))
|
||||
}
|
||||
None if attr::contains_name(attrs, sym::type_const) => {
|
||||
let const_arg = ConstArg {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::ConstArgKind::Error(
|
||||
DUMMY_SP,
|
||||
self.dcx().span_delayed_bug(DUMMY_SP, "no block"),
|
||||
),
|
||||
span: DUMMY_SP,
|
||||
};
|
||||
hir::ConstItemRhs::TypeConst(self.arena.alloc(const_arg))
|
||||
}
|
||||
|
|
@ -2386,16 +2399,65 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
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",
|
||||
);
|
||||
|
||||
ConstArg { hir_id: this.next_id(), kind: hir::ConstArgKind::Error(expr.span, e.emit()) }
|
||||
ConstArg { hir_id: this.next_id(), kind: hir::ConstArgKind::Error(e.emit()), span }
|
||||
};
|
||||
|
||||
match &expr.kind {
|
||||
ExprKind::Call(func, args) if let ExprKind::Path(qself, path) = &func.kind => {
|
||||
let qpath = self.lower_qpath(
|
||||
func.id,
|
||||
qself,
|
||||
path,
|
||||
ParamMode::Explicit,
|
||||
AllowReturnTypeNotation::No,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
|
||||
let lowered_args = self.arena.alloc_from_iter(args.iter().map(|arg| {
|
||||
let const_arg = if let ExprKind::ConstBlock(anon_const) = &arg.kind {
|
||||
let def_id = self.local_def_id(anon_const.id);
|
||||
let def_kind = self.tcx.def_kind(def_id);
|
||||
assert_eq!(DefKind::AnonConst, def_kind);
|
||||
self.lower_anon_const_to_const_arg(anon_const)
|
||||
} else {
|
||||
self.lower_expr_to_const_arg_direct(arg)
|
||||
};
|
||||
|
||||
&*self.arena.alloc(const_arg)
|
||||
}));
|
||||
|
||||
ConstArg {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::ConstArgKind::TupleCall(qpath, lowered_args),
|
||||
span,
|
||||
}
|
||||
}
|
||||
ExprKind::Tup(exprs) => {
|
||||
let exprs = self.arena.alloc_from_iter(exprs.iter().map(|expr| {
|
||||
let expr = if let ExprKind::ConstBlock(anon_const) = &expr.kind {
|
||||
let def_id = self.local_def_id(anon_const.id);
|
||||
let def_kind = self.tcx.def_kind(def_id);
|
||||
assert_eq!(DefKind::AnonConst, def_kind);
|
||||
|
||||
self.lower_anon_const_to_const_arg(anon_const)
|
||||
} else {
|
||||
self.lower_expr_to_const_arg_direct(&expr)
|
||||
};
|
||||
|
||||
&*self.arena.alloc(expr)
|
||||
}));
|
||||
|
||||
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Tup(exprs), span }
|
||||
}
|
||||
ExprKind::Path(qself, path) => {
|
||||
let qpath = self.lower_qpath(
|
||||
expr.id,
|
||||
|
|
@ -2408,7 +2470,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
None,
|
||||
);
|
||||
|
||||
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Path(qpath) }
|
||||
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Path(qpath), span }
|
||||
}
|
||||
ExprKind::Struct(se) => {
|
||||
let path = self.lower_qpath(
|
||||
|
|
@ -2436,7 +2498,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let def_kind = self.tcx.def_kind(def_id);
|
||||
assert_eq!(DefKind::AnonConst, def_kind);
|
||||
|
||||
self.lower_anon_const_to_const_arg_direct(anon_const)
|
||||
self.lower_anon_const_to_const_arg(anon_const)
|
||||
} else {
|
||||
self.lower_expr_to_const_arg_direct(&f.expr)
|
||||
};
|
||||
|
|
@ -2449,18 +2511,27 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
})
|
||||
}));
|
||||
|
||||
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Struct(path, fields) }
|
||||
ConstArg {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::ConstArgKind::Struct(path, fields),
|
||||
span,
|
||||
}
|
||||
}
|
||||
ExprKind::Underscore => ConstArg {
|
||||
hir_id: self.lower_node_id(expr.id),
|
||||
kind: hir::ConstArgKind::Infer(expr.span, ()),
|
||||
kind: hir::ConstArgKind::Infer(()),
|
||||
span,
|
||||
},
|
||||
ExprKind::Block(block, _) => {
|
||||
if let [stmt] = block.stmts.as_slice()
|
||||
&& let StmtKind::Expr(expr) = &stmt.kind
|
||||
&& matches!(
|
||||
expr.kind,
|
||||
ExprKind::Block(..) | ExprKind::Path(..) | ExprKind::Struct(..)
|
||||
ExprKind::Block(..)
|
||||
| ExprKind::Path(..)
|
||||
| ExprKind::Struct(..)
|
||||
| ExprKind::Call(..)
|
||||
| ExprKind::Tup(..)
|
||||
)
|
||||
{
|
||||
return self.lower_expr_to_const_arg_direct(expr);
|
||||
|
|
@ -2468,18 +2539,31 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
|
||||
overly_complex_const(self)
|
||||
}
|
||||
ExprKind::Lit(literal) => {
|
||||
let span = expr.span;
|
||||
let literal = self.lower_lit(literal, span);
|
||||
|
||||
ConstArg {
|
||||
hir_id: self.lower_node_id(expr.id),
|
||||
kind: hir::ConstArgKind::Literal(literal.node),
|
||||
span,
|
||||
}
|
||||
}
|
||||
_ => overly_complex_const(self),
|
||||
}
|
||||
}
|
||||
|
||||
/// See [`hir::ConstArg`] for when to use this function vs
|
||||
/// [`Self::lower_anon_const_to_anon_const`].
|
||||
fn lower_anon_const_to_const_arg(&mut self, anon: &AnonConst) -> &'hir hir::ConstArg<'hir> {
|
||||
self.arena.alloc(self.lower_anon_const_to_const_arg_direct(anon))
|
||||
fn lower_anon_const_to_const_arg_and_alloc(
|
||||
&mut self,
|
||||
anon: &AnonConst,
|
||||
) -> &'hir hir::ConstArg<'hir> {
|
||||
self.arena.alloc(self.lower_anon_const_to_const_arg(anon))
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn lower_anon_const_to_const_arg_direct(&mut self, anon: &AnonConst) -> hir::ConstArg<'hir> {
|
||||
fn lower_anon_const_to_const_arg(&mut self, anon: &AnonConst) -> hir::ConstArg<'hir> {
|
||||
let tcx = self.tcx;
|
||||
|
||||
// We cannot change parsing depending on feature gates available,
|
||||
|
|
@ -2491,7 +2575,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
return match anon.mgca_disambiguation {
|
||||
MgcaDisambiguation::AnonConst => {
|
||||
let lowered_anon = self.lower_anon_const_to_anon_const(anon);
|
||||
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Anon(lowered_anon) }
|
||||
ConstArg {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::ConstArgKind::Anon(lowered_anon),
|
||||
span: lowered_anon.span,
|
||||
}
|
||||
}
|
||||
MgcaDisambiguation::Direct => self.lower_expr_to_const_arg_direct(&anon.value),
|
||||
};
|
||||
|
|
@ -2528,11 +2616,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
return ConstArg {
|
||||
hir_id: self.lower_node_id(anon.id),
|
||||
kind: hir::ConstArgKind::Path(qpath),
|
||||
span: self.lower_span(expr.span),
|
||||
};
|
||||
}
|
||||
|
||||
let lowered_anon = self.lower_anon_const_to_anon_const(anon);
|
||||
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Anon(lowered_anon) }
|
||||
ConstArg {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::ConstArgKind::Anon(lowered_anon),
|
||||
span: self.lower_span(expr.span),
|
||||
}
|
||||
}
|
||||
|
||||
/// See [`hir::ConstArg`] for when to use this function vs
|
||||
|
|
|
|||
|
|
@ -444,16 +444,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let pat_hir_id = self.lower_node_id(pattern.id);
|
||||
let node = match &pattern.kind {
|
||||
TyPatKind::Range(e1, e2, Spanned { node: end, span }) => hir::TyPatKind::Range(
|
||||
e1.as_deref().map(|e| self.lower_anon_const_to_const_arg(e)).unwrap_or_else(|| {
|
||||
self.lower_ty_pat_range_end(
|
||||
hir::LangItem::RangeMin,
|
||||
span.shrink_to_lo(),
|
||||
base_type,
|
||||
)
|
||||
}),
|
||||
e1.as_deref()
|
||||
.map(|e| self.lower_anon_const_to_const_arg_and_alloc(e))
|
||||
.unwrap_or_else(|| {
|
||||
self.lower_ty_pat_range_end(
|
||||
hir::LangItem::RangeMin,
|
||||
span.shrink_to_lo(),
|
||||
base_type,
|
||||
)
|
||||
}),
|
||||
e2.as_deref()
|
||||
.map(|e| match end {
|
||||
RangeEnd::Included(..) => self.lower_anon_const_to_const_arg(e),
|
||||
RangeEnd::Included(..) => self.lower_anon_const_to_const_arg_and_alloc(e),
|
||||
RangeEnd::Excluded => self.lower_excluded_range_end(e),
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
|
|
@ -511,6 +513,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
self.arena.alloc(hir::ConstArg {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::ConstArgKind::Anon(self.arena.alloc(anon_const)),
|
||||
span,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -555,6 +558,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
})
|
||||
});
|
||||
let hir_id = self.next_id();
|
||||
self.arena.alloc(hir::ConstArg { kind: hir::ConstArgKind::Anon(ct), hir_id })
|
||||
self.arena.alloc(hir::ConstArg { kind: hir::ConstArgKind::Anon(ct), hir_id, span })
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let qself = qself
|
||||
.as_ref()
|
||||
// Reject cases like `<impl Trait>::Assoc` and `<impl Trait as Trait>::Assoc`.
|
||||
.map(|q| self.lower_ty(&q.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path)));
|
||||
.map(|q| {
|
||||
self.lower_ty_alloc(&q.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path))
|
||||
});
|
||||
|
||||
let partial_res =
|
||||
self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err));
|
||||
|
|
@ -510,7 +512,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// we generally don't permit such things (see #51008).
|
||||
let ParenthesizedArgs { span, inputs, inputs_span, output } = data;
|
||||
let inputs = self.arena.alloc_from_iter(inputs.iter().map(|ty| {
|
||||
self.lower_ty_direct(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam))
|
||||
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam))
|
||||
}));
|
||||
let output_ty = match output {
|
||||
// Only allow `impl Trait` in return position. i.e.:
|
||||
|
|
@ -520,9 +522,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// ```
|
||||
FnRetTy::Ty(ty) if matches!(itctx, ImplTraitContext::OpaqueTy { .. }) => {
|
||||
if self.tcx.features().impl_trait_in_fn_trait_return() {
|
||||
self.lower_ty(ty, itctx)
|
||||
self.lower_ty_alloc(ty, itctx)
|
||||
} else {
|
||||
self.lower_ty(
|
||||
self.lower_ty_alloc(
|
||||
ty,
|
||||
ImplTraitContext::FeatureGated(
|
||||
ImplTraitPosition::FnTraitReturn,
|
||||
|
|
@ -531,9 +533,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
)
|
||||
}
|
||||
}
|
||||
FnRetTy::Ty(ty) => {
|
||||
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn))
|
||||
}
|
||||
FnRetTy::Ty(ty) => self
|
||||
.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn)),
|
||||
FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])),
|
||||
};
|
||||
let args = smallvec![GenericArg::Type(
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@ impl<'a> PostExpansionVisitor<'a> {
|
|||
|
||||
impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
fn visit_attribute(&mut self, attr: &ast::Attribute) {
|
||||
let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
|
||||
let attr_info = attr.name().and_then(|name| BUILTIN_ATTRIBUTE_MAP.get(&name));
|
||||
// Check feature gates for built-in attributes.
|
||||
if let Some(BuiltinAttribute {
|
||||
gate: AttributeGate::Gated { feature, message, check, notes, .. },
|
||||
|
|
@ -505,7 +505,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
|||
half_open_range_patterns_in_slices,
|
||||
"half-open range patterns in slices are unstable"
|
||||
);
|
||||
gate_all!(associated_const_equality, "associated const equality is incomplete");
|
||||
gate_all!(yeet_expr, "`do yeet` expression is experimental");
|
||||
gate_all!(const_closures, "const closures are experimental");
|
||||
gate_all!(builtin_syntax, "`builtin #` syntax is unstable");
|
||||
|
|
@ -518,6 +517,23 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
|||
gate_all!(postfix_match, "postfix match is experimental");
|
||||
gate_all!(mut_ref, "mutable by-reference bindings are experimental");
|
||||
gate_all!(min_generic_const_args, "unbraced const blocks as const args are experimental");
|
||||
// associated_const_equality is stabilized as part of min_generic_const_args
|
||||
if let Some(spans) = spans.get(&sym::associated_const_equality) {
|
||||
for span in spans {
|
||||
if !visitor.features.min_generic_const_args()
|
||||
&& !span.allows_unstable(sym::min_generic_const_args)
|
||||
{
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
feature_err(
|
||||
&visitor.sess,
|
||||
sym::min_generic_const_args,
|
||||
*span,
|
||||
"associated const equality is incomplete",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
gate_all!(global_registration, "global registration is experimental");
|
||||
gate_all!(return_type_notation, "return type notation is experimental");
|
||||
gate_all!(pin_ergonomics, "pinned reference syntax is experimental");
|
||||
|
|
|
|||
|
|
@ -694,7 +694,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
}
|
||||
ast::Safety::Default | ast::Safety::Safe(_) => {}
|
||||
}
|
||||
match &item.args {
|
||||
match &item.args.unparsed_ref().expect("Parsed attributes are never printed") {
|
||||
AttrArgs::Delimited(DelimArgs { dspan: _, delim, tokens }) => self.print_mac_common(
|
||||
Some(MacHeader::Path(&item.path)),
|
||||
false,
|
||||
|
|
|
|||
|
|
@ -294,11 +294,9 @@ pub fn parse_cfg_attr(
|
|||
sess: &Session,
|
||||
features: Option<&Features>,
|
||||
) -> Option<(CfgEntry, Vec<(AttrItem, Span)>)> {
|
||||
match cfg_attr.get_normal_item().args {
|
||||
ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, ref tokens })
|
||||
if !tokens.is_empty() =>
|
||||
{
|
||||
check_cfg_attr_bad_delim(&sess.psess, dspan, delim);
|
||||
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)
|
||||
}) {
|
||||
|
|
@ -322,7 +320,7 @@ pub fn parse_cfg_attr(
|
|||
}
|
||||
_ => {
|
||||
let (span, reason) = if let ast::AttrArgs::Delimited(ast::DelimArgs { dspan, .. }) =
|
||||
cfg_attr.get_normal_item().args
|
||||
cfg_attr.get_normal_item().args.unparsed_ref()?
|
||||
{
|
||||
(dspan.entire(), AttributeParseErrorReason::ExpectedAtLeastOneArgument)
|
||||
} else {
|
||||
|
|
@ -371,13 +369,7 @@ fn parse_cfg_attr_internal<'a>(
|
|||
attribute.span,
|
||||
attribute.get_normal_item().span(),
|
||||
attribute.style,
|
||||
AttrPath {
|
||||
segments: attribute
|
||||
.ident_path()
|
||||
.expect("cfg_attr is not a doc comment")
|
||||
.into_boxed_slice(),
|
||||
span: attribute.span,
|
||||
},
|
||||
AttrPath { segments: attribute.path().into_boxed_slice(), span: attribute.span },
|
||||
Some(attribute.get_normal_item().unsafety),
|
||||
ParsedDescription::Attribute,
|
||||
pred_span,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use rustc_hir::attrs::CfgEntry;
|
|||
use rustc_parse::exp;
|
||||
use rustc_parse::parser::Parser;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::{ErrorGuaranteed, Ident, Span};
|
||||
use rustc_span::{ErrorGuaranteed, Span, sym};
|
||||
|
||||
use crate::parser::MetaItemOrLitParser;
|
||||
use crate::{AttributeParser, ParsedDescription, ShouldEmit, parse_cfg_entry};
|
||||
|
|
@ -86,10 +86,7 @@ pub fn parse_cfg_select(
|
|||
cfg_span,
|
||||
cfg_span,
|
||||
AttrStyle::Inner,
|
||||
AttrPath {
|
||||
segments: vec![Ident::from_str("cfg_select")].into_boxed_slice(),
|
||||
span: cfg_span,
|
||||
},
|
||||
AttrPath { segments: vec![sym::cfg_select].into_boxed_slice(), span: cfg_span },
|
||||
None,
|
||||
ParsedDescription::Macro,
|
||||
cfg_span,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ impl<S: Stage> SingleAttributeParser<S> for CrateNameParser {
|
|||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let ArgParser::NameValue(n) = args else {
|
||||
|
|
@ -33,7 +33,7 @@ impl<S: Stage> SingleAttributeParser<S> for RecursionLimitParser {
|
|||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N", "https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute");
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let ArgParser::NameValue(nv) = args else {
|
||||
|
|
@ -56,7 +56,7 @@ impl<S: Stage> SingleAttributeParser<S> for MoveSizeLimitParser {
|
|||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let ArgParser::NameValue(nv) = args else {
|
||||
|
|
@ -79,7 +79,7 @@ impl<S: Stage> SingleAttributeParser<S> for TypeLengthLimitParser {
|
|||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let ArgParser::NameValue(nv) = args else {
|
||||
|
|
@ -102,7 +102,7 @@ impl<S: Stage> SingleAttributeParser<S> for PatternComplexityLimitParser {
|
|||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let ArgParser::NameValue(nv) = args else {
|
||||
|
|
@ -123,7 +123,7 @@ pub(crate) struct NoCoreParser;
|
|||
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::CrateLevel;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoCore;
|
||||
}
|
||||
|
||||
|
|
@ -132,7 +132,7 @@ pub(crate) struct NoStdParser;
|
|||
impl<S: Stage> NoArgsAttributeParser<S> for NoStdParser {
|
||||
const PATH: &[Symbol] = &[sym::no_std];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoStd;
|
||||
}
|
||||
|
||||
|
|
@ -141,7 +141,7 @@ pub(crate) struct RustcCoherenceIsCoreParser;
|
|||
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::CrateLevel;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcCoherenceIsCore;
|
||||
}
|
||||
|
||||
|
|
@ -151,7 +151,7 @@ impl<S: Stage> SingleAttributeParser<S> for WindowsSubsystemParser {
|
|||
const PATH: &[Symbol] = &[sym::windows_subsystem];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: ["windows", "console"], "https://doc.rust-lang.org/reference/runtime.html#the-windows_subsystem-attribute");
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
|
|
|
|||
|
|
@ -305,3 +305,18 @@ impl<S: Stage> SingleAttributeParser<S> for RustcScalableVectorParser {
|
|||
Some(AttributeKind::RustcScalableVector { element_count: Some(n), span: cx.attr_span })
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct RustcHasIncoherentInherentImplsParser;
|
||||
|
||||
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),
|
||||
Allow(Target::Enum),
|
||||
Allow(Target::Union),
|
||||
Allow(Target::ForeignTy),
|
||||
]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcHasIncoherentInherentImpls;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use std::num::NonZero;
|
||||
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::target::GenericParamKind;
|
||||
use rustc_hir::{
|
||||
DefaultBodyStability, MethodKind, PartialConstStability, Stability, StabilityLevel,
|
||||
StableSince, Target, UnstableReason, VERSION_PLACEHOLDER,
|
||||
|
|
@ -43,7 +44,7 @@ const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
|||
Allow(Target::TyAlias),
|
||||
Allow(Target::Variant),
|
||||
Allow(Target::Field),
|
||||
Allow(Target::Param),
|
||||
Allow(Target::GenericParam { kind: GenericParamKind::Type, has_default: true }),
|
||||
Allow(Target::Static),
|
||||
Allow(Target::ForeignFn),
|
||||
Allow(Target::ForeignStatic),
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ impl<S: Stage> SingleAttributeParser<S> for TransparencyParser {
|
|||
});
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::MacroDef)]);
|
||||
const TEMPLATE: AttributeTemplate =
|
||||
template!(NameValueStr: ["transparent", "semitransparent", "opaque"]);
|
||||
template!(NameValueStr: ["transparent", "semiopaque", "opaque"]);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let Some(nv) = args.name_value() else {
|
||||
|
|
@ -24,12 +24,12 @@ impl<S: Stage> SingleAttributeParser<S> for TransparencyParser {
|
|||
};
|
||||
match nv.value_as_str() {
|
||||
Some(sym::transparent) => Some(Transparency::Transparent),
|
||||
Some(sym::semiopaque | sym::semitransparent) => Some(Transparency::SemiOpaque),
|
||||
Some(sym::semiopaque) => Some(Transparency::SemiOpaque),
|
||||
Some(sym::opaque) => Some(Transparency::Opaque),
|
||||
Some(_) => {
|
||||
cx.expected_specific_argument_strings(
|
||||
nv.value_span,
|
||||
&[sym::transparent, sym::semitransparent, sym::opaque],
|
||||
&[sym::transparent, sym::semiopaque, sym::opaque],
|
||||
);
|
||||
None
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@ pub fn parse_version(s: Symbol) -> Option<RustcVersion> {
|
|||
}
|
||||
|
||||
pub fn is_builtin_attr(attr: &impl AttributeExt) -> bool {
|
||||
attr.is_doc_comment().is_some()
|
||||
|| attr.ident().is_some_and(|ident| is_builtin_attr_name(ident.name))
|
||||
attr.is_doc_comment().is_some() || attr.name().is_some_and(|name| is_builtin_attr_name(name))
|
||||
}
|
||||
|
||||
/// Parse a single integer.
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@ use std::ops::{Deref, DerefMut};
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use private::Sealed;
|
||||
use rustc_ast::{AttrStyle, CRATE_NODE_ID, MetaItemLit, NodeId};
|
||||
use rustc_ast::{AttrStyle, MetaItemLit, NodeId};
|
||||
use rustc_errors::{Diag, Diagnostic, Level};
|
||||
use rustc_feature::{AttrSuggestionStyle, AttributeTemplate};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::lints::{AttributeLint, AttributeLintKind};
|
||||
use rustc_hir::{AttrPath, CRATE_HIR_ID, HirId};
|
||||
use rustc_hir::{AttrPath, HirId};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::lint::{Lint, LintId};
|
||||
use rustc_span::{ErrorGuaranteed, Span, Symbol};
|
||||
|
|
@ -62,12 +62,12 @@ use crate::attributes::proc_macro_attrs::{
|
|||
use crate::attributes::prototype::CustomMirParser;
|
||||
use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser};
|
||||
use crate::attributes::rustc_internal::{
|
||||
RustcLayoutScalarValidRangeEndParser, RustcLayoutScalarValidRangeStartParser,
|
||||
RustcLegacyConstGenericsParser, RustcLintDiagnosticsParser, RustcLintOptDenyFieldAccessParser,
|
||||
RustcLintOptTyParser, RustcLintQueryInstabilityParser,
|
||||
RustcLintUntrackedQueryInformationParser, RustcMainParser, RustcMustImplementOneOfParser,
|
||||
RustcNeverReturnsNullPointerParser, RustcNoImplicitAutorefsParser,
|
||||
RustcObjectLifetimeDefaultParser, RustcScalableVectorParser,
|
||||
RustcHasIncoherentInherentImplsParser, RustcLayoutScalarValidRangeEndParser,
|
||||
RustcLayoutScalarValidRangeStartParser, RustcLegacyConstGenericsParser,
|
||||
RustcLintDiagnosticsParser, RustcLintOptDenyFieldAccessParser, RustcLintOptTyParser,
|
||||
RustcLintQueryInstabilityParser, RustcLintUntrackedQueryInformationParser, RustcMainParser,
|
||||
RustcMustImplementOneOfParser, RustcNeverReturnsNullPointerParser,
|
||||
RustcNoImplicitAutorefsParser, RustcObjectLifetimeDefaultParser, RustcScalableVectorParser,
|
||||
RustcSimdMonomorphizeLaneLimitParser,
|
||||
};
|
||||
use crate::attributes::semantics::MayDangleParser;
|
||||
|
|
@ -264,6 +264,7 @@ attribute_parsers!(
|
|||
Single<WithoutArgs<ProcMacroParser>>,
|
||||
Single<WithoutArgs<PubTransparentParser>>,
|
||||
Single<WithoutArgs<RustcCoherenceIsCoreParser>>,
|
||||
Single<WithoutArgs<RustcHasIncoherentInherentImplsParser>>,
|
||||
Single<WithoutArgs<RustcLintDiagnosticsParser>>,
|
||||
Single<WithoutArgs<RustcLintOptTyParser>>,
|
||||
Single<WithoutArgs<RustcLintQueryInstabilityParser>>,
|
||||
|
|
@ -303,8 +304,6 @@ pub trait Stage: Sized + 'static + Sealed {
|
|||
) -> ErrorGuaranteed;
|
||||
|
||||
fn should_emit(&self) -> ShouldEmit;
|
||||
|
||||
fn id_is_crate_root(id: Self::Id) -> bool;
|
||||
}
|
||||
|
||||
// allow because it's a sealed trait
|
||||
|
|
@ -326,10 +325,6 @@ impl Stage for Early {
|
|||
fn should_emit(&self) -> ShouldEmit {
|
||||
self.emit_errors
|
||||
}
|
||||
|
||||
fn id_is_crate_root(id: Self::Id) -> bool {
|
||||
id == CRATE_NODE_ID
|
||||
}
|
||||
}
|
||||
|
||||
// allow because it's a sealed trait
|
||||
|
|
@ -351,10 +346,6 @@ impl Stage for Late {
|
|||
fn should_emit(&self) -> ShouldEmit {
|
||||
ShouldEmit::ErrorsAndLints
|
||||
}
|
||||
|
||||
fn id_is_crate_root(id: Self::Id) -> bool {
|
||||
id == CRATE_HIR_ID
|
||||
}
|
||||
}
|
||||
|
||||
/// used when parsing attributes for miscellaneous things *before* ast lowering
|
||||
|
|
|
|||
53
compiler/rustc_attr_parsing/src/early_parsed.rs
Normal file
53
compiler/rustc_attr_parsing/src/early_parsed.rs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
use rustc_ast::EarlyParsedAttribute;
|
||||
use rustc_ast::attr::data_structures::CfgEntry;
|
||||
use rustc_hir::Attribute;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
pub(crate) const EARLY_PARSED_ATTRIBUTES: &[&[Symbol]] =
|
||||
&[&[sym::cfg_trace], &[sym::cfg_attr_trace]];
|
||||
|
||||
/// This struct contains the state necessary to convert early parsed attributes to hir attributes
|
||||
/// The only conversion that really happens here is that multiple early parsed attributes are
|
||||
/// merged into a single hir attribute, representing their combined state.
|
||||
/// FIXME: We should make this a nice and extendable system if this is going to be used more often
|
||||
#[derive(Default)]
|
||||
pub(crate) struct EarlyParsedState {
|
||||
/// Attribute state for `#[cfg]` trace attributes
|
||||
cfg_trace: ThinVec<(CfgEntry, Span)>,
|
||||
|
||||
/// Attribute state for `#[cfg_attr]` trace attributes
|
||||
/// The arguments of these attributes is no longer relevant for any later passes, only their presence.
|
||||
/// So we discard the arguments here.
|
||||
cfg_attr_trace: bool,
|
||||
}
|
||||
|
||||
impl EarlyParsedState {
|
||||
pub(crate) fn accept_early_parsed_attribute(
|
||||
&mut self,
|
||||
attr_span: Span,
|
||||
lower_span: impl Copy + Fn(Span) -> Span,
|
||||
parsed: &EarlyParsedAttribute,
|
||||
) {
|
||||
match parsed {
|
||||
EarlyParsedAttribute::CfgTrace(cfg) => {
|
||||
let mut cfg = cfg.clone();
|
||||
cfg.lower_spans(lower_span);
|
||||
self.cfg_trace.push((cfg, attr_span));
|
||||
}
|
||||
EarlyParsedAttribute::CfgAttrTrace => {
|
||||
self.cfg_attr_trace = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn finalize_early_parsed_attributes(self, attributes: &mut Vec<Attribute>) {
|
||||
if !self.cfg_trace.is_empty() {
|
||||
attributes.push(Attribute::Parsed(AttributeKind::CfgTrace(self.cfg_trace)));
|
||||
}
|
||||
if self.cfg_attr_trace {
|
||||
attributes.push(Attribute::Parsed(AttributeKind::CfgAttrTrace));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@ use std::convert::identity;
|
|||
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::token::DocFragmentKind;
|
||||
use rustc_ast::{AttrStyle, NodeId, Safety};
|
||||
use rustc_ast::{AttrItemKind, AttrStyle, NodeId, Safety};
|
||||
use rustc_errors::DiagCtxtHandle;
|
||||
use rustc_feature::{AttributeTemplate, Features};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
|
|
@ -13,6 +13,7 @@ use rustc_session::lint::BuiltinLintDiag;
|
|||
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
|
||||
|
||||
use crate::context::{AcceptContext, FinalizeContext, SharedContext, Stage};
|
||||
use crate::early_parsed::{EARLY_PARSED_ATTRIBUTES, EarlyParsedState};
|
||||
use crate::parser::{ArgParser, PathParser, RefPathParser};
|
||||
use crate::session_diagnostics::ParsedDescription;
|
||||
use crate::{Early, Late, OmitDoc, ShouldEmit};
|
||||
|
|
@ -146,8 +147,12 @@ impl<'sess> AttributeParser<'sess, Early> {
|
|||
normal_attr.item.path.segments.iter().map(|seg| seg.ident.name).collect::<Vec<_>>();
|
||||
|
||||
let path = AttrPath::from_ast(&normal_attr.item.path, identity);
|
||||
let args =
|
||||
ArgParser::from_attr_args(&normal_attr.item.args, &parts, &sess.psess, emit_errors)?;
|
||||
let args = ArgParser::from_attr_args(
|
||||
&normal_attr.item.args.unparsed_ref().unwrap(),
|
||||
&parts,
|
||||
&sess.psess,
|
||||
emit_errors,
|
||||
)?;
|
||||
Self::parse_single_args(
|
||||
sess,
|
||||
attr.span,
|
||||
|
|
@ -263,12 +268,12 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
target_id: S::Id,
|
||||
target: Target,
|
||||
omit_doc: OmitDoc,
|
||||
|
||||
lower_span: impl Copy + Fn(Span) -> Span,
|
||||
mut emit_lint: impl FnMut(AttributeLint<S::Id>),
|
||||
) -> Vec<Attribute> {
|
||||
let mut attributes = Vec::new();
|
||||
let mut attr_paths: Vec<RefPathParser<'_>> = Vec::new();
|
||||
let mut early_parsed_state = EarlyParsedState::default();
|
||||
|
||||
for attr in attrs {
|
||||
// If we're only looking for a single attribute, skip all the ones we don't care about.
|
||||
|
|
@ -288,6 +293,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
continue;
|
||||
}
|
||||
|
||||
let attr_span = lower_span(attr.span);
|
||||
match &attr.kind {
|
||||
ast::AttrKind::DocComment(comment_kind, symbol) => {
|
||||
if omit_doc == OmitDoc::Skip {
|
||||
|
|
@ -297,7 +303,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
attributes.push(Attribute::Parsed(AttributeKind::DocComment {
|
||||
style: attr.style,
|
||||
kind: DocFragmentKind::Sugared(*comment_kind),
|
||||
span: lower_span(attr.span),
|
||||
span: attr_span,
|
||||
comment: *symbol,
|
||||
}))
|
||||
}
|
||||
|
|
@ -305,6 +311,15 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
attr_paths.push(PathParser(&n.item.path));
|
||||
let attr_path = AttrPath::from_ast(&n.item.path, lower_span);
|
||||
|
||||
let args = match &n.item.args {
|
||||
AttrItemKind::Unparsed(args) => args,
|
||||
AttrItemKind::Parsed(parsed) => {
|
||||
early_parsed_state
|
||||
.accept_early_parsed_attribute(attr_span, lower_span, parsed);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
self.check_attribute_safety(
|
||||
&attr_path,
|
||||
lower_span(n.item.span()),
|
||||
|
|
@ -318,7 +333,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
|
||||
if let Some(accepts) = S::parsers().accepters.get(parts.as_slice()) {
|
||||
let Some(args) = ArgParser::from_attr_args(
|
||||
&n.item.args,
|
||||
args,
|
||||
&parts,
|
||||
&self.sess.psess,
|
||||
self.stage.should_emit(),
|
||||
|
|
@ -351,7 +366,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
attributes.push(Attribute::Parsed(AttributeKind::DocComment {
|
||||
style: attr.style,
|
||||
kind: DocFragmentKind::Raw(nv.value_span),
|
||||
span: attr.span,
|
||||
span: attr_span,
|
||||
comment,
|
||||
}));
|
||||
continue;
|
||||
|
|
@ -365,7 +380,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
target_id,
|
||||
emit_lint: &mut emit_lint,
|
||||
},
|
||||
attr_span: lower_span(attr.span),
|
||||
attr_span,
|
||||
inner_span: lower_span(n.item.span()),
|
||||
attr_style: attr.style,
|
||||
parsed_description: ParsedDescription::Attribute,
|
||||
|
|
@ -396,17 +411,18 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
|
||||
attributes.push(Attribute::Unparsed(Box::new(AttrItem {
|
||||
path: attr_path.clone(),
|
||||
args: self.lower_attr_args(&n.item.args, lower_span),
|
||||
args: self
|
||||
.lower_attr_args(n.item.args.unparsed_ref().unwrap(), lower_span),
|
||||
id: HashIgnoredAttrId { attr_id: attr.id },
|
||||
style: attr.style,
|
||||
span: lower_span(attr.span),
|
||||
span: attr_span,
|
||||
})));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut parsed_attributes = Vec::new();
|
||||
early_parsed_state.finalize_early_parsed_attributes(&mut attributes);
|
||||
for f in &S::parsers().finalizers {
|
||||
if let Some(attr) = f(&mut FinalizeContext {
|
||||
shared: SharedContext {
|
||||
|
|
@ -417,18 +433,16 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
},
|
||||
all_attrs: &attr_paths,
|
||||
}) {
|
||||
parsed_attributes.push(Attribute::Parsed(attr));
|
||||
attributes.push(Attribute::Parsed(attr));
|
||||
}
|
||||
}
|
||||
|
||||
attributes.extend(parsed_attributes);
|
||||
|
||||
attributes
|
||||
}
|
||||
|
||||
/// Returns whether there is a parser for an attribute with this name
|
||||
pub fn is_parsed_attribute(path: &[Symbol]) -> bool {
|
||||
Late::parsers().accepters.contains_key(path)
|
||||
Late::parsers().accepters.contains_key(path) || EARLY_PARSED_ATTRIBUTES.contains(&path)
|
||||
}
|
||||
|
||||
fn lower_attr_args(&self, args: &ast::AttrArgs, lower_span: impl Fn(Span) -> Span) -> AttrArgs {
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ mod interface;
|
|||
/// like lists or name-value pairs.
|
||||
pub mod parser;
|
||||
|
||||
mod early_parsed;
|
||||
mod safety;
|
||||
mod session_diagnostics;
|
||||
mod target_checking;
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ pub type RefPathParser<'p> = PathParser<&'p Path>;
|
|||
impl<P: Borrow<Path>> PathParser<P> {
|
||||
pub fn get_attribute_path(&self) -> hir::AttrPath {
|
||||
AttrPath {
|
||||
segments: self.segments().copied().collect::<Vec<_>>().into_boxed_slice(),
|
||||
segments: self.segments().map(|s| s.name).collect::<Vec<_>>().into_boxed_slice(),
|
||||
span: self.span(),
|
||||
}
|
||||
}
|
||||
|
|
@ -122,10 +122,10 @@ impl ArgParser {
|
|||
}
|
||||
|
||||
if args.delim != Delimiter::Parenthesis {
|
||||
psess.dcx().emit_err(MetaBadDelim {
|
||||
should_emit.emit_err(psess.dcx().create_err(MetaBadDelim {
|
||||
span: args.dspan.entire(),
|
||||
sugg: MetaBadDelimSugg { open: args.dspan.open, close: args.dspan.close },
|
||||
});
|
||||
}));
|
||||
return None;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use rustc_hir::AttrPath;
|
|||
use rustc_hir::lints::{AttributeLint, AttributeLintKind};
|
||||
use rustc_session::lint::LintId;
|
||||
use rustc_session::lint::builtin::UNSAFE_ATTR_OUTSIDE_UNSAFE;
|
||||
use rustc_span::{Span, sym};
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::context::Stage;
|
||||
use crate::{AttributeParser, ShouldEmit};
|
||||
|
|
@ -22,12 +22,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
return;
|
||||
}
|
||||
|
||||
let name = (attr_path.segments.len() == 1).then_some(attr_path.segments[0].name);
|
||||
if let Some(name) = name
|
||||
&& [sym::cfg_trace, sym::cfg_attr_trace].contains(&name)
|
||||
{
|
||||
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));
|
||||
|
|
|
|||
|
|
@ -15,11 +15,6 @@ use crate::session_diagnostics::InvalidTarget;
|
|||
pub(crate) enum AllowedTargets {
|
||||
AllowList(&'static [Policy]),
|
||||
AllowListWarnRest(&'static [Policy]),
|
||||
/// Special, and not the same as `AllowList(&[Allow(Target::Crate)])`.
|
||||
/// For crate-level attributes we emit a specific set of lints to warn
|
||||
/// people about accidentally not using them on the crate.
|
||||
/// Only use this for attributes that are *exclusively* valid at the crate level.
|
||||
CrateLevel,
|
||||
}
|
||||
|
||||
pub(crate) enum AllowedResult {
|
||||
|
|
@ -53,7 +48,6 @@ impl AllowedTargets {
|
|||
AllowedResult::Warn
|
||||
}
|
||||
}
|
||||
AllowedTargets::CrateLevel => AllowedResult::Allowed,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -61,7 +55,6 @@ impl AllowedTargets {
|
|||
match self {
|
||||
AllowedTargets::AllowList(list) => list,
|
||||
AllowedTargets::AllowListWarnRest(list) => list,
|
||||
AllowedTargets::CrateLevel => ALL_TARGETS,
|
||||
}
|
||||
.iter()
|
||||
.filter_map(|target| match target {
|
||||
|
|
@ -95,7 +88,10 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
target: Target,
|
||||
cx: &mut AcceptContext<'_, 'sess, S>,
|
||||
) {
|
||||
Self::check_type(matches!(allowed_targets, AllowedTargets::CrateLevel), target, cx);
|
||||
if allowed_targets.allowed_targets() == &[Target::Crate] {
|
||||
Self::check_crate_level(target, cx);
|
||||
return;
|
||||
}
|
||||
|
||||
match allowed_targets.is_allowed(target) {
|
||||
AllowedResult::Allowed => {}
|
||||
|
|
@ -104,7 +100,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
let (applied, only) = allowed_targets_applied(allowed_targets, target, cx.features);
|
||||
let name = cx.attr_path.clone();
|
||||
|
||||
let lint = if name.segments[0].name == sym::deprecated
|
||||
let lint = if name.segments[0] == sym::deprecated
|
||||
&& ![
|
||||
Target::Closure,
|
||||
Target::Expression,
|
||||
|
|
@ -149,18 +145,10 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn check_type(
|
||||
crate_level: bool,
|
||||
target: Target,
|
||||
cx: &mut AcceptContext<'_, 'sess, S>,
|
||||
) {
|
||||
let is_crate_root = S::id_is_crate_root(cx.target_id);
|
||||
|
||||
if is_crate_root {
|
||||
return;
|
||||
}
|
||||
|
||||
if !crate_level {
|
||||
pub(crate) fn check_crate_level(target: Target, cx: &mut AcceptContext<'_, 'sess, S>) {
|
||||
// For crate-level attributes we emit a specific set of lints to warn
|
||||
// people about accidentally not using them on the crate.
|
||||
if target == Target::Crate {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -310,5 +298,29 @@ pub(crate) const ALL_TARGETS: &'static [Policy] = {
|
|||
Allow(Target::Crate),
|
||||
Allow(Target::Delegation { mac: false }),
|
||||
Allow(Target::Delegation { mac: true }),
|
||||
Allow(Target::GenericParam {
|
||||
kind: rustc_hir::target::GenericParamKind::Const,
|
||||
has_default: false,
|
||||
}),
|
||||
Allow(Target::GenericParam {
|
||||
kind: rustc_hir::target::GenericParamKind::Const,
|
||||
has_default: true,
|
||||
}),
|
||||
Allow(Target::GenericParam {
|
||||
kind: rustc_hir::target::GenericParamKind::Lifetime,
|
||||
has_default: false,
|
||||
}),
|
||||
Allow(Target::GenericParam {
|
||||
kind: rustc_hir::target::GenericParamKind::Lifetime,
|
||||
has_default: true,
|
||||
}),
|
||||
Allow(Target::GenericParam {
|
||||
kind: rustc_hir::target::GenericParamKind::Type,
|
||||
has_default: false,
|
||||
}),
|
||||
Allow(Target::GenericParam {
|
||||
kind: rustc_hir::target::GenericParamKind::Type,
|
||||
has_default: true,
|
||||
}),
|
||||
]
|
||||
};
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute) {
|
|||
return;
|
||||
}
|
||||
|
||||
let builtin_attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
|
||||
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 {
|
||||
|
|
@ -48,7 +48,7 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute) {
|
|||
}
|
||||
_ => {
|
||||
let attr_item = attr.get_normal_item();
|
||||
if let AttrArgs::Eq { .. } = attr_item.args {
|
||||
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(_) => {}
|
||||
|
|
@ -67,7 +67,7 @@ pub fn parse_meta<'a>(psess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Met
|
|||
unsafety: item.unsafety,
|
||||
span: attr.span,
|
||||
path: item.path.clone(),
|
||||
kind: match &item.args {
|
||||
kind: match &item.args.unparsed_ref().unwrap() {
|
||||
AttrArgs::Empty => MetaItemKind::Word,
|
||||
AttrArgs::Delimited(DelimArgs { dspan, delim, tokens }) => {
|
||||
check_meta_bad_delim(psess, *dspan, *delim);
|
||||
|
|
|
|||
|
|
@ -1581,12 +1581,18 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
.unwrap();
|
||||
}
|
||||
(None, None) => {
|
||||
// `struct_tail` returns regions which haven't been mapped
|
||||
// to nll vars yet so we do it here as `outlives_constraints`
|
||||
// expects nll vars.
|
||||
let src_lt = self.universal_regions.to_region_vid(src_lt);
|
||||
let dst_lt = self.universal_regions.to_region_vid(dst_lt);
|
||||
|
||||
// The principalless (no non-auto traits) case:
|
||||
// You can only cast `dyn Send + 'long` to `dyn Send + 'short`.
|
||||
self.constraints.outlives_constraints.push(
|
||||
OutlivesConstraint {
|
||||
sup: src_lt.as_var(),
|
||||
sub: dst_lt.as_var(),
|
||||
sup: src_lt,
|
||||
sub: dst_lt,
|
||||
locations: location.to_locations(),
|
||||
span: location.to_locations().span(self.body),
|
||||
category: ConstraintCategory::Cast {
|
||||
|
|
|
|||
|
|
@ -182,6 +182,8 @@ builtin_macros_expected_other = expected operand, {$is_inline_asm ->
|
|||
|
||||
builtin_macros_export_macro_rules = cannot export macro_rules! macros from a `proc-macro` crate type currently
|
||||
|
||||
builtin_macros_format_add_missing_colon = add a colon before the format specifier
|
||||
|
||||
builtin_macros_format_duplicate_arg = duplicate argument named `{$ident}`
|
||||
.label1 = previously here
|
||||
.label2 = duplicate argument
|
||||
|
|
|
|||
|
|
@ -358,7 +358,7 @@ mod llvm_enzyme {
|
|||
let inline_item = ast::AttrItem {
|
||||
unsafety: ast::Safety::Default,
|
||||
path: ast::Path::from_ident(Ident::with_dummy_span(sym::inline)),
|
||||
args: ast::AttrArgs::Delimited(never_arg),
|
||||
args: rustc_ast::ast::AttrItemKind::Unparsed(ast::AttrArgs::Delimited(never_arg)),
|
||||
tokens: None,
|
||||
};
|
||||
let inline_never_attr = Box::new(ast::NormalAttr { item: inline_item, tokens: None });
|
||||
|
|
@ -421,11 +421,13 @@ mod llvm_enzyme {
|
|||
}
|
||||
};
|
||||
// Now update for d_fn
|
||||
rustc_ad_attr.item.args = rustc_ast::AttrArgs::Delimited(rustc_ast::DelimArgs {
|
||||
dspan: DelimSpan::dummy(),
|
||||
delim: rustc_ast::token::Delimiter::Parenthesis,
|
||||
tokens: ts,
|
||||
});
|
||||
rustc_ad_attr.item.args = rustc_ast::ast::AttrItemKind::Unparsed(
|
||||
rustc_ast::AttrArgs::Delimited(rustc_ast::DelimArgs {
|
||||
dspan: DelimSpan::dummy(),
|
||||
delim: rustc_ast::token::Delimiter::Parenthesis,
|
||||
tokens: ts,
|
||||
}),
|
||||
);
|
||||
|
||||
let new_id = ecx.sess.psess.attr_id_generator.mk_attr_id();
|
||||
let d_attr = outer_normal_attr(&rustc_ad_attr, new_id, span);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpa
|
|||
use rustc_hir::AttrPath;
|
||||
use rustc_hir::attrs::CfgEntry;
|
||||
use rustc_parse::exp;
|
||||
use rustc_span::{ErrorGuaranteed, Ident, Span};
|
||||
use rustc_span::{ErrorGuaranteed, Span, sym};
|
||||
|
||||
use crate::errors;
|
||||
|
||||
|
|
@ -47,7 +47,7 @@ fn parse_cfg(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream) -> Result<CfgEntry,
|
|||
span,
|
||||
span,
|
||||
AttrStyle::Inner,
|
||||
AttrPath { segments: vec![Ident::from_str("cfg")].into_boxed_slice(), span },
|
||||
AttrPath { segments: vec![sym::cfg].into_boxed_slice(), span },
|
||||
None,
|
||||
ParsedDescription::Macro,
|
||||
span,
|
||||
|
|
|
|||
|
|
@ -47,10 +47,7 @@ fn has_cfg_or_cfg_attr(annotatable: &Annotatable) -> bool {
|
|||
impl<'ast> visit::Visitor<'ast> for CfgFinder {
|
||||
type Result = ControlFlow<()>;
|
||||
fn visit_attribute(&mut self, attr: &'ast Attribute) -> ControlFlow<()> {
|
||||
if attr
|
||||
.ident()
|
||||
.is_some_and(|ident| ident.name == sym::cfg || ident.name == sym::cfg_attr)
|
||||
{
|
||||
if attr.name().is_some_and(|name| name == sym::cfg || name == sym::cfg_attr) {
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
ControlFlow::Continue(())
|
||||
|
|
|
|||
|
|
@ -807,24 +807,29 @@ impl<'a> TraitDef<'a> {
|
|||
rustc_ast::AttrItem {
|
||||
unsafety: Safety::Default,
|
||||
path: rustc_const_unstable,
|
||||
args: AttrArgs::Delimited(DelimArgs {
|
||||
dspan: DelimSpan::from_single(self.span),
|
||||
delim: rustc_ast::token::Delimiter::Parenthesis,
|
||||
tokens: [
|
||||
TokenKind::Ident(sym::feature, IdentIsRaw::No),
|
||||
TokenKind::Eq,
|
||||
TokenKind::lit(LitKind::Str, sym::derive_const, None),
|
||||
TokenKind::Comma,
|
||||
TokenKind::Ident(sym::issue, IdentIsRaw::No),
|
||||
TokenKind::Eq,
|
||||
TokenKind::lit(LitKind::Str, sym::derive_const_issue, None),
|
||||
]
|
||||
.into_iter()
|
||||
.map(|kind| {
|
||||
TokenTree::Token(Token { kind, span: self.span }, Spacing::Alone)
|
||||
})
|
||||
.collect(),
|
||||
}),
|
||||
args: rustc_ast::ast::AttrItemKind::Unparsed(AttrArgs::Delimited(
|
||||
DelimArgs {
|
||||
dspan: DelimSpan::from_single(self.span),
|
||||
delim: rustc_ast::token::Delimiter::Parenthesis,
|
||||
tokens: [
|
||||
TokenKind::Ident(sym::feature, IdentIsRaw::No),
|
||||
TokenKind::Eq,
|
||||
TokenKind::lit(LitKind::Str, sym::derive_const, None),
|
||||
TokenKind::Comma,
|
||||
TokenKind::Ident(sym::issue, IdentIsRaw::No),
|
||||
TokenKind::Eq,
|
||||
TokenKind::lit(LitKind::Str, sym::derive_const_issue, None),
|
||||
]
|
||||
.into_iter()
|
||||
.map(|kind| {
|
||||
TokenTree::Token(
|
||||
Token { kind, span: self.span },
|
||||
Spacing::Alone,
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
},
|
||||
)),
|
||||
tokens: None,
|
||||
},
|
||||
self.span,
|
||||
|
|
|
|||
|
|
@ -103,19 +103,19 @@ fn eii_(
|
|||
|
||||
// span of the declaring item without attributes
|
||||
let item_span = func.sig.span;
|
||||
// span of the eii attribute and the item below it, i.e. the full declaration
|
||||
let decl_span = eii_attr_span.to(item_span);
|
||||
let foreign_item_name = func.ident;
|
||||
|
||||
let mut return_items = Vec::new();
|
||||
|
||||
if func.body.is_some() {
|
||||
return_items.push(Box::new(generate_default_impl(
|
||||
ecx,
|
||||
&func,
|
||||
impl_unsafe,
|
||||
macro_name,
|
||||
eii_attr_span,
|
||||
item_span,
|
||||
foreign_item_name,
|
||||
)))
|
||||
}
|
||||
|
||||
|
|
@ -133,7 +133,7 @@ fn eii_(
|
|||
macro_name,
|
||||
foreign_item_name,
|
||||
impl_unsafe,
|
||||
decl_span,
|
||||
&attrs_from_decl,
|
||||
)));
|
||||
|
||||
return_items.into_iter().map(wrap_item).collect()
|
||||
|
|
@ -187,11 +187,13 @@ fn filter_attrs_for_multiple_eii_attr(
|
|||
}
|
||||
|
||||
fn generate_default_impl(
|
||||
ecx: &mut ExtCtxt<'_>,
|
||||
func: &ast::Fn,
|
||||
impl_unsafe: bool,
|
||||
macro_name: Ident,
|
||||
eii_attr_span: Span,
|
||||
item_span: Span,
|
||||
foreign_item_name: Ident,
|
||||
) -> ast::Item {
|
||||
// FIXME: re-add some original attrs
|
||||
let attrs = ThinVec::new();
|
||||
|
|
@ -208,6 +210,21 @@ fn generate_default_impl(
|
|||
},
|
||||
span: eii_attr_span,
|
||||
is_default: true,
|
||||
known_eii_macro_resolution: Some(ast::EiiExternTarget {
|
||||
extern_item_path: ast::Path {
|
||||
span: foreign_item_name.span,
|
||||
segments: thin_vec![
|
||||
ast::PathSegment {
|
||||
ident: Ident::from_str_and_span("super", foreign_item_name.span,),
|
||||
id: DUMMY_NODE_ID,
|
||||
args: None
|
||||
},
|
||||
ast::PathSegment { ident: foreign_item_name, id: DUMMY_NODE_ID, args: None },
|
||||
],
|
||||
tokens: None,
|
||||
},
|
||||
impl_unsafe,
|
||||
}),
|
||||
});
|
||||
|
||||
ast::Item {
|
||||
|
|
@ -236,18 +253,66 @@ fn generate_default_impl(
|
|||
stmts: thin_vec![ast::Stmt {
|
||||
id: DUMMY_NODE_ID,
|
||||
kind: ast::StmtKind::Item(Box::new(ast::Item {
|
||||
attrs,
|
||||
attrs: ThinVec::new(),
|
||||
id: DUMMY_NODE_ID,
|
||||
span: item_span,
|
||||
vis: ast::Visibility {
|
||||
span: eii_attr_span,
|
||||
span: item_span,
|
||||
kind: ast::VisibilityKind::Inherited,
|
||||
tokens: None
|
||||
},
|
||||
kind: ItemKind::Fn(Box::new(default_func)),
|
||||
kind: ItemKind::Mod(
|
||||
ast::Safety::Default,
|
||||
Ident::from_str_and_span("dflt", item_span),
|
||||
ast::ModKind::Loaded(
|
||||
thin_vec![
|
||||
Box::new(ast::Item {
|
||||
attrs: thin_vec![ecx.attr_nested_word(
|
||||
sym::allow,
|
||||
sym::unused_imports,
|
||||
item_span
|
||||
),],
|
||||
id: DUMMY_NODE_ID,
|
||||
span: item_span,
|
||||
vis: ast::Visibility {
|
||||
span: eii_attr_span,
|
||||
kind: ast::VisibilityKind::Inherited,
|
||||
tokens: None
|
||||
},
|
||||
kind: ItemKind::Use(ast::UseTree {
|
||||
prefix: ast::Path::from_ident(
|
||||
Ident::from_str_and_span(
|
||||
"super", item_span,
|
||||
)
|
||||
),
|
||||
kind: ast::UseTreeKind::Glob,
|
||||
span: item_span,
|
||||
}),
|
||||
tokens: None,
|
||||
}),
|
||||
Box::new(ast::Item {
|
||||
attrs,
|
||||
id: DUMMY_NODE_ID,
|
||||
span: item_span,
|
||||
vis: ast::Visibility {
|
||||
span: eii_attr_span,
|
||||
kind: ast::VisibilityKind::Inherited,
|
||||
tokens: None
|
||||
},
|
||||
kind: ItemKind::Fn(Box::new(default_func)),
|
||||
tokens: None,
|
||||
}),
|
||||
],
|
||||
ast::Inline::Yes,
|
||||
ast::ModSpans {
|
||||
inner_span: item_span,
|
||||
inject_use_span: item_span,
|
||||
}
|
||||
)
|
||||
),
|
||||
tokens: None,
|
||||
})),
|
||||
span: eii_attr_span
|
||||
span: eii_attr_span,
|
||||
}],
|
||||
id: DUMMY_NODE_ID,
|
||||
rules: ast::BlockCheckMode::Default,
|
||||
|
|
@ -352,10 +417,17 @@ fn generate_attribute_macro_to_implement(
|
|||
macro_name: Ident,
|
||||
foreign_item_name: Ident,
|
||||
impl_unsafe: bool,
|
||||
decl_span: Span,
|
||||
attrs_from_decl: &[Attribute],
|
||||
) -> ast::Item {
|
||||
let mut macro_attrs = ThinVec::new();
|
||||
|
||||
// To avoid e.g. `error: attribute macro has missing stability attribute`
|
||||
// errors for eii's in std.
|
||||
macro_attrs.extend_from_slice(attrs_from_decl);
|
||||
|
||||
// Avoid "missing stability attribute" errors for eiis in std. See #146993.
|
||||
macro_attrs.push(ecx.attr_name_value_str(sym::rustc_macro_transparency, sym::semiopaque, span));
|
||||
|
||||
// #[builtin_macro(eii_shared_macro)]
|
||||
macro_attrs.push(ecx.attr_nested_word(sym::rustc_builtin_macro, sym::eii_shared_macro, span));
|
||||
|
||||
|
|
@ -394,7 +466,6 @@ fn generate_attribute_macro_to_implement(
|
|||
eii_extern_target: Some(ast::EiiExternTarget {
|
||||
extern_item_path: ast::Path::from_ident(foreign_item_name),
|
||||
impl_unsafe,
|
||||
span: decl_span,
|
||||
}),
|
||||
},
|
||||
),
|
||||
|
|
@ -451,7 +522,7 @@ pub(crate) fn eii_extern_target(
|
|||
false
|
||||
};
|
||||
|
||||
d.eii_extern_target = Some(EiiExternTarget { extern_item_path, impl_unsafe, span });
|
||||
d.eii_extern_target = Some(EiiExternTarget { extern_item_path, impl_unsafe });
|
||||
|
||||
// Return the original item and the new methods.
|
||||
vec![item]
|
||||
|
|
@ -508,6 +579,7 @@ pub(crate) fn eii_shared_macro(
|
|||
impl_safety: meta_item.unsafety,
|
||||
span,
|
||||
is_default,
|
||||
known_eii_macro_resolution: None,
|
||||
});
|
||||
|
||||
vec![item]
|
||||
|
|
|
|||
|
|
@ -643,6 +643,15 @@ pub(crate) enum InvalidFormatStringSuggestion {
|
|||
span: Span,
|
||||
replacement: String,
|
||||
},
|
||||
#[suggestion(
|
||||
builtin_macros_format_add_missing_colon,
|
||||
code = ":?",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
AddMissingColon {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
|
|||
|
|
@ -329,6 +329,10 @@ fn make_format_args(
|
|||
replacement,
|
||||
});
|
||||
}
|
||||
parse::Suggestion::AddMissingColon(span) => {
|
||||
let span = fmt_span.from_inner(InnerSpan::new(span.start, span.end));
|
||||
e.sugg_ = Some(errors::InvalidFormatStringSuggestion::AddMissingColon { span });
|
||||
}
|
||||
}
|
||||
let guar = ecx.dcx().emit_err(e);
|
||||
return ExpandResult::Ready(Err(guar));
|
||||
|
|
|
|||
|
|
@ -744,43 +744,43 @@ unsafe extern "C" {
|
|||
pub struct VaList<'a>(&'a mut VaListImpl);
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[rustc_macro_transparency = "semiopaque"]
|
||||
pub macro stringify($($t:tt)*) {
|
||||
/* compiler built-in */
|
||||
}
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[rustc_macro_transparency = "semiopaque"]
|
||||
pub macro file() {
|
||||
/* compiler built-in */
|
||||
}
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[rustc_macro_transparency = "semiopaque"]
|
||||
pub macro line() {
|
||||
/* compiler built-in */
|
||||
}
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[rustc_macro_transparency = "semiopaque"]
|
||||
pub macro cfg() {
|
||||
/* compiler built-in */
|
||||
}
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[rustc_macro_transparency = "semiopaque"]
|
||||
pub macro asm() {
|
||||
/* compiler built-in */
|
||||
}
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[rustc_macro_transparency = "semiopaque"]
|
||||
pub macro global_asm() {
|
||||
/* compiler built-in */
|
||||
}
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[rustc_macro_transparency = "semiopaque"]
|
||||
pub macro naked_asm() {
|
||||
/* compiler built-in */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -233,7 +233,7 @@ pub(crate) fn compile_global_asm(
|
|||
#![allow(internal_features)]
|
||||
#![no_core]
|
||||
#[rustc_builtin_macro]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[rustc_macro_transparency = "semiopaque"]
|
||||
macro global_asm() { /* compiler built-in */ }
|
||||
global_asm!(r###"
|
||||
"####,
|
||||
|
|
|
|||
|
|
@ -748,25 +748,25 @@ extern "C" {
|
|||
pub struct VaList<'a>(&'a mut VaListImpl);
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[rustc_macro_transparency = "semiopaque"]
|
||||
pub macro stringify($($t:tt)*) {
|
||||
/* compiler built-in */
|
||||
}
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[rustc_macro_transparency = "semiopaque"]
|
||||
pub macro file() {
|
||||
/* compiler built-in */
|
||||
}
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[rustc_macro_transparency = "semiopaque"]
|
||||
pub macro line() {
|
||||
/* compiler built-in */
|
||||
}
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[rustc_macro_transparency = "semiopaque"]
|
||||
pub macro cfg() {
|
||||
/* compiler built-in */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
codegen_llvm_autodiff_component_unavailable = failed to load our autodiff backend. Did you install it via rustup?
|
||||
codegen_llvm_autodiff_component_missing = autodiff backend not found in the sysroot: {$err}
|
||||
.note = it will be distributed via rustup in the future
|
||||
|
||||
codegen_llvm_autodiff_component_unavailable = failed to load our autodiff backend: {$err}
|
||||
|
||||
codegen_llvm_autodiff_without_enable = using the autodiff feature requires -Z autodiff=Enable
|
||||
codegen_llvm_autodiff_without_lto = using the autodiff feature requires setting `lto="fat"` in your Cargo.toml
|
||||
|
|
|
|||
|
|
@ -93,8 +93,13 @@ pub(crate) fn compile_codegen_unit(
|
|||
// They are necessary for correct offload execution. We do this here to simplify the
|
||||
// `offload` intrinsic, avoiding the need for tracking whether it's the first
|
||||
// intrinsic call or not.
|
||||
let has_host_offload =
|
||||
cx.sess().opts.unstable_opts.offload.iter().any(|o| matches!(o, Offload::Host(_)));
|
||||
let has_host_offload = cx
|
||||
.sess()
|
||||
.opts
|
||||
.unstable_opts
|
||||
.offload
|
||||
.iter()
|
||||
.any(|o| matches!(o, Offload::Host(_) | Offload::Test));
|
||||
if has_host_offload && !cx.sess().target.is_like_gpu {
|
||||
cx.offload_globals.replace(Some(OffloadGlobals::declare(&cx)));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,8 +49,9 @@ impl<'ll> OffloadGlobals<'ll> {
|
|||
let bin_desc = cx.type_named_struct("struct.__tgt_bin_desc");
|
||||
cx.set_struct_body(bin_desc, &tgt_bin_desc_ty, false);
|
||||
|
||||
let register_lib = declare_offload_fn(&cx, "__tgt_register_lib", mapper_fn_ty);
|
||||
let unregister_lib = declare_offload_fn(&cx, "__tgt_unregister_lib", mapper_fn_ty);
|
||||
let reg_lib_decl = cx.type_func(&[cx.type_ptr()], cx.type_void());
|
||||
let register_lib = declare_offload_fn(&cx, "__tgt_register_lib", reg_lib_decl);
|
||||
let unregister_lib = declare_offload_fn(&cx, "__tgt_unregister_lib", reg_lib_decl);
|
||||
let init_ty = cx.type_func(&[], cx.type_void());
|
||||
let init_rtls = declare_offload_fn(cx, "__tgt_init_all_rtls", init_ty);
|
||||
|
||||
|
|
|
|||
|
|
@ -187,6 +187,10 @@ fn check_and_apply_linkage<'ll, 'tcx>(
|
|||
};
|
||||
llvm::set_linkage(g1, base::linkage_to_llvm(linkage));
|
||||
|
||||
// Normally this is done in `get_static_inner`, but when as we generate an internal global,
|
||||
// it will apply the dso_local to the internal global instead, so do it here, too.
|
||||
cx.assume_dso_local(g1, true);
|
||||
|
||||
// Declare an internal global `extern_with_linkage_foo` which
|
||||
// is initialized with the address of `foo`. If `foo` is
|
||||
// discarded during linking (for example, if `foo` has weak
|
||||
|
|
|
|||
|
|
@ -211,6 +211,10 @@ pub(crate) unsafe fn create_module<'ll>(
|
|||
// LLVM 22 updated the NVPTX layout to indicate 256-bit vector load/store: https://github.com/llvm/llvm-project/pull/155198
|
||||
target_data_layout = target_data_layout.replace("-i256:256", "");
|
||||
}
|
||||
if sess.target.arch == Arch::PowerPC64 {
|
||||
// LLVM 22 updated the ABI alignment for double on AIX: https://github.com/llvm/llvm-project/pull/144673
|
||||
target_data_layout = target_data_layout.replace("-f64:32:64", "");
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the data-layout values hardcoded remain the defaults.
|
||||
|
|
|
|||
|
|
@ -34,7 +34,16 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for ParseTargetMachineConfig<'_> {
|
|||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_llvm_autodiff_component_unavailable)]
|
||||
pub(crate) struct AutoDiffComponentUnavailable;
|
||||
pub(crate) struct AutoDiffComponentUnavailable {
|
||||
pub err: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_llvm_autodiff_component_missing)]
|
||||
#[note]
|
||||
pub(crate) struct AutoDiffComponentMissing {
|
||||
pub err: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_llvm_autodiff_without_lto)]
|
||||
|
|
|
|||
|
|
@ -249,8 +249,14 @@ impl CodegenBackend for LlvmCodegenBackend {
|
|||
|
||||
use crate::back::lto::enable_autodiff_settings;
|
||||
if sess.opts.unstable_opts.autodiff.contains(&AutoDiff::Enable) {
|
||||
if let Err(_) = llvm::EnzymeWrapper::get_or_init(&sess.opts.sysroot) {
|
||||
sess.dcx().emit_fatal(crate::errors::AutoDiffComponentUnavailable);
|
||||
match llvm::EnzymeWrapper::get_or_init(&sess.opts.sysroot) {
|
||||
Ok(_) => {}
|
||||
Err(llvm::EnzymeLibraryError::NotFound { err }) => {
|
||||
sess.dcx().emit_fatal(crate::errors::AutoDiffComponentMissing { err });
|
||||
}
|
||||
Err(llvm::EnzymeLibraryError::LoadFailed { err }) => {
|
||||
sess.dcx().emit_fatal(crate::errors::AutoDiffComponentUnavailable { err });
|
||||
}
|
||||
}
|
||||
enable_autodiff_settings(&sess.opts.unstable_opts.autodiff);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ pub(crate) mod Enzyme_AD {
|
|||
fn load_ptr_by_symbol_mut_void(
|
||||
lib: &libloading::Library,
|
||||
bytes: &[u8],
|
||||
) -> Result<*mut c_void, Box<dyn std::error::Error>> {
|
||||
) -> Result<*mut c_void, libloading::Error> {
|
||||
unsafe {
|
||||
let s: libloading::Symbol<'_, *mut c_void> = lib.get(bytes)?;
|
||||
// libloading = 0.9.0: try_as_raw_ptr always succeeds and returns Some
|
||||
|
|
@ -192,15 +192,27 @@ pub(crate) mod Enzyme_AD {
|
|||
|
||||
static ENZYME_INSTANCE: OnceLock<Mutex<EnzymeWrapper>> = OnceLock::new();
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum EnzymeLibraryError {
|
||||
NotFound { err: String },
|
||||
LoadFailed { err: String },
|
||||
}
|
||||
|
||||
impl From<libloading::Error> for EnzymeLibraryError {
|
||||
fn from(err: libloading::Error) -> Self {
|
||||
Self::LoadFailed { err: format!("{err:?}") }
|
||||
}
|
||||
}
|
||||
|
||||
impl EnzymeWrapper {
|
||||
/// Initialize EnzymeWrapper with the given sysroot if not already initialized.
|
||||
/// Safe to call multiple times - subsequent calls are no-ops due to OnceLock.
|
||||
pub(crate) fn get_or_init(
|
||||
sysroot: &rustc_session::config::Sysroot,
|
||||
) -> Result<MutexGuard<'static, Self>, Box<dyn std::error::Error>> {
|
||||
) -> Result<MutexGuard<'static, Self>, EnzymeLibraryError> {
|
||||
let mtx: &'static Mutex<EnzymeWrapper> = ENZYME_INSTANCE.get_or_try_init(|| {
|
||||
let w = Self::call_dynamic(sysroot)?;
|
||||
Ok::<_, Box<dyn std::error::Error>>(Mutex::new(w))
|
||||
Ok::<_, EnzymeLibraryError>(Mutex::new(w))
|
||||
})?;
|
||||
|
||||
Ok(mtx.lock().unwrap())
|
||||
|
|
@ -351,7 +363,7 @@ pub(crate) mod Enzyme_AD {
|
|||
#[allow(non_snake_case)]
|
||||
fn call_dynamic(
|
||||
sysroot: &rustc_session::config::Sysroot,
|
||||
) -> Result<Self, Box<dyn std::error::Error>> {
|
||||
) -> Result<Self, EnzymeLibraryError> {
|
||||
let enzyme_path = Self::get_enzyme_path(sysroot)?;
|
||||
let lib = unsafe { libloading::Library::new(enzyme_path)? };
|
||||
|
||||
|
|
@ -416,7 +428,7 @@ pub(crate) mod Enzyme_AD {
|
|||
})
|
||||
}
|
||||
|
||||
fn get_enzyme_path(sysroot: &Sysroot) -> Result<String, String> {
|
||||
fn get_enzyme_path(sysroot: &Sysroot) -> Result<String, EnzymeLibraryError> {
|
||||
let llvm_version_major = unsafe { LLVMRustVersionMajor() };
|
||||
|
||||
let path_buf = sysroot
|
||||
|
|
@ -434,15 +446,19 @@ pub(crate) mod Enzyme_AD {
|
|||
.map(|p| p.join("lib").display().to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join("\n* ");
|
||||
format!(
|
||||
"failed to find a `libEnzyme-{llvm_version_major}` folder \
|
||||
EnzymeLibraryError::NotFound {
|
||||
err: format!(
|
||||
"failed to find a `libEnzyme-{llvm_version_major}` folder \
|
||||
in the sysroot candidates:\n* {candidates}"
|
||||
)
|
||||
),
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(path_buf
|
||||
.to_str()
|
||||
.ok_or_else(|| format!("invalid UTF-8 in path: {}", path_buf.display()))?
|
||||
.ok_or_else(|| EnzymeLibraryError::LoadFailed {
|
||||
err: format!("invalid UTF-8 in path: {}", path_buf.display()),
|
||||
})?
|
||||
.to_string())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -379,19 +379,19 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) {
|
|||
{
|
||||
false
|
||||
}
|
||||
// Unsupported <https://github.com/llvm/llvm-project/issues/94434>
|
||||
(Arch::Arm64EC, _) => false,
|
||||
// Unsupported <https://github.com/llvm/llvm-project/issues/94434> (fixed in llvm22)
|
||||
(Arch::Arm64EC, _) if major < 22 => false,
|
||||
// Selection failure <https://github.com/llvm/llvm-project/issues/50374> (fixed in llvm21)
|
||||
(Arch::S390x, _) if major < 21 => false,
|
||||
// MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054>
|
||||
(Arch::X86_64, Os::Windows) if *target_env == Env::Gnu && *target_abi != Abi::Llvm => false,
|
||||
// Infinite recursion <https://github.com/llvm/llvm-project/issues/97981>
|
||||
(Arch::CSky, _) => false,
|
||||
(Arch::CSky, _) if major < 22 => false, // (fixed in llvm22)
|
||||
(Arch::Hexagon, _) if major < 21 => false, // (fixed in llvm21)
|
||||
(Arch::LoongArch32 | Arch::LoongArch64, _) if major < 21 => false, // (fixed in llvm21)
|
||||
(Arch::PowerPC | Arch::PowerPC64, _) => false,
|
||||
(Arch::Sparc | Arch::Sparc64, _) => false,
|
||||
(Arch::Wasm32 | Arch::Wasm64, _) => false,
|
||||
(Arch::PowerPC | Arch::PowerPC64, _) if major < 22 => false, // (fixed in llvm22)
|
||||
(Arch::Sparc | Arch::Sparc64, _) if major < 22 => false, // (fixed in llvm22)
|
||||
(Arch::Wasm32 | Arch::Wasm64, _) if major < 22 => false, // (fixed in llvm22)
|
||||
// `f16` support only requires that symbols converting to and from `f32` are available. We
|
||||
// provide these in `compiler-builtins`, so `f16` should be available on all platforms that
|
||||
// do not have other ABI issues or LLVM crashes.
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ use rustc_middle::mir::mono::Visibility;
|
|||
use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv, LayoutOf};
|
||||
use rustc_middle::ty::{self, Instance, TypeVisitableExt};
|
||||
use rustc_session::config::CrateType;
|
||||
use rustc_span::Symbol;
|
||||
use rustc_target::spec::{Arch, RelocModel};
|
||||
use tracing::debug;
|
||||
|
||||
|
|
@ -92,17 +91,19 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
|
|||
}
|
||||
|
||||
impl CodegenCx<'_, '_> {
|
||||
fn add_aliases(&self, aliasee: &llvm::Value, aliases: &[(Symbol, Linkage, Visibility)]) {
|
||||
fn add_aliases(&self, aliasee: &llvm::Value, aliases: &[(DefId, Linkage, Visibility)]) {
|
||||
let ty = self.get_type_of_global(aliasee);
|
||||
|
||||
for (alias, linkage, visibility) in aliases {
|
||||
let symbol_name = self.tcx.symbol_name(Instance::mono(self.tcx, *alias));
|
||||
|
||||
tracing::debug!("ALIAS: {alias:?} {linkage:?} {visibility:?}");
|
||||
let lldecl = llvm::add_alias(
|
||||
self.llmod,
|
||||
ty,
|
||||
AddressSpace::ZERO,
|
||||
aliasee,
|
||||
&CString::new(alias.as_str()).unwrap(),
|
||||
&CString::new(symbol_name.name).unwrap(),
|
||||
);
|
||||
|
||||
llvm::set_visibility(lldecl, base::visibility_to_llvm(*visibility));
|
||||
|
|
@ -110,7 +111,7 @@ impl CodegenCx<'_, '_> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Whether a definition or declaration can be assumed to be local to a group of
|
||||
/// A definition or declaration can be assumed to be local to a group of
|
||||
/// libraries that form a single DSO or executable.
|
||||
/// Marks the local as DSO if so.
|
||||
pub(crate) fn assume_dso_local(&self, llval: &llvm::Value, is_declaration: bool) -> bool {
|
||||
|
|
@ -152,7 +153,7 @@ impl CodegenCx<'_, '_> {
|
|||
return false;
|
||||
}
|
||||
|
||||
// With pie relocation model calls of functions defined in the translation
|
||||
// With pie relocation model, calls of functions defined in the translation
|
||||
// unit can use copy relocations.
|
||||
if self.tcx.sess.relocation_model() == RelocModel::Pie && !is_declaration {
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
use rustc_abi::{Align, BackendRepr, Endian, HasDataLayout, Primitive, Size, TyAndLayout};
|
||||
use rustc_abi::{Align, BackendRepr, Endian, HasDataLayout, Primitive, Size};
|
||||
use rustc_codegen_ssa::MemFlags;
|
||||
use rustc_codegen_ssa::common::IntPredicate;
|
||||
use rustc_codegen_ssa::mir::operand::OperandRef;
|
||||
use rustc_codegen_ssa::traits::{
|
||||
BaseTypeCodegenMethods, BuilderMethods, ConstCodegenMethods, LayoutTypeCodegenMethods,
|
||||
};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
|
||||
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
|
||||
use rustc_target::spec::{Abi, Arch, Env};
|
||||
|
||||
use crate::builder::Builder;
|
||||
|
|
@ -82,6 +83,7 @@ enum PassMode {
|
|||
enum SlotSize {
|
||||
Bytes8 = 8,
|
||||
Bytes4 = 4,
|
||||
Bytes1 = 1,
|
||||
}
|
||||
|
||||
enum AllowHigherAlign {
|
||||
|
|
@ -728,7 +730,7 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>(
|
|||
fn copy_to_temporary_if_more_aligned<'ll, 'tcx>(
|
||||
bx: &mut Builder<'_, 'll, 'tcx>,
|
||||
reg_addr: &'ll Value,
|
||||
layout: TyAndLayout<'tcx, Ty<'tcx>>,
|
||||
layout: TyAndLayout<'tcx>,
|
||||
src_align: Align,
|
||||
) -> &'ll Value {
|
||||
if layout.layout.align.abi > src_align {
|
||||
|
|
@ -751,7 +753,7 @@ fn copy_to_temporary_if_more_aligned<'ll, 'tcx>(
|
|||
fn x86_64_sysv64_va_arg_from_memory<'ll, 'tcx>(
|
||||
bx: &mut Builder<'_, 'll, 'tcx>,
|
||||
va_list_addr: &'ll Value,
|
||||
layout: TyAndLayout<'tcx, Ty<'tcx>>,
|
||||
layout: TyAndLayout<'tcx>,
|
||||
) -> &'ll Value {
|
||||
let dl = bx.cx.data_layout();
|
||||
let ptr_align_abi = dl.data_layout().pointer_align().abi;
|
||||
|
|
@ -1003,15 +1005,17 @@ fn emit_xtensa_va_arg<'ll, 'tcx>(
|
|||
return bx.load(layout.llvm_type(bx), value_ptr, layout.align.abi);
|
||||
}
|
||||
|
||||
/// Determine the va_arg implementation to use. The LLVM va_arg instruction
|
||||
/// is lacking in some instances, so we should only use it as a fallback.
|
||||
pub(super) fn emit_va_arg<'ll, 'tcx>(
|
||||
bx: &mut Builder<'_, 'll, 'tcx>,
|
||||
addr: OperandRef<'tcx, &'ll Value>,
|
||||
target_ty: Ty<'tcx>,
|
||||
) -> &'ll Value {
|
||||
// Determine the va_arg implementation to use. The LLVM va_arg instruction
|
||||
// is lacking in some instances, so we should only use it as a fallback.
|
||||
let target = &bx.cx.tcx.sess.target;
|
||||
let layout = bx.cx.layout_of(target_ty);
|
||||
let target_ty_size = layout.layout.size().bytes();
|
||||
|
||||
let target = &bx.cx.tcx.sess.target;
|
||||
match target.arch {
|
||||
Arch::X86 => emit_ptr_va_arg(
|
||||
bx,
|
||||
|
|
@ -1069,23 +1073,79 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
|
|||
AllowHigherAlign::Yes,
|
||||
ForceRightAdjust::No,
|
||||
),
|
||||
Arch::LoongArch32 => emit_ptr_va_arg(
|
||||
bx,
|
||||
addr,
|
||||
target_ty,
|
||||
if target_ty_size > 2 * 4 { PassMode::Indirect } else { PassMode::Direct },
|
||||
SlotSize::Bytes4,
|
||||
AllowHigherAlign::Yes,
|
||||
ForceRightAdjust::No,
|
||||
),
|
||||
Arch::LoongArch64 => emit_ptr_va_arg(
|
||||
bx,
|
||||
addr,
|
||||
target_ty,
|
||||
if target_ty_size > 2 * 8 { PassMode::Indirect } else { PassMode::Direct },
|
||||
SlotSize::Bytes8,
|
||||
AllowHigherAlign::Yes,
|
||||
ForceRightAdjust::No,
|
||||
),
|
||||
Arch::AmdGpu => emit_ptr_va_arg(
|
||||
bx,
|
||||
addr,
|
||||
target_ty,
|
||||
PassMode::Direct,
|
||||
SlotSize::Bytes4,
|
||||
AllowHigherAlign::No,
|
||||
ForceRightAdjust::No,
|
||||
),
|
||||
Arch::Nvptx64 => emit_ptr_va_arg(
|
||||
bx,
|
||||
addr,
|
||||
target_ty,
|
||||
PassMode::Direct,
|
||||
SlotSize::Bytes1,
|
||||
AllowHigherAlign::Yes,
|
||||
ForceRightAdjust::No,
|
||||
),
|
||||
Arch::Wasm32 => emit_ptr_va_arg(
|
||||
bx,
|
||||
addr,
|
||||
target_ty,
|
||||
if layout.is_aggregate() || layout.is_zst() || layout.is_1zst() {
|
||||
PassMode::Indirect
|
||||
} else {
|
||||
PassMode::Direct
|
||||
},
|
||||
SlotSize::Bytes4,
|
||||
AllowHigherAlign::Yes,
|
||||
ForceRightAdjust::No,
|
||||
),
|
||||
Arch::Wasm64 => bug!("c-variadic functions are not fully implemented for wasm64"),
|
||||
Arch::CSky => emit_ptr_va_arg(
|
||||
bx,
|
||||
addr,
|
||||
target_ty,
|
||||
PassMode::Direct,
|
||||
SlotSize::Bytes4,
|
||||
AllowHigherAlign::Yes,
|
||||
ForceRightAdjust::No,
|
||||
),
|
||||
// Windows x86_64
|
||||
Arch::X86_64 if target.is_like_windows => {
|
||||
let target_ty_size = bx.cx.size_of(target_ty).bytes();
|
||||
emit_ptr_va_arg(
|
||||
bx,
|
||||
addr,
|
||||
target_ty,
|
||||
if target_ty_size > 8 || !target_ty_size.is_power_of_two() {
|
||||
PassMode::Indirect
|
||||
} else {
|
||||
PassMode::Direct
|
||||
},
|
||||
SlotSize::Bytes8,
|
||||
AllowHigherAlign::No,
|
||||
ForceRightAdjust::No,
|
||||
)
|
||||
}
|
||||
Arch::X86_64 if target.is_like_windows => emit_ptr_va_arg(
|
||||
bx,
|
||||
addr,
|
||||
target_ty,
|
||||
if target_ty_size > 8 || !target_ty_size.is_power_of_two() {
|
||||
PassMode::Indirect
|
||||
} else {
|
||||
PassMode::Direct
|
||||
},
|
||||
SlotSize::Bytes8,
|
||||
AllowHigherAlign::No,
|
||||
ForceRightAdjust::No,
|
||||
),
|
||||
// This includes `target.is_like_darwin`, which on x86_64 targets is like sysv64.
|
||||
Arch::X86_64 => emit_x86_64_sysv64_va_arg(bx, addr, target_ty),
|
||||
Arch::Xtensa => emit_xtensa_va_arg(bx, addr, target_ty),
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ codegen_ssa_archive_build_failure = failed to build archive at `{$path}`: {$erro
|
|||
|
||||
codegen_ssa_binary_output_to_tty = option `-o` or `--emit` is used to write binary output type `{$shorthand}` to stdout, but stdout is a tty
|
||||
|
||||
codegen_ssa_bpf_staticlib_not_supported = linking static libraries is not supported for BPF
|
||||
|
||||
codegen_ssa_cgu_not_recorded =
|
||||
CGU-reuse for `{$cgu_user_name}` is (mangled: `{$cgu_name}`) was not recorded
|
||||
|
||||
|
|
|
|||
|
|
@ -22,10 +22,11 @@ use tracing::trace;
|
|||
|
||||
use super::metadata::{create_compressed_metadata_file, search_for_section};
|
||||
use crate::common;
|
||||
// Re-exporting for rustc_codegen_llvm::back::archive
|
||||
pub use crate::errors::{ArchiveBuildFailure, ExtractBundledLibsError, UnknownArchiveKind};
|
||||
// Public for ArchiveBuilderBuilder::extract_bundled_libs
|
||||
pub use crate::errors::ExtractBundledLibsError;
|
||||
use crate::errors::{
|
||||
DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorCreatingImportLibrary, ErrorWritingDEFFile,
|
||||
ArchiveBuildFailure, DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorCreatingImportLibrary,
|
||||
ErrorWritingDEFFile, UnknownArchiveKind,
|
||||
};
|
||||
|
||||
/// An item to be included in an import library.
|
||||
|
|
|
|||
|
|
@ -839,6 +839,11 @@ impl<'a> Linker for GccLinker<'a> {
|
|||
self.sess.dcx().emit_fatal(errors::LibDefWriteFailure { error });
|
||||
}
|
||||
self.link_arg(path);
|
||||
} else if self.sess.target.is_like_wasm {
|
||||
self.link_arg("--no-export-dynamic");
|
||||
for (sym, _) in symbols {
|
||||
self.link_arg("--export").link_arg(sym);
|
||||
}
|
||||
} else if crate_type == CrateType::Executable && !self.sess.target.is_like_solaris {
|
||||
let res: io::Result<()> = try {
|
||||
let mut f = File::create_buffered(&path)?;
|
||||
|
|
@ -853,11 +858,6 @@ impl<'a> Linker for GccLinker<'a> {
|
|||
self.sess.dcx().emit_fatal(errors::VersionScriptWriteFailure { error });
|
||||
}
|
||||
self.link_arg("--dynamic-list").link_arg(path);
|
||||
} else if self.sess.target.is_like_wasm {
|
||||
self.link_arg("--no-export-dynamic");
|
||||
for (sym, _) in symbols {
|
||||
self.link_arg("--export").link_arg(sym);
|
||||
}
|
||||
} else {
|
||||
// Write an LD version script
|
||||
let res: io::Result<()> = try {
|
||||
|
|
@ -2075,7 +2075,7 @@ impl<'a> Linker for BpfLinker<'a> {
|
|||
}
|
||||
|
||||
fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) {
|
||||
panic!("staticlibs not supported")
|
||||
self.sess.dcx().emit_fatal(errors::BpfStaticlibNotSupported)
|
||||
}
|
||||
|
||||
fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ use std::time::{Duration, Instant};
|
|||
use itertools::Itertools;
|
||||
use rustc_abi::FIRST_VARIANT;
|
||||
use rustc_ast::expand::allocator::{
|
||||
ALLOC_ERROR_HANDLER, ALLOCATOR_METHODS, AllocatorKind, AllocatorMethod, AllocatorTy,
|
||||
ALLOC_ERROR_HANDLER, ALLOCATOR_METHODS, AllocatorKind, AllocatorMethod, AllocatorMethodInput,
|
||||
AllocatorTy,
|
||||
};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
|
||||
use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
|
||||
|
|
@ -671,7 +672,7 @@ pub fn allocator_shim_contents(tcx: TyCtxt<'_>, kind: AllocatorKind) -> Vec<Allo
|
|||
methods.push(AllocatorMethod {
|
||||
name: ALLOC_ERROR_HANDLER,
|
||||
special: None,
|
||||
inputs: &[],
|
||||
inputs: &[AllocatorMethodInput { name: "layout", ty: AllocatorTy::Layout }],
|
||||
output: AllocatorTy::Never,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@ use std::str::FromStr;
|
|||
use rustc_abi::{Align, ExternAbi};
|
||||
use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode};
|
||||
use rustc_ast::{LitKind, MetaItem, MetaItemInner, attr};
|
||||
use rustc_hir::attrs::{AttributeKind, InlineAttr, Linkage, RtsanSetting, UsedBy};
|
||||
use rustc_hir::attrs::{
|
||||
AttributeKind, EiiImplResolution, InlineAttr, Linkage, RtsanSetting, UsedBy,
|
||||
};
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
|
||||
use rustc_hir::{self as hir, Attribute, LangItem, find_attr, lang_items};
|
||||
|
|
@ -13,10 +15,10 @@ use rustc_middle::middle::codegen_fn_attrs::{
|
|||
use rustc_middle::mir::mono::Visibility;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::{self as ty, Instance, TyCtxt};
|
||||
use rustc_middle::ty::{self as ty, TyCtxt};
|
||||
use rustc_session::lint;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::{Ident, Span, Symbol, sym};
|
||||
use rustc_span::{Span, sym};
|
||||
use rustc_target::spec::Os;
|
||||
|
||||
use crate::errors;
|
||||
|
|
@ -285,13 +287,23 @@ fn process_builtin_attrs(
|
|||
}
|
||||
AttributeKind::EiiImpls(impls) => {
|
||||
for i in impls {
|
||||
let extern_item = find_attr!(
|
||||
tcx.get_all_attrs(i.eii_macro),
|
||||
AttributeKind::EiiExternTarget(target) => target.eii_extern_target
|
||||
)
|
||||
.expect("eii should have declaration macro with extern target attribute");
|
||||
|
||||
let symbol_name = tcx.symbol_name(Instance::mono(tcx, extern_item));
|
||||
let extern_item = match i.resolution {
|
||||
EiiImplResolution::Macro(def_id) => {
|
||||
let Some(extern_item) = find_attr!(
|
||||
tcx.get_all_attrs(def_id),
|
||||
AttributeKind::EiiExternTarget(target) => target.eii_extern_target
|
||||
) else {
|
||||
tcx.dcx().span_delayed_bug(
|
||||
i.span,
|
||||
"resolved to something that's not an EII",
|
||||
);
|
||||
continue;
|
||||
};
|
||||
extern_item
|
||||
}
|
||||
EiiImplResolution::Known(decl) => decl.eii_extern_target,
|
||||
EiiImplResolution::Error(_eg) => continue,
|
||||
};
|
||||
|
||||
// this is to prevent a bug where a single crate defines both the default and explicit implementation
|
||||
// for an EII. In that case, both of them may be part of the same final object file. I'm not 100% sure
|
||||
|
|
@ -304,13 +316,13 @@ fn process_builtin_attrs(
|
|||
// iterate over all implementations *in the current crate*
|
||||
// (this is ok since we generate codegen fn attrs in the local crate)
|
||||
// if any of them is *not default* then don't emit the alias.
|
||||
&& tcx.externally_implementable_items(LOCAL_CRATE).get(&i.eii_macro).expect("at least one").1.iter().any(|(_, imp)| !imp.is_default)
|
||||
&& tcx.externally_implementable_items(LOCAL_CRATE).get(&extern_item).expect("at least one").1.iter().any(|(_, imp)| !imp.is_default)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
codegen_fn_attrs.foreign_item_symbol_aliases.push((
|
||||
Symbol::intern(symbol_name.name),
|
||||
extern_item,
|
||||
if i.is_default { Linkage::LinkOnceAny } else { Linkage::External },
|
||||
Visibility::Default,
|
||||
));
|
||||
|
|
@ -327,7 +339,7 @@ fn process_builtin_attrs(
|
|||
}
|
||||
}
|
||||
|
||||
let Some(Ident { name, .. }) = attr.ident() else {
|
||||
let Some(name) = attr.name() else {
|
||||
continue;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -260,7 +260,7 @@ fn push_debuginfo_type_name<'tcx>(
|
|||
.map(|bound| {
|
||||
let ExistentialProjection { def_id: item_def_id, term, .. } =
|
||||
tcx.instantiate_bound_regions_with_erased(bound);
|
||||
// FIXME(associated_const_equality): allow for consts here
|
||||
// FIXME(mgca): allow for consts here
|
||||
(item_def_id, term.expect_type())
|
||||
})
|
||||
.collect();
|
||||
|
|
|
|||
|
|
@ -661,7 +661,7 @@ pub(crate) struct RlibArchiveBuildFailure {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
// Public for rustc_codegen_llvm::back::archive
|
||||
// Public for ArchiveBuilderBuilder::extract_bundled_libs
|
||||
pub enum ExtractBundledLibsError<'a> {
|
||||
#[diag(codegen_ssa_extract_bundled_libs_open_file)]
|
||||
OpenFile { rlib: &'a Path, error: Box<dyn std::error::Error> },
|
||||
|
|
@ -700,19 +700,21 @@ pub(crate) struct UnsupportedLinkSelfContained;
|
|||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_archive_build_failure)]
|
||||
// Public for rustc_codegen_llvm::back::archive
|
||||
pub struct ArchiveBuildFailure {
|
||||
pub(crate) struct ArchiveBuildFailure {
|
||||
pub path: PathBuf,
|
||||
pub error: std::io::Error,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_unknown_archive_kind)]
|
||||
// Public for rustc_codegen_llvm::back::archive
|
||||
pub struct UnknownArchiveKind<'a> {
|
||||
pub(crate) struct UnknownArchiveKind<'a> {
|
||||
pub kind: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_bpf_staticlib_not_supported)]
|
||||
pub(crate) struct BpfStaticlibNotSupported;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_multiple_main_functions)]
|
||||
#[help]
|
||||
|
|
|
|||
|
|
@ -181,7 +181,8 @@ fn prefix_and_suffix<'tcx>(
|
|||
}
|
||||
}
|
||||
Linkage::Internal => {
|
||||
// write nothing
|
||||
// LTO can fail when internal linkage is used.
|
||||
emit_fatal("naked functions may not have internal linkage")
|
||||
}
|
||||
Linkage::Common => emit_fatal("Functions may not have common linkage"),
|
||||
Linkage::AvailableExternally => {
|
||||
|
|
|
|||
|
|
@ -6,9 +6,7 @@
|
|||
// having basically only two use-cases that act in different ways.
|
||||
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::{LangItem, find_attr};
|
||||
use rustc_hir::LangItem;
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::{self, AdtDef, Ty};
|
||||
|
|
@ -366,14 +364,10 @@ where
|
|||
// check performed after the promotion. Verify that with an assertion.
|
||||
assert!(promoted.is_none() || Q::ALLOW_PROMOTED);
|
||||
|
||||
// Avoid looking at attrs of anon consts as that will ICE
|
||||
let is_type_const_item =
|
||||
matches!(cx.tcx.def_kind(def), DefKind::Const | DefKind::AssocConst)
|
||||
&& find_attr!(cx.tcx.get_all_attrs(def), AttributeKind::TypeConst(_));
|
||||
|
||||
// Don't peak inside trait associated constants, also `#[type_const] const` items
|
||||
// don't have bodies so there's nothing to look at
|
||||
if promoted.is_none() && cx.tcx.trait_of_assoc(def).is_none() && !is_type_const_item {
|
||||
if promoted.is_none() && cx.tcx.trait_of_assoc(def).is_none() && !cx.tcx.is_type_const(def)
|
||||
{
|
||||
let qualifs = cx.tcx.at(constant.span).mir_const_qualif(def);
|
||||
|
||||
if !Q::in_qualifs(&qualifs) {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexMap, IndexEntry};
|
|||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::{self as hir, CRATE_HIR_ID, LangItem};
|
||||
use rustc_middle::mir::AssertMessage;
|
||||
use rustc_middle::mir::interpret::ReportedErrorInfo;
|
||||
use rustc_middle::mir::interpret::{Pointer, ReportedErrorInfo};
|
||||
use rustc_middle::query::TyCtxtAt;
|
||||
use rustc_middle::ty::layout::{HasTypingEnv, TyAndLayout, ValidityRequirement};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
|
|
@ -22,7 +22,7 @@ use crate::errors::{LongRunning, LongRunningWarn};
|
|||
use crate::fluent_generated as fluent;
|
||||
use crate::interpret::{
|
||||
self, AllocId, AllocInit, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame,
|
||||
GlobalAlloc, ImmTy, InterpCx, InterpResult, OpTy, PlaceTy, Pointer, RangeSet, Scalar,
|
||||
GlobalAlloc, ImmTy, InterpCx, InterpResult, OpTy, PlaceTy, RangeSet, Scalar,
|
||||
compile_time_machine, err_inval, interp_ok, throw_exhaust, throw_inval, throw_ub,
|
||||
throw_ub_custom, throw_unsup, throw_unsup_format,
|
||||
};
|
||||
|
|
@ -586,6 +586,11 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
sym::type_of => {
|
||||
let ty = ecx.read_type_id(&args[0])?;
|
||||
ecx.write_type_info(ty, dest)?;
|
||||
}
|
||||
|
||||
_ => {
|
||||
// We haven't handled the intrinsic, let's see if we can use a fallback body.
|
||||
if ecx.tcx.intrinsic(instance.def_id()).unwrap().must_be_overridden {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ mod error;
|
|||
mod eval_queries;
|
||||
mod fn_queries;
|
||||
mod machine;
|
||||
mod type_info;
|
||||
mod valtrees;
|
||||
|
||||
pub use self::dummy_machine::*;
|
||||
|
|
|
|||
175
compiler/rustc_const_eval/src/const_eval/type_info.rs
Normal file
175
compiler/rustc_const_eval/src/const_eval/type_info.rs
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
use rustc_abi::FieldIdx;
|
||||
use rustc_hir::LangItem;
|
||||
use rustc_middle::mir::interpret::CtfeProvenance;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::layout::TyAndLayout;
|
||||
use rustc_middle::ty::{self, ScalarInt, Ty};
|
||||
use rustc_span::{Symbol, sym};
|
||||
|
||||
use crate::const_eval::CompileTimeMachine;
|
||||
use crate::interpret::{
|
||||
Immediate, InterpCx, InterpResult, MPlaceTy, MemoryKind, Writeable, interp_ok,
|
||||
};
|
||||
|
||||
impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
|
||||
/// Writes a `core::mem::type_info::TypeInfo` for a given type, `ty` to the given place.
|
||||
pub(crate) fn write_type_info(
|
||||
&mut self,
|
||||
ty: Ty<'tcx>,
|
||||
dest: &impl Writeable<'tcx, CtfeProvenance>,
|
||||
) -> InterpResult<'tcx> {
|
||||
let ty_struct = self.tcx.require_lang_item(LangItem::Type, self.tcx.span);
|
||||
let ty_struct = self.tcx.type_of(ty_struct).no_bound_vars().unwrap();
|
||||
assert_eq!(ty_struct, dest.layout().ty);
|
||||
let ty_struct = ty_struct.ty_adt_def().unwrap().non_enum_variant();
|
||||
// Fill all fields of the `TypeInfo` struct.
|
||||
for (idx, field) in ty_struct.fields.iter_enumerated() {
|
||||
let field_dest = self.project_field(dest, idx)?;
|
||||
let downcast = |name: Symbol| {
|
||||
let variants = field_dest.layout().ty.ty_adt_def().unwrap().variants();
|
||||
let variant_id = variants
|
||||
.iter_enumerated()
|
||||
.find(|(_idx, var)| var.name == name)
|
||||
.unwrap_or_else(|| panic!("got {name} but expected one of {variants:#?}"))
|
||||
.0;
|
||||
|
||||
interp_ok((variant_id, self.project_downcast(&field_dest, variant_id)?))
|
||||
};
|
||||
match field.name {
|
||||
sym::kind => {
|
||||
let variant_index = match ty.kind() {
|
||||
ty::Tuple(fields) => {
|
||||
let (variant, variant_place) = downcast(sym::Tuple)?;
|
||||
// project to the single tuple variant field of `type_info::Tuple` struct type
|
||||
let tuple_place = self.project_field(&variant_place, FieldIdx::ZERO)?;
|
||||
assert_eq!(
|
||||
1,
|
||||
tuple_place
|
||||
.layout()
|
||||
.ty
|
||||
.ty_adt_def()
|
||||
.unwrap()
|
||||
.non_enum_variant()
|
||||
.fields
|
||||
.len()
|
||||
);
|
||||
self.write_tuple_fields(tuple_place, fields, ty)?;
|
||||
variant
|
||||
}
|
||||
// For now just merge all primitives into one `Leaf` variant with no data
|
||||
ty::Uint(_) | ty::Int(_) | ty::Float(_) | ty::Char | ty::Bool => {
|
||||
downcast(sym::Leaf)?.0
|
||||
}
|
||||
ty::Adt(_, _)
|
||||
| ty::Foreign(_)
|
||||
| ty::Str
|
||||
| ty::Array(_, _)
|
||||
| ty::Pat(_, _)
|
||||
| ty::Slice(_)
|
||||
| ty::RawPtr(..)
|
||||
| ty::Ref(..)
|
||||
| ty::FnDef(..)
|
||||
| ty::FnPtr(..)
|
||||
| ty::UnsafeBinder(..)
|
||||
| ty::Dynamic(..)
|
||||
| ty::Closure(..)
|
||||
| ty::CoroutineClosure(..)
|
||||
| ty::Coroutine(..)
|
||||
| ty::CoroutineWitness(..)
|
||||
| ty::Never
|
||||
| ty::Alias(..)
|
||||
| ty::Param(_)
|
||||
| ty::Bound(..)
|
||||
| ty::Placeholder(_)
|
||||
| ty::Infer(..)
|
||||
| ty::Error(_) => downcast(sym::Other)?.0,
|
||||
};
|
||||
self.write_discriminant(variant_index, &field_dest)?
|
||||
}
|
||||
sym::size => {
|
||||
let layout = self.layout_of(ty)?;
|
||||
let variant_index = if layout.is_sized() {
|
||||
let (variant, variant_place) = downcast(sym::Some)?;
|
||||
let size_field_place =
|
||||
self.project_field(&variant_place, FieldIdx::ZERO)?;
|
||||
self.write_scalar(
|
||||
ScalarInt::try_from_target_usize(layout.size.bytes(), self.tcx.tcx)
|
||||
.unwrap(),
|
||||
&size_field_place,
|
||||
)?;
|
||||
variant
|
||||
} else {
|
||||
downcast(sym::None)?.0
|
||||
};
|
||||
self.write_discriminant(variant_index, &field_dest)?;
|
||||
}
|
||||
other => span_bug!(self.tcx.span, "unknown `Type` field {other}"),
|
||||
}
|
||||
}
|
||||
|
||||
interp_ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn write_tuple_fields(
|
||||
&mut self,
|
||||
tuple_place: impl Writeable<'tcx, CtfeProvenance>,
|
||||
fields: &[Ty<'tcx>],
|
||||
tuple_ty: Ty<'tcx>,
|
||||
) -> InterpResult<'tcx> {
|
||||
// project into the `type_info::Tuple::fields` field
|
||||
let fields_slice_place = self.project_field(&tuple_place, FieldIdx::ZERO)?;
|
||||
// get the `type_info::Field` type from `fields: &[Field]`
|
||||
let field_type = fields_slice_place
|
||||
.layout()
|
||||
.ty
|
||||
.builtin_deref(false)
|
||||
.unwrap()
|
||||
.sequence_element_type(self.tcx.tcx);
|
||||
// Create an array with as many elements as the number of fields in the inspected tuple
|
||||
let fields_layout =
|
||||
self.layout_of(Ty::new_array(self.tcx.tcx, field_type, fields.len() as u64))?;
|
||||
let fields_place = self.allocate(fields_layout, MemoryKind::Stack)?;
|
||||
let mut fields_places = self.project_array_fields(&fields_place)?;
|
||||
|
||||
let tuple_layout = self.layout_of(tuple_ty)?;
|
||||
|
||||
while let Some((i, place)) = fields_places.next(self)? {
|
||||
let field_ty = fields[i as usize];
|
||||
self.write_field(field_ty, place, tuple_layout, i)?;
|
||||
}
|
||||
|
||||
let fields_place = fields_place.map_provenance(CtfeProvenance::as_immutable);
|
||||
|
||||
let ptr = Immediate::new_slice(fields_place.ptr(), fields.len() as u64, self);
|
||||
|
||||
self.write_immediate(ptr, &fields_slice_place)
|
||||
}
|
||||
|
||||
fn write_field(
|
||||
&mut self,
|
||||
field_ty: Ty<'tcx>,
|
||||
place: MPlaceTy<'tcx>,
|
||||
layout: TyAndLayout<'tcx>,
|
||||
idx: u64,
|
||||
) -> InterpResult<'tcx> {
|
||||
for (field_idx, field_ty_field) in
|
||||
place.layout.ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
|
||||
{
|
||||
let field_place = self.project_field(&place, field_idx)?;
|
||||
match field_ty_field.name {
|
||||
sym::ty => self.write_type_id(field_ty, &field_place)?,
|
||||
sym::offset => {
|
||||
let offset = layout.fields.offset(idx as usize);
|
||||
self.write_scalar(
|
||||
ScalarInt::try_from_target_usize(offset.bytes(), self.tcx.tcx).unwrap(),
|
||||
&field_place,
|
||||
)?;
|
||||
}
|
||||
other => {
|
||||
span_bug!(self.tcx.def_span(field_ty_field.did), "unimplemented field {other}")
|
||||
}
|
||||
}
|
||||
}
|
||||
interp_ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -27,6 +27,7 @@ use super::{
|
|||
throw_ub_custom, throw_ub_format,
|
||||
};
|
||||
use crate::fluent_generated as fluent;
|
||||
use crate::interpret::Writeable;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
enum MulAddType {
|
||||
|
|
@ -68,10 +69,10 @@ pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> (AllocId
|
|||
}
|
||||
impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||
/// Generates a value of `TypeId` for `ty` in-place.
|
||||
fn write_type_id(
|
||||
pub(crate) fn write_type_id(
|
||||
&mut self,
|
||||
ty: Ty<'tcx>,
|
||||
dest: &PlaceTy<'tcx, M::Provenance>,
|
||||
dest: &impl Writeable<'tcx, M::Provenance>,
|
||||
) -> InterpResult<'tcx, ()> {
|
||||
let tcx = self.tcx;
|
||||
let type_id_hash = tcx.type_id_hash(ty).as_u128();
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ use rustc_ast::tokenstream::{
|
|||
AttrTokenStream, AttrTokenTree, LazyAttrTokenStream, Spacing, TokenTree,
|
||||
};
|
||||
use rustc_ast::{
|
||||
self as ast, AttrKind, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem, MetaItemInner,
|
||||
NodeId, NormalAttr,
|
||||
self as ast, AttrItemKind, AttrKind, AttrStyle, Attribute, EarlyParsedAttribute, HasAttrs,
|
||||
HasTokens, MetaItem, MetaItemInner, NodeId, NormalAttr,
|
||||
};
|
||||
use rustc_attr_parsing as attr;
|
||||
use rustc_attr_parsing::{
|
||||
|
|
@ -288,7 +288,9 @@ impl<'a> StripUnconfigured<'a> {
|
|||
pub(crate) fn expand_cfg_attr(&self, cfg_attr: &Attribute, recursive: bool) -> Vec<Attribute> {
|
||||
// A trace attribute left in AST in place of the original `cfg_attr` attribute.
|
||||
// It can later be used by lints or other diagnostics.
|
||||
let trace_attr = attr_into_trace(cfg_attr.clone(), sym::cfg_attr_trace);
|
||||
let mut trace_attr = cfg_attr.clone();
|
||||
trace_attr.replace_args(AttrItemKind::Parsed(EarlyParsedAttribute::CfgAttrTrace));
|
||||
let trace_attr = attr_into_trace(trace_attr, sym::cfg_attr_trace);
|
||||
|
||||
let Some((cfg_predicate, expanded_attrs)) =
|
||||
rustc_attr_parsing::parse_cfg_attr(cfg_attr, &self.sess, self.features)
|
||||
|
|
|
|||
|
|
@ -7,12 +7,16 @@ use rustc_ast::mut_visit::*;
|
|||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::visit::{self, AssocCtxt, Visitor, VisitorResult, try_visit, walk_list};
|
||||
use rustc_ast::{
|
||||
self as ast, AssocItemKind, AstNodeWrapper, AttrArgs, AttrStyle, AttrVec, DUMMY_NODE_ID,
|
||||
ExprKind, ForeignItemKind, HasAttrs, HasNodeId, Inline, ItemKind, MacStmtStyle, MetaItemInner,
|
||||
MetaItemKind, ModKind, NodeId, PatKind, StmtKind, TyKind, token,
|
||||
self as ast, AssocItemKind, AstNodeWrapper, AttrArgs, AttrItemKind, AttrStyle, AttrVec,
|
||||
DUMMY_NODE_ID, EarlyParsedAttribute, ExprKind, ForeignItemKind, HasAttrs, HasNodeId, Inline,
|
||||
ItemKind, MacStmtStyle, MetaItemInner, MetaItemKind, ModKind, NodeId, PatKind, StmtKind,
|
||||
TyKind, token,
|
||||
};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_attr_parsing::{AttributeParser, Early, EvalConfigResult, ShouldEmit, validate_attr};
|
||||
use rustc_attr_parsing::{
|
||||
AttributeParser, CFG_TEMPLATE, Early, EvalConfigResult, ShouldEmit, eval_config_entry,
|
||||
parse_cfg, validate_attr,
|
||||
};
|
||||
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_errors::PResult;
|
||||
|
|
@ -813,10 +817,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
};
|
||||
let attr_item = attr.get_normal_item();
|
||||
let safety = attr_item.unsafety;
|
||||
if let AttrArgs::Eq { .. } = attr_item.args {
|
||||
if let AttrArgs::Eq { .. } = attr_item.args.unparsed_ref().unwrap() {
|
||||
self.cx.dcx().emit_err(UnsupportedKeyValue { span });
|
||||
}
|
||||
let inner_tokens = attr_item.args.inner_tokens();
|
||||
let inner_tokens = attr_item.args.unparsed_ref().unwrap().inner_tokens();
|
||||
match expander.expand_with_safety(self.cx, safety, span, inner_tokens, tokens) {
|
||||
Ok(tok_result) => {
|
||||
let fragment = self.parse_ast_fragment(
|
||||
|
|
@ -2110,7 +2114,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
|||
let mut attr_pos = None;
|
||||
for (pos, attr) in item.attrs().iter().enumerate() {
|
||||
if !attr.is_doc_comment() && !self.cx.expanded_inert_attrs.is_marked(attr) {
|
||||
let name = attr.ident().map(|ident| ident.name);
|
||||
let name = attr.name();
|
||||
if name == Some(sym::cfg) || name == Some(sym::cfg_attr) {
|
||||
cfg_pos = Some(pos); // a cfg attr found, no need to search anymore
|
||||
break;
|
||||
|
|
@ -2187,22 +2191,18 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
|||
} else if rustc_attr_parsing::is_builtin_attr(attr)
|
||||
&& !AttributeParser::<Early>::is_parsed_attribute(&attr.path())
|
||||
{
|
||||
let attr_name = attr.ident().unwrap().name;
|
||||
// `#[cfg]` and `#[cfg_attr]` are special - they are
|
||||
// eagerly evaluated.
|
||||
if attr_name != sym::cfg_trace && attr_name != sym::cfg_attr_trace {
|
||||
self.cx.sess.psess.buffer_lint(
|
||||
UNUSED_ATTRIBUTES,
|
||||
attr.span,
|
||||
self.cx.current_expansion.lint_node_id,
|
||||
crate::errors::UnusedBuiltinAttribute {
|
||||
attr_name,
|
||||
macro_name: pprust::path_to_string(&call.path),
|
||||
invoc_span: call.path.span,
|
||||
attr_span: attr.span,
|
||||
},
|
||||
);
|
||||
}
|
||||
let attr_name = attr.name().unwrap();
|
||||
self.cx.sess.psess.buffer_lint(
|
||||
UNUSED_ATTRIBUTES,
|
||||
attr.span,
|
||||
self.cx.current_expansion.lint_node_id,
|
||||
crate::errors::UnusedBuiltinAttribute {
|
||||
attr_name,
|
||||
macro_name: pprust::path_to_string(&call.path),
|
||||
invoc_span: call.path.span,
|
||||
attr_span: attr.span,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2213,11 +2213,26 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
|||
attr: ast::Attribute,
|
||||
pos: usize,
|
||||
) -> EvalConfigResult {
|
||||
let res = self.cfg().cfg_true(&attr, ShouldEmit::ErrorsAndLints);
|
||||
let Some(cfg) = AttributeParser::parse_single(
|
||||
self.cfg().sess,
|
||||
&attr,
|
||||
attr.span,
|
||||
self.cfg().lint_node_id,
|
||||
self.cfg().features,
|
||||
ShouldEmit::ErrorsAndLints,
|
||||
parse_cfg,
|
||||
&CFG_TEMPLATE,
|
||||
) else {
|
||||
// Cfg attribute was not parsable, give up
|
||||
return EvalConfigResult::True;
|
||||
};
|
||||
|
||||
let res = eval_config_entry(self.cfg().sess, &cfg);
|
||||
if res.as_bool() {
|
||||
// A trace attribute left in AST in place of the original `cfg` attribute.
|
||||
// It can later be used by lints or other diagnostics.
|
||||
let trace_attr = attr_into_trace(attr, sym::cfg_trace);
|
||||
let mut trace_attr = attr_into_trace(attr, sym::cfg_trace);
|
||||
trace_attr.replace_args(AttrItemKind::Parsed(EarlyParsedAttribute::CfgTrace(cfg)));
|
||||
node.visit_attrs(|attrs| attrs.insert(pos, trace_attr));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -558,25 +558,20 @@ fn metavar_expr_concat<'tx>(
|
|||
MetaVarExprConcatElem::Ident(elem) => elem.name,
|
||||
MetaVarExprConcatElem::Literal(elem) => *elem,
|
||||
MetaVarExprConcatElem::Var(ident) => {
|
||||
match matched_from_ident(dcx, *ident, tscx.interp)? {
|
||||
NamedMatch::MatchedSeq(named_matches) => {
|
||||
let Some((curr_idx, _)) = tscx.repeats.last() else {
|
||||
return Err(dcx.struct_span_err(dspan.entire(), "invalid syntax"));
|
||||
};
|
||||
match &named_matches[*curr_idx] {
|
||||
// FIXME(c410-f3r) Nested repetitions are unimplemented
|
||||
MatchedSeq(_) => {
|
||||
return Err(dcx.struct_span_err(
|
||||
ident.span,
|
||||
"nested repetitions with `${concat(...)}` metavariable expressions are not yet supported",
|
||||
));
|
||||
}
|
||||
MatchedSingle(pnr) => extract_symbol_from_pnr(dcx, pnr, ident.span)?,
|
||||
}
|
||||
}
|
||||
NamedMatch::MatchedSingle(pnr) => {
|
||||
let key = MacroRulesNormalizedIdent::new(*ident);
|
||||
match lookup_cur_matched(key, tscx.interp, &tscx.repeats) {
|
||||
Some(NamedMatch::MatchedSingle(pnr)) => {
|
||||
extract_symbol_from_pnr(dcx, pnr, ident.span)?
|
||||
}
|
||||
Some(NamedMatch::MatchedSeq(..)) => {
|
||||
return Err(dcx.struct_span_err(
|
||||
ident.span,
|
||||
"`${concat(...)}` variable is still repeating at this depth",
|
||||
));
|
||||
}
|
||||
None => {
|
||||
return Err(dcx.create_err(MveUnrecognizedVar { span: ident.span, key }));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -235,7 +235,7 @@ declare_features! (
|
|||
(accepted, generic_param_attrs, "1.27.0", Some(48848)),
|
||||
/// Allows the `#[global_allocator]` attribute.
|
||||
(accepted, global_allocator, "1.28.0", Some(27389)),
|
||||
// FIXME: explain `globs`.
|
||||
/// Allows globs imports (`use module::*;`) to import all public items from a module.
|
||||
(accepted, globs, "1.0.0", None),
|
||||
/// Allows using `..=X` as a pattern.
|
||||
(accepted, half_open_range_patterns, "1.66.0", Some(67264)),
|
||||
|
|
|
|||
|
|
@ -60,6 +60,9 @@ declare_features! (
|
|||
(removed, allocator, "1.0.0", None, None),
|
||||
/// Allows a test to fail without failing the whole suite.
|
||||
(removed, allow_fail, "1.60.0", Some(46488), Some("removed due to no clear use cases"), 93416),
|
||||
/// Allows users to enforce equality of associated constants `TraitImpl<AssocConst=3>`.
|
||||
(removed, associated_const_equality, "CURRENT_RUSTC_VERSION", Some(92827),
|
||||
Some("merged into `min_generic_const_args`")),
|
||||
(removed, await_macro, "1.38.0", Some(50547),
|
||||
Some("subsumed by `.await` syntax"), 62293),
|
||||
/// Allows using the `box $expr` syntax.
|
||||
|
|
|
|||
|
|
@ -233,28 +233,20 @@ declare_features! (
|
|||
(internal, link_cfg, "1.14.0", None),
|
||||
/// Allows using `?Trait` trait bounds in more contexts.
|
||||
(internal, more_maybe_bounds, "1.82.0", None),
|
||||
/// Allows the `multiple_supertrait_upcastable` lint.
|
||||
(unstable, multiple_supertrait_upcastable, "1.69.0", None),
|
||||
/// Allow negative trait bounds. This is an internal-only feature for testing the trait solver!
|
||||
(internal, negative_bounds, "1.71.0", None),
|
||||
/// Set the maximum pattern complexity allowed (not limited by default).
|
||||
(internal, pattern_complexity_limit, "1.78.0", None),
|
||||
/// Allows using pattern types.
|
||||
(internal, pattern_types, "1.79.0", Some(123646)),
|
||||
/// Allows using `#[prelude_import]` on glob `use` items.
|
||||
(internal, prelude_import, "1.2.0", None),
|
||||
/// Used to identify crates that contain the profiler runtime.
|
||||
(internal, profiler_runtime, "1.18.0", None),
|
||||
/// Allows using `rustc_*` attributes (RFC 572).
|
||||
(internal, rustc_attrs, "1.0.0", None),
|
||||
/// Introduces a hierarchy of `Sized` traits (RFC 3729).
|
||||
(unstable, sized_hierarchy, "1.89.0", None),
|
||||
/// Allows using the `#[stable]` and `#[unstable]` attributes.
|
||||
(internal, staged_api, "1.0.0", None),
|
||||
/// Added for testing unstable lints; perma-unstable.
|
||||
(internal, test_unstable_lint, "1.60.0", None),
|
||||
/// Helps with formatting for `group_imports = "StdExternalCrate"`.
|
||||
(unstable, unqualified_local_imports, "1.83.0", Some(138299)),
|
||||
/// Use for stable + negative coherence and strict coherence depending on trait's
|
||||
/// rustc_strict_coherence value.
|
||||
(unstable, with_negative_coherence, "1.60.0", None),
|
||||
|
|
@ -295,6 +287,8 @@ declare_features! (
|
|||
(internal, needs_panic_runtime, "1.10.0", Some(32837)),
|
||||
/// Allows using the `#![panic_runtime]` attribute.
|
||||
(internal, panic_runtime, "1.10.0", Some(32837)),
|
||||
/// Allows using pattern types.
|
||||
(internal, pattern_types, "1.79.0", Some(123646)),
|
||||
/// Allows using `#[rustc_allow_const_fn_unstable]`.
|
||||
/// This is an attribute on `const fn` for the same
|
||||
/// purpose as `#[allow_internal_unstable]`.
|
||||
|
|
@ -305,12 +299,16 @@ declare_features! (
|
|||
(internal, rustdoc_internals, "1.58.0", Some(90418)),
|
||||
/// Allows using the `rustdoc::missing_doc_code_examples` lint
|
||||
(unstable, rustdoc_missing_doc_code_examples, "1.31.0", Some(101730)),
|
||||
/// Introduces a hierarchy of `Sized` traits (RFC 3729).
|
||||
(unstable, sized_hierarchy, "1.89.0", Some(144404)),
|
||||
/// Allows using `#[structural_match]` which indicates that a type is structurally matchable.
|
||||
/// FIXME: Subsumed by trait `StructuralPartialEq`, cannot move to removed until a library
|
||||
/// feature with the same name exists.
|
||||
(unstable, structural_match, "1.8.0", Some(31434)),
|
||||
/// Allows using the `rust-call` ABI.
|
||||
(unstable, unboxed_closures, "1.0.0", Some(29625)),
|
||||
/// Helps with formatting for `group_imports = "StdExternalCrate"`.
|
||||
(unstable, unqualified_local_imports, "1.83.0", Some(138299)),
|
||||
// !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
|
||||
// Features are listed in alphabetical order. Tidy will fail if you don't keep it this way.
|
||||
// !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
|
||||
|
|
@ -363,8 +361,6 @@ declare_features! (
|
|||
(unstable, asm_goto_with_outputs, "1.85.0", Some(119364)),
|
||||
/// Allows the `may_unwind` option in inline assembly.
|
||||
(unstable, asm_unwind, "1.58.0", Some(93334)),
|
||||
/// Allows users to enforce equality of associated constants `TraitImpl<AssocConst=3>`.
|
||||
(unstable, associated_const_equality, "1.58.0", Some(92827)),
|
||||
/// Allows associated type defaults.
|
||||
(unstable, associated_type_defaults, "1.2.0", Some(29661)),
|
||||
/// Allows implementing `AsyncDrop`.
|
||||
|
|
@ -571,6 +567,8 @@ declare_features! (
|
|||
(unstable, more_qualified_paths, "1.54.0", Some(86935)),
|
||||
/// The `movrs` target feature on x86.
|
||||
(unstable, movrs_target_feature, "1.88.0", Some(137976)),
|
||||
/// Allows the `multiple_supertrait_upcastable` lint.
|
||||
(unstable, multiple_supertrait_upcastable, "1.69.0", Some(150833)),
|
||||
/// Allows the `#[must_not_suspend]` attribute.
|
||||
(unstable, must_not_suspend, "1.57.0", Some(83310)),
|
||||
/// Allows `mut ref` and `mut ref mut` identifier patterns.
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub use ReprAttr::*;
|
||||
use rustc_abi::Align;
|
||||
pub use rustc_ast::attr::data_structures::*;
|
||||
use rustc_ast::token::DocFragmentKind;
|
||||
use rustc_ast::{AttrStyle, ast};
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
|
|
@ -11,7 +11,7 @@ use rustc_error_messages::{DiagArgValue, IntoDiagArg};
|
|||
use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute};
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::hygiene::Transparency;
|
||||
use rustc_span::{Ident, Span, Symbol};
|
||||
use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol};
|
||||
pub use rustc_target::spec::SanitizerSet;
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
|
|
@ -19,9 +19,22 @@ use crate::attrs::pretty_printing::PrintAttribute;
|
|||
use crate::limit::Limit;
|
||||
use crate::{DefaultBodyStability, PartialConstStability, RustcVersion, Stability};
|
||||
|
||||
#[derive(Copy, Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
|
||||
pub enum EiiImplResolution {
|
||||
/// Usually, finding the extern item that an EII implementation implements means finding
|
||||
/// the defid of the associated attribute macro, and looking at *its* attributes to find
|
||||
/// what foreign item its associated with.
|
||||
Macro(DefId),
|
||||
/// Sometimes though, we already know statically and can skip some name resolution.
|
||||
/// Stored together with the eii's name for diagnostics.
|
||||
Known(EiiDecl),
|
||||
/// For when resolution failed, but we want to continue compilation
|
||||
Error(ErrorGuaranteed),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
|
||||
pub struct EiiImpl {
|
||||
pub eii_macro: DefId,
|
||||
pub resolution: EiiImplResolution,
|
||||
pub impl_marked_unsafe: bool,
|
||||
pub span: Span,
|
||||
pub inner_span: Span,
|
||||
|
|
@ -33,7 +46,7 @@ pub struct EiiDecl {
|
|||
pub eii_extern_target: DefId,
|
||||
/// whether or not it is unsafe to implement this EII
|
||||
pub impl_unsafe: bool,
|
||||
pub span: Span,
|
||||
pub name: Ident,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, PrintAttribute)]
|
||||
|
|
@ -212,83 +225,6 @@ impl<ModId> StrippedCfgItem<ModId> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Encodable, Decodable, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[derive(HashStable_Generic, PrintAttribute)]
|
||||
pub enum CfgEntry {
|
||||
All(ThinVec<CfgEntry>, Span),
|
||||
Any(ThinVec<CfgEntry>, Span),
|
||||
Not(Box<CfgEntry>, Span),
|
||||
Bool(bool, Span),
|
||||
NameValue { name: Symbol, value: Option<Symbol>, span: Span },
|
||||
Version(Option<RustcVersion>, Span),
|
||||
}
|
||||
|
||||
impl CfgEntry {
|
||||
pub fn span(&self) -> Span {
|
||||
let (Self::All(_, span)
|
||||
| Self::Any(_, span)
|
||||
| Self::Not(_, span)
|
||||
| Self::Bool(_, span)
|
||||
| Self::NameValue { span, .. }
|
||||
| Self::Version(_, span)) = self;
|
||||
*span
|
||||
}
|
||||
|
||||
/// Same as `PartialEq` but doesn't check spans and ignore order of cfgs.
|
||||
pub fn is_equivalent_to(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::All(a, _), Self::All(b, _)) | (Self::Any(a, _), Self::Any(b, _)) => {
|
||||
a.len() == b.len() && a.iter().all(|a| b.iter().any(|b| a.is_equivalent_to(b)))
|
||||
}
|
||||
(Self::Not(a, _), Self::Not(b, _)) => a.is_equivalent_to(b),
|
||||
(Self::Bool(a, _), Self::Bool(b, _)) => a == b,
|
||||
(
|
||||
Self::NameValue { name: name1, value: value1, .. },
|
||||
Self::NameValue { name: name2, value: value2, .. },
|
||||
) => name1 == name2 && value1 == value2,
|
||||
(Self::Version(a, _), Self::Version(b, _)) => a == b,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CfgEntry {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fn write_entries(
|
||||
name: &str,
|
||||
entries: &[CfgEntry],
|
||||
f: &mut fmt::Formatter<'_>,
|
||||
) -> fmt::Result {
|
||||
write!(f, "{name}(")?;
|
||||
for (nb, entry) in entries.iter().enumerate() {
|
||||
if nb != 0 {
|
||||
f.write_str(", ")?;
|
||||
}
|
||||
entry.fmt(f)?;
|
||||
}
|
||||
f.write_str(")")
|
||||
}
|
||||
match self {
|
||||
Self::All(entries, _) => write_entries("all", entries, f),
|
||||
Self::Any(entries, _) => write_entries("any", entries, f),
|
||||
Self::Not(entry, _) => write!(f, "not({entry})"),
|
||||
Self::Bool(value, _) => write!(f, "{value}"),
|
||||
Self::NameValue { name, value, .. } => {
|
||||
match value {
|
||||
// We use `as_str` and debug display to have characters escaped and `"`
|
||||
// characters surrounding the string.
|
||||
Some(value) => write!(f, "{name} = {:?}", value.as_str()),
|
||||
None => write!(f, "{name}"),
|
||||
}
|
||||
}
|
||||
Self::Version(version, _) => match version {
|
||||
Some(version) => write!(f, "{version}"),
|
||||
None => Ok(()),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Possible values for the `#[linkage]` attribute, allowing to specify the
|
||||
/// linkage type for a `MonoItem`.
|
||||
///
|
||||
|
|
@ -713,6 +649,12 @@ pub enum AttributeKind {
|
|||
span: Span,
|
||||
},
|
||||
|
||||
/// Represents the trace attribute of `#[cfg_attr]`
|
||||
CfgAttrTrace,
|
||||
|
||||
/// Represents the trace attribute of `#[cfg]`
|
||||
CfgTrace(ThinVec<(CfgEntry, Span)>),
|
||||
|
||||
/// Represents `#[cfi_encoding]`
|
||||
CfiEncoding { encoding: Symbol },
|
||||
|
||||
|
|
@ -938,6 +880,9 @@ pub enum AttributeKind {
|
|||
/// Represents `#[rustc_coherence_is_core]`
|
||||
RustcCoherenceIsCore(Span),
|
||||
|
||||
/// Represents `#[rustc_has_incoherent_inherent_impls]`
|
||||
RustcHasIncoherentInherentImpls,
|
||||
|
||||
/// Represents `#[rustc_layout_scalar_valid_range_end]`.
|
||||
RustcLayoutScalarValidRangeEnd(Box<u128>, Span),
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ impl AttributeKind {
|
|||
AsPtr(..) => Yes,
|
||||
AutomaticallyDerived(..) => Yes,
|
||||
BodyStability { .. } => No,
|
||||
CfgAttrTrace => Yes,
|
||||
CfgTrace(..) => Yes,
|
||||
CfiEncoding { .. } => Yes,
|
||||
Coinductive(..) => No,
|
||||
Cold(..) => No,
|
||||
|
|
@ -93,6 +95,7 @@ impl AttributeKind {
|
|||
Repr { .. } => No,
|
||||
RustcBuiltinMacro { .. } => Yes,
|
||||
RustcCoherenceIsCore(..) => No,
|
||||
RustcHasIncoherentInherentImpls => Yes,
|
||||
RustcLayoutScalarValidRangeEnd(..) => Yes,
|
||||
RustcLayoutScalarValidRangeStart(..) => Yes,
|
||||
RustcLegacyConstGenerics { .. } => Yes,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ use std::num::NonZero;
|
|||
use std::ops::Deref;
|
||||
|
||||
use rustc_abi::Align;
|
||||
use rustc_ast::attr::data_structures::CfgEntry;
|
||||
use rustc_ast::attr::version::RustcVersion;
|
||||
use rustc_ast::token::{CommentKind, DocFragmentKind};
|
||||
use rustc_ast::{AttrStyle, IntTy, UintTy};
|
||||
use rustc_ast_pretty::pp::Printer;
|
||||
|
|
@ -182,4 +184,6 @@ print_debug!(
|
|||
Transparency,
|
||||
SanitizerSet,
|
||||
DefId,
|
||||
RustcVersion,
|
||||
CfgEntry,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -423,7 +423,7 @@ impl<'hir> ConstItemRhs<'hir> {
|
|||
pub fn span<'tcx>(&self, tcx: impl crate::intravisit::HirTyCtxt<'tcx>) -> Span {
|
||||
match self {
|
||||
ConstItemRhs::Body(body_id) => tcx.hir_body(*body_id).value.span,
|
||||
ConstItemRhs::TypeConst(ct_arg) => ct_arg.span(),
|
||||
ConstItemRhs::TypeConst(ct_arg) => ct_arg.span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -440,13 +440,14 @@ impl<'hir> ConstItemRhs<'hir> {
|
|||
/// versus const args that are literals or have arbitrary computations (e.g., `{ 1 + 3 }`).
|
||||
///
|
||||
/// For an explanation of the `Unambig` generic parameter see the dev-guide:
|
||||
/// <https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html>
|
||||
/// <https://rustc-dev-guide.rust-lang.org/ambig-unambig-ty-and-consts.html>
|
||||
#[derive(Clone, Copy, Debug, HashStable_Generic)]
|
||||
#[repr(C)]
|
||||
pub struct ConstArg<'hir, Unambig = ()> {
|
||||
#[stable_hasher(ignore)]
|
||||
pub hir_id: HirId,
|
||||
pub kind: ConstArgKind<'hir, Unambig>,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl<'hir> ConstArg<'hir, AmbigArg> {
|
||||
|
|
@ -475,7 +476,7 @@ impl<'hir> ConstArg<'hir> {
|
|||
/// Functions accepting ambiguous consts will not handle the [`ConstArgKind::Infer`] variant, if
|
||||
/// infer consts are relevant to you then care should be taken to handle them separately.
|
||||
pub fn try_as_ambig_ct(&self) -> Option<&ConstArg<'hir, AmbigArg>> {
|
||||
if let ConstArgKind::Infer(_, ()) = self.kind {
|
||||
if let ConstArgKind::Infer(()) = self.kind {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
|
@ -494,22 +495,13 @@ impl<'hir, Unambig> ConstArg<'hir, Unambig> {
|
|||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn span(&self) -> Span {
|
||||
match self.kind {
|
||||
ConstArgKind::Struct(path, _) => path.span(),
|
||||
ConstArgKind::Path(path) => path.span(),
|
||||
ConstArgKind::Anon(anon) => anon.span,
|
||||
ConstArgKind::Error(span, _) => span,
|
||||
ConstArgKind::Infer(span, _) => span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// See [`ConstArg`].
|
||||
#[derive(Clone, Copy, Debug, HashStable_Generic)]
|
||||
#[repr(u8, C)]
|
||||
pub enum ConstArgKind<'hir, Unambig = ()> {
|
||||
Tup(&'hir [&'hir ConstArg<'hir, Unambig>]),
|
||||
/// **Note:** Currently this is only used for bare const params
|
||||
/// (`N` where `fn foo<const N: usize>(...)`),
|
||||
/// not paths to any const (`N` where `const N: usize = ...`).
|
||||
|
|
@ -519,11 +511,14 @@ pub enum ConstArgKind<'hir, Unambig = ()> {
|
|||
Anon(&'hir AnonConst),
|
||||
/// Represents construction of struct/struct variants
|
||||
Struct(QPath<'hir>, &'hir [&'hir ConstArgExprField<'hir>]),
|
||||
/// Tuple constructor variant
|
||||
TupleCall(QPath<'hir>, &'hir [&'hir ConstArg<'hir>]),
|
||||
/// Error const
|
||||
Error(Span, ErrorGuaranteed),
|
||||
Error(ErrorGuaranteed),
|
||||
/// This variant is not always used to represent inference consts, sometimes
|
||||
/// [`GenericArg::Infer`] is used instead.
|
||||
Infer(Span, Unambig),
|
||||
Infer(Unambig),
|
||||
Literal(LitKind),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, HashStable_Generic)]
|
||||
|
|
@ -569,7 +564,7 @@ impl GenericArg<'_> {
|
|||
match self {
|
||||
GenericArg::Lifetime(l) => l.ident.span,
|
||||
GenericArg::Type(t) => t.span,
|
||||
GenericArg::Const(c) => c.span(),
|
||||
GenericArg::Const(c) => c.span,
|
||||
GenericArg::Infer(i) => i.span,
|
||||
}
|
||||
}
|
||||
|
|
@ -1196,7 +1191,7 @@ pub enum AttrArgs {
|
|||
|
||||
#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable)]
|
||||
pub struct AttrPath {
|
||||
pub segments: Box<[Ident]>,
|
||||
pub segments: Box<[Symbol]>,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
|
|
@ -1212,7 +1207,7 @@ impl AttrPath {
|
|||
segments: path
|
||||
.segments
|
||||
.iter()
|
||||
.map(|i| Ident { name: i.ident.name, span: lower_span(i.ident.span) })
|
||||
.map(|i| i.ident.name)
|
||||
.collect::<Vec<_>>()
|
||||
.into_boxed_slice(),
|
||||
span: lower_span(path.span),
|
||||
|
|
@ -1222,7 +1217,11 @@ impl AttrPath {
|
|||
|
||||
impl fmt::Display for AttrPath {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", join_path_idents(&self.segments))
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
join_path_idents(self.segments.iter().map(|i| Ident { name: *i, span: DUMMY_SP }))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1327,7 +1326,7 @@ impl AttributeExt for Attribute {
|
|||
|
||||
/// For a single-segment attribute, returns its name; otherwise, returns `None`.
|
||||
#[inline]
|
||||
fn ident(&self) -> Option<Ident> {
|
||||
fn name(&self) -> Option<Symbol> {
|
||||
match &self {
|
||||
Attribute::Unparsed(n) => {
|
||||
if let [ident] = n.path.segments.as_ref() {
|
||||
|
|
@ -1343,7 +1342,7 @@ impl AttributeExt for Attribute {
|
|||
#[inline]
|
||||
fn path_matches(&self, name: &[Symbol]) -> bool {
|
||||
match &self {
|
||||
Attribute::Unparsed(n) => n.path.segments.iter().map(|ident| &ident.name).eq(name),
|
||||
Attribute::Unparsed(n) => n.path.segments.iter().eq(name),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
@ -1364,6 +1363,7 @@ impl AttributeExt for Attribute {
|
|||
// FIXME: should not be needed anymore when all attrs are parsed
|
||||
Attribute::Parsed(AttributeKind::DocComment { span, .. }) => *span,
|
||||
Attribute::Parsed(AttributeKind::Deprecation { span, .. }) => *span,
|
||||
Attribute::Parsed(AttributeKind::CfgTrace(cfgs)) => cfgs[0].1,
|
||||
a => panic!("can't get the span of an arbitrary parsed attribute: {a:?}"),
|
||||
}
|
||||
}
|
||||
|
|
@ -1379,13 +1379,20 @@ impl AttributeExt for Attribute {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>> {
|
||||
fn symbol_path(&self) -> Option<SmallVec<[Symbol; 1]>> {
|
||||
match &self {
|
||||
Attribute::Unparsed(n) => Some(n.path.segments.iter().copied().collect()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn path_span(&self) -> Option<Span> {
|
||||
match &self {
|
||||
Attribute::Unparsed(attr) => Some(attr.path.span),
|
||||
Attribute::Parsed(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn doc_str(&self) -> Option<Symbol> {
|
||||
match &self {
|
||||
|
|
@ -1394,6 +1401,14 @@ impl AttributeExt for Attribute {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn deprecation_note(&self) -> Option<Symbol> {
|
||||
match &self {
|
||||
Attribute::Parsed(AttributeKind::Deprecation { deprecation, .. }) => deprecation.note,
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_automatically_derived_attr(&self) -> bool {
|
||||
matches!(self, Attribute::Parsed(AttributeKind::AutomaticallyDerived(..)))
|
||||
}
|
||||
|
|
@ -1465,11 +1480,6 @@ impl Attribute {
|
|||
AttributeExt::value_span(self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn ident(&self) -> Option<Ident> {
|
||||
AttributeExt::ident(self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn path_matches(&self, name: &[Symbol]) -> bool {
|
||||
AttributeExt::path_matches(self, name)
|
||||
|
|
@ -1505,11 +1515,6 @@ impl Attribute {
|
|||
AttributeExt::path(self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>> {
|
||||
AttributeExt::ident_path(self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn doc_str(&self) -> Option<Symbol> {
|
||||
AttributeExt::doc_str(self)
|
||||
|
|
@ -2620,6 +2625,12 @@ impl Expr<'_> {
|
|||
// them being used only for its side-effects.
|
||||
base.can_have_side_effects()
|
||||
}
|
||||
ExprKind::Binary(_, lhs, rhs) => {
|
||||
// This isn't exactly true for all `Binary`, but we are using this
|
||||
// method exclusively for diagnostics and there's a *cultural* pressure against
|
||||
// them being used only for its side-effects.
|
||||
lhs.can_have_side_effects() || rhs.can_have_side_effects()
|
||||
}
|
||||
ExprKind::Struct(_, fields, init) => {
|
||||
let init_side_effects = match init {
|
||||
StructTailExpr::Base(init) => init.can_have_side_effects(),
|
||||
|
|
@ -2642,13 +2653,13 @@ impl Expr<'_> {
|
|||
},
|
||||
args,
|
||||
) => args.iter().any(|arg| arg.can_have_side_effects()),
|
||||
ExprKind::Repeat(arg, _) => arg.can_have_side_effects(),
|
||||
ExprKind::If(..)
|
||||
| ExprKind::Match(..)
|
||||
| ExprKind::MethodCall(..)
|
||||
| ExprKind::Call(..)
|
||||
| ExprKind::Closure { .. }
|
||||
| ExprKind::Block(..)
|
||||
| ExprKind::Repeat(..)
|
||||
| ExprKind::Break(..)
|
||||
| ExprKind::Continue(..)
|
||||
| ExprKind::Ret(..)
|
||||
|
|
@ -2659,7 +2670,6 @@ impl Expr<'_> {
|
|||
| ExprKind::InlineAsm(..)
|
||||
| ExprKind::AssignOp(..)
|
||||
| ExprKind::ConstBlock(..)
|
||||
| ExprKind::Binary(..)
|
||||
| ExprKind::Yield(..)
|
||||
| ExprKind::DropTemps(..)
|
||||
| ExprKind::Err(_) => true,
|
||||
|
|
@ -3374,7 +3384,7 @@ pub enum AmbigArg {}
|
|||
/// Represents a type in the `HIR`.
|
||||
///
|
||||
/// For an explanation of the `Unambig` generic parameter see the dev-guide:
|
||||
/// <https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html>
|
||||
/// <https://rustc-dev-guide.rust-lang.org/ambig-unambig-ty-and-consts.html>
|
||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
#[repr(C)]
|
||||
pub struct Ty<'hir, Unambig = ()> {
|
||||
|
|
@ -3713,7 +3723,7 @@ pub enum InferDelegationKind {
|
|||
/// The various kinds of types recognized by the compiler.
|
||||
///
|
||||
/// For an explanation of the `Unambig` generic parameter see the dev-guide:
|
||||
/// <https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html>
|
||||
/// <https://rustc-dev-guide.rust-lang.org/ambig-unambig-ty-and-consts.html>
|
||||
// SAFETY: `repr(u8)` is required so that `TyKind<()>` and `TyKind<!>` are layout compatible
|
||||
#[repr(u8, C)]
|
||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
|
|
|
|||
|
|
@ -24,12 +24,16 @@ define_tests! {
|
|||
cast_ptr TyKind Ptr { 0: MutTy { ty: &Ty { span: DUMMY_SP, hir_id: HirId::INVALID, kind: TyKind::Never }, mutbl: Mutability::Not }}
|
||||
cast_array TyKind Array {
|
||||
0: &Ty { span: DUMMY_SP, hir_id: HirId::INVALID, kind: TyKind::Never },
|
||||
1: &ConstArg { hir_id: HirId::INVALID, kind: ConstArgKind::Anon(&AnonConst {
|
||||
1: &ConstArg {
|
||||
hir_id: HirId::INVALID,
|
||||
def_id: LocalDefId { local_def_index: DefIndex::ZERO },
|
||||
body: BodyId { hir_id: HirId::INVALID },
|
||||
kind: ConstArgKind::Anon(&AnonConst {
|
||||
hir_id: HirId::INVALID,
|
||||
def_id: LocalDefId { local_def_index: DefIndex::ZERO },
|
||||
body: BodyId { hir_id: HirId::INVALID },
|
||||
span: DUMMY_SP,
|
||||
}),
|
||||
span: DUMMY_SP,
|
||||
})}
|
||||
},
|
||||
}
|
||||
|
||||
cast_anon ConstArgKind Anon {
|
||||
|
|
|
|||
|
|
@ -1068,8 +1068,8 @@ pub fn walk_unambig_const_arg<'v, V: Visitor<'v>>(
|
|||
match const_arg.try_as_ambig_ct() {
|
||||
Some(ambig_ct) => visitor.visit_const_arg(ambig_ct),
|
||||
None => {
|
||||
let ConstArg { hir_id, kind: _ } = const_arg;
|
||||
visitor.visit_infer(*hir_id, const_arg.span(), InferKind::Const(const_arg))
|
||||
let ConstArg { hir_id, kind: _, span } = const_arg;
|
||||
visitor.visit_infer(*hir_id, *span, InferKind::Const(const_arg))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1078,9 +1078,13 @@ pub fn walk_const_arg<'v, V: Visitor<'v>>(
|
|||
visitor: &mut V,
|
||||
const_arg: &'v ConstArg<'v, AmbigArg>,
|
||||
) -> V::Result {
|
||||
let ConstArg { hir_id, kind } = const_arg;
|
||||
let ConstArg { hir_id, kind, span: _ } = const_arg;
|
||||
try_visit!(visitor.visit_id(*hir_id));
|
||||
match kind {
|
||||
ConstArgKind::Tup(exprs) => {
|
||||
walk_list!(visitor, visit_const_arg, *exprs);
|
||||
V::Result::output()
|
||||
}
|
||||
ConstArgKind::Struct(qpath, field_exprs) => {
|
||||
try_visit!(visitor.visit_qpath(qpath, *hir_id, qpath.span()));
|
||||
|
||||
|
|
@ -1090,9 +1094,17 @@ pub fn walk_const_arg<'v, V: Visitor<'v>>(
|
|||
|
||||
V::Result::output()
|
||||
}
|
||||
ConstArgKind::TupleCall(qpath, args) => {
|
||||
try_visit!(visitor.visit_qpath(qpath, *hir_id, qpath.span()));
|
||||
for arg in *args {
|
||||
try_visit!(visitor.visit_const_arg_unambig(*arg));
|
||||
}
|
||||
V::Result::output()
|
||||
}
|
||||
ConstArgKind::Path(qpath) => visitor.visit_qpath(qpath, *hir_id, qpath.span()),
|
||||
ConstArgKind::Anon(anon) => visitor.visit_anon_const(*anon),
|
||||
ConstArgKind::Error(_, _) => V::Result::output(), // errors and spans are not important
|
||||
ConstArgKind::Error(_) => V::Result::output(), // errors and spans are not important
|
||||
ConstArgKind::Literal(..) => V::Result::output(), // FIXME(mcga)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -278,6 +278,7 @@ language_item_table! {
|
|||
PartialOrd, sym::partial_ord, partial_ord_trait, Target::Trait, GenericRequirement::Exact(1);
|
||||
CVoid, sym::c_void, c_void, Target::Enum, GenericRequirement::None;
|
||||
|
||||
Type, sym::type_info, type_struct, Target::Struct, GenericRequirement::None;
|
||||
TypeId, sym::type_id, type_id, Target::Struct, GenericRequirement::None;
|
||||
|
||||
// A number of panic-related lang items. The `panic` item corresponds to divide-by-zero and
|
||||
|
|
|
|||
|
|
@ -32,8 +32,7 @@ pub mod lints;
|
|||
pub mod pat_util;
|
||||
mod stability;
|
||||
mod stable_hash_impls;
|
||||
mod target;
|
||||
mod version;
|
||||
pub mod target;
|
||||
pub mod weak_lang_items;
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
@ -42,9 +41,9 @@ mod tests;
|
|||
#[doc(no_inline)]
|
||||
pub use hir::*;
|
||||
pub use lang_items::{LangItem, LanguageItems};
|
||||
pub use rustc_ast::attr::version::*;
|
||||
pub use stability::*;
|
||||
pub use stable_hash_impls::HashStableContext;
|
||||
pub use target::{MethodKind, Target};
|
||||
pub use version::*;
|
||||
|
||||
arena_types!(rustc_arena::declare_arena);
|
||||
|
|
|
|||
|
|
@ -32,21 +32,21 @@ use crate::errors::{EiiWithGenerics, LifetimesOrBoundsMismatchOnEii};
|
|||
pub(crate) fn compare_eii_function_types<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
external_impl: LocalDefId,
|
||||
declaration: DefId,
|
||||
foreign_item: DefId,
|
||||
eii_name: Symbol,
|
||||
eii_attr_span: Span,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
check_is_structurally_compatible(tcx, external_impl, declaration, eii_name, eii_attr_span)?;
|
||||
check_is_structurally_compatible(tcx, external_impl, foreign_item, eii_name, eii_attr_span)?;
|
||||
|
||||
let external_impl_span = tcx.def_span(external_impl);
|
||||
let cause = ObligationCause::new(
|
||||
external_impl_span,
|
||||
external_impl,
|
||||
ObligationCauseCode::CompareEii { external_impl, declaration },
|
||||
ObligationCauseCode::CompareEii { external_impl, declaration: foreign_item },
|
||||
);
|
||||
|
||||
// FIXME(eii): even if we don't support generic functions, we should support explicit outlive bounds here
|
||||
let param_env = tcx.param_env(declaration);
|
||||
let param_env = tcx.param_env(foreign_item);
|
||||
|
||||
let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
|
||||
let ocx = ObligationCtxt::new_with_diagnostics(infcx);
|
||||
|
|
@ -62,7 +62,7 @@ pub(crate) fn compare_eii_function_types<'tcx>(
|
|||
let mut wf_tys = FxIndexSet::default();
|
||||
let norm_cause = ObligationCause::misc(external_impl_span, external_impl);
|
||||
|
||||
let declaration_sig = tcx.fn_sig(declaration).instantiate_identity();
|
||||
let declaration_sig = tcx.fn_sig(foreign_item).instantiate_identity();
|
||||
let declaration_sig = tcx.liberate_late_bound_regions(external_impl.into(), declaration_sig);
|
||||
debug!(?declaration_sig);
|
||||
|
||||
|
|
@ -103,7 +103,7 @@ pub(crate) fn compare_eii_function_types<'tcx>(
|
|||
cause,
|
||||
param_env,
|
||||
terr,
|
||||
(declaration, declaration_sig),
|
||||
(foreign_item, declaration_sig),
|
||||
(external_impl, external_impl_sig),
|
||||
eii_attr_span,
|
||||
eii_name,
|
||||
|
|
|
|||
|
|
@ -213,6 +213,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
|
|||
| sym::type_id
|
||||
| sym::type_id_eq
|
||||
| sym::type_name
|
||||
| sym::type_of
|
||||
| sym::ub_checks
|
||||
| sym::variant_count
|
||||
| sym::vtable_for
|
||||
|
|
@ -308,13 +309,22 @@ pub(crate) fn check_intrinsic_type(
|
|||
sym::needs_drop => (1, 0, vec![], tcx.types.bool),
|
||||
|
||||
sym::type_name => (1, 0, vec![], Ty::new_static_str(tcx)),
|
||||
sym::type_id => {
|
||||
(1, 0, vec![], tcx.type_of(tcx.lang_items().type_id().unwrap()).instantiate_identity())
|
||||
}
|
||||
sym::type_id => (
|
||||
1,
|
||||
0,
|
||||
vec![],
|
||||
tcx.type_of(tcx.lang_items().type_id().unwrap()).no_bound_vars().unwrap(),
|
||||
),
|
||||
sym::type_id_eq => {
|
||||
let type_id = tcx.type_of(tcx.lang_items().type_id().unwrap()).instantiate_identity();
|
||||
let type_id = tcx.type_of(tcx.lang_items().type_id().unwrap()).no_bound_vars().unwrap();
|
||||
(0, 0, vec![type_id, type_id], tcx.types.bool)
|
||||
}
|
||||
sym::type_of => (
|
||||
0,
|
||||
0,
|
||||
vec![tcx.type_of(tcx.lang_items().type_id().unwrap()).no_bound_vars().unwrap()],
|
||||
tcx.type_of(tcx.lang_items().type_struct().unwrap()).no_bound_vars().unwrap(),
|
||||
),
|
||||
sym::offload => (
|
||||
3,
|
||||
0,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use rustc_abi::{ExternAbi, ScalableElt};
|
|||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err};
|
||||
use rustc_hir::attrs::{AttributeKind, EiiDecl, EiiImpl};
|
||||
use rustc_hir::attrs::{AttributeKind, EiiDecl, EiiImpl, EiiImplResolution};
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
|
|
@ -1196,27 +1196,28 @@ fn check_item_fn(
|
|||
fn check_eiis(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
// does the function have an EiiImpl attribute? that contains the defid of a *macro*
|
||||
// that was used to mark the implementation. This is a two step process.
|
||||
for EiiImpl { eii_macro, span, .. } in
|
||||
for EiiImpl { resolution, span, .. } in
|
||||
find_attr!(tcx.get_all_attrs(def_id), AttributeKind::EiiImpls(impls) => impls)
|
||||
.into_iter()
|
||||
.flatten()
|
||||
{
|
||||
// we expect this macro to have the `EiiMacroFor` attribute, that points to a function
|
||||
// signature that we'd like to compare the function we're currently checking with
|
||||
if let Some(eii_extern_target) = find_attr!(tcx.get_all_attrs(*eii_macro), AttributeKind::EiiExternTarget(EiiDecl {eii_extern_target, ..}) => *eii_extern_target)
|
||||
{
|
||||
let _ = compare_eii_function_types(
|
||||
tcx,
|
||||
def_id,
|
||||
eii_extern_target,
|
||||
tcx.item_name(*eii_macro),
|
||||
*span,
|
||||
);
|
||||
} else {
|
||||
panic!(
|
||||
"EII impl macro {eii_macro:?} did not have an eii extern target attribute pointing to a foreign function"
|
||||
)
|
||||
}
|
||||
let (foreign_item, name) = match resolution {
|
||||
EiiImplResolution::Macro(def_id) => {
|
||||
// we expect this macro to have the `EiiMacroFor` attribute, that points to a function
|
||||
// signature that we'd like to compare the function we're currently checking with
|
||||
if let Some(foreign_item) = find_attr!(tcx.get_all_attrs(*def_id), AttributeKind::EiiExternTarget(EiiDecl {eii_extern_target: t, ..}) => *t)
|
||||
{
|
||||
(foreign_item, tcx.item_name(*def_id))
|
||||
} else {
|
||||
tcx.dcx().span_delayed_bug(*span, "resolved to something that's not an EII");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
EiiImplResolution::Known(decl) => (decl.eii_extern_target, decl.name.name),
|
||||
EiiImplResolution::Error(_eg) => continue,
|
||||
};
|
||||
|
||||
let _ = compare_eii_function_types(tcx, def_id, foreign_item, name, *span);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ use rustc_hir::find_attr;
|
|||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::fast_reject::{SimplifiedType, TreatParams, simplify_type};
|
||||
use rustc_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt};
|
||||
use rustc_span::{ErrorGuaranteed, sym};
|
||||
use rustc_span::ErrorGuaranteed;
|
||||
|
||||
use crate::errors;
|
||||
|
||||
|
|
@ -79,13 +79,15 @@ impl<'tcx> InherentCollect<'tcx> {
|
|||
}
|
||||
|
||||
if self.tcx.features().rustc_attrs() {
|
||||
let items = self.tcx.associated_item_def_ids(impl_def_id);
|
||||
|
||||
if !self.tcx.has_attr(ty_def_id, sym::rustc_has_incoherent_inherent_impls) {
|
||||
if !find_attr!(
|
||||
self.tcx.get_all_attrs(ty_def_id),
|
||||
AttributeKind::RustcHasIncoherentInherentImpls
|
||||
) {
|
||||
let impl_span = self.tcx.def_span(impl_def_id);
|
||||
return Err(self.tcx.dcx().emit_err(errors::InherentTyOutside { span: impl_span }));
|
||||
}
|
||||
|
||||
let items = self.tcx.associated_item_def_ids(impl_def_id);
|
||||
for &impl_item in items {
|
||||
if !find_attr!(
|
||||
self.tcx.get_all_attrs(impl_item),
|
||||
|
|
|
|||
|
|
@ -1479,23 +1479,27 @@ fn rendered_precise_capturing_args<'tcx>(
|
|||
|
||||
fn const_param_default<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
local_def_id: LocalDefId,
|
||||
) -> ty::EarlyBinder<'tcx, Const<'tcx>> {
|
||||
let hir::Node::GenericParam(hir::GenericParam {
|
||||
kind: hir::GenericParamKind::Const { default: Some(default_ct), .. },
|
||||
..
|
||||
}) = tcx.hir_node_by_def_id(def_id)
|
||||
}) = tcx.hir_node_by_def_id(local_def_id)
|
||||
else {
|
||||
span_bug!(
|
||||
tcx.def_span(def_id),
|
||||
tcx.def_span(local_def_id),
|
||||
"`const_param_default` expected a generic parameter with a constant"
|
||||
)
|
||||
};
|
||||
let icx = ItemCtxt::new(tcx, def_id);
|
||||
let identity_args = ty::GenericArgs::identity_for_item(tcx, def_id);
|
||||
|
||||
let icx = ItemCtxt::new(tcx, local_def_id);
|
||||
|
||||
let def_id = local_def_id.to_def_id();
|
||||
let identity_args = ty::GenericArgs::identity_for_item(tcx, tcx.parent(def_id));
|
||||
|
||||
let ct = icx
|
||||
.lowerer()
|
||||
.lower_const_arg(default_ct, FeedConstTy::Param(def_id.to_def_id(), identity_args));
|
||||
.lower_const_arg(default_ct, FeedConstTy::with_type_of(tcx, def_id, identity_args));
|
||||
ty::EarlyBinder::bind(ct)
|
||||
}
|
||||
|
||||
|
|
@ -1553,7 +1557,7 @@ fn const_of_item<'tcx>(
|
|||
let identity_args = ty::GenericArgs::identity_for_item(tcx, def_id);
|
||||
let ct = icx
|
||||
.lowerer()
|
||||
.lower_const_arg(ct_arg, FeedConstTy::Param(def_id.to_def_id(), identity_args));
|
||||
.lower_const_arg(ct_arg, FeedConstTy::with_type_of(tcx, def_id.to_def_id(), identity_args));
|
||||
if let Err(e) = icx.check_tainted_by_errors()
|
||||
&& !ct.references_error()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -420,7 +420,22 @@ fn infer_placeholder_type<'tcx>(
|
|||
kind: &'static str,
|
||||
) -> Ty<'tcx> {
|
||||
let tcx = cx.tcx();
|
||||
let ty = tcx.typeck(def_id).node_type(hir_id);
|
||||
// If the type is omitted on a #[type_const] we can't run
|
||||
// type check on since that requires the const have a body
|
||||
// which type_consts don't.
|
||||
let ty = if tcx.is_type_const(def_id.to_def_id()) {
|
||||
if let Some(trait_item_def_id) = tcx.trait_item_of(def_id.to_def_id()) {
|
||||
tcx.type_of(trait_item_def_id).instantiate_identity()
|
||||
} else {
|
||||
Ty::new_error_with_message(
|
||||
tcx,
|
||||
ty_span,
|
||||
"constant with #[type_const] requires an explicit type",
|
||||
)
|
||||
}
|
||||
} else {
|
||||
tcx.typeck(def_id).node_type(hir_id)
|
||||
};
|
||||
|
||||
// If this came from a free `const` or `static mut?` item,
|
||||
// then the user may have written e.g. `const A = 42;`.
|
||||
|
|
|
|||
|
|
@ -610,9 +610,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
AttributeKind::TypeConst(_)
|
||||
)
|
||||
{
|
||||
if tcx.features().min_generic_const_args()
|
||||
|| tcx.features().associated_const_equality()
|
||||
{
|
||||
if tcx.features().min_generic_const_args() {
|
||||
let mut err = self.dcx().struct_span_err(
|
||||
constraint.span,
|
||||
"use of trait associated const without `#[type_const]`",
|
||||
|
|
|
|||
|
|
@ -239,7 +239,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
// `trait_object_dummy_self`, so check for that.
|
||||
let references_self = match pred.skip_binder().term.kind() {
|
||||
ty::TermKind::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()),
|
||||
// FIXME(associated_const_equality): We should walk the const instead of not doing anything
|
||||
// FIXME(mgca): We should walk the const instead of not doing anything
|
||||
ty::TermKind::Const(_) => false,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -359,12 +359,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
None
|
||||
};
|
||||
|
||||
// FIXME(associated_const_equality): This has quite a few false positives and negatives.
|
||||
// FIXME(mgca): This has quite a few false positives and negatives.
|
||||
let wrap_in_braces_sugg = if let Some(constraint) = constraint
|
||||
&& let Some(hir_ty) = constraint.ty()
|
||||
&& let ty = self.lower_ty(hir_ty)
|
||||
&& (ty.is_enum() || ty.references_error())
|
||||
&& tcx.features().associated_const_equality()
|
||||
&& tcx.features().min_generic_const_args()
|
||||
{
|
||||
Some(errors::AssocKindMismatchWrapInBracesSugg {
|
||||
lo: hir_ty.span.shrink_to_lo(),
|
||||
|
|
@ -381,7 +381,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
{
|
||||
let span = match term {
|
||||
hir::Term::Ty(ty) => ty.span,
|
||||
hir::Term::Const(ct) => ct.span(),
|
||||
hir::Term::Const(ct) => ct.span,
|
||||
};
|
||||
(span, Some(ident.span), assoc_item.as_tag(), assoc_tag)
|
||||
} else {
|
||||
|
|
@ -1466,7 +1466,7 @@ pub fn prohibit_assoc_item_constraint(
|
|||
hir::AssocItemConstraintKind::Equality { term: hir::Term::Const(c) },
|
||||
GenericParamDefKind::Const { .. },
|
||||
) => {
|
||||
suggest_direct_use(&mut err, c.span());
|
||||
suggest_direct_use(&mut err, c.span);
|
||||
}
|
||||
(hir::AssocItemConstraintKind::Bound { bounds }, _) => {
|
||||
// Suggest `impl<T: Bound> Trait<T> for Foo` when finding
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ pub mod generics;
|
|||
use std::assert_matches::assert_matches;
|
||||
use std::slice;
|
||||
|
||||
use rustc_ast::LitKind;
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{
|
||||
|
|
@ -259,17 +260,26 @@ impl AssocItemQSelf {
|
|||
/// Use this enum with `<dyn HirTyLowerer>::lower_const_arg` to instruct it with the
|
||||
/// desired behavior.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum FeedConstTy<'a, 'tcx> {
|
||||
/// Feed the type.
|
||||
///
|
||||
pub enum FeedConstTy<'tcx> {
|
||||
/// Feed the type to the (anno) const arg.
|
||||
WithTy(Ty<'tcx>),
|
||||
/// Don't feed the type.
|
||||
No,
|
||||
}
|
||||
|
||||
impl<'tcx> FeedConstTy<'tcx> {
|
||||
/// The `DefId` belongs to the const param that we are supplying
|
||||
/// this (anon) const arg to.
|
||||
///
|
||||
/// The list of generic args is used to instantiate the parameters
|
||||
/// used by the type of the const param specified by `DefId`.
|
||||
Param(DefId, &'a [ty::GenericArg<'tcx>]),
|
||||
/// Don't feed the type.
|
||||
No,
|
||||
pub fn with_type_of(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: DefId,
|
||||
generic_args: &[ty::GenericArg<'tcx>],
|
||||
) -> Self {
|
||||
Self::WithTy(tcx.type_of(def_id).instantiate(tcx, generic_args))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
|
|
@ -314,6 +324,7 @@ pub enum PermitVariants {
|
|||
enum TypeRelativePath<'tcx> {
|
||||
AssocItem(DefId, GenericArgsRef<'tcx>),
|
||||
Variant { adt: Ty<'tcx>, variant_did: DefId },
|
||||
Ctor { ctor_def_id: DefId, args: GenericArgsRef<'tcx> },
|
||||
}
|
||||
|
||||
/// New-typed boolean indicating whether explicit late-bound lifetimes
|
||||
|
|
@ -722,7 +733,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
// Ambig portions of `ConstArg` are handled in the match arm below
|
||||
.lower_const_arg(
|
||||
ct.as_unambig_ct(),
|
||||
FeedConstTy::Param(param.def_id, preceding_args),
|
||||
FeedConstTy::with_type_of(tcx, param.def_id, preceding_args),
|
||||
)
|
||||
.into(),
|
||||
(&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
|
||||
|
|
@ -1375,6 +1386,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let adt = self.check_param_uses_if_mcg(adt, span, false);
|
||||
Ok((adt, DefKind::Variant, variant_did))
|
||||
}
|
||||
TypeRelativePath::Ctor { .. } => {
|
||||
let e = tcx.dcx().span_err(span, "expected type, found tuple constructor");
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1410,6 +1425,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let ct = self.check_param_uses_if_mcg(ct, span, false);
|
||||
Ok(ct)
|
||||
}
|
||||
TypeRelativePath::Ctor { ctor_def_id, args } => match tcx.def_kind(ctor_def_id) {
|
||||
DefKind::Ctor(_, CtorKind::Fn) => {
|
||||
Ok(ty::Const::zero_sized(tcx, Ty::new_fn_def(tcx, ctor_def_id, args)))
|
||||
}
|
||||
DefKind::Ctor(ctor_of, CtorKind::Const) => {
|
||||
Ok(self.construct_const_ctor_value(ctor_def_id, ctor_of, args))
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
// FIXME(mgca): implement support for this once ready to support all adt ctor expressions,
|
||||
// not just const ctors
|
||||
TypeRelativePath::Variant { .. } => {
|
||||
|
|
@ -1441,6 +1465,23 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
.iter()
|
||||
.find(|vd| tcx.hygienic_eq(segment.ident, vd.ident(tcx), adt_def.did()));
|
||||
if let Some(variant_def) = variant_def {
|
||||
// FIXME(mgca): do we want constructor resolutions to take priority over
|
||||
// other possible resolutions?
|
||||
if matches!(mode, LowerTypeRelativePathMode::Const)
|
||||
&& let Some((_, ctor_def_id)) = variant_def.ctor
|
||||
{
|
||||
tcx.check_stability(variant_def.def_id, Some(qpath_hir_id), span, None);
|
||||
let _ = self.prohibit_generic_args(
|
||||
slice::from_ref(segment).iter(),
|
||||
GenericsArgsErrExtend::EnumVariant {
|
||||
qself: hir_self_ty,
|
||||
assoc_segment: segment,
|
||||
adt_def,
|
||||
},
|
||||
);
|
||||
let ty::Adt(_, enum_args) = self_ty.kind() else { unreachable!() };
|
||||
return Ok(TypeRelativePath::Ctor { ctor_def_id, args: enum_args });
|
||||
}
|
||||
if let PermitVariants::Yes = mode.permit_variants() {
|
||||
tcx.check_stability(variant_def.def_id, Some(qpath_hir_id), span, None);
|
||||
let _ = self.prohibit_generic_args(
|
||||
|
|
@ -2272,15 +2313,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
pub fn lower_const_arg(
|
||||
&self,
|
||||
const_arg: &hir::ConstArg<'tcx>,
|
||||
feed: FeedConstTy<'_, 'tcx>,
|
||||
feed: FeedConstTy<'tcx>,
|
||||
) -> Const<'tcx> {
|
||||
let tcx = self.tcx();
|
||||
|
||||
if let FeedConstTy::Param(param_def_id, args) = feed
|
||||
if let FeedConstTy::WithTy(anon_const_type) = feed
|
||||
&& let hir::ConstArgKind::Anon(anon) = &const_arg.kind
|
||||
{
|
||||
let anon_const_type = tcx.type_of(param_def_id).instantiate(tcx, args);
|
||||
|
||||
// FIXME(generic_const_parameter_types): Ideally we remove these errors below when
|
||||
// we have the ability to intermix typeck of anon const const args with the parent
|
||||
// bodies typeck.
|
||||
|
|
@ -2293,7 +2332,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
&& (anon_const_type.has_free_regions() || anon_const_type.has_erased_regions())
|
||||
{
|
||||
let e = self.dcx().span_err(
|
||||
const_arg.span(),
|
||||
const_arg.span,
|
||||
"anonymous constants with lifetimes in their type are not yet supported",
|
||||
);
|
||||
tcx.feed_anon_const_type(anon.def_id, ty::EarlyBinder::bind(Ty::new_error(tcx, e)));
|
||||
|
|
@ -2304,7 +2343,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
// variables otherwise we will ICE.
|
||||
if anon_const_type.has_non_region_infer() {
|
||||
let e = self.dcx().span_err(
|
||||
const_arg.span(),
|
||||
const_arg.span,
|
||||
"anonymous constants with inferred types are not yet supported",
|
||||
);
|
||||
tcx.feed_anon_const_type(anon.def_id, ty::EarlyBinder::bind(Ty::new_error(tcx, e)));
|
||||
|
|
@ -2314,21 +2353,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
// give the anon const any of the generics from the parent.
|
||||
if anon_const_type.has_non_region_param() {
|
||||
let e = self.dcx().span_err(
|
||||
const_arg.span(),
|
||||
const_arg.span,
|
||||
"anonymous constants referencing generics are not yet supported",
|
||||
);
|
||||
tcx.feed_anon_const_type(anon.def_id, ty::EarlyBinder::bind(Ty::new_error(tcx, e)));
|
||||
return ty::Const::new_error(tcx, e);
|
||||
}
|
||||
|
||||
tcx.feed_anon_const_type(
|
||||
anon.def_id,
|
||||
ty::EarlyBinder::bind(tcx.type_of(param_def_id).instantiate(tcx, args)),
|
||||
);
|
||||
tcx.feed_anon_const_type(anon.def_id, ty::EarlyBinder::bind(anon_const_type));
|
||||
}
|
||||
|
||||
let hir_id = const_arg.hir_id;
|
||||
match const_arg.kind {
|
||||
hir::ConstArgKind::Tup(exprs) => self.lower_const_arg_tup(exprs, feed, const_arg.span),
|
||||
hir::ConstArgKind::Path(hir::QPath::Resolved(maybe_qself, path)) => {
|
||||
debug!(?maybe_qself, ?path);
|
||||
let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself));
|
||||
|
|
@ -2342,19 +2379,146 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
hir_self_ty,
|
||||
segment,
|
||||
hir_id,
|
||||
const_arg.span(),
|
||||
const_arg.span,
|
||||
)
|
||||
.unwrap_or_else(|guar| Const::new_error(tcx, guar))
|
||||
}
|
||||
hir::ConstArgKind::Struct(qpath, inits) => {
|
||||
self.lower_const_arg_struct(hir_id, qpath, inits, const_arg.span())
|
||||
self.lower_const_arg_struct(hir_id, qpath, inits, const_arg.span)
|
||||
}
|
||||
hir::ConstArgKind::TupleCall(qpath, args) => {
|
||||
self.lower_const_arg_tuple_call(hir_id, qpath, args, const_arg.span)
|
||||
}
|
||||
hir::ConstArgKind::Anon(anon) => self.lower_const_arg_anon(anon),
|
||||
hir::ConstArgKind::Infer(span, ()) => self.ct_infer(None, span),
|
||||
hir::ConstArgKind::Error(_, e) => ty::Const::new_error(tcx, e),
|
||||
hir::ConstArgKind::Infer(()) => self.ct_infer(None, const_arg.span),
|
||||
hir::ConstArgKind::Error(e) => ty::Const::new_error(tcx, e),
|
||||
hir::ConstArgKind::Literal(kind) if let FeedConstTy::WithTy(anon_const_type) = feed => {
|
||||
self.lower_const_arg_literal(&kind, anon_const_type, const_arg.span)
|
||||
}
|
||||
hir::ConstArgKind::Literal(..) => {
|
||||
let e = self.dcx().span_err(const_arg.span, "literal of unknown type");
|
||||
ty::Const::new_error(tcx, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_const_arg_tuple_call(
|
||||
&self,
|
||||
hir_id: HirId,
|
||||
qpath: hir::QPath<'tcx>,
|
||||
args: &'tcx [&'tcx hir::ConstArg<'tcx>],
|
||||
span: Span,
|
||||
) -> Const<'tcx> {
|
||||
let tcx = self.tcx();
|
||||
|
||||
let non_adt_or_variant_res = || {
|
||||
let e = tcx.dcx().span_err(span, "tuple constructor with invalid base path");
|
||||
ty::Const::new_error(tcx, e)
|
||||
};
|
||||
|
||||
let ctor_const = match qpath {
|
||||
hir::QPath::Resolved(maybe_qself, path) => {
|
||||
let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself));
|
||||
self.lower_resolved_const_path(opt_self_ty, path, hir_id)
|
||||
}
|
||||
hir::QPath::TypeRelative(hir_self_ty, segment) => {
|
||||
let self_ty = self.lower_ty(hir_self_ty);
|
||||
match self.lower_type_relative_const_path(
|
||||
self_ty,
|
||||
hir_self_ty,
|
||||
segment,
|
||||
hir_id,
|
||||
span,
|
||||
) {
|
||||
Ok(c) => c,
|
||||
Err(_) => return non_adt_or_variant_res(),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let Some(value) = ctor_const.try_to_value() else {
|
||||
return non_adt_or_variant_res();
|
||||
};
|
||||
|
||||
let (adt_def, adt_args, variant_did) = match value.ty.kind() {
|
||||
ty::FnDef(def_id, fn_args)
|
||||
if let DefKind::Ctor(CtorOf::Variant, _) = tcx.def_kind(*def_id) =>
|
||||
{
|
||||
let parent_did = tcx.parent(*def_id);
|
||||
let enum_did = tcx.parent(parent_did);
|
||||
(tcx.adt_def(enum_did), fn_args, parent_did)
|
||||
}
|
||||
ty::FnDef(def_id, fn_args)
|
||||
if let DefKind::Ctor(CtorOf::Struct, _) = tcx.def_kind(*def_id) =>
|
||||
{
|
||||
let parent_did = tcx.parent(*def_id);
|
||||
(tcx.adt_def(parent_did), fn_args, parent_did)
|
||||
}
|
||||
_ => return non_adt_or_variant_res(),
|
||||
};
|
||||
|
||||
let variant_def = adt_def.variant_with_id(variant_did);
|
||||
let variant_idx = adt_def.variant_index_with_id(variant_did).as_u32();
|
||||
|
||||
if args.len() != variant_def.fields.len() {
|
||||
let e = tcx.dcx().span_err(
|
||||
span,
|
||||
format!(
|
||||
"tuple constructor has {} arguments but {} were provided",
|
||||
variant_def.fields.len(),
|
||||
args.len()
|
||||
),
|
||||
);
|
||||
return ty::Const::new_error(tcx, e);
|
||||
}
|
||||
|
||||
let fields = variant_def
|
||||
.fields
|
||||
.iter()
|
||||
.zip(args)
|
||||
.map(|(field_def, arg)| {
|
||||
self.lower_const_arg(arg, FeedConstTy::with_type_of(tcx, field_def.did, adt_args))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let opt_discr_const = if adt_def.is_enum() {
|
||||
let valtree = ty::ValTree::from_scalar_int(tcx, variant_idx.into());
|
||||
Some(ty::Const::new_value(tcx, valtree, tcx.types.u32))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let valtree = ty::ValTree::from_branches(tcx, opt_discr_const.into_iter().chain(fields));
|
||||
let adt_ty = Ty::new_adt(tcx, adt_def, adt_args);
|
||||
ty::Const::new_value(tcx, valtree, adt_ty)
|
||||
}
|
||||
|
||||
fn lower_const_arg_tup(
|
||||
&self,
|
||||
exprs: &'tcx [&'tcx hir::ConstArg<'tcx>],
|
||||
feed: FeedConstTy<'tcx>,
|
||||
span: Span,
|
||||
) -> Const<'tcx> {
|
||||
let tcx = self.tcx();
|
||||
|
||||
let FeedConstTy::WithTy(ty) = feed else {
|
||||
return Const::new_error_with_message(tcx, span, "unsupported const tuple");
|
||||
};
|
||||
|
||||
let ty::Tuple(tys) = ty.kind() else {
|
||||
return Const::new_error_with_message(tcx, span, "const tuple must have a tuple type");
|
||||
};
|
||||
|
||||
let exprs = exprs
|
||||
.iter()
|
||||
.zip(tys.iter())
|
||||
.map(|(expr, ty)| self.lower_const_arg(expr, FeedConstTy::WithTy(ty)))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let valtree = ty::ValTree::from_branches(tcx, exprs);
|
||||
ty::Const::new_value(tcx, valtree, ty)
|
||||
}
|
||||
|
||||
fn lower_const_arg_struct(
|
||||
&self,
|
||||
hir_id: HirId,
|
||||
|
|
@ -2433,7 +2597,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
return ty::Const::new_error(tcx, e);
|
||||
}
|
||||
|
||||
self.lower_const_arg(expr.expr, FeedConstTy::Param(field_def.did, adt_args))
|
||||
self.lower_const_arg(
|
||||
expr.expr,
|
||||
FeedConstTy::with_type_of(tcx, field_def.did, adt_args),
|
||||
)
|
||||
}
|
||||
None => {
|
||||
let e = tcx.dcx().span_err(
|
||||
|
|
@ -2478,7 +2645,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
);
|
||||
self.lower_const_param(def_id, hir_id)
|
||||
}
|
||||
Res::Def(DefKind::Const | DefKind::Ctor(_, CtorKind::Const), did) => {
|
||||
Res::Def(DefKind::Const, did) => {
|
||||
assert_eq!(opt_self_ty, None);
|
||||
let [leading_segments @ .., segment] = path.segments else { bug!() };
|
||||
let _ = self
|
||||
|
|
@ -2486,6 +2653,35 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let args = self.lower_generic_args_of_path_segment(span, did, segment);
|
||||
ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(did, args))
|
||||
}
|
||||
Res::Def(DefKind::Ctor(ctor_of, CtorKind::Const), did) => {
|
||||
assert_eq!(opt_self_ty, None);
|
||||
let [leading_segments @ .., segment] = path.segments else { bug!() };
|
||||
let _ = self
|
||||
.prohibit_generic_args(leading_segments.iter(), GenericsArgsErrExtend::None);
|
||||
|
||||
let parent_did = tcx.parent(did);
|
||||
let generics_did = match ctor_of {
|
||||
CtorOf::Variant => tcx.parent(parent_did),
|
||||
CtorOf::Struct => parent_did,
|
||||
};
|
||||
let args = self.lower_generic_args_of_path_segment(span, generics_did, segment);
|
||||
|
||||
self.construct_const_ctor_value(did, ctor_of, args)
|
||||
}
|
||||
Res::Def(DefKind::Ctor(_, CtorKind::Fn), did) => {
|
||||
assert_eq!(opt_self_ty, None);
|
||||
let [leading_segments @ .., segment] = path.segments else { bug!() };
|
||||
let _ = self
|
||||
.prohibit_generic_args(leading_segments.iter(), GenericsArgsErrExtend::None);
|
||||
let parent_did = tcx.parent(did);
|
||||
let generics_did = if let DefKind::Ctor(CtorOf::Variant, _) = tcx.def_kind(did) {
|
||||
tcx.parent(parent_did)
|
||||
} else {
|
||||
parent_did
|
||||
};
|
||||
let args = self.lower_generic_args_of_path_segment(span, generics_did, segment);
|
||||
ty::Const::zero_sized(tcx, Ty::new_fn_def(tcx, did, args))
|
||||
}
|
||||
Res::Def(DefKind::AssocConst, did) => {
|
||||
let trait_segment = if let [modules @ .., trait_, _item] = path.segments {
|
||||
let _ = self.prohibit_generic_args(modules.iter(), GenericsArgsErrExtend::None);
|
||||
|
|
@ -2521,9 +2717,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
DefKind::Mod
|
||||
| DefKind::Enum
|
||||
| DefKind::Variant
|
||||
| DefKind::Ctor(CtorOf::Variant, CtorKind::Fn)
|
||||
| DefKind::Struct
|
||||
| DefKind::Ctor(CtorOf::Struct, CtorKind::Fn)
|
||||
| DefKind::OpaqueTy
|
||||
| DefKind::TyAlias
|
||||
| DefKind::TraitAlias
|
||||
|
|
@ -2587,6 +2781,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn lower_const_arg_literal(&self, kind: &LitKind, ty: Ty<'tcx>, span: Span) -> Const<'tcx> {
|
||||
let tcx = self.tcx();
|
||||
let input = LitToConstInput { lit: *kind, ty, neg: false };
|
||||
tcx.at(span).lit_to_const(input)
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn try_lower_anon_const_lit(
|
||||
&self,
|
||||
|
|
@ -3043,4 +3244,31 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
Some(r)
|
||||
}
|
||||
|
||||
fn construct_const_ctor_value(
|
||||
&self,
|
||||
ctor_def_id: DefId,
|
||||
ctor_of: CtorOf,
|
||||
args: GenericArgsRef<'tcx>,
|
||||
) -> Const<'tcx> {
|
||||
let tcx = self.tcx();
|
||||
let parent_did = tcx.parent(ctor_def_id);
|
||||
|
||||
let adt_def = tcx.adt_def(match ctor_of {
|
||||
CtorOf::Variant => tcx.parent(parent_did),
|
||||
CtorOf::Struct => parent_did,
|
||||
});
|
||||
|
||||
let variant_idx = adt_def.variant_index_with_id(parent_did);
|
||||
|
||||
let valtree = if adt_def.is_enum() {
|
||||
let discr = ty::ValTree::from_scalar_int(tcx, variant_idx.as_u32().into());
|
||||
ty::ValTree::from_branches(tcx, [ty::Const::new_value(tcx, discr, tcx.types.u32)])
|
||||
} else {
|
||||
ty::ValTree::zst(tcx)
|
||||
};
|
||||
|
||||
let adt_ty = Ty::new_adt(tcx, adt_def, args);
|
||||
ty::Const::new_value(tcx, valtree, adt_ty)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -301,7 +301,7 @@ pub fn lower_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
|
|||
pub fn lower_const_arg_for_rustdoc<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
hir_ct: &hir::ConstArg<'tcx>,
|
||||
feed: FeedConstTy<'_, 'tcx>,
|
||||
feed: FeedConstTy<'tcx>,
|
||||
) -> Const<'tcx> {
|
||||
let env_def_id = tcx.hir_get_parent_item(hir_ct.hir_id);
|
||||
collect::ItemCtxt::new(tcx, env_def_id.def_id).lowerer().lower_const_arg(hir_ct, feed)
|
||||
|
|
|
|||
|
|
@ -17,12 +17,12 @@ use rustc_ast_pretty::pprust::state::MacHeader;
|
|||
use rustc_ast_pretty::pprust::{Comments, PrintState};
|
||||
use rustc_hir::attrs::{AttributeKind, PrintAttribute};
|
||||
use rustc_hir::{
|
||||
BindingMode, ByRef, ConstArgKind, GenericArg, GenericBound, GenericParam, GenericParamKind,
|
||||
HirId, ImplicitSelfKind, LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term,
|
||||
TyPatKind,
|
||||
BindingMode, ByRef, ConstArg, ConstArgExprField, ConstArgKind, GenericArg, GenericBound,
|
||||
GenericParam, GenericParamKind, HirId, ImplicitSelfKind, LifetimeParamKind, Node, PatKind,
|
||||
PreciseCapturingArg, RangeEnd, Term, TyPatKind,
|
||||
};
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::{FileName, Ident, Span, Symbol, kw, sym};
|
||||
use rustc_span::source_map::{SourceMap, Spanned};
|
||||
use rustc_span::{DUMMY_SP, FileName, Ident, Span, Symbol, kw, sym};
|
||||
use {rustc_ast as ast, rustc_hir as hir};
|
||||
|
||||
pub fn id_to_string(cx: &dyn rustc_hir::intravisit::HirTyCtxt<'_>, hir_id: HirId) -> String {
|
||||
|
|
@ -136,7 +136,11 @@ impl<'a> State<'a> {
|
|||
.path
|
||||
.segments
|
||||
.iter()
|
||||
.map(|i| ast::PathSegment { ident: *i, args: None, id: DUMMY_NODE_ID })
|
||||
.map(|i| ast::PathSegment {
|
||||
ident: Ident { name: *i, span: DUMMY_SP },
|
||||
args: None,
|
||||
id: DUMMY_NODE_ID,
|
||||
})
|
||||
.collect(),
|
||||
tokens: None,
|
||||
};
|
||||
|
|
@ -1137,15 +1141,54 @@ impl<'a> State<'a> {
|
|||
|
||||
fn print_const_arg(&mut self, const_arg: &hir::ConstArg<'_>) {
|
||||
match &const_arg.kind {
|
||||
// FIXME(mgca): proper printing for struct exprs
|
||||
ConstArgKind::Struct(..) => self.word("/* STRUCT EXPR */"),
|
||||
ConstArgKind::Tup(exprs) => {
|
||||
self.popen();
|
||||
self.commasep_cmnt(
|
||||
Inconsistent,
|
||||
exprs,
|
||||
|s, arg| s.print_const_arg(arg),
|
||||
|arg| arg.span,
|
||||
);
|
||||
self.pclose();
|
||||
}
|
||||
ConstArgKind::Struct(qpath, fields) => self.print_const_struct(qpath, fields),
|
||||
ConstArgKind::TupleCall(qpath, args) => self.print_const_ctor(qpath, args),
|
||||
ConstArgKind::Path(qpath) => self.print_qpath(qpath, true),
|
||||
ConstArgKind::Anon(anon) => self.print_anon_const(anon),
|
||||
ConstArgKind::Error(_, _) => self.word("/*ERROR*/"),
|
||||
ConstArgKind::Error(_) => self.word("/*ERROR*/"),
|
||||
ConstArgKind::Infer(..) => self.word("_"),
|
||||
ConstArgKind::Literal(node) => {
|
||||
let span = const_arg.span;
|
||||
self.print_literal(&Spanned { span, node: *node })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn print_const_struct(&mut self, qpath: &hir::QPath<'_>, fields: &&[&ConstArgExprField<'_>]) {
|
||||
self.print_qpath(qpath, true);
|
||||
self.word(" ");
|
||||
self.word("{");
|
||||
if !fields.is_empty() {
|
||||
self.nbsp();
|
||||
}
|
||||
self.commasep(Inconsistent, *fields, |s, field| {
|
||||
s.word(field.field.as_str().to_string());
|
||||
s.word(":");
|
||||
s.nbsp();
|
||||
s.print_const_arg(field.expr);
|
||||
});
|
||||
self.word("}");
|
||||
}
|
||||
|
||||
fn print_const_ctor(&mut self, qpath: &hir::QPath<'_>, args: &&[&ConstArg<'_, ()>]) {
|
||||
self.print_qpath(qpath, true);
|
||||
self.word("(");
|
||||
self.commasep(Inconsistent, *args, |s, arg| {
|
||||
s.print_const_arg(arg);
|
||||
});
|
||||
self.word(")");
|
||||
}
|
||||
|
||||
fn print_call_post(&mut self, args: &[hir::Expr<'_>]) {
|
||||
self.popen();
|
||||
self.commasep_exprs(Inconsistent, args);
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ use rustc_middle::ty::adjustment::{
|
|||
};
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Span};
|
||||
use rustc_span::{BytePos, DUMMY_SP, Span};
|
||||
use rustc_trait_selection::infer::InferCtxtExt as _;
|
||||
use rustc_trait_selection::solve::inspect::{self, InferCtxtProofTreeExt, ProofTreeVisitor};
|
||||
use rustc_trait_selection::solve::{Certainty, Goal, NoSolution};
|
||||
|
|
@ -1828,10 +1828,9 @@ impl<'tcx> CoerceMany<'tcx> {
|
|||
// If the block is from an external macro or try (`?`) desugaring, then
|
||||
// do not suggest adding a semicolon, because there's nowhere to put it.
|
||||
// See issues #81943 and #87051.
|
||||
&& matches!(
|
||||
cond_expr.span.desugaring_kind(),
|
||||
None | Some(DesugaringKind::WhileLoop)
|
||||
)
|
||||
// Similarly, if the block is from a loop desugaring, then also do not
|
||||
// suggest adding a semicolon. See issue #150850.
|
||||
&& cond_expr.span.desugaring_kind().is_none()
|
||||
&& !cond_expr.span.in_external_macro(fcx.tcx.sess.source_map())
|
||||
&& !matches!(
|
||||
cond_expr.kind,
|
||||
|
|
|
|||
|
|
@ -1705,7 +1705,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
return;
|
||||
};
|
||||
if let hir::TyKind::Array(_, ct) = ty.peel_refs().kind {
|
||||
let span = ct.span();
|
||||
let span = ct.span;
|
||||
self.dcx().try_steal_modify_and_emit_err(
|
||||
span,
|
||||
StashKey::UnderscoreForArrayLengths,
|
||||
|
|
@ -1746,7 +1746,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
expr: &'tcx hir::Expr<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
let tcx = self.tcx;
|
||||
let count_span = count.span();
|
||||
let count_span = count.span;
|
||||
let count = self.try_structurally_resolve_const(
|
||||
count_span,
|
||||
self.normalize(count_span, self.lower_const_arg(count, FeedConstTy::No)),
|
||||
|
|
|
|||
|
|
@ -525,7 +525,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
pub(crate) fn lower_const_arg(
|
||||
&self,
|
||||
const_arg: &'tcx hir::ConstArg<'tcx>,
|
||||
feed: FeedConstTy<'_, 'tcx>,
|
||||
feed: FeedConstTy<'tcx>,
|
||||
) -> ty::Const<'tcx> {
|
||||
let ct = self.lowerer().lower_const_arg(const_arg, feed);
|
||||
self.register_wf_obligation(
|
||||
|
|
@ -1228,7 +1228,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// Ambiguous parts of `ConstArg` are handled in the match arms below
|
||||
.lower_const_arg(
|
||||
ct.as_unambig_ct(),
|
||||
FeedConstTy::Param(param.def_id, preceding_args),
|
||||
FeedConstTy::with_type_of(self.fcx.tcx, param.def_id, preceding_args),
|
||||
)
|
||||
.into(),
|
||||
(&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
|
|||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{
|
||||
self as hir, Arm, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind,
|
||||
GenericBound, HirId, Node, PatExpr, PatExprKind, Path, QPath, Stmt, StmtKind, TyKind,
|
||||
WherePredicateKind, expr_needs_parens, is_range_literal,
|
||||
GenericBound, HirId, LoopSource, Node, PatExpr, PatExprKind, Path, QPath, Stmt, StmtKind,
|
||||
TyKind, WherePredicateKind, expr_needs_parens, is_range_literal,
|
||||
};
|
||||
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
|
||||
use rustc_hir_analysis::suggest_impl_trait;
|
||||
|
|
@ -1170,15 +1170,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
let found = self.resolve_vars_if_possible(found);
|
||||
|
||||
let in_loop = self.is_loop(id)
|
||||
|| self
|
||||
.tcx
|
||||
let innermost_loop = if self.is_loop(id) {
|
||||
Some(self.tcx.hir_node(id))
|
||||
} else {
|
||||
self.tcx
|
||||
.hir_parent_iter(id)
|
||||
.take_while(|(_, node)| {
|
||||
// look at parents until we find the first body owner
|
||||
node.body_id().is_none()
|
||||
})
|
||||
.any(|(parent_id, _)| self.is_loop(parent_id));
|
||||
.find_map(|(parent_id, node)| self.is_loop(parent_id).then_some(node))
|
||||
};
|
||||
let can_break_with_value = innermost_loop.is_some_and(|node| {
|
||||
matches!(
|
||||
node,
|
||||
Node::Expr(Expr { kind: ExprKind::Loop(_, _, LoopSource::Loop, ..), .. })
|
||||
)
|
||||
});
|
||||
|
||||
let in_local_statement = self.is_local_statement(id)
|
||||
|| self
|
||||
|
|
@ -1186,7 +1194,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
.hir_parent_iter(id)
|
||||
.any(|(parent_id, _)| self.is_local_statement(parent_id));
|
||||
|
||||
if in_loop && in_local_statement {
|
||||
if can_break_with_value && in_local_statement {
|
||||
err.multipart_suggestion(
|
||||
"you might have meant to break the loop with this value",
|
||||
vec![
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue