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:
The rustc-josh-sync Cronjob Bot 2026-01-08 04:21:00 +00:00
commit 09c878a6ef
2485 changed files with 44385 additions and 24185 deletions

View file

@ -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

View file

@ -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]]

View file

@ -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.

View file

@ -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?

View file

@ -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

View 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(()),
},
}
}
}

View file

@ -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)
}

View file

@ -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()))
}
}

View file

@ -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,

View file

@ -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

View file

@ -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,

View file

@ -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);

View file

@ -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

View file

@ -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)]

View file

@ -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 {

View file

@ -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()),
);

View file

@ -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),
),
})
}
});

View file

@ -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(&param.ty, itctx)
self.lower_ty(&param.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

View file

@ -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 })
}
}

View file

@ -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(

View file

@ -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

View file

@ -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");

View file

@ -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,

View file

@ -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

View file

@ -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,

View file

@ -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,

View file

@ -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))
}
}

View file

@ -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;

View file

@ -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 {

View file

@ -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.

View file

@ -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)
}

View 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));
}
}
}

View file

@ -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 {

View file

@ -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;

View file

@ -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())

View file

@ -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));

View file

@ -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,
}

View file

@ -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,

View file

@ -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);

View file

@ -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 {

View file

@ -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, _) => {

View file

@ -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);

View file

@ -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,

View file

@ -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(())

View file

@ -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,

View file

@ -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.

View file

@ -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)

View file

@ -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 {

View file

@ -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) };

View file

@ -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

View file

@ -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

View file

@ -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);
}

View file

@ -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)));
}

View file

@ -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,

View file

@ -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,
];

View file

@ -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(),

View file

@ -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)]

View file

@ -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>(

View file

@ -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);
}

View file

@ -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())
}
}

View file

@ -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,

View file

@ -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)),

View file

@ -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)

View file

@ -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;
}

View file

@ -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,
});
}

View file

@ -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);

View file

@ -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();

View file

@ -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 {

View file

@ -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`.

View file

@ -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;
}
}

View file

@ -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 => {

View file

@ -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;

View file

@ -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.

View file

@ -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;
}

View file

@ -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())?;

View file

@ -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 {

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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));
}

View file

@ -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 }));
}
}
}
};

View file

@ -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

View file

@ -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

View file

@ -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,

View file

@ -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,

View file

@ -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,
);

View file

@ -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),

View file

@ -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)]

View file

@ -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 {

View file

@ -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
}
}

View file

@ -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);

View file

@ -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/

View file

@ -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}

View file

@ -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,

View file

@ -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,

View file

@ -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);
}
_ => {}
}
}

View file

@ -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())
{

View file

@ -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()
{

View file

@ -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