Merge ref '548e586795' from rust-lang/rust
Pull recent changes from https://github.com/rust-lang/rust via Josh.
Upstream ref: rust-lang/rust@548e586795
Filtered ref: rust-lang/rust-analyzer@aea42e3bfd
Upstream diff: e7d44143a1...548e586795
This merge was created using https://github.com/rust-lang/josh-sync.
This commit is contained in:
commit
09c878a6ef
2485 changed files with 44385 additions and 24185 deletions
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
|
||||
|
|
|
|||
157
Cargo.lock
157
Cargo.lock
|
|
@ -188,7 +188,20 @@ version = "0.14.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4"
|
||||
dependencies = [
|
||||
"askama_derive",
|
||||
"askama_derive 0.14.0",
|
||||
"itoa",
|
||||
"percent-encoding",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama"
|
||||
version = "0.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb7125972258312e79827b60c9eb93938334100245081cf701a2dee981b17427"
|
||||
dependencies = [
|
||||
"askama_macros",
|
||||
"itoa",
|
||||
"percent-encoding",
|
||||
"serde",
|
||||
|
|
@ -201,7 +214,7 @@ version = "0.14.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f"
|
||||
dependencies = [
|
||||
"askama_parser",
|
||||
"askama_parser 0.14.0",
|
||||
"basic-toml",
|
||||
"memchr",
|
||||
"proc-macro2",
|
||||
|
|
@ -212,6 +225,32 @@ dependencies = [
|
|||
"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",
|
||||
"basic-toml",
|
||||
"memchr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustc-hash 2.1.1",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama_macros"
|
||||
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"
|
||||
|
|
@ -224,6 +263,19 @@ dependencies = [
|
|||
"winnow 0.7.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama_parser"
|
||||
version = "0.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3c63392767bb2df6aa65a6e1e3b80fd89bb7af6d58359b924c0695620f1512e"
|
||||
dependencies = [
|
||||
"rustc-hash 2.1.1",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"unicode-ident",
|
||||
"winnow 0.7.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "assert_cmd"
|
||||
version = "2.1.1"
|
||||
|
|
@ -393,22 +445,21 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "capstone"
|
||||
version = "0.13.0"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "015ef5d5ca1743e3f94af9509ba6bd2886523cfee46e48d15c2ef5216fd4ac9a"
|
||||
checksum = "f442ae0f2f3f1b923334b4a5386c95c69c1cfa072bafa23d6fae6d9682eb1dd4"
|
||||
dependencies = [
|
||||
"capstone-sys",
|
||||
"libc",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "capstone-sys"
|
||||
version = "0.17.0"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2267cb8d16a1e4197863ec4284ffd1aec26fe7e57c58af46b02590a0235809a0"
|
||||
checksum = "a4e8087cab6731295f5a2a2bd82989ba4f41d3a428aab2e7c98d8f4db38aac05"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -624,7 +675,7 @@ name = "clippy"
|
|||
version = "0.1.94"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"askama",
|
||||
"askama 0.14.0",
|
||||
"cargo_metadata 0.18.1",
|
||||
"clippy_config",
|
||||
"clippy_lints",
|
||||
|
|
@ -666,6 +717,7 @@ dependencies = [
|
|||
"indoc",
|
||||
"itertools",
|
||||
"opener",
|
||||
"rustc-literal-escaper",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
|
|
@ -1514,7 +1566,7 @@ name = "generate-copyright"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"askama",
|
||||
"askama 0.15.1",
|
||||
"cargo_metadata 0.21.0",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
@ -2179,9 +2231,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libffi"
|
||||
version = "5.0.0"
|
||||
version = "5.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0444124f3ffd67e1b0b0c661a7f81a278a135eb54aaad4078e79fbc8be50c8a5"
|
||||
checksum = "0498fe5655f857803e156523e644dcdcdc3b3c7edda42ea2afdae2e09b2db87b"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"libffi-sys",
|
||||
|
|
@ -2189,9 +2241,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libffi-sys"
|
||||
version = "4.0.0"
|
||||
version = "4.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d722da8817ea580d0669da6babe2262d7b86a1af1103da24102b8bb9c101ce7"
|
||||
checksum = "71d4f1d4ce15091955144350b75db16a96d4a63728500122706fb4d29a26afbb"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
|
@ -3637,8 +3689,6 @@ dependencies = [
|
|||
"rustc_span",
|
||||
"rustc_symbol_mangling",
|
||||
"rustc_target",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"smallvec",
|
||||
"tracing",
|
||||
]
|
||||
|
|
@ -4145,8 +4195,8 @@ version = "0.0.0"
|
|||
dependencies = [
|
||||
"expect-test",
|
||||
"memchr",
|
||||
"unicode-ident",
|
||||
"unicode-properties",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -4573,7 +4623,6 @@ dependencies = [
|
|||
name = "rustc_resolve"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"indexmap",
|
||||
"itertools",
|
||||
"pulldown-cmark",
|
||||
|
|
@ -4863,7 +4912,7 @@ name = "rustdoc"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"askama",
|
||||
"askama 0.15.1",
|
||||
"base64",
|
||||
"expect-test",
|
||||
"indexmap",
|
||||
|
|
@ -5357,9 +5406,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "stringdex"
|
||||
version = "0.0.4"
|
||||
version = "0.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6204af9e1e433f1ef9b6d44475c7089be33c91111d896463b9dfa20464b87f1"
|
||||
checksum = "07ab85c3f308f022ce6861ab57576b5b6ebc4835f9577e67e0f35f6c351e3f0a"
|
||||
dependencies = [
|
||||
"stacker",
|
||||
]
|
||||
|
|
@ -5609,6 +5658,7 @@ dependencies = [
|
|||
"build_helper",
|
||||
"cargo_metadata 0.21.0",
|
||||
"fluent-syntax",
|
||||
"globset",
|
||||
"ignore",
|
||||
"miropt-test-tools",
|
||||
"regex",
|
||||
|
|
@ -5982,24 +6032,24 @@ checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539"
|
|||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.18"
|
||||
version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
||||
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.24"
|
||||
version = "0.1.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956"
|
||||
checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8"
|
||||
dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-properties"
|
||||
version = "0.1.3"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0"
|
||||
checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-script"
|
||||
|
|
@ -6172,9 +6222,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"
|
||||
|
|
@ -6223,17 +6273,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",
|
||||
|
|
@ -6260,24 +6311,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]]
|
||||
|
|
@ -6302,9 +6353,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",
|
||||
|
|
@ -6315,22 +6366,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",
|
||||
]
|
||||
|
|
@ -6726,9 +6777,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",
|
||||
|
|
@ -6737,17 +6788,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",
|
||||
|
|
@ -6758,7 +6809,7 @@ dependencies = [
|
|||
"serde_derive",
|
||||
"serde_json",
|
||||
"unicode-xid",
|
||||
"wasmparser 0.241.2",
|
||||
"wasmparser 0.243.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
|
|
@ -106,6 +106,9 @@
|
|||
# Whether to build LLVM with support for it's gpu offload runtime.
|
||||
#llvm.offload = false
|
||||
|
||||
# Absolute path to the directory containing ClangConfig.cmake
|
||||
#llvm.offload-clang-dir = ""
|
||||
|
||||
# When true, link libstdc++ statically into the rustc_llvm.
|
||||
# This is useful if you don't want to use the dynamic version of that
|
||||
# library provided by LLVM.
|
||||
|
|
|
|||
|
|
@ -67,7 +67,6 @@ pub enum ExternAbi {
|
|||
|
||||
/* gpu */
|
||||
/// An entry-point function called by the GPU's host
|
||||
// FIXME: should not be callable from Rust on GPU targets, is for host's use only
|
||||
GpuKernel,
|
||||
/// An entry-point function called by the GPU's host
|
||||
// FIXME: why do we have two of these?
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
|
@ -3390,7 +3391,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 +3403,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
|
||||
|
|
|
|||
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
|
||||
}
|
||||
|
|
@ -294,7 +316,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 +337,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 +361,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 +377,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 +712,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 +822,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 +833,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 +845,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 +859,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")`.
|
||||
|
|
@ -903,10 +926,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 +957,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,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ ast_lowering_abi_specified_multiple_times =
|
|||
ast_lowering_arbitrary_expression_in_pattern =
|
||||
arbitrary expressions aren't allowed in patterns
|
||||
.pattern_from_macro_note = the `expr` fragment specifier forces the metavariable's content to be an expression
|
||||
.const_block_in_pattern_help = use a named `const`-item or an `if`-guard (`x if x == const {"{ ... }"}`) instead
|
||||
|
||||
ast_lowering_argument = argument
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
| asm::InlineAsmArch::LoongArch64
|
||||
| asm::InlineAsmArch::S390x
|
||||
);
|
||||
if !is_stable && !self.tcx.features().asm_experimental_arch() {
|
||||
if !is_stable
|
||||
&& !self.tcx.features().asm_experimental_arch()
|
||||
&& sp
|
||||
.ctxt()
|
||||
.outer_expn_data()
|
||||
.allow_internal_unstable
|
||||
.filter(|features| features.contains(&sym::asm_experimental_arch))
|
||||
.is_none()
|
||||
{
|
||||
feature_err(
|
||||
&self.tcx.sess,
|
||||
sym::asm_experimental_arch,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -48,11 +48,12 @@ use rustc_data_structures::fx::FxHashSet;
|
|||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::Target;
|
||||
use rustc_hir::attrs::{AttributeKind, InlineAttr};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::{Asyncness, DelegationFnSigAttrs, ResolverAstLowering};
|
||||
use rustc_middle::ty::{Asyncness, DelegationAttrs, DelegationFnSigAttrs, ResolverAstLowering};
|
||||
use rustc_span::symbol::kw;
|
||||
use rustc_span::{DUMMY_SP, Ident, Span, Symbol};
|
||||
use smallvec::SmallVec;
|
||||
use {rustc_ast as ast, rustc_hir as hir};
|
||||
|
||||
use super::{GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode};
|
||||
|
|
@ -66,24 +67,24 @@ pub(crate) struct DelegationResults<'hir> {
|
|||
pub generics: &'hir hir::Generics<'hir>,
|
||||
}
|
||||
|
||||
struct AttributeAdditionInfo {
|
||||
struct AttrAdditionInfo {
|
||||
pub equals: fn(&hir::Attribute) -> bool,
|
||||
pub kind: AttributeAdditionKind,
|
||||
pub kind: AttrAdditionKind,
|
||||
}
|
||||
|
||||
enum AttributeAdditionKind {
|
||||
enum AttrAdditionKind {
|
||||
Default { factory: fn(Span) -> hir::Attribute },
|
||||
Inherit { flag: DelegationFnSigAttrs, factory: fn(Span, &hir::Attribute) -> hir::Attribute },
|
||||
}
|
||||
|
||||
const PARENT_ID: hir::ItemLocalId = hir::ItemLocalId::ZERO;
|
||||
|
||||
static ATTRIBUTES_ADDITIONS: &[AttributeAdditionInfo] = &[
|
||||
AttributeAdditionInfo {
|
||||
static ATTRS_ADDITIONS: &[AttrAdditionInfo] = &[
|
||||
AttrAdditionInfo {
|
||||
equals: |a| matches!(a, hir::Attribute::Parsed(AttributeKind::MustUse { .. })),
|
||||
kind: AttributeAdditionKind::Inherit {
|
||||
factory: |span, original_attribute| {
|
||||
let reason = match original_attribute {
|
||||
kind: AttrAdditionKind::Inherit {
|
||||
factory: |span, original_attr| {
|
||||
let reason = match original_attr {
|
||||
hir::Attribute::Parsed(AttributeKind::MustUse { reason, .. }) => *reason,
|
||||
_ => None,
|
||||
};
|
||||
|
|
@ -93,14 +94,41 @@ static ATTRIBUTES_ADDITIONS: &[AttributeAdditionInfo] = &[
|
|||
flag: DelegationFnSigAttrs::MUST_USE,
|
||||
},
|
||||
},
|
||||
AttributeAdditionInfo {
|
||||
AttrAdditionInfo {
|
||||
equals: |a| matches!(a, hir::Attribute::Parsed(AttributeKind::Inline(..))),
|
||||
kind: AttributeAdditionKind::Default {
|
||||
kind: AttrAdditionKind::Default {
|
||||
factory: |span| hir::Attribute::Parsed(AttributeKind::Inline(InlineAttr::Hint, span)),
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
type DelegationIdsVec = SmallVec<[DefId; 1]>;
|
||||
|
||||
// As delegations can now refer to another delegation, we have a delegation path
|
||||
// of the following type: reuse (current delegation) <- reuse (delegee_id) <- ... <- reuse <- function (root_function_id).
|
||||
// In its most basic and widely used form: reuse (current delegation) <- function (delegee_id, root_function_id)
|
||||
struct DelegationIds {
|
||||
path: DelegationIdsVec,
|
||||
}
|
||||
|
||||
impl DelegationIds {
|
||||
fn new(path: DelegationIdsVec) -> Self {
|
||||
assert!(!path.is_empty());
|
||||
Self { path }
|
||||
}
|
||||
|
||||
// Id of the first function in (non)local crate that is being reused
|
||||
fn root_function_id(&self) -> DefId {
|
||||
*self.path.last().expect("Ids vector can't be empty")
|
||||
}
|
||||
|
||||
// Id of the first definition which is being reused,
|
||||
// can be either function, in this case `root_id == delegee_id`, or other delegation
|
||||
fn delegee_id(&self) -> DefId {
|
||||
*self.path.first().expect("Ids vector can't be empty")
|
||||
}
|
||||
}
|
||||
|
||||
impl<'hir> LoweringContext<'_, 'hir> {
|
||||
fn is_method(&self, def_id: DefId, span: Span) -> bool {
|
||||
match self.tcx.def_kind(def_id) {
|
||||
|
|
@ -124,19 +152,36 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
) -> DelegationResults<'hir> {
|
||||
let span = self.lower_span(delegation.path.segments.last().unwrap().ident.span);
|
||||
|
||||
let sig_id = self.get_delegation_sig_id(
|
||||
self.resolver.delegation_sig_resolution_nodes[&self.local_def_id(item_id)],
|
||||
let ids = self.get_delegation_ids(
|
||||
self.resolver.delegation_infos[&self.local_def_id(item_id)].resolution_node,
|
||||
span,
|
||||
);
|
||||
|
||||
match sig_id {
|
||||
Ok(sig_id) => {
|
||||
self.add_attributes_if_needed(span, sig_id);
|
||||
match ids {
|
||||
Ok(ids) => {
|
||||
self.add_attrs_if_needed(span, &ids);
|
||||
|
||||
let delegee_id = ids.delegee_id();
|
||||
let root_function_id = ids.root_function_id();
|
||||
|
||||
// `is_method` is used to choose the name of the first parameter (`self` or `arg0`),
|
||||
// if the original function is not a method (without `self`), then it can not be added
|
||||
// during chain of reuses, so we use `root_function_id` here
|
||||
let is_method = self.is_method(root_function_id, span);
|
||||
|
||||
// Here we use `root_function_id` as we can not get params information out of potential delegation reuse,
|
||||
// we need a function to extract this information
|
||||
let (param_count, c_variadic) = self.param_count(root_function_id);
|
||||
|
||||
// Here we use `delegee_id`, as this id will then be used to calculate parent for generics
|
||||
// inheritance, and we want this id to point on a delegee, not on the original
|
||||
// function (see https://github.com/rust-lang/rust/issues/150152#issuecomment-3674834654)
|
||||
let decl = self.lower_delegation_decl(delegee_id, param_count, c_variadic, span);
|
||||
|
||||
// Here we pass `root_function_id` as we want to inherit signature (including consts, async)
|
||||
// from the root function that started delegation
|
||||
let sig = self.lower_delegation_sig(root_function_id, decl, span);
|
||||
|
||||
let is_method = self.is_method(sig_id, span);
|
||||
let (param_count, c_variadic) = self.param_count(sig_id);
|
||||
let decl = self.lower_delegation_decl(sig_id, param_count, c_variadic, span);
|
||||
let sig = self.lower_delegation_sig(sig_id, decl, span);
|
||||
let body_id = self.lower_delegation_body(delegation, is_method, param_count, span);
|
||||
let ident = self.lower_ident(delegation.ident);
|
||||
let generics = self.lower_delegation_generics(span);
|
||||
|
|
@ -146,36 +191,36 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
fn add_attributes_if_needed(&mut self, span: Span, sig_id: DefId) {
|
||||
let new_attributes = self.create_new_attributes(
|
||||
ATTRIBUTES_ADDITIONS,
|
||||
span,
|
||||
sig_id,
|
||||
self.attrs.get(&PARENT_ID),
|
||||
);
|
||||
fn add_attrs_if_needed(&mut self, span: Span, ids: &DelegationIds) {
|
||||
let new_attrs =
|
||||
self.create_new_attrs(ATTRS_ADDITIONS, span, ids, self.attrs.get(&PARENT_ID));
|
||||
|
||||
if new_attributes.is_empty() {
|
||||
if new_attrs.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let new_arena_allocated_attributes = match self.attrs.get(&PARENT_ID) {
|
||||
let new_arena_allocated_attrs = match self.attrs.get(&PARENT_ID) {
|
||||
Some(existing_attrs) => self.arena.alloc_from_iter(
|
||||
existing_attrs.iter().map(|a| a.clone()).chain(new_attributes.into_iter()),
|
||||
existing_attrs.iter().map(|a| a.clone()).chain(new_attrs.into_iter()),
|
||||
),
|
||||
None => self.arena.alloc_from_iter(new_attributes.into_iter()),
|
||||
None => self.arena.alloc_from_iter(new_attrs.into_iter()),
|
||||
};
|
||||
|
||||
self.attrs.insert(PARENT_ID, new_arena_allocated_attributes);
|
||||
self.attrs.insert(PARENT_ID, new_arena_allocated_attrs);
|
||||
}
|
||||
|
||||
fn create_new_attributes(
|
||||
fn create_new_attrs(
|
||||
&self,
|
||||
candidate_additions: &[AttributeAdditionInfo],
|
||||
candidate_additions: &[AttrAdditionInfo],
|
||||
span: Span,
|
||||
sig_id: DefId,
|
||||
ids: &DelegationIds,
|
||||
existing_attrs: Option<&&[hir::Attribute]>,
|
||||
) -> Vec<hir::Attribute> {
|
||||
let local_original_attributes = self.parse_local_original_attributes(sig_id);
|
||||
let defs_orig_attrs = ids
|
||||
.path
|
||||
.iter()
|
||||
.map(|def_id| (*def_id, self.parse_local_original_attrs(*def_id)))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
candidate_additions
|
||||
.iter()
|
||||
|
|
@ -189,65 +234,81 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
|
||||
match addition_info.kind {
|
||||
AttributeAdditionKind::Default { factory } => Some(factory(span)),
|
||||
AttributeAdditionKind::Inherit { flag, factory } => {
|
||||
let original_attribute = match sig_id.as_local() {
|
||||
Some(local_id) => self
|
||||
.resolver
|
||||
.delegation_fn_sigs
|
||||
.get(&local_id)
|
||||
.is_some_and(|sig| sig.attrs_flags.contains(flag))
|
||||
.then(|| {
|
||||
local_original_attributes
|
||||
.as_ref()
|
||||
.map(|attrs| {
|
||||
attrs
|
||||
.iter()
|
||||
.find(|base_attr| (addition_info.equals)(base_attr))
|
||||
})
|
||||
.flatten()
|
||||
})
|
||||
.flatten(),
|
||||
None => self
|
||||
.tcx
|
||||
.get_all_attrs(sig_id)
|
||||
.iter()
|
||||
.find(|base_attr| (addition_info.equals)(base_attr)),
|
||||
};
|
||||
AttrAdditionKind::Default { factory } => Some(factory(span)),
|
||||
AttrAdditionKind::Inherit { flag, factory } => {
|
||||
for (def_id, orig_attrs) in &defs_orig_attrs {
|
||||
let original_attr = match def_id.as_local() {
|
||||
Some(local_id) => self
|
||||
.get_attrs(local_id)
|
||||
.flags
|
||||
.contains(flag)
|
||||
.then(|| {
|
||||
orig_attrs
|
||||
.as_ref()
|
||||
.map(|attrs| {
|
||||
attrs.iter().find(|base_attr| {
|
||||
(addition_info.equals)(base_attr)
|
||||
})
|
||||
})
|
||||
.flatten()
|
||||
})
|
||||
.flatten(),
|
||||
None => self
|
||||
.tcx
|
||||
.get_all_attrs(*def_id)
|
||||
.iter()
|
||||
.find(|base_attr| (addition_info.equals)(base_attr)),
|
||||
};
|
||||
|
||||
original_attribute.map(|a| factory(span, a))
|
||||
if let Some(original_attr) = original_attr {
|
||||
return Some(factory(span, original_attr));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fn parse_local_original_attributes(&self, sig_id: DefId) -> Option<Vec<hir::Attribute>> {
|
||||
if let Some(local_id) = sig_id.as_local()
|
||||
&& let Some(info) = self.resolver.delegation_fn_sigs.get(&local_id)
|
||||
&& !info.to_inherit_attrs.is_empty()
|
||||
{
|
||||
Some(AttributeParser::parse_limited_all(
|
||||
self.tcx.sess,
|
||||
info.to_inherit_attrs.as_slice(),
|
||||
None,
|
||||
Target::Fn,
|
||||
DUMMY_SP,
|
||||
DUMMY_NODE_ID,
|
||||
Some(self.tcx.features()),
|
||||
ShouldEmit::Nothing,
|
||||
))
|
||||
fn parse_local_original_attrs(&self, def_id: DefId) -> Option<Vec<hir::Attribute>> {
|
||||
if let Some(local_id) = def_id.as_local() {
|
||||
let attrs = &self.get_attrs(local_id).to_inherit;
|
||||
|
||||
if !attrs.is_empty() {
|
||||
return Some(AttributeParser::parse_limited_all(
|
||||
self.tcx.sess,
|
||||
attrs,
|
||||
None,
|
||||
Target::Fn,
|
||||
DUMMY_SP,
|
||||
DUMMY_NODE_ID,
|
||||
Some(self.tcx.features()),
|
||||
ShouldEmit::Nothing,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn get_attrs(&self, local_id: LocalDefId) -> &DelegationAttrs {
|
||||
// local_id can correspond either to a function or other delegation
|
||||
if let Some(fn_sig) = self.resolver.delegation_fn_sigs.get(&local_id) {
|
||||
&fn_sig.attrs
|
||||
} else {
|
||||
None
|
||||
&self.resolver.delegation_infos[&local_id].attrs
|
||||
}
|
||||
}
|
||||
|
||||
fn get_delegation_sig_id(
|
||||
fn get_delegation_ids(
|
||||
&self,
|
||||
mut node_id: NodeId,
|
||||
span: Span,
|
||||
) -> Result<DefId, ErrorGuaranteed> {
|
||||
) -> Result<DelegationIds, ErrorGuaranteed> {
|
||||
let mut visited: FxHashSet<NodeId> = Default::default();
|
||||
let mut path: DelegationIdsVec = Default::default();
|
||||
|
||||
loop {
|
||||
visited.insert(node_id);
|
||||
|
|
@ -262,14 +323,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
));
|
||||
};
|
||||
|
||||
path.push(def_id);
|
||||
|
||||
// If def_id is in local crate and it corresponds to another delegation
|
||||
// it means that we refer to another delegation as a callee, so in order to obtain
|
||||
// a signature DefId we obtain NodeId of the callee delegation and try to get signature from it.
|
||||
if let Some(local_id) = def_id.as_local()
|
||||
&& let Some(next_node_id) =
|
||||
self.resolver.delegation_sig_resolution_nodes.get(&local_id)
|
||||
&& let Some(delegation_info) = self.resolver.delegation_infos.get(&local_id)
|
||||
{
|
||||
node_id = *next_node_id;
|
||||
node_id = delegation_info.resolution_node;
|
||||
if visited.contains(&node_id) {
|
||||
// We encountered a cycle in the resolution, or delegation callee refers to non-existent
|
||||
// entity, in this case emit an error.
|
||||
|
|
@ -279,7 +341,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
});
|
||||
}
|
||||
} else {
|
||||
return Ok(def_id);
|
||||
return Ok(DelegationIds::new(path));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -299,14 +361,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
|
||||
// Function parameter count, including C variadic `...` if present.
|
||||
fn param_count(&self, sig_id: DefId) -> (usize, bool /*c_variadic*/) {
|
||||
if let Some(local_sig_id) = sig_id.as_local() {
|
||||
fn param_count(&self, def_id: DefId) -> (usize, bool /*c_variadic*/) {
|
||||
if let Some(local_sig_id) = def_id.as_local() {
|
||||
match self.resolver.delegation_fn_sigs.get(&local_sig_id) {
|
||||
Some(sig) => (sig.param_count, sig.c_variadic),
|
||||
None => (0, false),
|
||||
}
|
||||
} else {
|
||||
let sig = self.tcx.fn_sig(sig_id).skip_binder().skip_binder();
|
||||
let sig = self.tcx.fn_sig(def_id).skip_binder().skip_binder();
|
||||
(sig.inputs().len() + usize::from(sig.c_variadic), sig.c_variadic)
|
||||
}
|
||||
}
|
||||
|
|
@ -356,7 +418,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
// We are not forwarding the attributes, as the delegation fn sigs are collected on the ast,
|
||||
// and here we need the hir attributes.
|
||||
let default_safety =
|
||||
if sig.attrs_flags.contains(DelegationFnSigAttrs::TARGET_FEATURE)
|
||||
if sig.attrs.flags.contains(DelegationFnSigAttrs::TARGET_FEATURE)
|
||||
|| self.tcx.def_kind(parent) == DefKind::ForeignMod
|
||||
{
|
||||
hir::Safety::Unsafe
|
||||
|
|
|
|||
|
|
@ -357,6 +357,8 @@ pub(crate) struct ArbitraryExpressionInPattern {
|
|||
pub span: Span,
|
||||
#[note(ast_lowering_pattern_from_macro_note)]
|
||||
pub pattern_from_macro_note: bool,
|
||||
#[help(ast_lowering_const_block_in_pattern_help)]
|
||||
pub const_block_in_pattern_help: bool,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
|
|||
|
|
@ -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()),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -264,8 +264,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 +279,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 +381,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 +455,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 +760,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 +872,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 +911,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 +1013,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 +1125,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 +1187,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 +1923,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 +1952,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, &[])),
|
||||
};
|
||||
|
|
@ -2036,7 +2036,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
})
|
||||
.map(|def| {
|
||||
self.lower_ty(
|
||||
self.lower_ty_alloc(
|
||||
def,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault),
|
||||
)
|
||||
|
|
@ -2047,8 +2047,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 +2066,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 +2200,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 +2285,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 +2360,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 +2375,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 +2396,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 +2467,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 +2495,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 +2508,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);
|
||||
|
|
@ -2474,12 +2542,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
|
||||
/// 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 +2562,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 +2603,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
|
||||
|
|
|
|||
|
|
@ -399,7 +399,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
ExprKind::Lit(lit) => {
|
||||
hir::PatExprKind::Lit { lit: self.lower_lit(lit, span), negated: false }
|
||||
}
|
||||
ExprKind::ConstBlock(c) => hir::PatExprKind::ConstBlock(self.lower_const_block(c)),
|
||||
ExprKind::IncludedBytes(byte_sym) => hir::PatExprKind::Lit {
|
||||
lit: respan(span, LitKind::ByteStr(*byte_sym, StrStyle::Cooked)),
|
||||
negated: false,
|
||||
|
|
@ -419,10 +418,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
hir::PatExprKind::Lit { lit: self.lower_lit(lit, span), negated: true }
|
||||
}
|
||||
_ => {
|
||||
let is_const_block = matches!(expr.kind, ExprKind::ConstBlock(_));
|
||||
let pattern_from_macro = expr.is_approximately_pattern();
|
||||
let guar = self.dcx().emit_err(ArbitraryExpressionInPattern {
|
||||
span,
|
||||
pattern_from_macro_note: pattern_from_macro,
|
||||
const_block_in_pattern_help: is_const_block,
|
||||
});
|
||||
err(guar)
|
||||
}
|
||||
|
|
@ -443,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(|| {
|
||||
|
|
@ -510,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,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -554,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(
|
||||
|
|
|
|||
|
|
@ -401,9 +401,16 @@ impl<'a> AstValidator<'a> {
|
|||
| CanonAbi::Rust
|
||||
| CanonAbi::RustCold
|
||||
| CanonAbi::Arm(_)
|
||||
| CanonAbi::GpuKernel
|
||||
| CanonAbi::X86(_) => { /* nothing to check */ }
|
||||
|
||||
CanonAbi::GpuKernel => {
|
||||
// An `extern "gpu-kernel"` function cannot be `async` and/or `gen`.
|
||||
self.reject_coroutine(abi, sig);
|
||||
|
||||
// An `extern "gpu-kernel"` function cannot return a value.
|
||||
self.reject_return(abi, sig);
|
||||
}
|
||||
|
||||
CanonAbi::Custom => {
|
||||
// An `extern "custom"` function must be unsafe.
|
||||
self.reject_safe_fn(abi, ctxt, sig);
|
||||
|
|
@ -433,18 +440,7 @@ impl<'a> AstValidator<'a> {
|
|||
self.dcx().emit_err(errors::AbiX86Interrupt { spans, param_count });
|
||||
}
|
||||
|
||||
if let FnRetTy::Ty(ref ret_ty) = sig.decl.output
|
||||
&& match &ret_ty.kind {
|
||||
TyKind::Never => false,
|
||||
TyKind::Tup(tup) if tup.is_empty() => false,
|
||||
_ => true,
|
||||
}
|
||||
{
|
||||
self.dcx().emit_err(errors::AbiMustNotHaveReturnType {
|
||||
span: ret_ty.span,
|
||||
abi,
|
||||
});
|
||||
}
|
||||
self.reject_return(abi, sig);
|
||||
} else {
|
||||
// An `extern "interrupt"` function must have type `fn()`.
|
||||
self.reject_params_or_return(abi, ident, sig);
|
||||
|
|
@ -496,6 +492,18 @@ impl<'a> AstValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn reject_return(&self, abi: ExternAbi, sig: &FnSig) {
|
||||
if let FnRetTy::Ty(ref ret_ty) = sig.decl.output
|
||||
&& match &ret_ty.kind {
|
||||
TyKind::Never => false,
|
||||
TyKind::Tup(tup) if tup.is_empty() => false,
|
||||
_ => true,
|
||||
}
|
||||
{
|
||||
self.dcx().emit_err(errors::AbiMustNotHaveReturnType { span: ret_ty.span, abi });
|
||||
}
|
||||
}
|
||||
|
||||
fn reject_params_or_return(&self, abi: ExternAbi, ident: &Ident, sig: &FnSig) {
|
||||
let mut spans: Vec<_> = sig.decl.inputs.iter().map(|p| p.span).collect();
|
||||
if let FnRetTy::Ty(ref ret_ty) = sig.decl.output
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -229,6 +229,8 @@ attr_parsing_unstable_cfg_target_compact =
|
|||
attr_parsing_unstable_feature_bound_incompatible_stability = item annotated with `#[unstable_feature_bound]` should not be stable
|
||||
.help = If this item is meant to be stable, do not use any functions annotated with `#[unstable_feature_bound]`. Otherwise, mark this item as unstable with `#[unstable]`
|
||||
|
||||
attr_parsing_unsupported_instruction_set = target `{$current_target}` does not support `#[instruction_set({$instruction_set}::*)]`
|
||||
|
||||
attr_parsing_unsupported_literal_suggestion =
|
||||
consider removing the prefix
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,73 @@
|
|||
use rustc_hir::attrs::InstructionSetAttr;
|
||||
|
||||
use super::prelude::*;
|
||||
use crate::session_diagnostics;
|
||||
|
||||
pub(crate) struct InstructionSetParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for InstructionSetParser {
|
||||
const PATH: &[Symbol] = &[sym::instruction_set];
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::Closure),
|
||||
Allow(Target::Method(MethodKind::Inherent)),
|
||||
Allow(Target::Method(MethodKind::TraitImpl)),
|
||||
Allow(Target::Method(MethodKind::Trait { body: true })),
|
||||
]);
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &["set"], "https://doc.rust-lang.org/reference/attributes/codegen.html#the-instruction_set-attribute");
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
const POSSIBLE_SYMBOLS: &[Symbol] = &[sym::arm_a32, sym::arm_t32];
|
||||
const POSSIBLE_ARM_SYMBOLS: &[Symbol] = &[sym::a32, sym::t32];
|
||||
let Some(maybe_meta_item) = args.list().and_then(MetaItemListParser::single) else {
|
||||
cx.expected_specific_argument(cx.attr_span, POSSIBLE_SYMBOLS);
|
||||
return None;
|
||||
};
|
||||
|
||||
let Some(meta_item) = maybe_meta_item.meta_item() else {
|
||||
cx.expected_specific_argument(maybe_meta_item.span(), POSSIBLE_SYMBOLS);
|
||||
return None;
|
||||
};
|
||||
|
||||
let mut segments = meta_item.path().segments();
|
||||
|
||||
let Some(architecture) = segments.next() else {
|
||||
cx.expected_specific_argument(meta_item.span(), POSSIBLE_SYMBOLS);
|
||||
return None;
|
||||
};
|
||||
|
||||
let Some(instruction_set) = segments.next() else {
|
||||
cx.expected_specific_argument(architecture.span, POSSIBLE_SYMBOLS);
|
||||
return None;
|
||||
};
|
||||
|
||||
let instruction_set = match architecture.name {
|
||||
sym::arm => {
|
||||
if !cx.sess.target.has_thumb_interworking {
|
||||
cx.dcx().emit_err(session_diagnostics::UnsupportedInstructionSet {
|
||||
span: cx.attr_span,
|
||||
instruction_set: sym::arm,
|
||||
current_target: &cx.sess.opts.target_triple,
|
||||
});
|
||||
return None;
|
||||
}
|
||||
match instruction_set.name {
|
||||
sym::a32 => InstructionSetAttr::ArmA32,
|
||||
sym::t32 => InstructionSetAttr::ArmT32,
|
||||
_ => {
|
||||
cx.expected_specific_argument(instruction_set.span, POSSIBLE_ARM_SYMBOLS);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
cx.expected_specific_argument(architecture.span, POSSIBLE_SYMBOLS);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
Some(AttributeKind::InstructionSet(instruction_set))
|
||||
}
|
||||
}
|
||||
|
|
@ -42,6 +42,7 @@ pub(crate) mod deprecation;
|
|||
pub(crate) mod doc;
|
||||
pub(crate) mod dummy;
|
||||
pub(crate) mod inline;
|
||||
pub(crate) mod instruction_set;
|
||||
pub(crate) mod link_attrs;
|
||||
pub(crate) mod lint_helpers;
|
||||
pub(crate) mod loop_match;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use rustc_ast::{LitIntType, LitKind, MetaItemLit};
|
||||
use rustc_session::errors;
|
||||
|
||||
use super::prelude::*;
|
||||
use super::util::parse_single_integer;
|
||||
|
|
@ -13,6 +14,52 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcMainParser {
|
|||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcMain;
|
||||
}
|
||||
|
||||
pub(crate) struct RustcMustImplementOneOfParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcMustImplementOneOfParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_must_implement_one_of];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &["function1, function2, ..."]);
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let Some(list) = args.list() else {
|
||||
cx.expected_list(cx.attr_span, args);
|
||||
return None;
|
||||
};
|
||||
|
||||
let mut fn_names = ThinVec::new();
|
||||
|
||||
let inputs: Vec<_> = list.mixed().collect();
|
||||
|
||||
if inputs.len() < 2 {
|
||||
cx.expected_list_with_num_args_or_more(2, list.span);
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut errored = false;
|
||||
for argument in inputs {
|
||||
let Some(meta) = argument.meta_item() else {
|
||||
cx.expected_identifier(argument.span());
|
||||
return None;
|
||||
};
|
||||
|
||||
let Some(ident) = meta.ident() else {
|
||||
cx.dcx().emit_err(errors::MustBeNameOfAssociatedFunction { span: meta.span() });
|
||||
errored = true;
|
||||
continue;
|
||||
};
|
||||
|
||||
fn_names.push(ident);
|
||||
}
|
||||
if errored {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(AttributeKind::RustcMustImplementOneOf { attr_span: cx.attr_span, fn_names })
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct RustcNeverReturnsNullPointerParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcNeverReturnsNullPointerParser {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ use crate::attributes::deprecation::DeprecationParser;
|
|||
use crate::attributes::doc::DocParser;
|
||||
use crate::attributes::dummy::DummyParser;
|
||||
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
|
||||
use crate::attributes::instruction_set::InstructionSetParser;
|
||||
use crate::attributes::link_attrs::{
|
||||
ExportStableParser, FfiConstParser, FfiPureParser, LinkNameParser, LinkOrdinalParser,
|
||||
LinkParser, LinkSectionParser, LinkageParser, StdInternalSymbolParser,
|
||||
|
|
@ -64,8 +65,9 @@ use crate::attributes::rustc_internal::{
|
|||
RustcLayoutScalarValidRangeEndParser, RustcLayoutScalarValidRangeStartParser,
|
||||
RustcLegacyConstGenericsParser, RustcLintDiagnosticsParser, RustcLintOptDenyFieldAccessParser,
|
||||
RustcLintOptTyParser, RustcLintQueryInstabilityParser,
|
||||
RustcLintUntrackedQueryInformationParser, RustcMainParser, RustcNeverReturnsNullPointerParser,
|
||||
RustcNoImplicitAutorefsParser, RustcObjectLifetimeDefaultParser, RustcScalableVectorParser,
|
||||
RustcLintUntrackedQueryInformationParser, RustcMainParser, RustcMustImplementOneOfParser,
|
||||
RustcNeverReturnsNullPointerParser, RustcNoImplicitAutorefsParser,
|
||||
RustcObjectLifetimeDefaultParser, RustcScalableVectorParser,
|
||||
RustcSimdMonomorphizeLaneLimitParser,
|
||||
};
|
||||
use crate::attributes::semantics::MayDangleParser;
|
||||
|
|
@ -197,6 +199,7 @@ attribute_parsers!(
|
|||
Single<ExportNameParser>,
|
||||
Single<IgnoreParser>,
|
||||
Single<InlineParser>,
|
||||
Single<InstructionSetParser>,
|
||||
Single<LinkNameParser>,
|
||||
Single<LinkOrdinalParser>,
|
||||
Single<LinkSectionParser>,
|
||||
|
|
@ -217,6 +220,7 @@ attribute_parsers!(
|
|||
Single<RustcLayoutScalarValidRangeStartParser>,
|
||||
Single<RustcLegacyConstGenericsParser>,
|
||||
Single<RustcLintOptDenyFieldAccessParser>,
|
||||
Single<RustcMustImplementOneOfParser>,
|
||||
Single<RustcObjectLifetimeDefaultParser>,
|
||||
Single<RustcScalableVectorParser>,
|
||||
Single<RustcSimdMonomorphizeLaneLimitParser>,
|
||||
|
|
@ -492,6 +496,17 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
|||
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedList)
|
||||
}
|
||||
|
||||
pub(crate) fn expected_list_with_num_args_or_more(
|
||||
&self,
|
||||
args: usize,
|
||||
span: Span,
|
||||
) -> ErrorGuaranteed {
|
||||
self.emit_parse_error(
|
||||
span,
|
||||
AttributeParseErrorReason::ExpectedListWithNumArgsOrMore { args },
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn expected_list_or_no_args(&self, span: Span) -> ErrorGuaranteed {
|
||||
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedListOrNoArgs)
|
||||
}
|
||||
|
|
|
|||
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;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@ use std::fmt::{Debug, Display};
|
|||
|
||||
use rustc_ast::token::{self, Delimiter, MetaVarKind};
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::{AttrArgs, Expr, ExprKind, LitKind, MetaItemLit, Path, StmtKind, UnOp};
|
||||
use rustc_ast::{
|
||||
AttrArgs, Expr, ExprKind, LitKind, MetaItemLit, Path, PathSegment, StmtKind, UnOp,
|
||||
};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_errors::{Diag, PResult};
|
||||
use rustc_hir::{self as hir, AttrPath};
|
||||
|
|
@ -34,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(),
|
||||
}
|
||||
}
|
||||
|
|
@ -120,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;
|
||||
}
|
||||
|
||||
|
|
@ -256,6 +258,11 @@ impl Debug for MetaItemParser {
|
|||
}
|
||||
|
||||
impl MetaItemParser {
|
||||
/// For a single-segment meta item, returns its name; otherwise, returns `None`.
|
||||
pub fn ident(&self) -> Option<Ident> {
|
||||
if let [PathSegment { ident, .. }] = self.path.0.segments[..] { Some(ident) } else { None }
|
||||
}
|
||||
|
||||
pub fn span(&self) -> Span {
|
||||
if let Some(other) = self.args.span() {
|
||||
self.path.borrow().span().with_hi(other.hi())
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ use rustc_feature::AttributeTemplate;
|
|||
use rustc_hir::AttrPath;
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_span::{Span, Symbol};
|
||||
use rustc_target::spec::TargetTuple;
|
||||
|
||||
use crate::fluent_generated as fluent;
|
||||
|
||||
|
|
@ -520,6 +521,9 @@ pub(crate) enum AttributeParseErrorReason<'a> {
|
|||
ExpectedSingleArgument,
|
||||
ExpectedList,
|
||||
ExpectedListOrNoArgs,
|
||||
ExpectedListWithNumArgsOrMore {
|
||||
args: usize,
|
||||
},
|
||||
ExpectedNameValueOrNoArgs,
|
||||
ExpectedNonEmptyStringLiteral,
|
||||
UnexpectedLiteral,
|
||||
|
|
@ -597,6 +601,9 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> {
|
|||
AttributeParseErrorReason::ExpectedListOrNoArgs => {
|
||||
diag.span_label(self.span, "expected a list or no arguments here");
|
||||
}
|
||||
AttributeParseErrorReason::ExpectedListWithNumArgsOrMore { args } => {
|
||||
diag.span_label(self.span, format!("expected {args} or more items"));
|
||||
}
|
||||
AttributeParseErrorReason::ExpectedNameValueOrNoArgs => {
|
||||
diag.span_label(self.span, "didn't expect a list here");
|
||||
}
|
||||
|
|
@ -930,3 +937,12 @@ pub(crate) struct DocAliasMalformed {
|
|||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_unsupported_instruction_set)]
|
||||
pub(crate) struct UnsupportedInstructionSet<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub instruction_set: Symbol,
|
||||
pub current_target: &'a TargetTuple,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,7 +104,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,
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -543,38 +543,9 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
|||
&indices,
|
||||
);
|
||||
|
||||
let (unnormalized_output_ty, mut unnormalized_input_tys) =
|
||||
let (unnormalized_output_ty, unnormalized_input_tys) =
|
||||
inputs_and_output.split_last().unwrap();
|
||||
|
||||
// C-variadic fns also have a `VaList` input that's not listed in the signature
|
||||
// (as it's created inside the body itself, not passed in from outside).
|
||||
if let DefiningTy::FnDef(def_id, _) = defining_ty {
|
||||
if self.infcx.tcx.fn_sig(def_id).skip_binder().c_variadic() {
|
||||
let va_list_did = self
|
||||
.infcx
|
||||
.tcx
|
||||
.require_lang_item(LangItem::VaList, self.infcx.tcx.def_span(self.mir_def));
|
||||
|
||||
let reg_vid = self
|
||||
.infcx
|
||||
.next_nll_region_var(NllRegionVariableOrigin::FreeRegion, || {
|
||||
RegionCtxt::Free(sym::c_dash_variadic)
|
||||
})
|
||||
.as_var();
|
||||
|
||||
let region = ty::Region::new_var(self.infcx.tcx, reg_vid);
|
||||
let va_list_ty = self
|
||||
.infcx
|
||||
.tcx
|
||||
.type_of(va_list_did)
|
||||
.instantiate(self.infcx.tcx, &[region.into()]);
|
||||
|
||||
unnormalized_input_tys = self.infcx.tcx.mk_type_list_from_iter(
|
||||
unnormalized_input_tys.iter().copied().chain(iter::once(va_list_ty)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let fr_fn_body = self
|
||||
.infcx
|
||||
.next_nll_region_var(NllRegionVariableOrigin::FreeRegion, || {
|
||||
|
|
@ -816,7 +787,40 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
|||
DefiningTy::FnDef(def_id, _) => {
|
||||
let sig = tcx.fn_sig(def_id).instantiate_identity();
|
||||
let sig = indices.fold_to_region_vids(tcx, sig);
|
||||
sig.inputs_and_output()
|
||||
let inputs_and_output = sig.inputs_and_output();
|
||||
|
||||
// C-variadic fns also have a `VaList` input that's not listed in the signature
|
||||
// (as it's created inside the body itself, not passed in from outside).
|
||||
if self.infcx.tcx.fn_sig(def_id).skip_binder().c_variadic() {
|
||||
let va_list_did = self
|
||||
.infcx
|
||||
.tcx
|
||||
.require_lang_item(LangItem::VaList, self.infcx.tcx.def_span(self.mir_def));
|
||||
|
||||
let reg_vid = self
|
||||
.infcx
|
||||
.next_nll_region_var(NllRegionVariableOrigin::FreeRegion, || {
|
||||
RegionCtxt::Free(sym::c_dash_variadic)
|
||||
})
|
||||
.as_var();
|
||||
|
||||
let region = ty::Region::new_var(self.infcx.tcx, reg_vid);
|
||||
let va_list_ty = self
|
||||
.infcx
|
||||
.tcx
|
||||
.type_of(va_list_did)
|
||||
.instantiate(self.infcx.tcx, &[region.into()]);
|
||||
|
||||
// The signature needs to follow the order [input_tys, va_list_ty, output_ty]
|
||||
return inputs_and_output.map_bound(|tys| {
|
||||
let (output_ty, input_tys) = tys.split_last().unwrap();
|
||||
tcx.mk_type_list_from_iter(
|
||||
input_tys.iter().copied().chain([va_list_ty, *output_ty]),
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
inputs_and_output
|
||||
}
|
||||
|
||||
DefiningTy::Const(def_id, _) => {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -314,14 +314,12 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
|||
self.block.get_function()
|
||||
}
|
||||
|
||||
fn function_call(
|
||||
pub fn function_call(
|
||||
&mut self,
|
||||
func: RValue<'gcc>,
|
||||
func: Function<'gcc>,
|
||||
args: &[RValue<'gcc>],
|
||||
_funclet: Option<&Funclet>,
|
||||
) -> RValue<'gcc> {
|
||||
// TODO(antoyo): remove when the API supports a different type for functions.
|
||||
let func: Function<'gcc> = self.cx.rvalue_as_function(func);
|
||||
let args = self.check_call("call", func, args);
|
||||
|
||||
// gccjit requires to use the result of functions, even when it's not used.
|
||||
|
|
@ -514,6 +512,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
type CodegenCx = CodegenCx<'gcc, 'tcx>;
|
||||
|
||||
fn build(cx: &'a CodegenCx<'gcc, 'tcx>, block: Block<'gcc>) -> Builder<'a, 'gcc, 'tcx> {
|
||||
*cx.current_func.borrow_mut() = Some(block.get_function());
|
||||
Builder::with_cx(cx, block)
|
||||
}
|
||||
|
||||
|
|
@ -1765,6 +1764,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
// FIXME(antoyo): remove when having a proper API.
|
||||
let gcc_func = unsafe { std::mem::transmute::<RValue<'gcc>, Function<'gcc>>(func) };
|
||||
let call = if self.functions.borrow().values().any(|value| *value == gcc_func) {
|
||||
// TODO(antoyo): remove when the API supports a different type for functions.
|
||||
let func: Function<'gcc> = self.cx.rvalue_as_function(func);
|
||||
self.function_call(func, args, funclet)
|
||||
} else {
|
||||
// If it's a not function that was defined, it's a function pointer.
|
||||
|
|
|
|||
|
|
@ -92,6 +92,8 @@ pub struct CodegenCx<'gcc, 'tcx> {
|
|||
pub instances: RefCell<FxHashMap<Instance<'tcx>, LValue<'gcc>>>,
|
||||
/// Cache function instances of monomorphic and polymorphic items
|
||||
pub function_instances: RefCell<FxHashMap<Instance<'tcx>, Function<'gcc>>>,
|
||||
/// Cache function instances of intrinsics
|
||||
pub intrinsic_instances: RefCell<FxHashMap<Instance<'tcx>, Function<'gcc>>>,
|
||||
/// Cache generated vtables
|
||||
pub vtables:
|
||||
RefCell<FxHashMap<(Ty<'tcx>, Option<ty::ExistentialTraitRef<'tcx>>), RValue<'gcc>>>,
|
||||
|
|
@ -280,6 +282,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
linkage: Cell::new(FunctionType::Internal),
|
||||
instances: Default::default(),
|
||||
function_instances: Default::default(),
|
||||
intrinsic_instances: Default::default(),
|
||||
on_stack_params: Default::default(),
|
||||
on_stack_function_params: Default::default(),
|
||||
vtables: Default::default(),
|
||||
|
|
@ -391,17 +394,13 @@ impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
}
|
||||
|
||||
fn get_fn(&self, instance: Instance<'tcx>) -> Function<'gcc> {
|
||||
let func = get_fn(self, instance);
|
||||
*self.current_func.borrow_mut() = Some(func);
|
||||
func
|
||||
get_fn(self, instance)
|
||||
}
|
||||
|
||||
fn get_fn_addr(&self, instance: Instance<'tcx>) -> RValue<'gcc> {
|
||||
let func_name = self.tcx.symbol_name(instance).name;
|
||||
|
||||
let func = if self.intrinsics.borrow().contains_key(func_name) {
|
||||
self.intrinsics.borrow()[func_name]
|
||||
} else if let Some(variable) = self.get_declared_value(func_name) {
|
||||
let func = if let Some(variable) = self.get_declared_value(func_name) {
|
||||
return variable;
|
||||
} else {
|
||||
get_fn(self, instance)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ use rustc_target::callconv::FnAbi;
|
|||
|
||||
use crate::abi::{FnAbiGcc, FnAbiGccExt};
|
||||
use crate::context::CodegenCx;
|
||||
use crate::intrinsic::llvm;
|
||||
|
||||
impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
||||
pub fn get_or_insert_global(
|
||||
|
|
@ -100,18 +99,14 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
let return_type = self.type_i32();
|
||||
let variadic = false;
|
||||
self.linkage.set(FunctionType::Exported);
|
||||
let func = declare_raw_fn(
|
||||
declare_raw_fn(
|
||||
self,
|
||||
name,
|
||||
callconv,
|
||||
return_type,
|
||||
&[self.type_i32(), const_string],
|
||||
variadic,
|
||||
);
|
||||
// NOTE: it is needed to set the current_func here as well, because get_fn() is not called
|
||||
// for the main function.
|
||||
*self.current_func.borrow_mut() = Some(func);
|
||||
func
|
||||
)
|
||||
}
|
||||
|
||||
pub fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Function<'gcc> {
|
||||
|
|
@ -166,19 +161,6 @@ fn declare_raw_fn<'gcc>(
|
|||
param_types: &[Type<'gcc>],
|
||||
variadic: bool,
|
||||
) -> Function<'gcc> {
|
||||
if name.starts_with("llvm.") {
|
||||
let intrinsic = match name {
|
||||
"llvm.fma.f16" => {
|
||||
// fma is not a target builtin, but a normal builtin, so we handle it differently
|
||||
// here.
|
||||
cx.context.get_builtin_function("fma")
|
||||
}
|
||||
_ => llvm::intrinsic(name, cx),
|
||||
};
|
||||
|
||||
cx.intrinsics.borrow_mut().insert(name.to_string(), intrinsic);
|
||||
return intrinsic;
|
||||
}
|
||||
let func = if cx.functions.borrow().contains_key(name) {
|
||||
cx.functions.borrow()[name]
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use gccjit::Type;
|
|||
use gccjit::{ComparisonOp, Function, FunctionType, RValue, ToRValue, UnaryOp};
|
||||
#[cfg(feature = "master")]
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_abi::{BackendRepr, HasDataLayout};
|
||||
use rustc_abi::{BackendRepr, HasDataLayout, WrappingRange};
|
||||
use rustc_codegen_ssa::MemFlags;
|
||||
use rustc_codegen_ssa::base::wants_msvc_seh;
|
||||
use rustc_codegen_ssa::common::IntPredicate;
|
||||
|
|
@ -20,19 +20,15 @@ use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue};
|
|||
use rustc_codegen_ssa::traits::MiscCodegenMethods;
|
||||
use rustc_codegen_ssa::traits::{
|
||||
ArgAbiBuilderMethods, BaseTypeCodegenMethods, BuilderMethods, ConstCodegenMethods,
|
||||
IntrinsicCallBuilderMethods,
|
||||
IntrinsicCallBuilderMethods, LayoutTypeCodegenMethods,
|
||||
};
|
||||
use rustc_middle::bug;
|
||||
#[cfg(feature = "master")]
|
||||
use rustc_middle::ty::layout::FnAbiOf;
|
||||
use rustc_middle::ty::layout::LayoutOf;
|
||||
use rustc_middle::ty::layout::{FnAbiOf, LayoutOf};
|
||||
use rustc_middle::ty::{self, Instance, Ty};
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
use rustc_target::callconv::{ArgAbi, PassMode};
|
||||
|
||||
#[cfg(feature = "master")]
|
||||
use crate::abi::FnAbiGccExt;
|
||||
use crate::abi::GccType;
|
||||
use crate::abi::{FnAbiGccExt, GccType};
|
||||
use crate::builder::Builder;
|
||||
use crate::common::{SignType, TypeReflection};
|
||||
use crate::context::CodegenCx;
|
||||
|
|
@ -609,6 +605,94 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn codegen_llvm_intrinsic_call(
|
||||
&mut self,
|
||||
instance: ty::Instance<'tcx>,
|
||||
args: &[OperandRef<'tcx, Self::Value>],
|
||||
is_cleanup: bool,
|
||||
) -> Self::Value {
|
||||
let func = if let Some(&func) = self.intrinsic_instances.borrow().get(&instance) {
|
||||
func
|
||||
} else {
|
||||
let sym = self.tcx.symbol_name(instance).name;
|
||||
|
||||
let func = if let Some(func) = self.intrinsics.borrow().get(sym) {
|
||||
*func
|
||||
} else {
|
||||
self.linkage.set(FunctionType::Extern);
|
||||
let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty());
|
||||
let fn_ty = fn_abi.gcc_type(self);
|
||||
|
||||
let func = match sym {
|
||||
"llvm.fma.f16" => {
|
||||
// fma is not a target builtin, but a normal builtin, so we handle it differently
|
||||
// here.
|
||||
self.context.get_builtin_function("fma")
|
||||
}
|
||||
_ => llvm::intrinsic(sym, self),
|
||||
};
|
||||
|
||||
self.intrinsics.borrow_mut().insert(sym.to_string(), func);
|
||||
|
||||
self.on_stack_function_params
|
||||
.borrow_mut()
|
||||
.insert(func, fn_ty.on_stack_param_indices);
|
||||
#[cfg(feature = "master")]
|
||||
for fn_attr in fn_ty.fn_attributes {
|
||||
func.add_attribute(fn_attr);
|
||||
}
|
||||
|
||||
crate::attributes::from_fn_attrs(self, func, instance);
|
||||
|
||||
func
|
||||
};
|
||||
|
||||
self.intrinsic_instances.borrow_mut().insert(instance, func);
|
||||
|
||||
func
|
||||
};
|
||||
let fn_ptr = func.get_address(None);
|
||||
let fn_ty = fn_ptr.get_type();
|
||||
|
||||
let mut llargs = vec![];
|
||||
|
||||
for arg in args {
|
||||
match arg.val {
|
||||
OperandValue::ZeroSized => {}
|
||||
OperandValue::Immediate(_) => llargs.push(arg.immediate()),
|
||||
OperandValue::Pair(a, b) => {
|
||||
llargs.push(a);
|
||||
llargs.push(b);
|
||||
}
|
||||
OperandValue::Ref(op_place_val) => {
|
||||
let mut llval = op_place_val.llval;
|
||||
// We can't use `PlaceRef::load` here because the argument
|
||||
// may have a type we don't treat as immediate, but the ABI
|
||||
// used for this call is passing it by-value. In that case,
|
||||
// the load would just produce `OperandValue::Ref` instead
|
||||
// of the `OperandValue::Immediate` we need for the call.
|
||||
llval = self.load(self.backend_type(arg.layout), llval, op_place_val.align);
|
||||
if let BackendRepr::Scalar(scalar) = arg.layout.backend_repr {
|
||||
if scalar.is_bool() {
|
||||
self.range_metadata(llval, WrappingRange { start: 0, end: 1 });
|
||||
}
|
||||
// We store bools as `i8` so we need to truncate to `i1`.
|
||||
llval = self.to_immediate_scalar(llval, scalar);
|
||||
}
|
||||
llargs.push(llval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME directly use the llvm intrinsic adjustment functions here
|
||||
let llret = self.call(fn_ty, None, None, fn_ptr, &llargs, None, None);
|
||||
if is_cleanup {
|
||||
self.apply_attrs_to_cleanup_callsite(llret);
|
||||
}
|
||||
|
||||
llret
|
||||
}
|
||||
|
||||
fn abort(&mut self) {
|
||||
let func = self.context.get_builtin_function("abort");
|
||||
let func: RValue<'gcc> = unsafe { std::mem::transmute(func) };
|
||||
|
|
|
|||
|
|
@ -38,8 +38,6 @@ rustc_session = { path = "../rustc_session" }
|
|||
rustc_span = { path = "../rustc_span" }
|
||||
rustc_symbol_mangling = { path = "../rustc_symbol_mangling" }
|
||||
rustc_target = { path = "../rustc_target" }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
|
||||
tracing = "0.1"
|
||||
# tidy-alphabetical-end
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -250,7 +250,7 @@ pub(crate) fn target_machine_factory(
|
|||
|
||||
let use_emulated_tls = matches!(sess.tls_model(), TlsModel::Emulated);
|
||||
|
||||
let debuginfo_compression = match sess.opts.debuginfo_compression {
|
||||
let debuginfo_compression = match sess.opts.unstable_opts.debuginfo_compression {
|
||||
config::DebugInfoCompression::None => llvm::CompressionKind::None,
|
||||
config::DebugInfoCompression::Zlib => {
|
||||
if llvm::LLVMRustLLVMHasZlibCompression() {
|
||||
|
|
@ -1136,7 +1136,7 @@ pub(crate) fn codegen(
|
|||
EmitObj::None => {}
|
||||
}
|
||||
|
||||
record_llvm_cgu_instructions_stats(&cgcx.prof, llmod);
|
||||
record_llvm_cgu_instructions_stats(&cgcx.prof, &module.name, llmod);
|
||||
}
|
||||
|
||||
// `.dwo` files are only emitted if:
|
||||
|
|
@ -1343,22 +1343,11 @@ fn record_artifact_size(
|
|||
}
|
||||
}
|
||||
|
||||
fn record_llvm_cgu_instructions_stats(prof: &SelfProfilerRef, llmod: &llvm::Module) {
|
||||
fn record_llvm_cgu_instructions_stats(prof: &SelfProfilerRef, name: &str, llmod: &llvm::Module) {
|
||||
if !prof.enabled() {
|
||||
return;
|
||||
}
|
||||
|
||||
let raw_stats =
|
||||
llvm::build_string(|s| unsafe { llvm::LLVMRustModuleInstructionStats(llmod, s) })
|
||||
.expect("cannot get module instruction stats");
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
struct InstructionsStats {
|
||||
module: String,
|
||||
total: u64,
|
||||
}
|
||||
|
||||
let InstructionsStats { module, total } =
|
||||
serde_json::from_str(&raw_stats).expect("cannot parse llvm cgu instructions stats");
|
||||
prof.artifact_size("cgu_instructions", module, total);
|
||||
let total = unsafe { llvm::LLVMRustModuleInstructionStats(llmod) };
|
||||
prof.artifact_size("cgu_instructions", name, total);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1705,7 +1705,7 @@ impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
|
|||
ret.expect("LLVM does not have support for catchret")
|
||||
}
|
||||
|
||||
fn check_call<'b>(
|
||||
pub(crate) fn check_call<'b>(
|
||||
&mut self,
|
||||
typ: &str,
|
||||
fn_ty: &'ll Type,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@ use std::ffi::CString;
|
|||
|
||||
use llvm::Linkage::*;
|
||||
use rustc_abi::Align;
|
||||
use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
|
||||
use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, BuilderMethods};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::offload_meta::OffloadMetadata;
|
||||
|
||||
use crate::builder::Builder;
|
||||
|
|
@ -47,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);
|
||||
|
||||
|
|
@ -69,6 +72,57 @@ impl<'ll> OffloadGlobals<'ll> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) struct OffloadKernelDims<'ll> {
|
||||
num_workgroups: &'ll Value,
|
||||
threads_per_block: &'ll Value,
|
||||
workgroup_dims: &'ll Value,
|
||||
thread_dims: &'ll Value,
|
||||
}
|
||||
|
||||
impl<'ll> OffloadKernelDims<'ll> {
|
||||
pub(crate) fn from_operands<'tcx>(
|
||||
builder: &mut Builder<'_, 'll, 'tcx>,
|
||||
workgroup_op: &OperandRef<'tcx, &'ll llvm::Value>,
|
||||
thread_op: &OperandRef<'tcx, &'ll llvm::Value>,
|
||||
) -> Self {
|
||||
let cx = builder.cx;
|
||||
let arr_ty = cx.type_array(cx.type_i32(), 3);
|
||||
let four = Align::from_bytes(4).unwrap();
|
||||
|
||||
let OperandValue::Ref(place) = workgroup_op.val else {
|
||||
bug!("expected array operand by reference");
|
||||
};
|
||||
let workgroup_val = builder.load(arr_ty, place.llval, four);
|
||||
|
||||
let OperandValue::Ref(place) = thread_op.val else {
|
||||
bug!("expected array operand by reference");
|
||||
};
|
||||
let thread_val = builder.load(arr_ty, place.llval, four);
|
||||
|
||||
fn mul_dim3<'ll, 'tcx>(
|
||||
builder: &mut Builder<'_, 'll, 'tcx>,
|
||||
arr: &'ll Value,
|
||||
) -> &'ll Value {
|
||||
let x = builder.extract_value(arr, 0);
|
||||
let y = builder.extract_value(arr, 1);
|
||||
let z = builder.extract_value(arr, 2);
|
||||
|
||||
let xy = builder.mul(x, y);
|
||||
builder.mul(xy, z)
|
||||
}
|
||||
|
||||
let num_workgroups = mul_dim3(builder, workgroup_val);
|
||||
let threads_per_block = mul_dim3(builder, thread_val);
|
||||
|
||||
OffloadKernelDims {
|
||||
workgroup_dims: workgroup_val,
|
||||
thread_dims: thread_val,
|
||||
num_workgroups,
|
||||
threads_per_block,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ; Function Attrs: nounwind
|
||||
// declare i32 @__tgt_target_kernel(ptr, i64, i32, i32, ptr, ptr) #2
|
||||
fn generate_launcher<'ll>(cx: &CodegenCx<'ll, '_>) -> (&'ll llvm::Value, &'ll llvm::Type) {
|
||||
|
|
@ -204,12 +258,12 @@ impl KernelArgsTy {
|
|||
num_args: u64,
|
||||
memtransfer_types: &'ll Value,
|
||||
geps: [&'ll Value; 3],
|
||||
workgroup_dims: &'ll Value,
|
||||
thread_dims: &'ll Value,
|
||||
) -> [(Align, &'ll Value); 13] {
|
||||
let four = Align::from_bytes(4).expect("4 Byte alignment should work");
|
||||
let eight = Align::EIGHT;
|
||||
|
||||
let ti32 = cx.type_i32();
|
||||
let ci32_0 = cx.get_const_i32(0);
|
||||
[
|
||||
(four, cx.get_const_i32(KernelArgsTy::OFFLOAD_VERSION)),
|
||||
(four, cx.get_const_i32(num_args)),
|
||||
|
|
@ -222,8 +276,8 @@ impl KernelArgsTy {
|
|||
(eight, cx.const_null(cx.type_ptr())), // dbg
|
||||
(eight, cx.get_const_i64(KernelArgsTy::TRIPCOUNT)),
|
||||
(eight, cx.get_const_i64(KernelArgsTy::FLAGS)),
|
||||
(four, cx.const_array(ti32, &[cx.get_const_i32(2097152), ci32_0, ci32_0])),
|
||||
(four, cx.const_array(ti32, &[cx.get_const_i32(256), ci32_0, ci32_0])),
|
||||
(four, workgroup_dims),
|
||||
(four, thread_dims),
|
||||
(four, cx.get_const_i32(0)),
|
||||
]
|
||||
}
|
||||
|
|
@ -413,10 +467,13 @@ pub(crate) fn gen_call_handling<'ll, 'tcx>(
|
|||
types: &[&Type],
|
||||
metadata: &[OffloadMetadata],
|
||||
offload_globals: &OffloadGlobals<'ll>,
|
||||
offload_dims: &OffloadKernelDims<'ll>,
|
||||
) {
|
||||
let cx = builder.cx;
|
||||
let OffloadKernelGlobals { offload_sizes, offload_entry, memtransfer_types, region_id } =
|
||||
offload_data;
|
||||
let OffloadKernelDims { num_workgroups, threads_per_block, workgroup_dims, thread_dims } =
|
||||
offload_dims;
|
||||
|
||||
let tgt_decl = offload_globals.launcher_fn;
|
||||
let tgt_target_kernel_ty = offload_globals.launcher_ty;
|
||||
|
|
@ -430,7 +487,7 @@ pub(crate) fn gen_call_handling<'ll, 'tcx>(
|
|||
let fn_ty = offload_globals.mapper_fn_ty;
|
||||
|
||||
let num_args = types.len() as u64;
|
||||
let ip = unsafe { llvm::LLVMRustGetInsertPoint(&builder.llbuilder) };
|
||||
let bb = builder.llbb();
|
||||
|
||||
// FIXME(Sa4dUs): dummy loads are a temp workaround, we should find a proper way to prevent these
|
||||
// variables from being optimized away
|
||||
|
|
@ -468,7 +525,7 @@ pub(crate) fn gen_call_handling<'ll, 'tcx>(
|
|||
|
||||
// Step 1)
|
||||
unsafe {
|
||||
llvm::LLVMRustRestoreInsertPoint(&builder.llbuilder, ip);
|
||||
llvm::LLVMPositionBuilderAtEnd(&builder.llbuilder, bb);
|
||||
}
|
||||
builder.memset(tgt_bin_desc_alloca, cx.get_const_i8(0), cx.get_const_i64(32), Align::EIGHT);
|
||||
|
||||
|
|
@ -554,7 +611,8 @@ pub(crate) fn gen_call_handling<'ll, 'tcx>(
|
|||
num_args,
|
||||
s_ident_t,
|
||||
);
|
||||
let values = KernelArgsTy::new(&cx, num_args, memtransfer_types, geps);
|
||||
let values =
|
||||
KernelArgsTy::new(&cx, num_args, memtransfer_types, geps, workgroup_dims, thread_dims);
|
||||
|
||||
// Step 3)
|
||||
// Here we fill the KernelArgsTy, see the documentation above
|
||||
|
|
@ -567,9 +625,8 @@ pub(crate) fn gen_call_handling<'ll, 'tcx>(
|
|||
s_ident_t,
|
||||
// FIXME(offload) give users a way to select which GPU to use.
|
||||
cx.get_const_i64(u64::MAX), // MAX == -1.
|
||||
// FIXME(offload): Don't hardcode the numbers of threads in the future.
|
||||
cx.get_const_i32(2097152),
|
||||
cx.get_const_i32(256),
|
||||
num_workgroups,
|
||||
threads_per_block,
|
||||
region_id,
|
||||
a5,
|
||||
];
|
||||
|
|
|
|||
|
|
@ -101,6 +101,8 @@ pub(crate) struct FullCx<'ll, 'tcx> {
|
|||
|
||||
/// Cache instances of monomorphic and polymorphic items
|
||||
pub instances: RefCell<FxHashMap<Instance<'tcx>, &'ll Value>>,
|
||||
/// Cache instances of intrinsics
|
||||
pub intrinsic_instances: RefCell<FxHashMap<Instance<'tcx>, &'ll Value>>,
|
||||
/// Cache generated vtables
|
||||
pub vtables: RefCell<FxHashMap<(Ty<'tcx>, Option<ty::ExistentialTraitRef<'tcx>>), &'ll Value>>,
|
||||
/// Cache of constant strings,
|
||||
|
|
@ -209,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.
|
||||
|
|
@ -627,6 +633,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
|
|||
tls_model,
|
||||
codegen_unit,
|
||||
instances: Default::default(),
|
||||
intrinsic_instances: Default::default(),
|
||||
vtables: Default::default(),
|
||||
const_str_cache: Default::default(),
|
||||
const_globals: Default::default(),
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
use std::assert_matches::assert_matches;
|
||||
use std::cmp::Ordering;
|
||||
use std::ffi::c_uint;
|
||||
use std::ptr;
|
||||
|
||||
use rustc_abi::{Align, BackendRepr, ExternAbi, Float, HasDataLayout, Primitive, Size};
|
||||
use rustc_abi::{
|
||||
Align, BackendRepr, ExternAbi, Float, HasDataLayout, Primitive, Size, WrappingRange,
|
||||
};
|
||||
use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh, wants_wasm_eh};
|
||||
use rustc_codegen_ssa::codegen_attrs::autodiff_attrs;
|
||||
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
|
||||
|
|
@ -26,8 +30,9 @@ use tracing::debug;
|
|||
use crate::abi::FnAbiLlvmExt;
|
||||
use crate::builder::Builder;
|
||||
use crate::builder::autodiff::{adjust_activity_to_abi, generate_enzyme_call};
|
||||
use crate::builder::gpu_offload::{gen_call_handling, gen_define_handling};
|
||||
use crate::builder::gpu_offload::{OffloadKernelDims, gen_call_handling, gen_define_handling};
|
||||
use crate::context::CodegenCx;
|
||||
use crate::declare::declare_raw_fn;
|
||||
use crate::errors::{
|
||||
AutoDiffWithoutEnable, AutoDiffWithoutLto, OffloadWithoutEnable, OffloadWithoutFatLTO,
|
||||
};
|
||||
|
|
@ -633,6 +638,99 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn codegen_llvm_intrinsic_call(
|
||||
&mut self,
|
||||
instance: ty::Instance<'tcx>,
|
||||
args: &[OperandRef<'tcx, Self::Value>],
|
||||
is_cleanup: bool,
|
||||
) -> Self::Value {
|
||||
let tcx = self.tcx();
|
||||
|
||||
// FIXME remove usage of fn_abi
|
||||
let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty());
|
||||
assert!(!fn_abi.ret.is_indirect());
|
||||
let fn_ty = fn_abi.llvm_type(self);
|
||||
|
||||
let fn_ptr = if let Some(&llfn) = self.intrinsic_instances.borrow().get(&instance) {
|
||||
llfn
|
||||
} else {
|
||||
let sym = tcx.symbol_name(instance).name;
|
||||
|
||||
// FIXME use get_intrinsic
|
||||
let llfn = if let Some(llfn) = self.get_declared_value(sym) {
|
||||
llfn
|
||||
} else {
|
||||
// Function addresses in Rust are never significant, allowing functions to
|
||||
// be merged.
|
||||
let llfn = declare_raw_fn(
|
||||
self,
|
||||
sym,
|
||||
fn_abi.llvm_cconv(self),
|
||||
llvm::UnnamedAddr::Global,
|
||||
llvm::Visibility::Default,
|
||||
fn_ty,
|
||||
);
|
||||
fn_abi.apply_attrs_llfn(self, llfn, Some(instance));
|
||||
|
||||
llfn
|
||||
};
|
||||
|
||||
self.intrinsic_instances.borrow_mut().insert(instance, llfn);
|
||||
|
||||
llfn
|
||||
};
|
||||
|
||||
let mut llargs = vec![];
|
||||
|
||||
for arg in args {
|
||||
match arg.val {
|
||||
OperandValue::ZeroSized => {}
|
||||
OperandValue::Immediate(_) => llargs.push(arg.immediate()),
|
||||
OperandValue::Pair(a, b) => {
|
||||
llargs.push(a);
|
||||
llargs.push(b);
|
||||
}
|
||||
OperandValue::Ref(op_place_val) => {
|
||||
let mut llval = op_place_val.llval;
|
||||
// We can't use `PlaceRef::load` here because the argument
|
||||
// may have a type we don't treat as immediate, but the ABI
|
||||
// used for this call is passing it by-value. In that case,
|
||||
// the load would just produce `OperandValue::Ref` instead
|
||||
// of the `OperandValue::Immediate` we need for the call.
|
||||
llval = self.load(self.backend_type(arg.layout), llval, op_place_val.align);
|
||||
if let BackendRepr::Scalar(scalar) = arg.layout.backend_repr {
|
||||
if scalar.is_bool() {
|
||||
self.range_metadata(llval, WrappingRange { start: 0, end: 1 });
|
||||
}
|
||||
// We store bools as `i8` so we need to truncate to `i1`.
|
||||
llval = self.to_immediate_scalar(llval, scalar);
|
||||
}
|
||||
llargs.push(llval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug!("call intrinsic {:?} with args ({:?})", instance, llargs);
|
||||
let args = self.check_call("call", fn_ty, fn_ptr, &llargs);
|
||||
let llret = unsafe {
|
||||
llvm::LLVMBuildCallWithOperandBundles(
|
||||
self.llbuilder,
|
||||
fn_ty,
|
||||
fn_ptr,
|
||||
args.as_ptr() as *const &llvm::Value,
|
||||
args.len() as c_uint,
|
||||
ptr::dangling(),
|
||||
0,
|
||||
c"".as_ptr(),
|
||||
)
|
||||
};
|
||||
if is_cleanup {
|
||||
self.apply_attrs_to_cleanup_callsite(llret);
|
||||
}
|
||||
|
||||
llret
|
||||
}
|
||||
|
||||
fn abort(&mut self) {
|
||||
self.call_intrinsic("llvm.trap", &[], &[]);
|
||||
}
|
||||
|
|
@ -1286,7 +1384,8 @@ fn codegen_offload<'ll, 'tcx>(
|
|||
}
|
||||
};
|
||||
|
||||
let args = get_args_from_tuple(bx, args[1], fn_target);
|
||||
let offload_dims = OffloadKernelDims::from_operands(bx, &args[1], &args[2]);
|
||||
let args = get_args_from_tuple(bx, args[3], fn_target);
|
||||
let target_symbol = symbol_name_for_instance_in_crate(tcx, fn_target, LOCAL_CRATE);
|
||||
|
||||
let sig = tcx.fn_sig(fn_target.def_id()).skip_binder().skip_binder();
|
||||
|
|
@ -1305,7 +1404,7 @@ fn codegen_offload<'ll, 'tcx>(
|
|||
}
|
||||
};
|
||||
let offload_data = gen_define_handling(&cx, &metadata, &types, target_symbol, offload_globals);
|
||||
gen_call_handling(bx, &offload_data, &args, &types, &metadata, offload_globals);
|
||||
gen_call_handling(bx, &offload_data, &args, &types, &metadata, offload_globals, &offload_dims);
|
||||
}
|
||||
|
||||
fn get_args_from_tuple<'ll, 'tcx>(
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2443,8 +2443,6 @@ unsafe extern "C" {
|
|||
|
||||
pub(crate) fn LLVMRustPositionBuilderPastAllocas<'a>(B: &Builder<'a>, Fn: &'a Value);
|
||||
pub(crate) fn LLVMRustPositionBuilderAtStart<'a>(B: &Builder<'a>, BB: &'a BasicBlock);
|
||||
pub(crate) fn LLVMRustGetInsertPoint<'a>(B: &Builder<'a>) -> &'a Value;
|
||||
pub(crate) fn LLVMRustRestoreInsertPoint<'a>(B: &Builder<'a>, IP: &'a Value);
|
||||
|
||||
pub(crate) fn LLVMRustSetModulePICLevel(M: &Module);
|
||||
pub(crate) fn LLVMRustSetModulePIELevel(M: &Module);
|
||||
|
|
@ -2454,7 +2452,7 @@ unsafe extern "C" {
|
|||
pub(crate) fn LLVMRustModuleBufferLen(p: &ModuleBuffer) -> usize;
|
||||
pub(crate) fn LLVMRustModuleBufferFree(p: &'static mut ModuleBuffer);
|
||||
pub(crate) fn LLVMRustModuleCost(M: &Module) -> u64;
|
||||
pub(crate) fn LLVMRustModuleInstructionStats(M: &Module, Str: &RustString);
|
||||
pub(crate) fn LLVMRustModuleInstructionStats(M: &Module) -> u64;
|
||||
|
||||
pub(crate) fn LLVMRustThinLTOBufferCreate(
|
||||
M: &Module,
|
||||
|
|
|
|||
|
|
@ -262,6 +262,11 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
|
|||
"power8-crypto" => Some(LLVMFeature::new("crypto")),
|
||||
s => Some(LLVMFeature::new(s)),
|
||||
},
|
||||
Arch::RiscV32 | Arch::RiscV64 => match s {
|
||||
// Filter out Rust-specific *virtual* target feature
|
||||
"zkne_or_zknd" => None,
|
||||
s => Some(LLVMFeature::new(s)),
|
||||
},
|
||||
Arch::Sparc | Arch::Sparc64 => match s {
|
||||
"leoncasa" => Some(LLVMFeature::new("hasleoncasa")),
|
||||
s => Some(LLVMFeature::new(s)),
|
||||
|
|
|
|||
|
|
@ -8,8 +8,6 @@ codegen_ssa_aix_strip_not_used = using host's `strip` binary to cross-compile to
|
|||
|
||||
codegen_ssa_archive_build_failure = failed to build archive at `{$path}`: {$error}
|
||||
|
||||
codegen_ssa_bare_instruction_set = `#[instruction_set]` requires an argument
|
||||
|
||||
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_cgu_not_recorded =
|
||||
|
|
@ -90,8 +88,6 @@ codegen_ssa_incorrect_cgu_reuse_type =
|
|||
|
||||
codegen_ssa_insufficient_vs_code_product = VS Code is a different product, and is not sufficient.
|
||||
|
||||
codegen_ssa_invalid_instruction_set = invalid instruction set specified
|
||||
|
||||
codegen_ssa_invalid_literal_value = invalid literal value
|
||||
.label = value must be an integer between `0` and `255`
|
||||
|
||||
|
|
@ -215,8 +211,6 @@ codegen_ssa_msvc_missing_linker = the msvc targets depend on the msvc linker but
|
|||
|
||||
codegen_ssa_multiple_external_func_decl = multiple declarations of external function `{$function}` from library `{$library_name}` have different calling conventions
|
||||
|
||||
codegen_ssa_multiple_instruction_set = cannot specify more than one instruction set
|
||||
|
||||
codegen_ssa_multiple_main_functions = entry symbol `main` declared multiple times
|
||||
.help = did you use `#[no_mangle]` on `fn main`? Use `#![no_main]` to suppress the usual Rust-generated entry point
|
||||
|
||||
|
|
@ -383,8 +377,6 @@ codegen_ssa_unstable_ctarget_feature =
|
|||
unstable feature specified for `-Ctarget-feature`: `{$feature}`
|
||||
.note = this feature is not stably supported; its behavior can change in the future
|
||||
|
||||
codegen_ssa_unsupported_instruction_set = target does not support `#[instruction_set]`
|
||||
|
||||
codegen_ssa_unsupported_link_self_contained = option `-C link-self-contained` is not supported on this target
|
||||
|
||||
codegen_ssa_use_cargo_directive = use the `cargo:rustc-link-lib` directive to specify the native libraries to link with Cargo (see https://doc.rust-lang.org/cargo/reference/build-scripts.html#rustc-link-lib)
|
||||
|
|
|
|||
|
|
@ -330,14 +330,12 @@ pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 {
|
|||
let mut e_flags: u32 = 0x0;
|
||||
|
||||
// Check if compression is enabled
|
||||
// `unstable_target_features` is used here because "zca" is gated behind riscv_target_feature.
|
||||
if sess.unstable_target_features.contains(&sym::zca) {
|
||||
if sess.target_features.contains(&sym::zca) {
|
||||
e_flags |= elf::EF_RISCV_RVC;
|
||||
}
|
||||
|
||||
// Check if RVTSO is enabled
|
||||
// `unstable_target_features` is used here because "ztso" is gated behind riscv_target_feature.
|
||||
if sess.unstable_target_features.contains(&sym::ztso) {
|
||||
if sess.target_features.contains(&sym::ztso) {
|
||||
e_flags |= elf::EF_RISCV_TSO;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,9 +3,7 @@ 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, InstructionSetAttr, Linkage, RtsanSetting, UsedBy,
|
||||
};
|
||||
use rustc_hir::attrs::{AttributeKind, 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};
|
||||
|
|
@ -18,7 +16,7 @@ use rustc_middle::span_bug;
|
|||
use rustc_middle::ty::{self as ty, Instance, TyCtxt};
|
||||
use rustc_session::lint;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::{Ident, Span, Symbol, sym};
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
use rustc_target::spec::Os;
|
||||
|
||||
use crate::errors;
|
||||
|
|
@ -47,37 +45,6 @@ fn try_fn_sig<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME(jdonszelmann): remove when instruction_set becomes a parsed attr
|
||||
fn parse_instruction_set_attr(tcx: TyCtxt<'_>, attr: &Attribute) -> Option<InstructionSetAttr> {
|
||||
let list = attr.meta_item_list()?;
|
||||
|
||||
match &list[..] {
|
||||
[MetaItemInner::MetaItem(set)] => {
|
||||
let segments = set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>();
|
||||
match segments.as_slice() {
|
||||
[sym::arm, sym::a32 | sym::t32] if !tcx.sess.target.has_thumb_interworking => {
|
||||
tcx.dcx().emit_err(errors::UnsupportedInstructionSet { span: attr.span() });
|
||||
None
|
||||
}
|
||||
[sym::arm, sym::a32] => Some(InstructionSetAttr::ArmA32),
|
||||
[sym::arm, sym::t32] => Some(InstructionSetAttr::ArmT32),
|
||||
_ => {
|
||||
tcx.dcx().emit_err(errors::InvalidInstructionSet { span: attr.span() });
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
[] => {
|
||||
tcx.dcx().emit_err(errors::BareInstructionSet { span: attr.span() });
|
||||
None
|
||||
}
|
||||
_ => {
|
||||
tcx.dcx().emit_err(errors::MultipleInstructionSet { span: attr.span() });
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(jdonszelmann): remove when patchable_function_entry becomes a parsed attr
|
||||
fn parse_patchable_function_entry(
|
||||
tcx: TyCtxt<'_>,
|
||||
|
|
@ -353,11 +320,14 @@ fn process_builtin_attrs(
|
|||
AttributeKind::ThreadLocal => {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL
|
||||
}
|
||||
AttributeKind::InstructionSet(instruction_set) => {
|
||||
codegen_fn_attrs.instruction_set = Some(*instruction_set)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let Some(Ident { name, .. }) = attr.ident() else {
|
||||
let Some(name) = attr.name() else {
|
||||
continue;
|
||||
};
|
||||
|
||||
|
|
@ -369,9 +339,6 @@ fn process_builtin_attrs(
|
|||
sym::rustc_allocator_zeroed => {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED
|
||||
}
|
||||
sym::instruction_set => {
|
||||
codegen_fn_attrs.instruction_set = parse_instruction_set_attr(tcx, attr)
|
||||
}
|
||||
sym::patchable_function_entry => {
|
||||
codegen_fn_attrs.patchable_function_entry =
|
||||
parse_patchable_function_entry(tcx, attr);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -136,34 +136,6 @@ pub(crate) struct RequiresRustAbi {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_unsupported_instruction_set, code = E0779)]
|
||||
pub(crate) struct UnsupportedInstructionSet {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_invalid_instruction_set, code = E0779)]
|
||||
pub(crate) struct InvalidInstructionSet {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_bare_instruction_set, code = E0778)]
|
||||
pub(crate) struct BareInstructionSet {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_multiple_instruction_set, code = E0779)]
|
||||
pub(crate) struct MultipleInstructionSet {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_expected_name_value_pair)]
|
||||
pub(crate) struct ExpectedNameValuePair {
|
||||
|
|
|
|||
|
|
@ -9,12 +9,12 @@ use rustc_lint_defs::builtin::TAIL_CALL_TRACK_CALLER;
|
|||
use rustc_middle::mir::{self, AssertKind, InlineAsmMacro, SwitchTargets, UnwindTerminateReason};
|
||||
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement};
|
||||
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
|
||||
use rustc_middle::ty::{self, Instance, Ty};
|
||||
use rustc_middle::ty::{self, Instance, Ty, TypeVisitableExt};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_session::config::OptLevel;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_target::callconv::{ArgAbi, CastTarget, FnAbi, PassMode};
|
||||
use rustc_target::callconv::{ArgAbi, ArgAttributes, CastTarget, FnAbi, PassMode};
|
||||
use tracing::{debug, info};
|
||||
|
||||
use super::operand::OperandRef;
|
||||
|
|
@ -1036,6 +1036,59 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
_ => bug!("{} is not callable", callee.layout.ty),
|
||||
};
|
||||
|
||||
if let Some(instance) = instance
|
||||
&& let Some(name) = bx.tcx().codegen_fn_attrs(instance.def_id()).symbol_name
|
||||
&& name.as_str().starts_with("llvm.")
|
||||
// This is the only LLVM intrinsic we use that unwinds
|
||||
// FIXME either add unwind support to codegen_llvm_intrinsic_call or replace usage of
|
||||
// this intrinsic with something else
|
||||
&& name.as_str() != "llvm.wasm.throw"
|
||||
{
|
||||
assert!(!instance.args.has_infer());
|
||||
assert!(!instance.args.has_escaping_bound_vars());
|
||||
|
||||
let result_layout =
|
||||
self.cx.layout_of(self.monomorphized_place_ty(destination.as_ref()));
|
||||
|
||||
let return_dest = if result_layout.is_zst() {
|
||||
ReturnDest::Nothing
|
||||
} else if let Some(index) = destination.as_local() {
|
||||
match self.locals[index] {
|
||||
LocalRef::Place(dest) => ReturnDest::Store(dest),
|
||||
LocalRef::UnsizedPlace(_) => bug!("return type must be sized"),
|
||||
LocalRef::PendingOperand => {
|
||||
// Handle temporary places, specifically `Operand` ones, as
|
||||
// they don't have `alloca`s.
|
||||
ReturnDest::DirectOperand(index)
|
||||
}
|
||||
LocalRef::Operand(_) => bug!("place local already assigned to"),
|
||||
}
|
||||
} else {
|
||||
ReturnDest::Store(self.codegen_place(bx, destination.as_ref()))
|
||||
};
|
||||
|
||||
let args =
|
||||
args.into_iter().map(|arg| self.codegen_operand(bx, &arg.node)).collect::<Vec<_>>();
|
||||
|
||||
self.set_debug_loc(bx, source_info);
|
||||
|
||||
let llret =
|
||||
bx.codegen_llvm_intrinsic_call(instance, &args, self.mir[helper.bb].is_cleanup);
|
||||
|
||||
if let Some(target) = target {
|
||||
self.store_return(
|
||||
bx,
|
||||
return_dest,
|
||||
&ArgAbi { layout: result_layout, mode: PassMode::Direct(ArgAttributes::new()) },
|
||||
llret,
|
||||
);
|
||||
return helper.funclet_br(self, bx, target, mergeable_succ);
|
||||
} else {
|
||||
bx.unreachable();
|
||||
return MergingSucc::False;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(eddyb) avoid computing this if possible, when `instance` is
|
||||
// available - right now `sig` is only needed for getting the `abi`
|
||||
// and figuring out how many extra args were passed to a C-variadic `fn`.
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::collections::hash_map::Entry;
|
|||
use std::marker::PhantomData;
|
||||
use std::ops::Range;
|
||||
|
||||
use rustc_abi::{BackendRepr, FieldIdx, FieldsShape, ScalableElt, Size, VariantIdx};
|
||||
use rustc_abi::{BackendRepr, FieldIdx, FieldsShape, Size, VariantIdx};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
|
|
@ -431,22 +431,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
// Internally, with an intrinsic operating on a `svint32_t`/`<vscale x 4 x i32>`
|
||||
// (for example), the intrinsic takes the `svbool_t`/`<vscale x 16 x i1>` predicate
|
||||
// and casts it to a `svbool4_t`/`<vscale x 4 x i1>`. Therefore, it's important that
|
||||
// the `<vscale x 4 x i32>` never spills because that'll cause errors during
|
||||
// the `<vscale x 4 x i1>` never spills because that'll cause errors during
|
||||
// instruction selection. Spilling to the stack to create debuginfo for these
|
||||
// intermediate values must be avoided and won't degrade the debugging experience
|
||||
// anyway.
|
||||
// intermediate values must be avoided and doing so won't affect the
|
||||
// debugging experience anyway.
|
||||
if operand.layout.ty.is_scalable_vector()
|
||||
&& bx.sess().target.arch == rustc_target::spec::Arch::AArch64
|
||||
&& let ty::Adt(adt, args) = &operand.layout.ty.kind()
|
||||
&& let Some(marker_type_field) =
|
||||
adt.non_enum_variant().fields.get(FieldIdx::from_u32(0))
|
||||
{
|
||||
let marker_type = marker_type_field.ty(bx.tcx(), args);
|
||||
let (count, element_ty) =
|
||||
operand.layout.ty.scalable_vector_element_count_and_type(bx.tcx());
|
||||
// i.e. `<vscale x N x i1>` when `N != 16`
|
||||
if let ty::Slice(element_ty) = marker_type.kind()
|
||||
&& element_ty.is_bool()
|
||||
&& adt.repr().scalable != Some(ScalableElt::ElementCount(16))
|
||||
{
|
||||
if element_ty.is_bool() && count != 16 {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 => {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,13 @@ pub trait IntrinsicCallBuilderMethods<'tcx>: BackendTypes {
|
|||
span: Span,
|
||||
) -> Result<(), ty::Instance<'tcx>>;
|
||||
|
||||
fn codegen_llvm_intrinsic_call(
|
||||
&mut self,
|
||||
instance: ty::Instance<'tcx>,
|
||||
args: &[OperandRef<'tcx, Self::Value>],
|
||||
is_cleanup: bool,
|
||||
) -> Self::Value;
|
||||
|
||||
fn abort(&mut self);
|
||||
fn assume(&mut self, val: Self::Value);
|
||||
fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value;
|
||||
|
|
|
|||
|
|
@ -251,7 +251,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
|
|||
let mut transient = DenseBitSet::new_filled(ccx.body.local_decls.len());
|
||||
// Make sure to only visit reachable blocks, the dataflow engine can ICE otherwise.
|
||||
for (bb, data) in traversal::reachable(&ccx.body) {
|
||||
if matches!(data.terminator().kind, TerminatorKind::Return) {
|
||||
if data.terminator().kind == TerminatorKind::Return {
|
||||
let location = ccx.body.terminator_loc(bb);
|
||||
maybe_storage_live.seek_after_primary_effect(location);
|
||||
// If a local may be live here, it is definitely not transient.
|
||||
|
|
|
|||
|
|
@ -312,7 +312,7 @@ where
|
|||
// i.e., we treat all qualifs as non-structural for deref projections. Generally,
|
||||
// we can say very little about `*ptr` even if we know that `ptr` satisfies all
|
||||
// sorts of properties.
|
||||
if matches!(elem, ProjectionElem::Deref) {
|
||||
if elem == ProjectionElem::Deref {
|
||||
// We have to assume that this qualifies.
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -283,7 +283,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
'tcx: 'y,
|
||||
{
|
||||
assert_eq!(callee_ty, callee_abi.layout.ty);
|
||||
if matches!(callee_abi.mode, PassMode::Ignore) {
|
||||
if callee_abi.mode == PassMode::Ignore {
|
||||
// This one is skipped. Still must be made live though!
|
||||
if !already_live {
|
||||
self.storage_live(callee_arg.as_local().unwrap())?;
|
||||
|
|
|
|||
|
|
@ -861,7 +861,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
}
|
||||
} else {
|
||||
// unsigned
|
||||
if matches!(mir_op, BinOp::Add) {
|
||||
if mir_op == BinOp::Add {
|
||||
// max unsigned
|
||||
Scalar::from_uint(size.unsigned_int_max(), size)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -327,7 +327,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
return Err(ConstEvalErrKind::ConstMakeGlobalWithOffset(ptr)).into();
|
||||
}
|
||||
|
||||
if matches!(self.tcx.try_get_global_alloc(alloc_id), Some(_)) {
|
||||
if self.tcx.try_get_global_alloc(alloc_id).is_some() {
|
||||
// This points to something outside the current interpreter.
|
||||
return Err(ConstEvalErrKind::ConstMakeGlobalPtrIsNonHeap(ptr)).into();
|
||||
}
|
||||
|
|
@ -981,7 +981,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
msg: CheckInAllocMsg,
|
||||
) -> InterpResult<'tcx, (Size, Align)> {
|
||||
let info = self.get_alloc_info(id);
|
||||
if matches!(info.kind, AllocKind::Dead) {
|
||||
if info.kind == AllocKind::Dead {
|
||||
throw_ub!(PointerUseAfterFree(id, msg))
|
||||
}
|
||||
interp_ok((info.size, info.align))
|
||||
|
|
@ -1072,7 +1072,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
// Recurse, if there is data here.
|
||||
// Do this *before* invoking the callback, as the callback might mutate the
|
||||
// allocation and e.g. replace all provenance by wildcards!
|
||||
if matches!(info.kind, AllocKind::LiveData) {
|
||||
if info.kind == AllocKind::LiveData {
|
||||
let alloc = self.get_alloc_raw(id)?;
|
||||
for prov in alloc.provenance().provenances() {
|
||||
if let Some(id) = prov.get_alloc_id() {
|
||||
|
|
@ -1605,7 +1605,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
match self.ptr_try_get_alloc_id(ptr, 0) {
|
||||
Ok((alloc_id, offset, _)) => {
|
||||
let info = self.get_alloc_info(alloc_id);
|
||||
if matches!(info.kind, AllocKind::TypeId) {
|
||||
if info.kind == AllocKind::TypeId {
|
||||
// We *could* actually precisely answer this question since here,
|
||||
// the offset *is* the integer value. But the entire point of making
|
||||
// this a pointer is not to leak the integer value, so we say everything
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
#### Note: this error code is no longer emitted by the compiler
|
||||
The `instruction_set` attribute was malformed.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0778
|
||||
```compile_fail
|
||||
#![feature(isa_attribute)]
|
||||
|
||||
#[instruction_set()] // error: expected one argument
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
#### Note: this error code is no longer emitted by the compiler
|
||||
An unknown argument was given to the `instruction_set` attribute.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0779
|
||||
```compile_fail
|
||||
#![feature(isa_attribute)]
|
||||
|
||||
#[instruction_set(intel::x64)] // error: invalid argument
|
||||
|
|
|
|||
|
|
@ -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 }));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -271,6 +274,8 @@ declare_features! (
|
|||
/// Allows `#[link(kind = "static-nobundle", ...)]`.
|
||||
(removed, static_nobundle, "1.63.0", Some(37403),
|
||||
Some(r#"subsumed by `#[link(kind = "static", modifiers = "-bundle", ...)]`"#), 95818),
|
||||
/// Allows string patterns to dereference values to match them.
|
||||
(removed, string_deref_patterns, "CURRENT_RUSTC_VERSION", Some(87121), Some("superseded by `deref_patterns`"), 150530),
|
||||
(removed, struct_inherit, "1.0.0", None, None),
|
||||
(removed, test_removed_feature, "1.0.0", None, None),
|
||||
/// Allows using items which are missing stability attributes
|
||||
|
|
|
|||
|
|
@ -239,22 +239,16 @@ declare_features! (
|
|||
(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 +289,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 +301,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.
|
||||
// !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
|
||||
|
|
@ -319,47 +319,14 @@ declare_features! (
|
|||
// feature-group-end: internal feature gates
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// feature-group-start: actual feature gates (target features)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// FIXME: Document these and merge with the list below.
|
||||
|
||||
// Unstable `#[target_feature]` directives.
|
||||
(unstable, aarch64_unstable_target_feature, "1.82.0", Some(44839)),
|
||||
(unstable, aarch64_ver_target_feature, "1.27.0", Some(44839)),
|
||||
(unstable, apx_target_feature, "1.88.0", Some(139284)),
|
||||
(unstable, arm_target_feature, "1.27.0", Some(44839)),
|
||||
(unstable, bpf_target_feature, "1.54.0", Some(44839)),
|
||||
(unstable, csky_target_feature, "1.73.0", Some(44839)),
|
||||
(unstable, ermsb_target_feature, "1.49.0", Some(44839)),
|
||||
(unstable, hexagon_target_feature, "1.27.0", Some(44839)),
|
||||
(unstable, lahfsahf_target_feature, "1.78.0", Some(44839)),
|
||||
(unstable, loongarch_target_feature, "1.73.0", Some(44839)),
|
||||
(unstable, m68k_target_feature, "1.85.0", Some(134328)),
|
||||
(unstable, mips_target_feature, "1.27.0", Some(44839)),
|
||||
(unstable, movrs_target_feature, "1.88.0", Some(137976)),
|
||||
(unstable, nvptx_target_feature, "1.91.0", Some(44839)),
|
||||
(unstable, powerpc_target_feature, "1.27.0", Some(44839)),
|
||||
(unstable, prfchw_target_feature, "1.78.0", Some(44839)),
|
||||
(unstable, riscv_target_feature, "1.45.0", Some(44839)),
|
||||
(unstable, rtm_target_feature, "1.35.0", Some(44839)),
|
||||
(unstable, s390x_target_feature, "1.82.0", Some(44839)),
|
||||
(unstable, sparc_target_feature, "1.84.0", Some(132783)),
|
||||
(unstable, wasm_target_feature, "1.30.0", Some(44839)),
|
||||
(unstable, x87_target_feature, "1.85.0", Some(44839)),
|
||||
// !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
|
||||
// Features are listed in alphabetical order. Tidy will fail if you don't keep it this way.
|
||||
// !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// feature-group-end: actual feature gates (target features)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// feature-group-start: actual feature gates
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/// The remaining unstable target features on aarch64.
|
||||
(unstable, aarch64_unstable_target_feature, "1.82.0", Some(150244)),
|
||||
/// Instruction set "version" target features on aarch64.
|
||||
(unstable, aarch64_ver_target_feature, "1.27.0", Some(150245)),
|
||||
/// Allows `extern "avr-interrupt" fn()` and `extern "avr-non-blocking-interrupt" fn()`.
|
||||
(unstable, abi_avr_interrupt, "1.45.0", Some(69664)),
|
||||
/// Allows `extern "cmse-nonsecure-call" fn()`.
|
||||
|
|
@ -380,10 +347,14 @@ declare_features! (
|
|||
(unstable, adt_const_params, "1.56.0", Some(95174)),
|
||||
/// Allows defining an `#[alloc_error_handler]`.
|
||||
(unstable, alloc_error_handler, "1.29.0", Some(51540)),
|
||||
/// The `apxf` target feature on x86
|
||||
(unstable, apx_target_feature, "1.88.0", Some(139284)),
|
||||
/// Allows inherent and trait methods with arbitrary self types.
|
||||
(unstable, arbitrary_self_types, "1.23.0", Some(44874)),
|
||||
/// Allows inherent and trait methods with arbitrary self types that are raw pointers.
|
||||
(unstable, arbitrary_self_types_pointers, "1.83.0", Some(44874)),
|
||||
/// Target features on arm.
|
||||
(unstable, arm_target_feature, "1.27.0", Some(150246)),
|
||||
/// Enables experimental inline assembly support for additional architectures.
|
||||
(unstable, asm_experimental_arch, "1.58.0", Some(93335)),
|
||||
/// Enables experimental register support in inline assembly.
|
||||
|
|
@ -392,8 +363,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`.
|
||||
|
|
@ -408,6 +377,8 @@ declare_features! (
|
|||
(unstable, async_trait_bounds, "1.85.0", Some(62290)),
|
||||
/// Allows using Intel AVX10 target features and intrinsics
|
||||
(unstable, avx10_target_feature, "1.88.0", Some(138843)),
|
||||
/// Target features on bpf.
|
||||
(unstable, bpf_target_feature, "1.54.0", Some(150247)),
|
||||
/// Allows using C-variadics.
|
||||
(unstable, c_variadic, "1.34.0", Some(44930)),
|
||||
/// Allows defining c-variadic naked functions with any extern ABI that is allowed
|
||||
|
|
@ -468,6 +439,8 @@ declare_features! (
|
|||
/// Allows function attribute `#[coverage(on/off)]`, to control coverage
|
||||
/// instrumentation of that function.
|
||||
(unstable, coverage_attribute, "1.74.0", Some(84605)),
|
||||
/// Target features on csky.
|
||||
(unstable, csky_target_feature, "1.73.0", Some(150248)),
|
||||
/// Allows non-builtin attributes in inner attribute position.
|
||||
(unstable, custom_inner_attributes, "1.30.0", Some(54726)),
|
||||
/// Allows custom test frameworks with `#![test_runner]` and `#[test_case]`.
|
||||
|
|
@ -495,6 +468,8 @@ declare_features! (
|
|||
(incomplete, effective_target_features, "1.91.0", Some(143352)),
|
||||
/// Allows the .use postfix syntax `x.use` and use closures `use |x| { ... }`
|
||||
(incomplete, ergonomic_clones, "1.87.0", Some(132290)),
|
||||
/// ermsb target feature on x86.
|
||||
(unstable, ermsb_target_feature, "1.49.0", Some(150249)),
|
||||
/// Allows exhaustive pattern matching on types that contain uninhabited types.
|
||||
(unstable, exhaustive_patterns, "1.13.0", Some(51085)),
|
||||
/// Disallows `extern` without an explicit ABI.
|
||||
|
|
@ -541,6 +516,8 @@ declare_features! (
|
|||
(incomplete, guard_patterns, "1.85.0", Some(129967)),
|
||||
/// Allows using `..=X` as a patterns in slices.
|
||||
(unstable, half_open_range_patterns_in_slices, "1.66.0", Some(67264)),
|
||||
/// Target features on hexagon.
|
||||
(unstable, hexagon_target_feature, "1.27.0", Some(150250)),
|
||||
/// Allows `if let` guard in match arms.
|
||||
(unstable, if_let_guard, "1.47.0", Some(51114)),
|
||||
/// Allows `impl Trait` to be used inside associated types (RFC 2515).
|
||||
|
|
@ -555,6 +532,8 @@ declare_features! (
|
|||
(incomplete, inherent_associated_types, "1.52.0", Some(8995)),
|
||||
/// Allows using `pointer` and `reference` in intra-doc links
|
||||
(unstable, intra_doc_pointers, "1.51.0", Some(80896)),
|
||||
/// lahfsahf target feature on x86.
|
||||
(unstable, lahfsahf_target_feature, "1.78.0", Some(150251)),
|
||||
/// Allows setting the threshold for the `large_assignments` lint.
|
||||
(unstable, large_assignments, "1.52.0", Some(83518)),
|
||||
/// Allow to have type alias types for inter-crate use.
|
||||
|
|
@ -562,8 +541,12 @@ declare_features! (
|
|||
/// Allows using `#[link(kind = "link-arg", name = "...")]`
|
||||
/// to pass custom arguments to the linker.
|
||||
(unstable, link_arg_attribute, "1.76.0", Some(99427)),
|
||||
/// Target features on loongarch.
|
||||
(unstable, loongarch_target_feature, "1.73.0", Some(150252)),
|
||||
/// Allows fused `loop`/`match` for direct intraprocedural jumps.
|
||||
(incomplete, loop_match, "1.90.0", Some(132306)),
|
||||
/// Target features on m68k.
|
||||
(unstable, m68k_target_feature, "1.85.0", Some(134328)),
|
||||
/// Allow `macro_rules!` attribute rules
|
||||
(unstable, macro_attr, "1.91.0", Some(143547)),
|
||||
/// Allow `macro_rules!` derive rules
|
||||
|
|
@ -580,8 +563,12 @@ declare_features! (
|
|||
/// standard library until the soundness issues with specialization
|
||||
/// are fixed.
|
||||
(unstable, min_specialization, "1.7.0", Some(31844)),
|
||||
/// Target features on mips.
|
||||
(unstable, mips_target_feature, "1.27.0", Some(150253)),
|
||||
/// Allows qualified paths in struct expressions, struct patterns and tuple struct patterns.
|
||||
(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 `#[must_not_suspend]` attribute.
|
||||
(unstable, must_not_suspend, "1.57.0", Some(83310)),
|
||||
/// Allows `mut ref` and `mut ref mut` identifier patterns.
|
||||
|
|
@ -606,6 +593,8 @@ declare_features! (
|
|||
(unstable, non_exhaustive_omitted_patterns_lint, "1.57.0", Some(89554)),
|
||||
/// Allows `for<T>` binders in where-clauses
|
||||
(incomplete, non_lifetime_binders, "1.69.0", Some(108185)),
|
||||
/// Target feaures on nvptx.
|
||||
(unstable, nvptx_target_feature, "1.91.0", Some(150254)),
|
||||
/// Allows using enums in offset_of!
|
||||
(unstable, offset_of_enum, "1.75.0", Some(120141)),
|
||||
/// Allows using fields with slice type in offset_of!
|
||||
|
|
@ -618,6 +607,10 @@ declare_features! (
|
|||
(incomplete, pin_ergonomics, "1.83.0", Some(130494)),
|
||||
/// Allows postfix match `expr.match { ... }`
|
||||
(unstable, postfix_match, "1.79.0", Some(121618)),
|
||||
/// Target features on powerpc.
|
||||
(unstable, powerpc_target_feature, "1.27.0", Some(150255)),
|
||||
/// The prfchw target feature on x86.
|
||||
(unstable, prfchw_target_feature, "1.78.0", Some(150256)),
|
||||
/// Allows macro attributes on expressions, statements and non-inline modules.
|
||||
(unstable, proc_macro_hygiene, "1.30.0", Some(54727)),
|
||||
/// Allows the use of raw-dylibs on ELF platforms
|
||||
|
|
@ -633,12 +626,20 @@ declare_features! (
|
|||
(unstable, repr_simd, "1.4.0", Some(27731)),
|
||||
/// Allows bounding the return type of AFIT/RPITIT.
|
||||
(unstable, return_type_notation, "1.70.0", Some(109417)),
|
||||
/// Target features on riscv.
|
||||
(unstable, riscv_target_feature, "1.45.0", Some(150257)),
|
||||
/// The rtm target feature on x86.
|
||||
(unstable, rtm_target_feature, "1.35.0", Some(150258)),
|
||||
/// Allows `extern "rust-cold"`.
|
||||
(unstable, rust_cold_cc, "1.63.0", Some(97544)),
|
||||
/// Target features on s390x.
|
||||
(unstable, s390x_target_feature, "1.82.0", Some(150259)),
|
||||
/// Allows the use of the `sanitize` attribute.
|
||||
(unstable, sanitize, "1.91.0", Some(39699)),
|
||||
/// Allows the use of SIMD types in functions declared in `extern` blocks.
|
||||
(unstable, simd_ffi, "1.0.0", Some(27731)),
|
||||
/// Target features on sparc.
|
||||
(unstable, sparc_target_feature, "1.84.0", Some(132783)),
|
||||
/// Allows specialization of implementations (RFC 1210).
|
||||
(incomplete, specialization, "1.7.0", Some(31844)),
|
||||
/// Allows using `#[rustc_align_static(...)]` on static items.
|
||||
|
|
@ -647,8 +648,6 @@ declare_features! (
|
|||
(unstable, stmt_expr_attributes, "1.6.0", Some(15701)),
|
||||
/// Allows lints part of the strict provenance effort.
|
||||
(unstable, strict_provenance_lints, "1.61.0", Some(130351)),
|
||||
/// Allows string patterns to dereference values to match them.
|
||||
(unstable, string_deref_patterns, "1.67.0", Some(87121)),
|
||||
/// Allows `super let` statements.
|
||||
(unstable, super_let, "1.88.0", Some(139076)),
|
||||
/// Allows subtrait items to shadow supertrait items.
|
||||
|
|
@ -685,10 +684,14 @@ declare_features! (
|
|||
(internal, unsized_fn_params, "1.49.0", Some(48055)),
|
||||
/// Allows using the `#[used(linker)]` (or `#[used(compiler)]`) attribute.
|
||||
(unstable, used_with_arg, "1.60.0", Some(93798)),
|
||||
/// Target features on wasm.
|
||||
(unstable, wasm_target_feature, "1.30.0", Some(150260)),
|
||||
/// Allows use of attributes in `where` clauses.
|
||||
(unstable, where_clause_attrs, "1.87.0", Some(115590)),
|
||||
/// Allows use of x86 `AMX` target-feature attributes and intrinsics
|
||||
(unstable, x86_amx_intrinsics, "1.81.0", Some(126622)),
|
||||
/// The x87 target feature on x86.
|
||||
(unstable, x87_target_feature, "1.85.0", Some(150261)),
|
||||
/// Allows use of the `xop` target-feature
|
||||
(unstable, xop_target_feature, "1.81.0", Some(127208)),
|
||||
/// Allows `do yeet` expressions
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -60,7 +60,17 @@ impl InlineAttr {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq, HashStable_Generic)]
|
||||
#[derive(
|
||||
Copy,
|
||||
Clone,
|
||||
Encodable,
|
||||
Decodable,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
HashStable_Generic,
|
||||
PrintAttribute
|
||||
)]
|
||||
pub enum InstructionSetAttr {
|
||||
ArmA32,
|
||||
ArmT32,
|
||||
|
|
@ -202,83 +212,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`.
|
||||
///
|
||||
|
|
@ -703,6 +636,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 },
|
||||
|
||||
|
|
@ -807,6 +746,9 @@ pub enum AttributeKind {
|
|||
/// Represents `#[inline]` and `#[rustc_force_inline]`.
|
||||
Inline(InlineAttr, Span),
|
||||
|
||||
/// Represents `#[instruction_set]`
|
||||
InstructionSet(InstructionSetAttr),
|
||||
|
||||
/// Represents `#[link]`.
|
||||
Link(ThinVec<LinkEntry>, Span),
|
||||
|
||||
|
|
@ -952,6 +894,9 @@ pub enum AttributeKind {
|
|||
/// Represents `#[rustc_main]`.
|
||||
RustcMain,
|
||||
|
||||
/// Represents `#[rustc_must_implement_one_of]`
|
||||
RustcMustImplementOneOf { attr_span: Span, fn_names: ThinVec<Ident> },
|
||||
|
||||
/// Represents `#[rustc_never_returns_null_ptr]`
|
||||
RustcNeverReturnsNullPointer,
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ impl AttributeKind {
|
|||
AsPtr(..) => Yes,
|
||||
AutomaticallyDerived(..) => Yes,
|
||||
BodyStability { .. } => No,
|
||||
CfgAttrTrace => Yes,
|
||||
CfgTrace(..) => Yes,
|
||||
CfiEncoding { .. } => Yes,
|
||||
Coinductive(..) => No,
|
||||
Cold(..) => No,
|
||||
|
|
@ -54,6 +56,7 @@ impl AttributeKind {
|
|||
Fundamental { .. } => Yes,
|
||||
Ignore { .. } => No,
|
||||
Inline(..) => No,
|
||||
InstructionSet(..) => No,
|
||||
Link(..) => No,
|
||||
LinkName { .. } => Yes, // Needed for rustdoc
|
||||
LinkOrdinal { .. } => No,
|
||||
|
|
@ -101,6 +104,7 @@ impl AttributeKind {
|
|||
RustcLintQueryInstability => Yes,
|
||||
RustcLintUntrackedQueryInformation => Yes,
|
||||
RustcMain => No,
|
||||
RustcMustImplementOneOf { .. } => No,
|
||||
RustcNeverReturnsNullPointer => Yes,
|
||||
RustcNoImplicitAutorefs => Yes,
|
||||
RustcObjectLifetimeDefault => No,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -563,29 +563,6 @@ pub enum Res<Id = hir::HirId> {
|
|||
/// to get the underlying type.
|
||||
alias_to: DefId,
|
||||
|
||||
/// Whether the `Self` type is disallowed from mentioning generics (i.e. when used in an
|
||||
/// anonymous constant).
|
||||
///
|
||||
/// HACK(min_const_generics): self types also have an optional requirement to **not**
|
||||
/// mention any generic parameters to allow the following with `min_const_generics`:
|
||||
/// ```
|
||||
/// # struct Foo;
|
||||
/// impl Foo { fn test() -> [u8; size_of::<Self>()] { todo!() } }
|
||||
///
|
||||
/// struct Bar([u8; baz::<Self>()]);
|
||||
/// const fn baz<T>() -> usize { 10 }
|
||||
/// ```
|
||||
/// We do however allow `Self` in repeat expression even if it is generic to not break code
|
||||
/// which already works on stable while causing the `const_evaluatable_unchecked` future
|
||||
/// compat lint:
|
||||
/// ```
|
||||
/// fn foo<T>() {
|
||||
/// let _bar = [1_u8; size_of::<*mut T>()];
|
||||
/// }
|
||||
/// ```
|
||||
// FIXME(generic_const_exprs): Remove this bodge once that feature is stable.
|
||||
forbid_generic: bool,
|
||||
|
||||
/// Is this within an `impl Foo for bar`?
|
||||
is_trait_impl: bool,
|
||||
},
|
||||
|
|
@ -910,8 +887,8 @@ impl<Id> Res<Id> {
|
|||
Res::PrimTy(id) => Res::PrimTy(id),
|
||||
Res::Local(id) => Res::Local(map(id)),
|
||||
Res::SelfTyParam { trait_ } => Res::SelfTyParam { trait_ },
|
||||
Res::SelfTyAlias { alias_to, forbid_generic, is_trait_impl } => {
|
||||
Res::SelfTyAlias { alias_to, forbid_generic, is_trait_impl }
|
||||
Res::SelfTyAlias { alias_to, is_trait_impl } => {
|
||||
Res::SelfTyAlias { alias_to, is_trait_impl }
|
||||
}
|
||||
Res::ToolMod => Res::ToolMod,
|
||||
Res::NonMacroAttr(attr_kind) => Res::NonMacroAttr(attr_kind),
|
||||
|
|
@ -926,8 +903,8 @@ impl<Id> Res<Id> {
|
|||
Res::PrimTy(id) => Res::PrimTy(id),
|
||||
Res::Local(id) => Res::Local(map(id)?),
|
||||
Res::SelfTyParam { trait_ } => Res::SelfTyParam { trait_ },
|
||||
Res::SelfTyAlias { alias_to, forbid_generic, is_trait_impl } => {
|
||||
Res::SelfTyAlias { alias_to, forbid_generic, is_trait_impl }
|
||||
Res::SelfTyAlias { alias_to, is_trait_impl } => {
|
||||
Res::SelfTyAlias { alias_to, is_trait_impl }
|
||||
}
|
||||
Res::ToolMod => Res::ToolMod,
|
||||
Res::NonMacroAttr(attr_kind) => Res::NonMacroAttr(attr_kind),
|
||||
|
|
|
|||
|
|
@ -150,10 +150,13 @@ impl From<Ident> for LifetimeSyntax {
|
|||
/// `LifetimeSource::OutlivesBound` or `LifetimeSource::PreciseCapturing`
|
||||
/// — there's no way to "elide" these lifetimes.
|
||||
#[derive(Debug, Copy, Clone, HashStable_Generic)]
|
||||
// Raise the aligement to at least 4 bytes - this is relied on in other parts of the compiler(for pointer tagging):
|
||||
// https://github.com/rust-lang/rust/blob/ce5fdd7d42aba9a2925692e11af2bd39cf37798a/compiler/rustc_data_structures/src/tagged_ptr.rs#L163
|
||||
// Removing this `repr(4)` will cause the compiler to not build on platforms like `m68k` Linux, where the aligement of u32 and usize is only 2.
|
||||
// Since `repr(align)` may only raise aligement, this has no effect on platforms where the aligement is already sufficient.
|
||||
// Raise the alignment to at least 4 bytes.
|
||||
// This is relied on in other parts of the compiler (for pointer tagging):
|
||||
// <https://github.com/rust-lang/rust/blob/ce5fdd7d42aba9a2925692e11af2bd39cf37798a/compiler/rustc_data_structures/src/tagged_ptr.rs#L163>
|
||||
// Removing this `repr(4)` will cause the compiler to not build on platforms
|
||||
// like `m68k` Linux, where the alignment of u32 and usize is only 2.
|
||||
// Since `repr(align)` may only raise alignment, this has no effect on
|
||||
// platforms where the alignment is already sufficient.
|
||||
#[repr(align(4))]
|
||||
pub struct Lifetime {
|
||||
#[stable_hasher(ignore)]
|
||||
|
|
@ -420,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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -437,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> {
|
||||
|
|
@ -472,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;
|
||||
}
|
||||
|
||||
|
|
@ -491,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 = ...`).
|
||||
|
|
@ -516,11 +511,13 @@ 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),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, HashStable_Generic)]
|
||||
|
|
@ -566,7 +563,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,
|
||||
}
|
||||
}
|
||||
|
|
@ -1193,7 +1190,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,
|
||||
}
|
||||
|
||||
|
|
@ -1209,7 +1206,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),
|
||||
|
|
@ -1219,7 +1216,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 }))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1324,7 +1325,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() {
|
||||
|
|
@ -1340,7 +1341,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,
|
||||
}
|
||||
}
|
||||
|
|
@ -1361,6 +1362,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:?}"),
|
||||
}
|
||||
}
|
||||
|
|
@ -1376,13 +1378,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 {
|
||||
|
|
@ -1462,11 +1471,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)
|
||||
|
|
@ -1502,11 +1506,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)
|
||||
|
|
@ -1941,7 +1940,6 @@ pub enum PatExprKind<'hir> {
|
|||
// once instead of matching on unop neg expressions everywhere.
|
||||
negated: bool,
|
||||
},
|
||||
ConstBlock(ConstBlock),
|
||||
/// A path pattern for a unit struct/variant or a (maybe-associated) constant.
|
||||
Path(QPath<'hir>),
|
||||
}
|
||||
|
|
@ -3372,7 +3370,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 = ()> {
|
||||
|
|
@ -3711,7 +3709,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 {
|
||||
|
|
|
|||
|
|
@ -792,7 +792,6 @@ pub fn walk_pat_expr<'v, V: Visitor<'v>>(visitor: &mut V, expr: &'v PatExpr<'v>)
|
|||
try_visit!(visitor.visit_id(*hir_id));
|
||||
match kind {
|
||||
PatExprKind::Lit { lit, negated } => visitor.visit_lit(*hir_id, *lit, *negated),
|
||||
PatExprKind::ConstBlock(c) => visitor.visit_inline_const(c),
|
||||
PatExprKind::Path(qpath) => visitor.visit_qpath(qpath, *hir_id, *span),
|
||||
}
|
||||
}
|
||||
|
|
@ -1069,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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1079,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()));
|
||||
|
||||
|
|
@ -1091,9 +1094,16 @@ 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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ pub mod pat_util;
|
|||
mod stability;
|
||||
mod stable_hash_impls;
|
||||
mod target;
|
||||
mod version;
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
For high-level intro to how type checking works in rustc, see the
|
||||
[type checking] chapter of the [rustc dev guide].
|
||||
[hir typeck] chapter of the [rustc dev guide].
|
||||
|
||||
[type checking]: https://rustc-dev-guide.rust-lang.org/type-checking.html
|
||||
[hir typeck]: https://rustc-dev-guide.rust-lang.org/hir-typeck/summary.html
|
||||
[rustc dev guide]: https://rustc-dev-guide.rust-lang.org/
|
||||
|
|
|
|||
|
|
@ -208,14 +208,6 @@ hir_analysis_field_already_declared_previous_nested =
|
|||
.previous_decl_label = `{$field_name}` first declared here in this unnamed field
|
||||
.previous_nested_field_decl_note = field `{$field_name}` first declared here
|
||||
|
||||
hir_analysis_function_not_found_in_trait = function not found in this trait
|
||||
|
||||
hir_analysis_function_not_have_default_implementation = function doesn't have a default implementation
|
||||
.note = required by this annotation
|
||||
|
||||
hir_analysis_functions_names_duplicated = functions names are duplicated
|
||||
.note = all `#[rustc_must_implement_one_of]` arguments must be unique
|
||||
|
||||
hir_analysis_generic_args_on_overridden_impl = could not resolve generic parameters on overridden impl
|
||||
|
||||
hir_analysis_impl_not_marked_default = `{$ident}` specializes an item from a parent `impl`, but that item is not marked `default`
|
||||
|
|
@ -381,16 +373,6 @@ hir_analysis_missing_type_params =
|
|||
*[other] parameters
|
||||
} must be specified on the object type
|
||||
|
||||
hir_analysis_must_be_name_of_associated_function = must be a name of an associated function
|
||||
|
||||
hir_analysis_must_implement_not_function = not a function
|
||||
|
||||
hir_analysis_must_implement_not_function_note = all `#[rustc_must_implement_one_of]` arguments must be associated function names
|
||||
|
||||
hir_analysis_must_implement_not_function_span_note = required by this annotation
|
||||
|
||||
hir_analysis_must_implement_one_of_attribute = the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args
|
||||
|
||||
hir_analysis_no_variant_named = no variant named `{$ident}` found for enum `{$ty}`
|
||||
|
||||
hir_analysis_not_supported_delegation = {$descr}
|
||||
|
|
|
|||
|
|
@ -1340,9 +1340,7 @@ fn check_impl_items_against_trait<'tcx>(
|
|||
}
|
||||
|
||||
if let Some(missing_items) = must_implement_one_of {
|
||||
let attr_span = tcx
|
||||
.get_attr(trait_ref.def_id, sym::rustc_must_implement_one_of)
|
||||
.map(|attr| attr.span());
|
||||
let attr_span = find_attr!(tcx.get_all_attrs(trait_ref.def_id), AttributeKind::RustcMustImplementOneOf {attr_span, ..} => *attr_span);
|
||||
|
||||
missing_items_must_implement_one_of_err(
|
||||
tcx,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use rustc_abi::ExternAbi;
|
|||
use rustc_errors::DiagMessage;
|
||||
use rustc_hir::{self as hir, LangItem};
|
||||
use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, Const, Ty, TyCtxt};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
|
||||
|
|
@ -315,7 +315,17 @@ pub(crate) fn check_intrinsic_type(
|
|||
let type_id = tcx.type_of(tcx.lang_items().type_id().unwrap()).instantiate_identity();
|
||||
(0, 0, vec![type_id, type_id], tcx.types.bool)
|
||||
}
|
||||
sym::offload => (3, 0, vec![param(0), param(1)], param(2)),
|
||||
sym::offload => (
|
||||
3,
|
||||
0,
|
||||
vec![
|
||||
param(0),
|
||||
Ty::new_array_with_const_len(tcx, tcx.types.u32, Const::from_target_usize(tcx, 3)),
|
||||
Ty::new_array_with_const_len(tcx, tcx.types.u32, Const::from_target_usize(tcx, 3)),
|
||||
param(1),
|
||||
],
|
||||
param(2),
|
||||
),
|
||||
sym::offset => (2, 0, vec![param(0), param(1)], param(0)),
|
||||
sym::arith_offset => (
|
||||
1,
|
||||
|
|
|
|||
|
|
@ -701,31 +701,25 @@ fn resolve_local<'tcx>(
|
|||
/// Note: ET is intended to match "rvalues or places based on rvalues".
|
||||
fn record_subexpr_extended_temp_scopes(
|
||||
scope_tree: &mut ScopeTree,
|
||||
mut expr: &hir::Expr<'_>,
|
||||
expr: &hir::Expr<'_>,
|
||||
lifetime: Option<Scope>,
|
||||
) {
|
||||
debug!(?expr, ?lifetime);
|
||||
// Note: give all the expressions matching `ET` with the
|
||||
// extended temporary lifetime, not just the innermost rvalue,
|
||||
// because in MIR building if we must compile e.g., `*rvalue()`
|
||||
// into a temporary, we request the temporary scope of the
|
||||
// outer expression.
|
||||
|
||||
loop {
|
||||
// Note: give all the expressions matching `ET` with the
|
||||
// extended temporary lifetime, not just the innermost rvalue,
|
||||
// because in MIR building if we must compile e.g., `*rvalue()`
|
||||
// into a temporary, we request the temporary scope of the
|
||||
// outer expression.
|
||||
scope_tree.record_extended_temp_scope(expr.hir_id.local_id, lifetime);
|
||||
|
||||
scope_tree.record_extended_temp_scope(expr.hir_id.local_id, lifetime);
|
||||
|
||||
match expr.kind {
|
||||
hir::ExprKind::AddrOf(_, _, subexpr)
|
||||
| hir::ExprKind::Unary(hir::UnOp::Deref, subexpr)
|
||||
| hir::ExprKind::Field(subexpr, _)
|
||||
| hir::ExprKind::Index(subexpr, _, _) => {
|
||||
expr = subexpr;
|
||||
}
|
||||
_ => {
|
||||
return;
|
||||
}
|
||||
match expr.kind {
|
||||
hir::ExprKind::AddrOf(_, _, subexpr)
|
||||
| hir::ExprKind::Unary(hir::UnOp::Deref, subexpr)
|
||||
| hir::ExprKind::Field(subexpr, _)
|
||||
| hir::ExprKind::Index(subexpr, _, _) => {
|
||||
record_subexpr_extended_temp_scopes(scope_tree, subexpr, lifetime);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -327,7 +327,7 @@ pub(crate) fn check_trait_item<'tcx>(
|
|||
|
||||
let mut res = Ok(());
|
||||
|
||||
if matches!(tcx.def_kind(def_id), DefKind::AssocFn) {
|
||||
if tcx.def_kind(def_id) == DefKind::AssocFn {
|
||||
for &assoc_ty_def_id in
|
||||
tcx.associated_types_for_impl_traits_in_associated_fn(def_id.to_def_id())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ use std::ops::Bound;
|
|||
use rustc_abi::{ExternAbi, Size};
|
||||
use rustc_ast::Recovered;
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
||||
use rustc_data_structures::unord::UnordMap;
|
||||
use rustc_errors::{
|
||||
Applicability, Diag, DiagCtxtHandle, E0228, ErrorGuaranteed, StashKey, struct_span_code_err,
|
||||
};
|
||||
|
|
@ -916,84 +915,15 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
|
|||
} else {
|
||||
ty::trait_def::TraitSpecializationKind::None
|
||||
};
|
||||
let must_implement_one_of = attrs
|
||||
.iter()
|
||||
.find(|attr| attr.has_name(sym::rustc_must_implement_one_of))
|
||||
// Check that there are at least 2 arguments of `#[rustc_must_implement_one_of]`
|
||||
// and that they are all identifiers
|
||||
.and_then(|attr| match attr.meta_item_list() {
|
||||
Some(items) if items.len() < 2 => {
|
||||
tcx.dcx().emit_err(errors::MustImplementOneOfAttribute { span: attr.span() });
|
||||
|
||||
None
|
||||
}
|
||||
Some(items) => items
|
||||
.into_iter()
|
||||
.map(|item| item.ident().ok_or(item.span()))
|
||||
.collect::<Result<Box<[_]>, _>>()
|
||||
.map_err(|span| {
|
||||
tcx.dcx().emit_err(errors::MustBeNameOfAssociatedFunction { span });
|
||||
})
|
||||
.ok()
|
||||
.zip(Some(attr.span())),
|
||||
// Error is reported by `rustc_attr!`
|
||||
None => None,
|
||||
})
|
||||
// Check that all arguments of `#[rustc_must_implement_one_of]` reference
|
||||
// functions in the trait with default implementations
|
||||
.and_then(|(list, attr_span)| {
|
||||
let errors = list.iter().filter_map(|ident| {
|
||||
let item = tcx
|
||||
.associated_items(def_id)
|
||||
.filter_by_name_unhygienic(ident.name)
|
||||
.find(|item| item.ident(tcx) == *ident);
|
||||
|
||||
match item {
|
||||
Some(item) if matches!(item.kind, ty::AssocKind::Fn { .. }) => {
|
||||
if !item.defaultness(tcx).has_value() {
|
||||
tcx.dcx().emit_err(errors::FunctionNotHaveDefaultImplementation {
|
||||
span: tcx.def_span(item.def_id),
|
||||
note_span: attr_span,
|
||||
});
|
||||
|
||||
return Some(());
|
||||
}
|
||||
|
||||
return None;
|
||||
}
|
||||
Some(item) => {
|
||||
tcx.dcx().emit_err(errors::MustImplementNotFunction {
|
||||
span: tcx.def_span(item.def_id),
|
||||
span_note: errors::MustImplementNotFunctionSpanNote { span: attr_span },
|
||||
note: errors::MustImplementNotFunctionNote {},
|
||||
});
|
||||
}
|
||||
None => {
|
||||
tcx.dcx().emit_err(errors::FunctionNotFoundInTrait { span: ident.span });
|
||||
}
|
||||
}
|
||||
|
||||
Some(())
|
||||
});
|
||||
|
||||
(errors.count() == 0).then_some(list)
|
||||
})
|
||||
// Check for duplicates
|
||||
.and_then(|list| {
|
||||
let mut set: UnordMap<Symbol, Span> = Default::default();
|
||||
let mut no_dups = true;
|
||||
|
||||
for ident in &*list {
|
||||
if let Some(dup) = set.insert(ident.name, ident.span) {
|
||||
tcx.dcx()
|
||||
.emit_err(errors::FunctionNamesDuplicated { spans: vec![dup, ident.span] });
|
||||
|
||||
no_dups = false;
|
||||
}
|
||||
}
|
||||
|
||||
no_dups.then_some(list)
|
||||
});
|
||||
let must_implement_one_of = find_attr!(
|
||||
attrs,
|
||||
AttributeKind::RustcMustImplementOneOf { fn_names, .. } =>
|
||||
fn_names
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect::<Box<[_]>>()
|
||||
);
|
||||
|
||||
let deny_explicit_impl = find_attr!(attrs, AttributeKind::DenyExplicitImpl(_));
|
||||
let implement_via_object = !find_attr!(attrs, AttributeKind::DoNotImplementViaObject(_));
|
||||
|
|
@ -1549,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)
|
||||
}
|
||||
|
||||
|
|
@ -1623,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()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -543,7 +543,7 @@ pub(super) fn explicit_predicates_of<'tcx>(
|
|||
}
|
||||
}
|
||||
} else {
|
||||
if matches!(def_kind, DefKind::AnonConst)
|
||||
if def_kind == DefKind::AnonConst
|
||||
&& tcx.features().generic_const_exprs()
|
||||
&& let Some(defaulted_param_def_id) =
|
||||
tcx.hir_opt_const_param_default_param_def_id(tcx.local_def_id_to_hir_id(def_id))
|
||||
|
|
|
|||
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