Merge ref '44a5b55557' from rust-lang/rust

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

Upstream ref: rust-lang/rust@44a5b55557
Filtered ref: rust-lang/rustc-dev-guide@df5b7c44b8
Upstream diff: 85c8ff69cb...44a5b55557

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-12 04:29:34 +00:00
commit d53ec2a0c8
2178 changed files with 26494 additions and 15400 deletions

View file

@ -289,7 +289,7 @@ jobs:
fi
# Get closest bors merge commit
PARENT_COMMIT=`git rev-list --author='bors <bors@rust-lang.org>' -n1 --first-parent HEAD^1`
PARENT_COMMIT=`git rev-list --author='122020455+rust-bors\[bot\]@users.noreply.github.com' -n1 --first-parent HEAD^1`
./build/citool/debug/citool postprocess-metrics \
--job-name ${CI_JOB_NAME} \

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

@ -182,19 +182,6 @@ version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
[[package]]
name = "askama"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4"
dependencies = [
"askama_derive 0.14.0",
"itoa",
"percent-encoding",
"serde",
"serde_json",
]
[[package]]
name = "askama"
version = "0.15.1"
@ -208,30 +195,13 @@ dependencies = [
"serde_json",
]
[[package]]
name = "askama_derive"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f"
dependencies = [
"askama_parser 0.14.0",
"basic-toml",
"memchr",
"proc-macro2",
"quote",
"rustc-hash 2.1.1",
"serde",
"serde_derive",
"syn 2.0.110",
]
[[package]]
name = "askama_derive"
version = "0.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ba5e7259a1580c61571e3116ebaaa01e3c001b2132b17c4cc5c70780ca3e994"
dependencies = [
"askama_parser 0.15.1",
"askama_parser",
"basic-toml",
"memchr",
"proc-macro2",
@ -248,19 +218,7 @@ version = "0.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "236ce20b77cb13506eaf5024899f4af6e12e8825f390bd943c4c37fd8f322e46"
dependencies = [
"askama_derive 0.15.1",
]
[[package]]
name = "askama_parser"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358"
dependencies = [
"memchr",
"serde",
"serde_derive",
"winnow 0.7.13",
"askama_derive",
]
[[package]]
@ -445,22 +403,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]]
@ -676,7 +633,7 @@ name = "clippy"
version = "0.1.94"
dependencies = [
"anstream",
"askama 0.14.0",
"askama",
"cargo_metadata 0.18.1",
"clippy_config",
"clippy_lints",
@ -1567,7 +1524,7 @@ name = "generate-copyright"
version = "0.1.0"
dependencies = [
"anyhow",
"askama 0.15.1",
"askama",
"cargo_metadata 0.21.0",
"serde",
"serde_json",
@ -2232,9 +2189,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",
@ -2242,9 +2199,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",
]
@ -3413,9 +3370,9 @@ checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
[[package]]
name = "rustc-literal-escaper"
version = "0.0.5"
version = "0.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4ee29da77c5a54f42697493cd4c9b9f31b74df666a6c04dfc4fde77abe0438b"
checksum = "8be87abb9e40db7466e0681dc8ecd9dcfd40360cb10b4c8fe24a7c4c3669b198"
[[package]]
name = "rustc-main"
@ -4422,6 +4379,7 @@ dependencies = [
"rustc_errors",
"rustc_fluent_macro",
"rustc_hir",
"rustc_index",
"rustc_macros",
"rustc_middle",
"rustc_session",
@ -4913,7 +4871,7 @@ name = "rustdoc"
version = "0.0.0"
dependencies = [
"arrayvec",
"askama 0.15.1",
"askama",
"base64",
"expect-test",
"indexmap",
@ -5659,6 +5617,7 @@ dependencies = [
"build_helper",
"cargo_metadata 0.21.0",
"fluent-syntax",
"globset",
"ignore",
"miropt-test-tools",
"regex",
@ -6222,9 +6181,9 @@ dependencies = [
[[package]]
name = "wasi-preview1-component-adapter-provider"
version = "38.0.4"
version = "40.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ec3ef3783e18f2457796ed91b1e6c2adc46f2905f740d1527ab3053fe8e5682"
checksum = "bb5e2b9858989c3a257de4ca169977f4f79897b64e4f482f188f4fcf8ac557d1"
[[package]]
name = "wasm-bindgen"
@ -6273,17 +6232,18 @@ dependencies = [
[[package]]
name = "wasm-component-ld"
version = "0.5.19"
version = "0.5.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bfc50dd0b883d841bc1dba5ff7020ca52fa7b2c3bb1266d8bf6a09dd032e115"
checksum = "846d20ed66ae37b7a237e36dfcd2fdc979eae82a46cdb0586f9bba80782fd789"
dependencies = [
"anyhow",
"clap",
"clap_lex",
"lexopt",
"libc",
"tempfile",
"wasi-preview1-component-adapter-provider",
"wasmparser 0.241.2",
"wasmparser 0.243.0",
"wat",
"windows-sys 0.61.2",
"winsplit",
@ -6310,24 +6270,24 @@ dependencies = [
[[package]]
name = "wasm-encoder"
version = "0.241.2"
version = "0.243.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e01164c9dda68301e34fdae536c23ed6fe90ce6d97213ccc171eebbd3d02d6b8"
checksum = "c55db9c896d70bd9fa535ce83cd4e1f2ec3726b0edd2142079f594fc3be1cb35"
dependencies = [
"leb128fmt",
"wasmparser 0.241.2",
"wasmparser 0.243.0",
]
[[package]]
name = "wasm-metadata"
version = "0.241.2"
version = "0.243.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "876fe286f2fa416386deedebe8407e6f19e0b5aeaef3d03161e77a15fa80f167"
checksum = "eae05bf9579f45a62e8d0a4e3f52eaa8da518883ac5afa482ec8256c329ecd56"
dependencies = [
"anyhow",
"indexmap",
"wasm-encoder 0.241.2",
"wasmparser 0.241.2",
"wasm-encoder 0.243.0",
"wasmparser 0.243.0",
]
[[package]]
@ -6352,9 +6312,9 @@ dependencies = [
[[package]]
name = "wasmparser"
version = "0.241.2"
version = "0.243.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46d90019b1afd4b808c263e428de644f3003691f243387d30d673211ee0cb8e8"
checksum = "f6d8db401b0528ec316dfbe579e6ab4152d61739cfe076706d2009127970159d"
dependencies = [
"bitflags",
"hashbrown 0.15.5",
@ -6365,22 +6325,22 @@ dependencies = [
[[package]]
name = "wast"
version = "241.0.2"
version = "243.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63f66e07e2ddf531fef6344dbf94d112df7c2f23ed6ffb10962e711500b8d816"
checksum = "df21d01c2d91e46cb7a221d79e58a2d210ea02020d57c092e79255cc2999ca7f"
dependencies = [
"bumpalo",
"leb128fmt",
"memchr",
"unicode-width 0.2.2",
"wasm-encoder 0.241.2",
"wasm-encoder 0.243.0",
]
[[package]]
name = "wat"
version = "1.241.2"
version = "1.243.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45f923705c40830af909c5dec2352ec2821202e4a66008194585e1917458a26d"
checksum = "226a9a91cd80a50449312fef0c75c23478fcecfcc4092bdebe1dc8e760ef521b"
dependencies = [
"wast",
]
@ -6776,9 +6736,9 @@ dependencies = [
[[package]]
name = "wit-component"
version = "0.241.2"
version = "0.243.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0c57df25e7ee612d946d3b7646c1ddb2310f8280aa2c17e543b66e0812241"
checksum = "36f9fc53513e461ce51dcf17a3e331752cb829f1d187069e54af5608fc998fe4"
dependencies = [
"anyhow",
"bitflags",
@ -6787,17 +6747,17 @@ dependencies = [
"serde",
"serde_derive",
"serde_json",
"wasm-encoder 0.241.2",
"wasm-encoder 0.243.0",
"wasm-metadata",
"wasmparser 0.241.2",
"wasmparser 0.243.0",
"wit-parser",
]
[[package]]
name = "wit-parser"
version = "0.241.2"
version = "0.243.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ef1c6ad67f35c831abd4039c02894de97034100899614d1c44e2268ad01c91"
checksum = "df983a8608e513d8997f435bb74207bf0933d0e49ca97aa9d8a6157164b9b7fc"
dependencies = [
"anyhow",
"id-arena",
@ -6808,7 +6768,7 @@ dependencies = [
"serde_derive",
"serde_json",
"unicode-xid",
"wasmparser 0.241.2",
"wasmparser 0.243.0",
]
[[package]]

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

@ -618,7 +618,7 @@ impl DroplessArena {
/// - Types that are `!Copy` and `Drop`: these must be specified in the
/// arguments. The `TypedArena` will be used for them.
///
#[rustc_macro_transparency = "semitransparent"]
#[rustc_macro_transparency = "semiopaque"]
pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
#[derive(Default)]
pub struct Arena<'tcx> {

View file

@ -7,7 +7,7 @@ edition = "2024"
# tidy-alphabetical-start
bitflags = "2.4.1"
memchr = "2.7.6"
rustc-literal-escaper = "0.0.5"
rustc-literal-escaper = "0.0.7"
rustc_ast_ir = { path = "../rustc_ast_ir" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_index = { path = "../rustc_index" }

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};
@ -2116,10 +2117,9 @@ pub struct MacroDef {
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic, Walkable)]
pub struct EiiExternTarget {
/// path to the extern item we're targetting
/// path to the extern item we're targeting
pub extern_item_path: Path,
pub impl_unsafe: bool,
pub span: Span,
}
#[derive(Clone, Encodable, Decodable, Debug, Copy, Hash, Eq, PartialEq)]
@ -3390,7 +3390,7 @@ impl NormalAttr {
item: AttrItem {
unsafety: Safety::Default,
path: Path::from_ident(ident),
args: AttrArgs::Empty,
args: AttrItemKind::Unparsed(AttrArgs::Empty),
tokens: None,
},
tokens: None,
@ -3402,11 +3402,53 @@ impl NormalAttr {
pub struct AttrItem {
pub unsafety: Safety,
pub path: Path,
pub args: AttrArgs,
pub args: AttrItemKind,
// Tokens for the meta item, e.g. just the `foo` within `#[foo]` or `#![foo]`.
pub tokens: Option<LazyAttrTokenStream>,
}
/// Some attributes are stored in a parsed form, for performance reasons.
/// Their arguments don't have to be reparsed everytime they're used
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
pub enum AttrItemKind {
Parsed(EarlyParsedAttribute),
Unparsed(AttrArgs),
}
impl AttrItemKind {
pub fn unparsed(self) -> Option<AttrArgs> {
match self {
AttrItemKind::Unparsed(args) => Some(args),
AttrItemKind::Parsed(_) => None,
}
}
pub fn unparsed_ref(&self) -> Option<&AttrArgs> {
match self {
AttrItemKind::Unparsed(args) => Some(args),
AttrItemKind::Parsed(_) => None,
}
}
pub fn span(&self) -> Option<Span> {
match self {
AttrItemKind::Unparsed(args) => args.span(),
AttrItemKind::Parsed(_) => None,
}
}
}
/// Some attributes are stored in parsed form in the AST.
/// This is done for performance reasons, so the attributes don't need to be reparsed on every use.
///
/// Currently all early parsed attributes are excluded from pretty printing at rustc_ast_pretty::pprust::state::print_attribute_inline.
/// When adding new early parsed attributes, consider whether they should be pretty printed.
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
pub enum EarlyParsedAttribute {
CfgTrace(CfgEntry),
CfgAttrTrace,
}
impl AttrItem {
pub fn is_valid_for_outer_style(&self) -> bool {
self.path == sym::cfg_attr
@ -3770,6 +3812,19 @@ pub struct Fn {
pub struct EiiImpl {
pub node_id: NodeId,
pub eii_macro_path: Path,
/// This field is an implementation detail that prevents a lot of bugs.
/// See <https://github.com/rust-lang/rust/issues/149981> for an example.
///
/// The problem is, that if we generate a declaration *together* with its default,
/// we generate both a declaration and an implementation. The generated implementation
/// uses the same mechanism to register itself as a user-defined implementation would,
/// despite being invisible to users. What does happen is a name resolution step.
/// The invisible default implementation has to find the declaration.
/// Both are generated at the same time, so we can skip that name resolution step.
///
/// This field is that shortcut: we prefill the extern target to skip a name resolution step,
/// making sure it never fails. It'd be awful UX if we fail name resolution in code invisible to the user.
pub known_eii_macro_resolution: Option<EiiExternTarget>,
pub impl_safety: Safety,
pub span: Span,
pub inner_span: Span,

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
}
@ -213,6 +235,34 @@ impl AttributeExt for Attribute {
}
}
fn deprecation_note(&self) -> Option<Symbol> {
match &self.kind {
AttrKind::Normal(normal) if normal.item.path == sym::deprecated => {
let meta = &normal.item;
// #[deprecated = "..."]
if let Some(s) = meta.value_str() {
return Some(s);
}
// #[deprecated(note = "...")]
if let Some(list) = meta.meta_item_list() {
for nested in list {
if let Some(mi) = nested.meta_item()
&& mi.path == sym::note
&& let Some(s) = mi.value_str()
{
return Some(s);
}
}
}
None
}
_ => None,
}
}
fn doc_resolution_scope(&self) -> Option<AttrStyle> {
match &self.kind {
AttrKind::DocComment(..) => Some(self.style),
@ -255,6 +305,7 @@ impl Attribute {
pub fn may_have_doc_links(&self) -> bool {
self.doc_str().is_some_and(|s| comments::may_have_doc_links(s.as_str()))
|| self.deprecation_note().is_some_and(|s| comments::may_have_doc_links(s.as_str()))
}
/// Extracts the MetaItem from inside this Attribute.
@ -294,7 +345,7 @@ impl AttrItem {
}
pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
match &self.args {
match &self.args.unparsed_ref()? {
AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => {
MetaItemKind::list_from_tokens(args.tokens.clone())
}
@ -315,7 +366,7 @@ impl AttrItem {
/// #[attr("value")]
/// ```
fn value_str(&self) -> Option<Symbol> {
match &self.args {
match &self.args.unparsed_ref()? {
AttrArgs::Eq { expr, .. } => match expr.kind {
ExprKind::Lit(token_lit) => {
LitKind::from_token_lit(token_lit).ok().and_then(|lit| lit.str())
@ -339,7 +390,7 @@ impl AttrItem {
/// #[attr("value")]
/// ```
fn value_span(&self) -> Option<Span> {
match &self.args {
match &self.args.unparsed_ref()? {
AttrArgs::Eq { expr, .. } => Some(expr.span),
AttrArgs::Delimited(_) | AttrArgs::Empty => None,
}
@ -355,7 +406,7 @@ impl AttrItem {
}
pub fn meta_kind(&self) -> Option<MetaItemKind> {
MetaItemKind::from_attr_args(&self.args)
MetaItemKind::from_attr_args(self.args.unparsed_ref()?)
}
}
@ -690,7 +741,13 @@ fn mk_attr(
args: AttrArgs,
span: Span,
) -> Attribute {
mk_attr_from_item(g, AttrItem { unsafety, path, args, tokens: None }, None, style, span)
mk_attr_from_item(
g,
AttrItem { unsafety, path, args: AttrItemKind::Unparsed(args), tokens: None },
None,
style,
span,
)
}
pub fn mk_attr_from_item(
@ -794,9 +851,7 @@ pub trait AttributeExt: Debug {
/// For a single-segment attribute (i.e., `#[attr]` and not `#[path::atrr]`),
/// return the name of the attribute; otherwise, returns `None`.
fn name(&self) -> Option<Symbol> {
self.ident().map(|ident| ident.name)
}
fn name(&self) -> Option<Symbol>;
/// Get the meta item list, `#[attr(meta item list)]`
fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>>;
@ -807,9 +862,6 @@ pub trait AttributeExt: Debug {
/// Gets the span of the value literal, as string, when using `#[attr = value]`
fn value_span(&self) -> Option<Span>;
/// For a single-segment attribute, returns its ident; otherwise, returns `None`.
fn ident(&self) -> Option<Ident>;
/// Checks whether the path of this attribute matches the name.
///
/// Matches one segment of the path to each element in `name`
@ -822,7 +874,7 @@ pub trait AttributeExt: Debug {
#[inline]
fn has_name(&self, name: Symbol) -> bool {
self.ident().map(|x| x.name == name).unwrap_or(false)
self.name().map(|x| x == name).unwrap_or(false)
}
#[inline]
@ -836,13 +888,13 @@ pub trait AttributeExt: Debug {
fn is_word(&self) -> bool;
fn path(&self) -> SmallVec<[Symbol; 1]> {
self.ident_path()
.map(|i| i.into_iter().map(|i| i.name).collect())
.unwrap_or(smallvec![sym::doc])
self.symbol_path().unwrap_or(smallvec![sym::doc])
}
fn path_span(&self) -> Option<Span>;
/// Returns None for doc comments
fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>>;
fn symbol_path(&self) -> Option<SmallVec<[Symbol; 1]>>;
/// Returns the documentation if this is a doc comment or a sugared doc comment.
/// * `///doc` returns `Some("doc")`.
@ -850,6 +902,11 @@ pub trait AttributeExt: Debug {
/// * `#[doc(...)]` returns `None`.
fn doc_str(&self) -> Option<Symbol>;
/// Returns the deprecation note if this is deprecation attribute.
/// * `#[deprecated = "note"]` returns `Some("note")`.
/// * `#[deprecated(note = "note", ...)]` returns `Some("note")`.
fn deprecation_note(&self) -> Option<Symbol>;
fn is_proc_macro_attr(&self) -> bool {
[sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
.iter()
@ -903,10 +960,6 @@ impl Attribute {
AttributeExt::value_span(self)
}
pub fn ident(&self) -> Option<Ident> {
AttributeExt::ident(self)
}
pub fn path_matches(&self, name: &[Symbol]) -> bool {
AttributeExt::path_matches(self, name)
}
@ -938,10 +991,6 @@ impl Attribute {
AttributeExt::path(self)
}
pub fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>> {
AttributeExt::ident_path(self)
}
pub fn doc_str(&self) -> Option<Symbol> {
AttributeExt::doc_str(self)
}

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

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

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

@ -2,7 +2,7 @@ use rustc_abi::ExternAbi;
use rustc_ast::visit::AssocCtxt;
use rustc_ast::*;
use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err};
use rustc_hir::attrs::{AttributeKind, EiiDecl};
use rustc_hir::attrs::{AttributeKind, EiiDecl, EiiImplResolution};
use rustc_hir::def::{DefKind, PerNS, Res};
use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
use rustc_hir::{
@ -134,6 +134,56 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
}
fn lower_eii_extern_target(
&mut self,
id: NodeId,
eii_name: Ident,
EiiExternTarget { extern_item_path, impl_unsafe }: &EiiExternTarget,
) -> Option<EiiDecl> {
self.lower_path_simple_eii(id, extern_item_path).map(|did| EiiDecl {
eii_extern_target: did,
impl_unsafe: *impl_unsafe,
name: eii_name,
})
}
fn lower_eii_impl(
&mut self,
EiiImpl {
node_id,
eii_macro_path,
impl_safety,
span,
inner_span,
is_default,
known_eii_macro_resolution,
}: &EiiImpl,
) -> hir::attrs::EiiImpl {
let resolution = if let Some(target) = known_eii_macro_resolution
&& let Some(decl) = self.lower_eii_extern_target(
*node_id,
// the expect is ok here since we always generate this path in the eii macro.
eii_macro_path.segments.last().expect("at least one segment").ident,
target,
) {
EiiImplResolution::Known(decl)
} else if let Some(macro_did) = self.lower_path_simple_eii(*node_id, eii_macro_path) {
EiiImplResolution::Macro(macro_did)
} else {
EiiImplResolution::Error(
self.dcx().span_delayed_bug(*span, "eii never resolved without errors given"),
)
};
hir::attrs::EiiImpl {
span: self.lower_span(*span),
inner_span: self.lower_span(*inner_span),
impl_marked_unsafe: self.lower_safety(*impl_safety, hir::Safety::Safe).is_unsafe(),
is_default: *is_default,
resolution,
}
}
fn generate_extra_attrs_for_item_kind(
&mut self,
id: NodeId,
@ -143,49 +193,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
ItemKind::Fn(box Fn { eii_impls, .. }) if eii_impls.is_empty() => Vec::new(),
ItemKind::Fn(box Fn { eii_impls, .. }) => {
vec![hir::Attribute::Parsed(AttributeKind::EiiImpls(
eii_impls
.iter()
.flat_map(
|EiiImpl {
node_id,
eii_macro_path,
impl_safety,
span,
inner_span,
is_default,
}| {
self.lower_path_simple_eii(*node_id, eii_macro_path).map(|did| {
hir::attrs::EiiImpl {
eii_macro: did,
span: self.lower_span(*span),
inner_span: self.lower_span(*inner_span),
impl_marked_unsafe: self
.lower_safety(*impl_safety, hir::Safety::Safe)
.is_unsafe(),
is_default: *is_default,
}
})
},
)
.collect(),
eii_impls.iter().map(|i| self.lower_eii_impl(i)).collect(),
))]
}
ItemKind::MacroDef(
_,
MacroDef {
eii_extern_target: Some(EiiExternTarget { extern_item_path, impl_unsafe, span }),
..
},
) => self
.lower_path_simple_eii(id, extern_item_path)
.map(|did| {
vec![hir::Attribute::Parsed(AttributeKind::EiiExternTarget(EiiDecl {
eii_extern_target: did,
impl_unsafe: *impl_unsafe,
span: self.lower_span(*span),
}))]
})
ItemKind::MacroDef(name, MacroDef { eii_extern_target: Some(target), .. }) => self
.lower_eii_extern_target(id, *name, target)
.map(|decl| vec![hir::Attribute::Parsed(AttributeKind::EiiExternTarget(decl))])
.unwrap_or_default(),
ItemKind::ExternCrate(..)
| ItemKind::Use(..)
| ItemKind::Static(..)
@ -264,8 +279,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
define_opaque,
}) => {
let ident = self.lower_ident(*ident);
let ty =
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy));
let ty = self
.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy));
let body_id = self.lower_const_body(span, e.as_deref());
self.lower_define_opaque(hir_id, define_opaque);
hir::ItemKind::Static(*m, ident, ty, body_id)
@ -279,8 +294,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
let ty = this
.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
let ty = this.lower_ty_alloc(
ty,
ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
);
let rhs = this.lower_const_item_rhs(attrs, rhs.as_ref(), span);
(ty, rhs)
},
@ -379,7 +396,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
);
this.arena.alloc(this.ty(span, hir::TyKind::Err(guar)))
}
Some(ty) => this.lower_ty(
Some(ty) => this.lower_ty_alloc(
ty,
ImplTraitContext::OpaqueTy {
origin: hir::OpaqueTyOrigin::TyAlias {
@ -453,7 +470,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
.as_deref()
.map(|of_trait| this.lower_trait_impl_header(of_trait));
let lowered_ty = this.lower_ty(
let lowered_ty = this.lower_ty_alloc(
ty,
ImplTraitContext::Disallowed(ImplTraitPosition::ImplSelf),
);
@ -758,8 +775,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
safety,
define_opaque,
}) => {
let ty =
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy));
let ty = self
.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy));
let safety = self.lower_safety(*safety, hir::Safety::Unsafe);
if define_opaque.is_some() {
self.dcx().span_err(i.span, "foreign statics cannot define opaque types");
@ -870,7 +887,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
&mut self,
(index, f): (usize, &FieldDef),
) -> hir::FieldDef<'hir> {
let ty = self.lower_ty(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy));
let ty =
self.lower_ty_alloc(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy));
let hir_id = self.lower_node_id(f.id);
self.lower_attrs(hir_id, &f.attrs, f.span, Target::Field);
hir::FieldDef {
@ -908,8 +926,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
i.id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
let ty = this
.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
let ty = this.lower_ty_alloc(
ty,
ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
);
let rhs = rhs
.as_ref()
.map(|rhs| this.lower_const_item_rhs(attrs, Some(rhs), i.span));
@ -1008,7 +1028,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
let ty = ty.as_ref().map(|x| {
this.lower_ty(
this.lower_ty_alloc(
x,
ImplTraitContext::Disallowed(ImplTraitPosition::AssocTy),
)
@ -1120,8 +1140,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
i.id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
let ty = this
.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
let ty = this.lower_ty_alloc(
ty,
ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
);
this.lower_define_opaque(hir_id, &define_opaque);
let rhs = this.lower_const_item_rhs(attrs, rhs.as_ref(), i.span);
hir::ImplItemKind::Const(ty, rhs)
@ -1180,7 +1202,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir::ImplItemKind::Type(ty)
}
Some(ty) => {
let ty = this.lower_ty(
let ty = this.lower_ty_alloc(
ty,
ImplTraitContext::OpaqueTy {
origin: hir::OpaqueTyOrigin::TyAlias {
@ -1916,7 +1938,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
bound_generic_params,
hir::GenericParamSource::Binder,
),
bounded_ty: self.lower_ty(
bounded_ty: self.lower_ty_alloc(
bounded_ty,
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
),
@ -1945,10 +1967,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
WherePredicateKind::EqPredicate(WhereEqPredicate { lhs_ty, rhs_ty }) => {
hir::WherePredicateKind::EqPredicate(hir::WhereEqPredicate {
lhs_ty: self
.lower_ty(lhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound)),
rhs_ty: self
.lower_ty(rhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound)),
lhs_ty: self.lower_ty_alloc(
lhs_ty,
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
),
rhs_ty: self.lower_ty_alloc(
rhs_ty,
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
),
})
}
});

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, &[])),
};
@ -1986,8 +1986,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let (name, kind) = self.lower_generic_param_kind(param, source);
let hir_id = self.lower_node_id(param.id);
self.lower_attrs(hir_id, &param.attrs, param.span(), Target::Param);
hir::GenericParam {
let param_attrs = &param.attrs;
let param_span = param.span();
let param = hir::GenericParam {
hir_id,
def_id: self.local_def_id(param.id),
name,
@ -1996,7 +1997,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
kind,
colon_span: param.colon_span.map(|s| self.lower_span(s)),
source,
}
};
self.lower_attrs(hir_id, param_attrs, param_span, Target::from_generic_param(&param));
param
}
fn lower_generic_param_kind(
@ -2036,7 +2039,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
})
.map(|def| {
self.lower_ty(
self.lower_ty_alloc(
def,
ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault),
)
@ -2047,8 +2050,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
(hir::ParamName::Plain(self.lower_ident(param.ident)), kind)
}
GenericParamKind::Const { ty, span: _, default } => {
let ty = self
.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault));
let ty = self.lower_ty_alloc(
ty,
ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault),
);
// Not only do we deny const param defaults in binders but we also map them to `None`
// since later compiler stages cannot handle them (and shouldn't need to be able to).
@ -2064,7 +2069,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
false
}
})
.map(|def| self.lower_anon_const_to_const_arg(def));
.map(|def| self.lower_anon_const_to_const_arg_and_alloc(def));
(
hir::ParamName::Plain(self.lower_ident(param.ident)),
@ -2198,7 +2203,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> {
hir::MutTy { ty: self.lower_ty(&mt.ty, itctx), mutbl: mt.mutbl }
hir::MutTy { ty: self.lower_ty_alloc(&mt.ty, itctx), mutbl: mt.mutbl }
}
#[instrument(level = "debug", skip(self), ret)]
@ -2283,10 +2288,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// `ExprKind::Paren(ExprKind::Underscore)` and should also be lowered to `GenericArg::Infer`
match c.value.peel_parens().kind {
ExprKind::Underscore => {
let ct_kind = hir::ConstArgKind::Infer(self.lower_span(c.value.span), ());
self.arena.alloc(hir::ConstArg { hir_id: self.lower_node_id(c.id), kind: ct_kind })
let ct_kind = hir::ConstArgKind::Infer(());
self.arena.alloc(hir::ConstArg {
hir_id: self.lower_node_id(c.id),
kind: ct_kind,
span: self.lower_span(c.value.span),
})
}
_ => self.lower_anon_const_to_const_arg(c),
_ => self.lower_anon_const_to_const_arg_and_alloc(c),
}
}
@ -2354,7 +2363,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
hir::ConstArgKind::Anon(ct)
};
self.arena.alloc(hir::ConstArg { hir_id: self.next_id(), kind: ct_kind })
self.arena.alloc(hir::ConstArg {
hir_id: self.next_id(),
kind: ct_kind,
span: self.lower_span(span),
})
}
fn lower_const_item_rhs(
@ -2365,15 +2378,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
) -> hir::ConstItemRhs<'hir> {
match rhs {
Some(ConstItemRhs::TypeConst(anon)) => {
hir::ConstItemRhs::TypeConst(self.lower_anon_const_to_const_arg(anon))
hir::ConstItemRhs::TypeConst(self.lower_anon_const_to_const_arg_and_alloc(anon))
}
None if attr::contains_name(attrs, sym::type_const) => {
let const_arg = ConstArg {
hir_id: self.next_id(),
kind: hir::ConstArgKind::Error(
DUMMY_SP,
self.dcx().span_delayed_bug(DUMMY_SP, "no block"),
),
span: DUMMY_SP,
};
hir::ConstItemRhs::TypeConst(self.arena.alloc(const_arg))
}
@ -2386,16 +2399,65 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
#[instrument(level = "debug", skip(self), ret)]
fn lower_expr_to_const_arg_direct(&mut self, expr: &Expr) -> hir::ConstArg<'hir> {
let span = self.lower_span(expr.span);
let overly_complex_const = |this: &mut Self| {
let e = this.dcx().struct_span_err(
expr.span,
"complex const arguments must be placed inside of a `const` block",
);
ConstArg { hir_id: this.next_id(), kind: hir::ConstArgKind::Error(expr.span, e.emit()) }
ConstArg { hir_id: this.next_id(), kind: hir::ConstArgKind::Error(e.emit()), span }
};
match &expr.kind {
ExprKind::Call(func, args) if let ExprKind::Path(qself, path) = &func.kind => {
let qpath = self.lower_qpath(
func.id,
qself,
path,
ParamMode::Explicit,
AllowReturnTypeNotation::No,
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
);
let lowered_args = self.arena.alloc_from_iter(args.iter().map(|arg| {
let const_arg = if let ExprKind::ConstBlock(anon_const) = &arg.kind {
let def_id = self.local_def_id(anon_const.id);
let def_kind = self.tcx.def_kind(def_id);
assert_eq!(DefKind::AnonConst, def_kind);
self.lower_anon_const_to_const_arg(anon_const)
} else {
self.lower_expr_to_const_arg_direct(arg)
};
&*self.arena.alloc(const_arg)
}));
ConstArg {
hir_id: self.next_id(),
kind: hir::ConstArgKind::TupleCall(qpath, lowered_args),
span,
}
}
ExprKind::Tup(exprs) => {
let exprs = self.arena.alloc_from_iter(exprs.iter().map(|expr| {
let expr = if let ExprKind::ConstBlock(anon_const) = &expr.kind {
let def_id = self.local_def_id(anon_const.id);
let def_kind = self.tcx.def_kind(def_id);
assert_eq!(DefKind::AnonConst, def_kind);
self.lower_anon_const_to_const_arg(anon_const)
} else {
self.lower_expr_to_const_arg_direct(&expr)
};
&*self.arena.alloc(expr)
}));
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Tup(exprs), span }
}
ExprKind::Path(qself, path) => {
let qpath = self.lower_qpath(
expr.id,
@ -2408,7 +2470,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
None,
);
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Path(qpath) }
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Path(qpath), span }
}
ExprKind::Struct(se) => {
let path = self.lower_qpath(
@ -2436,7 +2498,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let def_kind = self.tcx.def_kind(def_id);
assert_eq!(DefKind::AnonConst, def_kind);
self.lower_anon_const_to_const_arg_direct(anon_const)
self.lower_anon_const_to_const_arg(anon_const)
} else {
self.lower_expr_to_const_arg_direct(&f.expr)
};
@ -2449,18 +2511,27 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
})
}));
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Struct(path, fields) }
ConstArg {
hir_id: self.next_id(),
kind: hir::ConstArgKind::Struct(path, fields),
span,
}
}
ExprKind::Underscore => ConstArg {
hir_id: self.lower_node_id(expr.id),
kind: hir::ConstArgKind::Infer(expr.span, ()),
kind: hir::ConstArgKind::Infer(()),
span,
},
ExprKind::Block(block, _) => {
if let [stmt] = block.stmts.as_slice()
&& let StmtKind::Expr(expr) = &stmt.kind
&& matches!(
expr.kind,
ExprKind::Block(..) | ExprKind::Path(..) | ExprKind::Struct(..)
ExprKind::Block(..)
| ExprKind::Path(..)
| ExprKind::Struct(..)
| ExprKind::Call(..)
| ExprKind::Tup(..)
)
{
return self.lower_expr_to_const_arg_direct(expr);
@ -2468,18 +2539,31 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
overly_complex_const(self)
}
ExprKind::Lit(literal) => {
let span = expr.span;
let literal = self.lower_lit(literal, span);
ConstArg {
hir_id: self.lower_node_id(expr.id),
kind: hir::ConstArgKind::Literal(literal.node),
span,
}
}
_ => overly_complex_const(self),
}
}
/// See [`hir::ConstArg`] for when to use this function vs
/// [`Self::lower_anon_const_to_anon_const`].
fn lower_anon_const_to_const_arg(&mut self, anon: &AnonConst) -> &'hir hir::ConstArg<'hir> {
self.arena.alloc(self.lower_anon_const_to_const_arg_direct(anon))
fn lower_anon_const_to_const_arg_and_alloc(
&mut self,
anon: &AnonConst,
) -> &'hir hir::ConstArg<'hir> {
self.arena.alloc(self.lower_anon_const_to_const_arg(anon))
}
#[instrument(level = "debug", skip(self))]
fn lower_anon_const_to_const_arg_direct(&mut self, anon: &AnonConst) -> hir::ConstArg<'hir> {
fn lower_anon_const_to_const_arg(&mut self, anon: &AnonConst) -> hir::ConstArg<'hir> {
let tcx = self.tcx;
// We cannot change parsing depending on feature gates available,
@ -2491,7 +2575,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
return match anon.mgca_disambiguation {
MgcaDisambiguation::AnonConst => {
let lowered_anon = self.lower_anon_const_to_anon_const(anon);
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Anon(lowered_anon) }
ConstArg {
hir_id: self.next_id(),
kind: hir::ConstArgKind::Anon(lowered_anon),
span: lowered_anon.span,
}
}
MgcaDisambiguation::Direct => self.lower_expr_to_const_arg_direct(&anon.value),
};
@ -2528,11 +2616,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
return ConstArg {
hir_id: self.lower_node_id(anon.id),
kind: hir::ConstArgKind::Path(qpath),
span: self.lower_span(expr.span),
};
}
let lowered_anon = self.lower_anon_const_to_anon_const(anon);
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Anon(lowered_anon) }
ConstArg {
hir_id: self.next_id(),
kind: hir::ConstArgKind::Anon(lowered_anon),
span: self.lower_span(expr.span),
}
}
/// See [`hir::ConstArg`] for when to use this function vs

View file

@ -444,16 +444,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let pat_hir_id = self.lower_node_id(pattern.id);
let node = match &pattern.kind {
TyPatKind::Range(e1, e2, Spanned { node: end, span }) => hir::TyPatKind::Range(
e1.as_deref().map(|e| self.lower_anon_const_to_const_arg(e)).unwrap_or_else(|| {
self.lower_ty_pat_range_end(
hir::LangItem::RangeMin,
span.shrink_to_lo(),
base_type,
)
}),
e1.as_deref()
.map(|e| self.lower_anon_const_to_const_arg_and_alloc(e))
.unwrap_or_else(|| {
self.lower_ty_pat_range_end(
hir::LangItem::RangeMin,
span.shrink_to_lo(),
base_type,
)
}),
e2.as_deref()
.map(|e| match end {
RangeEnd::Included(..) => self.lower_anon_const_to_const_arg(e),
RangeEnd::Included(..) => self.lower_anon_const_to_const_arg_and_alloc(e),
RangeEnd::Excluded => self.lower_excluded_range_end(e),
})
.unwrap_or_else(|| {
@ -511,6 +513,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.arena.alloc(hir::ConstArg {
hir_id: self.next_id(),
kind: hir::ConstArgKind::Anon(self.arena.alloc(anon_const)),
span,
})
}
@ -555,6 +558,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
})
});
let hir_id = self.next_id();
self.arena.alloc(hir::ConstArg { kind: hir::ConstArgKind::Anon(ct), hir_id })
self.arena.alloc(hir::ConstArg { kind: hir::ConstArgKind::Anon(ct), hir_id, span })
}
}

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

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

@ -9,7 +9,7 @@ impl<S: Stage> SingleAttributeParser<S> for CrateNameParser {
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
let ArgParser::NameValue(n) = args else {
@ -33,7 +33,7 @@ impl<S: Stage> SingleAttributeParser<S> for RecursionLimitParser {
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N", "https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute");
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
let ArgParser::NameValue(nv) = args else {
@ -56,7 +56,7 @@ impl<S: Stage> SingleAttributeParser<S> for MoveSizeLimitParser {
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
let ArgParser::NameValue(nv) = args else {
@ -79,7 +79,7 @@ impl<S: Stage> SingleAttributeParser<S> for TypeLengthLimitParser {
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
let ArgParser::NameValue(nv) = args else {
@ -102,7 +102,7 @@ impl<S: Stage> SingleAttributeParser<S> for PatternComplexityLimitParser {
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
let ArgParser::NameValue(nv) = args else {
@ -123,7 +123,7 @@ pub(crate) struct NoCoreParser;
impl<S: Stage> NoArgsAttributeParser<S> for NoCoreParser {
const PATH: &[Symbol] = &[sym::no_core];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoCore;
}
@ -132,7 +132,7 @@ pub(crate) struct NoStdParser;
impl<S: Stage> NoArgsAttributeParser<S> for NoStdParser {
const PATH: &[Symbol] = &[sym::no_std];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoStd;
}
@ -141,7 +141,7 @@ pub(crate) struct RustcCoherenceIsCoreParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcCoherenceIsCoreParser {
const PATH: &[Symbol] = &[sym::rustc_coherence_is_core];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcCoherenceIsCore;
}
@ -151,7 +151,7 @@ impl<S: Stage> SingleAttributeParser<S> for WindowsSubsystemParser {
const PATH: &[Symbol] = &[sym::windows_subsystem];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const TEMPLATE: AttributeTemplate = template!(NameValueStr: ["windows", "console"], "https://doc.rust-lang.org/reference/runtime.html#the-windows_subsystem-attribute");
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {

View file

@ -305,3 +305,18 @@ impl<S: Stage> SingleAttributeParser<S> for RustcScalableVectorParser {
Some(AttributeKind::RustcScalableVector { element_count: Some(n), span: cx.attr_span })
}
}
pub(crate) struct RustcHasIncoherentInherentImplsParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcHasIncoherentInherentImplsParser {
const PATH: &[Symbol] = &[sym::rustc_has_incoherent_inherent_impls];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Trait),
Allow(Target::Struct),
Allow(Target::Enum),
Allow(Target::Union),
Allow(Target::ForeignTy),
]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcHasIncoherentInherentImpls;
}

View file

@ -1,6 +1,7 @@
use std::num::NonZero;
use rustc_errors::ErrorGuaranteed;
use rustc_hir::target::GenericParamKind;
use rustc_hir::{
DefaultBodyStability, MethodKind, PartialConstStability, Stability, StabilityLevel,
StableSince, Target, UnstableReason, VERSION_PLACEHOLDER,
@ -43,7 +44,7 @@ const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::TyAlias),
Allow(Target::Variant),
Allow(Target::Field),
Allow(Target::Param),
Allow(Target::GenericParam { kind: GenericParamKind::Type, has_default: true }),
Allow(Target::Static),
Allow(Target::ForeignFn),
Allow(Target::ForeignStatic),

View file

@ -15,7 +15,7 @@ impl<S: Stage> SingleAttributeParser<S> for TransparencyParser {
});
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::MacroDef)]);
const TEMPLATE: AttributeTemplate =
template!(NameValueStr: ["transparent", "semitransparent", "opaque"]);
template!(NameValueStr: ["transparent", "semiopaque", "opaque"]);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
let Some(nv) = args.name_value() else {
@ -24,12 +24,12 @@ impl<S: Stage> SingleAttributeParser<S> for TransparencyParser {
};
match nv.value_as_str() {
Some(sym::transparent) => Some(Transparency::Transparent),
Some(sym::semiopaque | sym::semitransparent) => Some(Transparency::SemiOpaque),
Some(sym::semiopaque) => Some(Transparency::SemiOpaque),
Some(sym::opaque) => Some(Transparency::Opaque),
Some(_) => {
cx.expected_specific_argument_strings(
nv.value_span,
&[sym::transparent, sym::semitransparent, sym::opaque],
&[sym::transparent, sym::semiopaque, sym::opaque],
);
None
}

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

@ -4,12 +4,12 @@ use std::ops::{Deref, DerefMut};
use std::sync::LazyLock;
use private::Sealed;
use rustc_ast::{AttrStyle, CRATE_NODE_ID, MetaItemLit, NodeId};
use rustc_ast::{AttrStyle, MetaItemLit, NodeId};
use rustc_errors::{Diag, Diagnostic, Level};
use rustc_feature::{AttrSuggestionStyle, AttributeTemplate};
use rustc_hir::attrs::AttributeKind;
use rustc_hir::lints::{AttributeLint, AttributeLintKind};
use rustc_hir::{AttrPath, CRATE_HIR_ID, HirId};
use rustc_hir::{AttrPath, HirId};
use rustc_session::Session;
use rustc_session::lint::{Lint, LintId};
use rustc_span::{ErrorGuaranteed, Span, Symbol};
@ -62,12 +62,12 @@ use crate::attributes::proc_macro_attrs::{
use crate::attributes::prototype::CustomMirParser;
use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser};
use crate::attributes::rustc_internal::{
RustcLayoutScalarValidRangeEndParser, RustcLayoutScalarValidRangeStartParser,
RustcLegacyConstGenericsParser, RustcLintDiagnosticsParser, RustcLintOptDenyFieldAccessParser,
RustcLintOptTyParser, RustcLintQueryInstabilityParser,
RustcLintUntrackedQueryInformationParser, RustcMainParser, RustcMustImplementOneOfParser,
RustcNeverReturnsNullPointerParser, RustcNoImplicitAutorefsParser,
RustcObjectLifetimeDefaultParser, RustcScalableVectorParser,
RustcHasIncoherentInherentImplsParser, RustcLayoutScalarValidRangeEndParser,
RustcLayoutScalarValidRangeStartParser, RustcLegacyConstGenericsParser,
RustcLintDiagnosticsParser, RustcLintOptDenyFieldAccessParser, RustcLintOptTyParser,
RustcLintQueryInstabilityParser, RustcLintUntrackedQueryInformationParser, RustcMainParser,
RustcMustImplementOneOfParser, RustcNeverReturnsNullPointerParser,
RustcNoImplicitAutorefsParser, RustcObjectLifetimeDefaultParser, RustcScalableVectorParser,
RustcSimdMonomorphizeLaneLimitParser,
};
use crate::attributes::semantics::MayDangleParser;
@ -264,6 +264,7 @@ attribute_parsers!(
Single<WithoutArgs<ProcMacroParser>>,
Single<WithoutArgs<PubTransparentParser>>,
Single<WithoutArgs<RustcCoherenceIsCoreParser>>,
Single<WithoutArgs<RustcHasIncoherentInherentImplsParser>>,
Single<WithoutArgs<RustcLintDiagnosticsParser>>,
Single<WithoutArgs<RustcLintOptTyParser>>,
Single<WithoutArgs<RustcLintQueryInstabilityParser>>,
@ -303,8 +304,6 @@ pub trait Stage: Sized + 'static + Sealed {
) -> ErrorGuaranteed;
fn should_emit(&self) -> ShouldEmit;
fn id_is_crate_root(id: Self::Id) -> bool;
}
// allow because it's a sealed trait
@ -326,10 +325,6 @@ impl Stage for Early {
fn should_emit(&self) -> ShouldEmit {
self.emit_errors
}
fn id_is_crate_root(id: Self::Id) -> bool {
id == CRATE_NODE_ID
}
}
// allow because it's a sealed trait
@ -351,10 +346,6 @@ impl Stage for Late {
fn should_emit(&self) -> ShouldEmit {
ShouldEmit::ErrorsAndLints
}
fn id_is_crate_root(id: Self::Id) -> bool {
id == CRATE_HIR_ID
}
}
/// used when parsing attributes for miscellaneous things *before* ast lowering

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

@ -36,7 +36,7 @@ pub type RefPathParser<'p> = PathParser<&'p Path>;
impl<P: Borrow<Path>> PathParser<P> {
pub fn get_attribute_path(&self) -> hir::AttrPath {
AttrPath {
segments: self.segments().copied().collect::<Vec<_>>().into_boxed_slice(),
segments: self.segments().map(|s| s.name).collect::<Vec<_>>().into_boxed_slice(),
span: self.span(),
}
}
@ -122,10 +122,10 @@ impl ArgParser {
}
if args.delim != Delimiter::Parenthesis {
psess.dcx().emit_err(MetaBadDelim {
should_emit.emit_err(psess.dcx().create_err(MetaBadDelim {
span: args.dspan.entire(),
sugg: MetaBadDelimSugg { open: args.dspan.open, close: args.dspan.close },
});
}));
return None;
}

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

@ -15,11 +15,6 @@ use crate::session_diagnostics::InvalidTarget;
pub(crate) enum AllowedTargets {
AllowList(&'static [Policy]),
AllowListWarnRest(&'static [Policy]),
/// Special, and not the same as `AllowList(&[Allow(Target::Crate)])`.
/// For crate-level attributes we emit a specific set of lints to warn
/// people about accidentally not using them on the crate.
/// Only use this for attributes that are *exclusively* valid at the crate level.
CrateLevel,
}
pub(crate) enum AllowedResult {
@ -53,7 +48,6 @@ impl AllowedTargets {
AllowedResult::Warn
}
}
AllowedTargets::CrateLevel => AllowedResult::Allowed,
}
}
@ -61,7 +55,6 @@ impl AllowedTargets {
match self {
AllowedTargets::AllowList(list) => list,
AllowedTargets::AllowListWarnRest(list) => list,
AllowedTargets::CrateLevel => ALL_TARGETS,
}
.iter()
.filter_map(|target| match target {
@ -95,7 +88,10 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
target: Target,
cx: &mut AcceptContext<'_, 'sess, S>,
) {
Self::check_type(matches!(allowed_targets, AllowedTargets::CrateLevel), target, cx);
if allowed_targets.allowed_targets() == &[Target::Crate] {
Self::check_crate_level(target, cx);
return;
}
match allowed_targets.is_allowed(target) {
AllowedResult::Allowed => {}
@ -104,7 +100,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
let (applied, only) = allowed_targets_applied(allowed_targets, target, cx.features);
let name = cx.attr_path.clone();
let lint = if name.segments[0].name == sym::deprecated
let lint = if name.segments[0] == sym::deprecated
&& ![
Target::Closure,
Target::Expression,
@ -149,18 +145,10 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
}
}
pub(crate) fn check_type(
crate_level: bool,
target: Target,
cx: &mut AcceptContext<'_, 'sess, S>,
) {
let is_crate_root = S::id_is_crate_root(cx.target_id);
if is_crate_root {
return;
}
if !crate_level {
pub(crate) fn check_crate_level(target: Target, cx: &mut AcceptContext<'_, 'sess, S>) {
// For crate-level attributes we emit a specific set of lints to warn
// people about accidentally not using them on the crate.
if target == Target::Crate {
return;
}
@ -310,5 +298,29 @@ pub(crate) const ALL_TARGETS: &'static [Policy] = {
Allow(Target::Crate),
Allow(Target::Delegation { mac: false }),
Allow(Target::Delegation { mac: true }),
Allow(Target::GenericParam {
kind: rustc_hir::target::GenericParamKind::Const,
has_default: false,
}),
Allow(Target::GenericParam {
kind: rustc_hir::target::GenericParamKind::Const,
has_default: true,
}),
Allow(Target::GenericParam {
kind: rustc_hir::target::GenericParamKind::Lifetime,
has_default: false,
}),
Allow(Target::GenericParam {
kind: rustc_hir::target::GenericParamKind::Lifetime,
has_default: true,
}),
Allow(Target::GenericParam {
kind: rustc_hir::target::GenericParamKind::Type,
has_default: false,
}),
Allow(Target::GenericParam {
kind: rustc_hir::target::GenericParamKind::Type,
has_default: true,
}),
]
};

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

@ -182,6 +182,8 @@ builtin_macros_expected_other = expected operand, {$is_inline_asm ->
builtin_macros_export_macro_rules = cannot export macro_rules! macros from a `proc-macro` crate type currently
builtin_macros_format_add_missing_colon = add a colon before the format specifier
builtin_macros_format_duplicate_arg = duplicate argument named `{$ident}`
.label1 = previously here
.label2 = duplicate argument

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

@ -103,19 +103,19 @@ fn eii_(
// span of the declaring item without attributes
let item_span = func.sig.span;
// span of the eii attribute and the item below it, i.e. the full declaration
let decl_span = eii_attr_span.to(item_span);
let foreign_item_name = func.ident;
let mut return_items = Vec::new();
if func.body.is_some() {
return_items.push(Box::new(generate_default_impl(
ecx,
&func,
impl_unsafe,
macro_name,
eii_attr_span,
item_span,
foreign_item_name,
)))
}
@ -133,7 +133,7 @@ fn eii_(
macro_name,
foreign_item_name,
impl_unsafe,
decl_span,
&attrs_from_decl,
)));
return_items.into_iter().map(wrap_item).collect()
@ -187,11 +187,13 @@ fn filter_attrs_for_multiple_eii_attr(
}
fn generate_default_impl(
ecx: &mut ExtCtxt<'_>,
func: &ast::Fn,
impl_unsafe: bool,
macro_name: Ident,
eii_attr_span: Span,
item_span: Span,
foreign_item_name: Ident,
) -> ast::Item {
// FIXME: re-add some original attrs
let attrs = ThinVec::new();
@ -208,6 +210,21 @@ fn generate_default_impl(
},
span: eii_attr_span,
is_default: true,
known_eii_macro_resolution: Some(ast::EiiExternTarget {
extern_item_path: ast::Path {
span: foreign_item_name.span,
segments: thin_vec![
ast::PathSegment {
ident: Ident::from_str_and_span("super", foreign_item_name.span,),
id: DUMMY_NODE_ID,
args: None
},
ast::PathSegment { ident: foreign_item_name, id: DUMMY_NODE_ID, args: None },
],
tokens: None,
},
impl_unsafe,
}),
});
ast::Item {
@ -236,18 +253,66 @@ fn generate_default_impl(
stmts: thin_vec![ast::Stmt {
id: DUMMY_NODE_ID,
kind: ast::StmtKind::Item(Box::new(ast::Item {
attrs,
attrs: ThinVec::new(),
id: DUMMY_NODE_ID,
span: item_span,
vis: ast::Visibility {
span: eii_attr_span,
span: item_span,
kind: ast::VisibilityKind::Inherited,
tokens: None
},
kind: ItemKind::Fn(Box::new(default_func)),
kind: ItemKind::Mod(
ast::Safety::Default,
Ident::from_str_and_span("dflt", item_span),
ast::ModKind::Loaded(
thin_vec![
Box::new(ast::Item {
attrs: thin_vec![ecx.attr_nested_word(
sym::allow,
sym::unused_imports,
item_span
),],
id: DUMMY_NODE_ID,
span: item_span,
vis: ast::Visibility {
span: eii_attr_span,
kind: ast::VisibilityKind::Inherited,
tokens: None
},
kind: ItemKind::Use(ast::UseTree {
prefix: ast::Path::from_ident(
Ident::from_str_and_span(
"super", item_span,
)
),
kind: ast::UseTreeKind::Glob,
span: item_span,
}),
tokens: None,
}),
Box::new(ast::Item {
attrs,
id: DUMMY_NODE_ID,
span: item_span,
vis: ast::Visibility {
span: eii_attr_span,
kind: ast::VisibilityKind::Inherited,
tokens: None
},
kind: ItemKind::Fn(Box::new(default_func)),
tokens: None,
}),
],
ast::Inline::Yes,
ast::ModSpans {
inner_span: item_span,
inject_use_span: item_span,
}
)
),
tokens: None,
})),
span: eii_attr_span
span: eii_attr_span,
}],
id: DUMMY_NODE_ID,
rules: ast::BlockCheckMode::Default,
@ -352,10 +417,14 @@ fn generate_attribute_macro_to_implement(
macro_name: Ident,
foreign_item_name: Ident,
impl_unsafe: bool,
decl_span: Span,
attrs_from_decl: &[Attribute],
) -> ast::Item {
let mut macro_attrs = ThinVec::new();
// To avoid e.g. `error: attribute macro has missing stability attribute`
// errors for eii's in std.
macro_attrs.extend_from_slice(attrs_from_decl);
// #[builtin_macro(eii_shared_macro)]
macro_attrs.push(ecx.attr_nested_word(sym::rustc_builtin_macro, sym::eii_shared_macro, span));
@ -394,7 +463,6 @@ fn generate_attribute_macro_to_implement(
eii_extern_target: Some(ast::EiiExternTarget {
extern_item_path: ast::Path::from_ident(foreign_item_name),
impl_unsafe,
span: decl_span,
}),
},
),
@ -451,7 +519,7 @@ pub(crate) fn eii_extern_target(
false
};
d.eii_extern_target = Some(EiiExternTarget { extern_item_path, impl_unsafe, span });
d.eii_extern_target = Some(EiiExternTarget { extern_item_path, impl_unsafe });
// Return the original item and the new methods.
vec![item]
@ -508,6 +576,7 @@ pub(crate) fn eii_shared_macro(
impl_safety: meta_item.unsafety,
span,
is_default,
known_eii_macro_resolution: None,
});
vec![item]

View file

@ -643,6 +643,15 @@ pub(crate) enum InvalidFormatStringSuggestion {
span: Span,
replacement: String,
},
#[suggestion(
builtin_macros_format_add_missing_colon,
code = ":?",
applicability = "machine-applicable"
)]
AddMissingColon {
#[primary_span]
span: Span,
},
}
#[derive(Diagnostic)]

View file

@ -329,6 +329,10 @@ fn make_format_args(
replacement,
});
}
parse::Suggestion::AddMissingColon(span) => {
let span = fmt_span.from_inner(InnerSpan::new(span.start, span.end));
e.sugg_ = Some(errors::InvalidFormatStringSuggestion::AddMissingColon { span });
}
}
let guar = ecx.dcx().emit_err(e);
return ExpandResult::Ready(Err(guar));

View file

@ -744,43 +744,43 @@ unsafe extern "C" {
pub struct VaList<'a>(&'a mut VaListImpl);
#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
#[rustc_macro_transparency = "semiopaque"]
pub macro stringify($($t:tt)*) {
/* compiler built-in */
}
#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
#[rustc_macro_transparency = "semiopaque"]
pub macro file() {
/* compiler built-in */
}
#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
#[rustc_macro_transparency = "semiopaque"]
pub macro line() {
/* compiler built-in */
}
#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
#[rustc_macro_transparency = "semiopaque"]
pub macro cfg() {
/* compiler built-in */
}
#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
#[rustc_macro_transparency = "semiopaque"]
pub macro asm() {
/* compiler built-in */
}
#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
#[rustc_macro_transparency = "semiopaque"]
pub macro global_asm() {
/* compiler built-in */
}
#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
#[rustc_macro_transparency = "semiopaque"]
pub macro naked_asm() {
/* compiler built-in */
}

View file

@ -233,7 +233,7 @@ pub(crate) fn compile_global_asm(
#![allow(internal_features)]
#![no_core]
#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
#[rustc_macro_transparency = "semiopaque"]
macro global_asm() { /* compiler built-in */ }
global_asm!(r###"
"####,

View file

@ -748,25 +748,25 @@ extern "C" {
pub struct VaList<'a>(&'a mut VaListImpl);
#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
#[rustc_macro_transparency = "semiopaque"]
pub macro stringify($($t:tt)*) {
/* compiler built-in */
}
#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
#[rustc_macro_transparency = "semiopaque"]
pub macro file() {
/* compiler built-in */
}
#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
#[rustc_macro_transparency = "semiopaque"]
pub macro line() {
/* compiler built-in */
}
#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
#[rustc_macro_transparency = "semiopaque"]
pub macro cfg() {
/* compiler built-in */
}

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

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

@ -49,8 +49,9 @@ impl<'ll> OffloadGlobals<'ll> {
let bin_desc = cx.type_named_struct("struct.__tgt_bin_desc");
cx.set_struct_body(bin_desc, &tgt_bin_desc_ty, false);
let register_lib = declare_offload_fn(&cx, "__tgt_register_lib", mapper_fn_ty);
let unregister_lib = declare_offload_fn(&cx, "__tgt_unregister_lib", mapper_fn_ty);
let reg_lib_decl = cx.type_func(&[cx.type_ptr()], cx.type_void());
let register_lib = declare_offload_fn(&cx, "__tgt_register_lib", reg_lib_decl);
let unregister_lib = declare_offload_fn(&cx, "__tgt_unregister_lib", reg_lib_decl);
let init_ty = cx.type_func(&[], cx.type_void());
let init_rtls = declare_offload_fn(cx, "__tgt_init_all_rtls", init_ty);

View file

@ -187,6 +187,10 @@ fn check_and_apply_linkage<'ll, 'tcx>(
};
llvm::set_linkage(g1, base::linkage_to_llvm(linkage));
// Normally this is done in `get_static_inner`, but when as we generate an internal global,
// it will apply the dso_local to the internal global instead, so do it here, too.
cx.assume_dso_local(g1, true);
// Declare an internal global `extern_with_linkage_foo` which
// is initialized with the address of `foo`. If `foo` is
// discarded during linking (for example, if `foo` has weak

View file

@ -211,6 +211,10 @@ pub(crate) unsafe fn create_module<'ll>(
// LLVM 22 updated the NVPTX layout to indicate 256-bit vector load/store: https://github.com/llvm/llvm-project/pull/155198
target_data_layout = target_data_layout.replace("-i256:256", "");
}
if sess.target.arch == Arch::PowerPC64 {
// LLVM 22 updated the ABI alignment for double on AIX: https://github.com/llvm/llvm-project/pull/144673
target_data_layout = target_data_layout.replace("-f64:32:64", "");
}
}
// Ensure the data-layout values hardcoded remain the defaults.

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

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

@ -379,19 +379,19 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) {
{
false
}
// Unsupported <https://github.com/llvm/llvm-project/issues/94434>
(Arch::Arm64EC, _) => false,
// Unsupported <https://github.com/llvm/llvm-project/issues/94434> (fixed in llvm22)
(Arch::Arm64EC, _) if major < 22 => false,
// Selection failure <https://github.com/llvm/llvm-project/issues/50374> (fixed in llvm21)
(Arch::S390x, _) if major < 21 => false,
// MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054>
(Arch::X86_64, Os::Windows) if *target_env == Env::Gnu && *target_abi != Abi::Llvm => false,
// Infinite recursion <https://github.com/llvm/llvm-project/issues/97981>
(Arch::CSky, _) => false,
(Arch::CSky, _) if major < 22 => false, // (fixed in llvm22)
(Arch::Hexagon, _) if major < 21 => false, // (fixed in llvm21)
(Arch::LoongArch32 | Arch::LoongArch64, _) if major < 21 => false, // (fixed in llvm21)
(Arch::PowerPC | Arch::PowerPC64, _) => false,
(Arch::Sparc | Arch::Sparc64, _) => false,
(Arch::Wasm32 | Arch::Wasm64, _) => false,
(Arch::PowerPC | Arch::PowerPC64, _) if major < 22 => false, // (fixed in llvm22)
(Arch::Sparc | Arch::Sparc64, _) if major < 22 => false, // (fixed in llvm22)
(Arch::Wasm32 | Arch::Wasm64, _) if major < 22 => false, // (fixed in llvm22)
// `f16` support only requires that symbols converting to and from `f32` are available. We
// provide these in `compiler-builtins`, so `f16` should be available on all platforms that
// do not have other ABI issues or LLVM crashes.

View file

@ -10,7 +10,6 @@ use rustc_middle::mir::mono::Visibility;
use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv, LayoutOf};
use rustc_middle::ty::{self, Instance, TypeVisitableExt};
use rustc_session::config::CrateType;
use rustc_span::Symbol;
use rustc_target::spec::{Arch, RelocModel};
use tracing::debug;
@ -92,17 +91,19 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
}
impl CodegenCx<'_, '_> {
fn add_aliases(&self, aliasee: &llvm::Value, aliases: &[(Symbol, Linkage, Visibility)]) {
fn add_aliases(&self, aliasee: &llvm::Value, aliases: &[(DefId, Linkage, Visibility)]) {
let ty = self.get_type_of_global(aliasee);
for (alias, linkage, visibility) in aliases {
let symbol_name = self.tcx.symbol_name(Instance::mono(self.tcx, *alias));
tracing::debug!("ALIAS: {alias:?} {linkage:?} {visibility:?}");
let lldecl = llvm::add_alias(
self.llmod,
ty,
AddressSpace::ZERO,
aliasee,
&CString::new(alias.as_str()).unwrap(),
&CString::new(symbol_name.name).unwrap(),
);
llvm::set_visibility(lldecl, base::visibility_to_llvm(*visibility));
@ -110,7 +111,7 @@ impl CodegenCx<'_, '_> {
}
}
/// Whether a definition or declaration can be assumed to be local to a group of
/// A definition or declaration can be assumed to be local to a group of
/// libraries that form a single DSO or executable.
/// Marks the local as DSO if so.
pub(crate) fn assume_dso_local(&self, llval: &llvm::Value, is_declaration: bool) -> bool {
@ -152,7 +153,7 @@ impl CodegenCx<'_, '_> {
return false;
}
// With pie relocation model calls of functions defined in the translation
// With pie relocation model, calls of functions defined in the translation
// unit can use copy relocations.
if self.tcx.sess.relocation_model() == RelocModel::Pie && !is_declaration {
return true;

View file

@ -1,12 +1,13 @@
use rustc_abi::{Align, BackendRepr, Endian, HasDataLayout, Primitive, Size, TyAndLayout};
use rustc_abi::{Align, BackendRepr, Endian, HasDataLayout, Primitive, Size};
use rustc_codegen_ssa::MemFlags;
use rustc_codegen_ssa::common::IntPredicate;
use rustc_codegen_ssa::mir::operand::OperandRef;
use rustc_codegen_ssa::traits::{
BaseTypeCodegenMethods, BuilderMethods, ConstCodegenMethods, LayoutTypeCodegenMethods,
};
use rustc_middle::bug;
use rustc_middle::ty::Ty;
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
use rustc_target::spec::{Abi, Arch, Env};
use crate::builder::Builder;
@ -82,6 +83,7 @@ enum PassMode {
enum SlotSize {
Bytes8 = 8,
Bytes4 = 4,
Bytes1 = 1,
}
enum AllowHigherAlign {
@ -728,7 +730,7 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>(
fn copy_to_temporary_if_more_aligned<'ll, 'tcx>(
bx: &mut Builder<'_, 'll, 'tcx>,
reg_addr: &'ll Value,
layout: TyAndLayout<'tcx, Ty<'tcx>>,
layout: TyAndLayout<'tcx>,
src_align: Align,
) -> &'ll Value {
if layout.layout.align.abi > src_align {
@ -751,7 +753,7 @@ fn copy_to_temporary_if_more_aligned<'ll, 'tcx>(
fn x86_64_sysv64_va_arg_from_memory<'ll, 'tcx>(
bx: &mut Builder<'_, 'll, 'tcx>,
va_list_addr: &'ll Value,
layout: TyAndLayout<'tcx, Ty<'tcx>>,
layout: TyAndLayout<'tcx>,
) -> &'ll Value {
let dl = bx.cx.data_layout();
let ptr_align_abi = dl.data_layout().pointer_align().abi;
@ -1003,15 +1005,17 @@ fn emit_xtensa_va_arg<'ll, 'tcx>(
return bx.load(layout.llvm_type(bx), value_ptr, layout.align.abi);
}
/// Determine the va_arg implementation to use. The LLVM va_arg instruction
/// is lacking in some instances, so we should only use it as a fallback.
pub(super) fn emit_va_arg<'ll, 'tcx>(
bx: &mut Builder<'_, 'll, 'tcx>,
addr: OperandRef<'tcx, &'ll Value>,
target_ty: Ty<'tcx>,
) -> &'ll Value {
// Determine the va_arg implementation to use. The LLVM va_arg instruction
// is lacking in some instances, so we should only use it as a fallback.
let target = &bx.cx.tcx.sess.target;
let layout = bx.cx.layout_of(target_ty);
let target_ty_size = layout.layout.size().bytes();
let target = &bx.cx.tcx.sess.target;
match target.arch {
Arch::X86 => emit_ptr_va_arg(
bx,
@ -1069,23 +1073,79 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
AllowHigherAlign::Yes,
ForceRightAdjust::No,
),
Arch::LoongArch32 => emit_ptr_va_arg(
bx,
addr,
target_ty,
if target_ty_size > 2 * 4 { PassMode::Indirect } else { PassMode::Direct },
SlotSize::Bytes4,
AllowHigherAlign::Yes,
ForceRightAdjust::No,
),
Arch::LoongArch64 => emit_ptr_va_arg(
bx,
addr,
target_ty,
if target_ty_size > 2 * 8 { PassMode::Indirect } else { PassMode::Direct },
SlotSize::Bytes8,
AllowHigherAlign::Yes,
ForceRightAdjust::No,
),
Arch::AmdGpu => emit_ptr_va_arg(
bx,
addr,
target_ty,
PassMode::Direct,
SlotSize::Bytes4,
AllowHigherAlign::No,
ForceRightAdjust::No,
),
Arch::Nvptx64 => emit_ptr_va_arg(
bx,
addr,
target_ty,
PassMode::Direct,
SlotSize::Bytes1,
AllowHigherAlign::Yes,
ForceRightAdjust::No,
),
Arch::Wasm32 => emit_ptr_va_arg(
bx,
addr,
target_ty,
if layout.is_aggregate() || layout.is_zst() || layout.is_1zst() {
PassMode::Indirect
} else {
PassMode::Direct
},
SlotSize::Bytes4,
AllowHigherAlign::Yes,
ForceRightAdjust::No,
),
Arch::Wasm64 => bug!("c-variadic functions are not fully implemented for wasm64"),
Arch::CSky => emit_ptr_va_arg(
bx,
addr,
target_ty,
PassMode::Direct,
SlotSize::Bytes4,
AllowHigherAlign::Yes,
ForceRightAdjust::No,
),
// Windows x86_64
Arch::X86_64 if target.is_like_windows => {
let target_ty_size = bx.cx.size_of(target_ty).bytes();
emit_ptr_va_arg(
bx,
addr,
target_ty,
if target_ty_size > 8 || !target_ty_size.is_power_of_two() {
PassMode::Indirect
} else {
PassMode::Direct
},
SlotSize::Bytes8,
AllowHigherAlign::No,
ForceRightAdjust::No,
)
}
Arch::X86_64 if target.is_like_windows => emit_ptr_va_arg(
bx,
addr,
target_ty,
if target_ty_size > 8 || !target_ty_size.is_power_of_two() {
PassMode::Indirect
} else {
PassMode::Direct
},
SlotSize::Bytes8,
AllowHigherAlign::No,
ForceRightAdjust::No,
),
// This includes `target.is_like_darwin`, which on x86_64 targets is like sysv64.
Arch::X86_64 => emit_x86_64_sysv64_va_arg(bx, addr, target_ty),
Arch::Xtensa => emit_xtensa_va_arg(bx, addr, target_ty),

View file

@ -10,6 +10,8 @@ codegen_ssa_archive_build_failure = failed to build archive at `{$path}`: {$erro
codegen_ssa_binary_output_to_tty = option `-o` or `--emit` is used to write binary output type `{$shorthand}` to stdout, but stdout is a tty
codegen_ssa_bpf_staticlib_not_supported = linking static libraries is not supported for BPF
codegen_ssa_cgu_not_recorded =
CGU-reuse for `{$cgu_user_name}` is (mangled: `{$cgu_name}`) was not recorded

View file

@ -22,10 +22,11 @@ use tracing::trace;
use super::metadata::{create_compressed_metadata_file, search_for_section};
use crate::common;
// Re-exporting for rustc_codegen_llvm::back::archive
pub use crate::errors::{ArchiveBuildFailure, ExtractBundledLibsError, UnknownArchiveKind};
// Public for ArchiveBuilderBuilder::extract_bundled_libs
pub use crate::errors::ExtractBundledLibsError;
use crate::errors::{
DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorCreatingImportLibrary, ErrorWritingDEFFile,
ArchiveBuildFailure, DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorCreatingImportLibrary,
ErrorWritingDEFFile, UnknownArchiveKind,
};
/// An item to be included in an import library.

View file

@ -839,6 +839,11 @@ impl<'a> Linker for GccLinker<'a> {
self.sess.dcx().emit_fatal(errors::LibDefWriteFailure { error });
}
self.link_arg(path);
} else if self.sess.target.is_like_wasm {
self.link_arg("--no-export-dynamic");
for (sym, _) in symbols {
self.link_arg("--export").link_arg(sym);
}
} else if crate_type == CrateType::Executable && !self.sess.target.is_like_solaris {
let res: io::Result<()> = try {
let mut f = File::create_buffered(&path)?;
@ -853,11 +858,6 @@ impl<'a> Linker for GccLinker<'a> {
self.sess.dcx().emit_fatal(errors::VersionScriptWriteFailure { error });
}
self.link_arg("--dynamic-list").link_arg(path);
} else if self.sess.target.is_like_wasm {
self.link_arg("--no-export-dynamic");
for (sym, _) in symbols {
self.link_arg("--export").link_arg(sym);
}
} else {
// Write an LD version script
let res: io::Result<()> = try {
@ -2075,7 +2075,7 @@ impl<'a> Linker for BpfLinker<'a> {
}
fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) {
panic!("staticlibs not supported")
self.sess.dcx().emit_fatal(errors::BpfStaticlibNotSupported)
}
fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {

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,7 +3,9 @@ use std::str::FromStr;
use rustc_abi::{Align, ExternAbi};
use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode};
use rustc_ast::{LitKind, MetaItem, MetaItemInner, attr};
use rustc_hir::attrs::{AttributeKind, InlineAttr, Linkage, RtsanSetting, UsedBy};
use rustc_hir::attrs::{
AttributeKind, EiiImplResolution, InlineAttr, Linkage, RtsanSetting, UsedBy,
};
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
use rustc_hir::{self as hir, Attribute, LangItem, find_attr, lang_items};
@ -13,10 +15,10 @@ use rustc_middle::middle::codegen_fn_attrs::{
use rustc_middle::mir::mono::Visibility;
use rustc_middle::query::Providers;
use rustc_middle::span_bug;
use rustc_middle::ty::{self as ty, Instance, TyCtxt};
use rustc_middle::ty::{self as ty, TyCtxt};
use rustc_session::lint;
use rustc_session::parse::feature_err;
use rustc_span::{Ident, Span, Symbol, sym};
use rustc_span::{Span, sym};
use rustc_target::spec::Os;
use crate::errors;
@ -285,13 +287,23 @@ fn process_builtin_attrs(
}
AttributeKind::EiiImpls(impls) => {
for i in impls {
let extern_item = find_attr!(
tcx.get_all_attrs(i.eii_macro),
AttributeKind::EiiExternTarget(target) => target.eii_extern_target
)
.expect("eii should have declaration macro with extern target attribute");
let symbol_name = tcx.symbol_name(Instance::mono(tcx, extern_item));
let extern_item = match i.resolution {
EiiImplResolution::Macro(def_id) => {
let Some(extern_item) = find_attr!(
tcx.get_all_attrs(def_id),
AttributeKind::EiiExternTarget(target) => target.eii_extern_target
) else {
tcx.dcx().span_delayed_bug(
i.span,
"resolved to something that's not an EII",
);
continue;
};
extern_item
}
EiiImplResolution::Known(decl) => decl.eii_extern_target,
EiiImplResolution::Error(_eg) => continue,
};
// this is to prevent a bug where a single crate defines both the default and explicit implementation
// for an EII. In that case, both of them may be part of the same final object file. I'm not 100% sure
@ -304,13 +316,13 @@ fn process_builtin_attrs(
// iterate over all implementations *in the current crate*
// (this is ok since we generate codegen fn attrs in the local crate)
// if any of them is *not default* then don't emit the alias.
&& tcx.externally_implementable_items(LOCAL_CRATE).get(&i.eii_macro).expect("at least one").1.iter().any(|(_, imp)| !imp.is_default)
&& tcx.externally_implementable_items(LOCAL_CRATE).get(&extern_item).expect("at least one").1.iter().any(|(_, imp)| !imp.is_default)
{
continue;
}
codegen_fn_attrs.foreign_item_symbol_aliases.push((
Symbol::intern(symbol_name.name),
extern_item,
if i.is_default { Linkage::LinkOnceAny } else { Linkage::External },
Visibility::Default,
));
@ -327,7 +339,7 @@ fn process_builtin_attrs(
}
}
let Some(Ident { name, .. }) = attr.ident() else {
let Some(name) = attr.name() else {
continue;
};

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

@ -661,7 +661,7 @@ pub(crate) struct RlibArchiveBuildFailure {
}
#[derive(Diagnostic)]
// Public for rustc_codegen_llvm::back::archive
// Public for ArchiveBuilderBuilder::extract_bundled_libs
pub enum ExtractBundledLibsError<'a> {
#[diag(codegen_ssa_extract_bundled_libs_open_file)]
OpenFile { rlib: &'a Path, error: Box<dyn std::error::Error> },
@ -700,19 +700,21 @@ pub(crate) struct UnsupportedLinkSelfContained;
#[derive(Diagnostic)]
#[diag(codegen_ssa_archive_build_failure)]
// Public for rustc_codegen_llvm::back::archive
pub struct ArchiveBuildFailure {
pub(crate) struct ArchiveBuildFailure {
pub path: PathBuf,
pub error: std::io::Error,
}
#[derive(Diagnostic)]
#[diag(codegen_ssa_unknown_archive_kind)]
// Public for rustc_codegen_llvm::back::archive
pub struct UnknownArchiveKind<'a> {
pub(crate) struct UnknownArchiveKind<'a> {
pub kind: &'a str,
}
#[derive(Diagnostic)]
#[diag(codegen_ssa_bpf_staticlib_not_supported)]
pub(crate) struct BpfStaticlibNotSupported;
#[derive(Diagnostic)]
#[diag(codegen_ssa_multiple_main_functions)]
#[help]

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

@ -6,9 +6,7 @@
// having basically only two use-cases that act in different ways.
use rustc_errors::ErrorGuaranteed;
use rustc_hir::attrs::AttributeKind;
use rustc_hir::def::DefKind;
use rustc_hir::{LangItem, find_attr};
use rustc_hir::LangItem;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::mir::*;
use rustc_middle::ty::{self, AdtDef, Ty};
@ -366,14 +364,10 @@ where
// check performed after the promotion. Verify that with an assertion.
assert!(promoted.is_none() || Q::ALLOW_PROMOTED);
// Avoid looking at attrs of anon consts as that will ICE
let is_type_const_item =
matches!(cx.tcx.def_kind(def), DefKind::Const | DefKind::AssocConst)
&& find_attr!(cx.tcx.get_all_attrs(def), AttributeKind::TypeConst(_));
// Don't peak inside trait associated constants, also `#[type_const] const` items
// don't have bodies so there's nothing to look at
if promoted.is_none() && cx.tcx.trait_of_assoc(def).is_none() && !is_type_const_item {
if promoted.is_none() && cx.tcx.trait_of_assoc(def).is_none() && !cx.tcx.is_type_const(def)
{
let qualifs = cx.tcx.at(constant.span).mir_const_qualif(def);
if !Q::in_qualifs(&qualifs) {

View file

@ -8,7 +8,7 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexMap, IndexEntry};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::{self as hir, CRATE_HIR_ID, LangItem};
use rustc_middle::mir::AssertMessage;
use rustc_middle::mir::interpret::ReportedErrorInfo;
use rustc_middle::mir::interpret::{Pointer, ReportedErrorInfo};
use rustc_middle::query::TyCtxtAt;
use rustc_middle::ty::layout::{HasTypingEnv, TyAndLayout, ValidityRequirement};
use rustc_middle::ty::{self, Ty, TyCtxt};
@ -22,7 +22,7 @@ use crate::errors::{LongRunning, LongRunningWarn};
use crate::fluent_generated as fluent;
use crate::interpret::{
self, AllocId, AllocInit, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame,
GlobalAlloc, ImmTy, InterpCx, InterpResult, OpTy, PlaceTy, Pointer, RangeSet, Scalar,
GlobalAlloc, ImmTy, InterpCx, InterpResult, OpTy, PlaceTy, RangeSet, Scalar,
compile_time_machine, err_inval, interp_ok, throw_exhaust, throw_inval, throw_ub,
throw_ub_custom, throw_unsup, throw_unsup_format,
};
@ -586,6 +586,11 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
}
}
sym::type_of => {
let ty = ecx.read_type_id(&args[0])?;
ecx.write_type_info(ty, dest)?;
}
_ => {
// We haven't handled the intrinsic, let's see if we can use a fallback body.
if ecx.tcx.intrinsic(instance.def_id()).unwrap().must_be_overridden {

View file

@ -13,6 +13,7 @@ mod error;
mod eval_queries;
mod fn_queries;
mod machine;
mod type_info;
mod valtrees;
pub use self::dummy_machine::*;

View file

@ -0,0 +1,175 @@
use rustc_abi::FieldIdx;
use rustc_hir::LangItem;
use rustc_middle::mir::interpret::CtfeProvenance;
use rustc_middle::span_bug;
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::{self, ScalarInt, Ty};
use rustc_span::{Symbol, sym};
use crate::const_eval::CompileTimeMachine;
use crate::interpret::{
Immediate, InterpCx, InterpResult, MPlaceTy, MemoryKind, Writeable, interp_ok,
};
impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
/// Writes a `core::mem::type_info::TypeInfo` for a given type, `ty` to the given place.
pub(crate) fn write_type_info(
&mut self,
ty: Ty<'tcx>,
dest: &impl Writeable<'tcx, CtfeProvenance>,
) -> InterpResult<'tcx> {
let ty_struct = self.tcx.require_lang_item(LangItem::Type, self.tcx.span);
let ty_struct = self.tcx.type_of(ty_struct).no_bound_vars().unwrap();
assert_eq!(ty_struct, dest.layout().ty);
let ty_struct = ty_struct.ty_adt_def().unwrap().non_enum_variant();
// Fill all fields of the `TypeInfo` struct.
for (idx, field) in ty_struct.fields.iter_enumerated() {
let field_dest = self.project_field(dest, idx)?;
let downcast = |name: Symbol| {
let variants = field_dest.layout().ty.ty_adt_def().unwrap().variants();
let variant_id = variants
.iter_enumerated()
.find(|(_idx, var)| var.name == name)
.unwrap_or_else(|| panic!("got {name} but expected one of {variants:#?}"))
.0;
interp_ok((variant_id, self.project_downcast(&field_dest, variant_id)?))
};
match field.name {
sym::kind => {
let variant_index = match ty.kind() {
ty::Tuple(fields) => {
let (variant, variant_place) = downcast(sym::Tuple)?;
// project to the single tuple variant field of `type_info::Tuple` struct type
let tuple_place = self.project_field(&variant_place, FieldIdx::ZERO)?;
assert_eq!(
1,
tuple_place
.layout()
.ty
.ty_adt_def()
.unwrap()
.non_enum_variant()
.fields
.len()
);
self.write_tuple_fields(tuple_place, fields, ty)?;
variant
}
// For now just merge all primitives into one `Leaf` variant with no data
ty::Uint(_) | ty::Int(_) | ty::Float(_) | ty::Char | ty::Bool => {
downcast(sym::Leaf)?.0
}
ty::Adt(_, _)
| ty::Foreign(_)
| ty::Str
| ty::Array(_, _)
| ty::Pat(_, _)
| ty::Slice(_)
| ty::RawPtr(..)
| ty::Ref(..)
| ty::FnDef(..)
| ty::FnPtr(..)
| ty::UnsafeBinder(..)
| ty::Dynamic(..)
| ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Coroutine(..)
| ty::CoroutineWitness(..)
| ty::Never
| ty::Alias(..)
| ty::Param(_)
| ty::Bound(..)
| ty::Placeholder(_)
| ty::Infer(..)
| ty::Error(_) => downcast(sym::Other)?.0,
};
self.write_discriminant(variant_index, &field_dest)?
}
sym::size => {
let layout = self.layout_of(ty)?;
let variant_index = if layout.is_sized() {
let (variant, variant_place) = downcast(sym::Some)?;
let size_field_place =
self.project_field(&variant_place, FieldIdx::ZERO)?;
self.write_scalar(
ScalarInt::try_from_target_usize(layout.size.bytes(), self.tcx.tcx)
.unwrap(),
&size_field_place,
)?;
variant
} else {
downcast(sym::None)?.0
};
self.write_discriminant(variant_index, &field_dest)?;
}
other => span_bug!(self.tcx.span, "unknown `Type` field {other}"),
}
}
interp_ok(())
}
pub(crate) fn write_tuple_fields(
&mut self,
tuple_place: impl Writeable<'tcx, CtfeProvenance>,
fields: &[Ty<'tcx>],
tuple_ty: Ty<'tcx>,
) -> InterpResult<'tcx> {
// project into the `type_info::Tuple::fields` field
let fields_slice_place = self.project_field(&tuple_place, FieldIdx::ZERO)?;
// get the `type_info::Field` type from `fields: &[Field]`
let field_type = fields_slice_place
.layout()
.ty
.builtin_deref(false)
.unwrap()
.sequence_element_type(self.tcx.tcx);
// Create an array with as many elements as the number of fields in the inspected tuple
let fields_layout =
self.layout_of(Ty::new_array(self.tcx.tcx, field_type, fields.len() as u64))?;
let fields_place = self.allocate(fields_layout, MemoryKind::Stack)?;
let mut fields_places = self.project_array_fields(&fields_place)?;
let tuple_layout = self.layout_of(tuple_ty)?;
while let Some((i, place)) = fields_places.next(self)? {
let field_ty = fields[i as usize];
self.write_field(field_ty, place, tuple_layout, i)?;
}
let fields_place = fields_place.map_provenance(CtfeProvenance::as_immutable);
let ptr = Immediate::new_slice(fields_place.ptr(), fields.len() as u64, self);
self.write_immediate(ptr, &fields_slice_place)
}
fn write_field(
&mut self,
field_ty: Ty<'tcx>,
place: MPlaceTy<'tcx>,
layout: TyAndLayout<'tcx>,
idx: u64,
) -> InterpResult<'tcx> {
for (field_idx, field_ty_field) in
place.layout.ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
{
let field_place = self.project_field(&place, field_idx)?;
match field_ty_field.name {
sym::ty => self.write_type_id(field_ty, &field_place)?,
sym::offset => {
let offset = layout.fields.offset(idx as usize);
self.write_scalar(
ScalarInt::try_from_target_usize(offset.bytes(), self.tcx.tcx).unwrap(),
&field_place,
)?;
}
other => {
span_bug!(self.tcx.def_span(field_ty_field.did), "unimplemented field {other}")
}
}
}
interp_ok(())
}
}

View file

@ -27,6 +27,7 @@ use super::{
throw_ub_custom, throw_ub_format,
};
use crate::fluent_generated as fluent;
use crate::interpret::Writeable;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum MulAddType {
@ -68,10 +69,10 @@ pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> (AllocId
}
impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
/// Generates a value of `TypeId` for `ty` in-place.
fn write_type_id(
pub(crate) fn write_type_id(
&mut self,
ty: Ty<'tcx>,
dest: &PlaceTy<'tcx, M::Provenance>,
dest: &impl Writeable<'tcx, M::Provenance>,
) -> InterpResult<'tcx, ()> {
let tcx = self.tcx;
let type_id_hash = tcx.type_id_hash(ty).as_u128();

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

@ -235,7 +235,7 @@ declare_features! (
(accepted, generic_param_attrs, "1.27.0", Some(48848)),
/// Allows the `#[global_allocator]` attribute.
(accepted, global_allocator, "1.28.0", Some(27389)),
// FIXME: explain `globs`.
/// Allows globs imports (`use module::*;`) to import all public items from a module.
(accepted, globs, "1.0.0", None),
/// Allows using `..=X` as a pattern.
(accepted, half_open_range_patterns, "1.66.0", Some(67264)),

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.

View file

@ -233,28 +233,20 @@ declare_features! (
(internal, link_cfg, "1.14.0", None),
/// Allows using `?Trait` trait bounds in more contexts.
(internal, more_maybe_bounds, "1.82.0", None),
/// Allows the `multiple_supertrait_upcastable` lint.
(unstable, multiple_supertrait_upcastable, "1.69.0", None),
/// Allow negative trait bounds. This is an internal-only feature for testing the trait solver!
(internal, negative_bounds, "1.71.0", None),
/// Set the maximum pattern complexity allowed (not limited by default).
(internal, pattern_complexity_limit, "1.78.0", None),
/// Allows using pattern types.
(internal, pattern_types, "1.79.0", Some(123646)),
/// Allows using `#[prelude_import]` on glob `use` items.
(internal, prelude_import, "1.2.0", None),
/// Used to identify crates that contain the profiler runtime.
(internal, profiler_runtime, "1.18.0", None),
/// Allows using `rustc_*` attributes (RFC 572).
(internal, rustc_attrs, "1.0.0", None),
/// Introduces a hierarchy of `Sized` traits (RFC 3729).
(unstable, sized_hierarchy, "1.89.0", None),
/// Allows using the `#[stable]` and `#[unstable]` attributes.
(internal, staged_api, "1.0.0", None),
/// Added for testing unstable lints; perma-unstable.
(internal, test_unstable_lint, "1.60.0", None),
/// Helps with formatting for `group_imports = "StdExternalCrate"`.
(unstable, unqualified_local_imports, "1.83.0", Some(138299)),
/// Use for stable + negative coherence and strict coherence depending on trait's
/// rustc_strict_coherence value.
(unstable, with_negative_coherence, "1.60.0", None),
@ -295,6 +287,8 @@ declare_features! (
(internal, needs_panic_runtime, "1.10.0", Some(32837)),
/// Allows using the `#![panic_runtime]` attribute.
(internal, panic_runtime, "1.10.0", Some(32837)),
/// Allows using pattern types.
(internal, pattern_types, "1.79.0", Some(123646)),
/// Allows using `#[rustc_allow_const_fn_unstable]`.
/// This is an attribute on `const fn` for the same
/// purpose as `#[allow_internal_unstable]`.
@ -305,12 +299,16 @@ declare_features! (
(internal, rustdoc_internals, "1.58.0", Some(90418)),
/// Allows using the `rustdoc::missing_doc_code_examples` lint
(unstable, rustdoc_missing_doc_code_examples, "1.31.0", Some(101730)),
/// Introduces a hierarchy of `Sized` traits (RFC 3729).
(unstable, sized_hierarchy, "1.89.0", Some(144404)),
/// Allows using `#[structural_match]` which indicates that a type is structurally matchable.
/// FIXME: Subsumed by trait `StructuralPartialEq`, cannot move to removed until a library
/// feature with the same name exists.
(unstable, structural_match, "1.8.0", Some(31434)),
/// Allows using the `rust-call` ABI.
(unstable, unboxed_closures, "1.0.0", Some(29625)),
/// Helps with formatting for `group_imports = "StdExternalCrate"`.
(unstable, unqualified_local_imports, "1.83.0", Some(138299)),
// !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
// Features are listed in alphabetical order. Tidy will fail if you don't keep it this way.
// !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
@ -363,8 +361,6 @@ declare_features! (
(unstable, asm_goto_with_outputs, "1.85.0", Some(119364)),
/// Allows the `may_unwind` option in inline assembly.
(unstable, asm_unwind, "1.58.0", Some(93334)),
/// Allows users to enforce equality of associated constants `TraitImpl<AssocConst=3>`.
(unstable, associated_const_equality, "1.58.0", Some(92827)),
/// Allows associated type defaults.
(unstable, associated_type_defaults, "1.2.0", Some(29661)),
/// Allows implementing `AsyncDrop`.
@ -571,6 +567,8 @@ declare_features! (
(unstable, more_qualified_paths, "1.54.0", Some(86935)),
/// The `movrs` target feature on x86.
(unstable, movrs_target_feature, "1.88.0", Some(137976)),
/// Allows the `multiple_supertrait_upcastable` lint.
(unstable, multiple_supertrait_upcastable, "1.69.0", Some(150833)),
/// Allows the `#[must_not_suspend]` attribute.
(unstable, must_not_suspend, "1.57.0", Some(83310)),
/// Allows `mut ref` and `mut ref mut` identifier patterns.

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;
@ -11,7 +11,7 @@ use rustc_error_messages::{DiagArgValue, IntoDiagArg};
use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute};
use rustc_span::def_id::DefId;
use rustc_span::hygiene::Transparency;
use rustc_span::{Ident, Span, Symbol};
use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol};
pub use rustc_target::spec::SanitizerSet;
use thin_vec::ThinVec;
@ -19,9 +19,22 @@ use crate::attrs::pretty_printing::PrintAttribute;
use crate::limit::Limit;
use crate::{DefaultBodyStability, PartialConstStability, RustcVersion, Stability};
#[derive(Copy, Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
pub enum EiiImplResolution {
/// Usually, finding the extern item that an EII implementation implements means finding
/// the defid of the associated attribute macro, and looking at *its* attributes to find
/// what foreign item its associated with.
Macro(DefId),
/// Sometimes though, we already know statically and can skip some name resolution.
/// Stored together with the eii's name for diagnostics.
Known(EiiDecl),
/// For when resolution failed, but we want to continue compilation
Error(ErrorGuaranteed),
}
#[derive(Copy, Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
pub struct EiiImpl {
pub eii_macro: DefId,
pub resolution: EiiImplResolution,
pub impl_marked_unsafe: bool,
pub span: Span,
pub inner_span: Span,
@ -33,7 +46,7 @@ pub struct EiiDecl {
pub eii_extern_target: DefId,
/// whether or not it is unsafe to implement this EII
pub impl_unsafe: bool,
pub span: Span,
pub name: Ident,
}
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, PrintAttribute)]
@ -212,83 +225,6 @@ impl<ModId> StrippedCfgItem<ModId> {
}
}
#[derive(Encodable, Decodable, Clone, Debug, PartialEq, Eq, Hash)]
#[derive(HashStable_Generic, PrintAttribute)]
pub enum CfgEntry {
All(ThinVec<CfgEntry>, Span),
Any(ThinVec<CfgEntry>, Span),
Not(Box<CfgEntry>, Span),
Bool(bool, Span),
NameValue { name: Symbol, value: Option<Symbol>, span: Span },
Version(Option<RustcVersion>, Span),
}
impl CfgEntry {
pub fn span(&self) -> Span {
let (Self::All(_, span)
| Self::Any(_, span)
| Self::Not(_, span)
| Self::Bool(_, span)
| Self::NameValue { span, .. }
| Self::Version(_, span)) = self;
*span
}
/// Same as `PartialEq` but doesn't check spans and ignore order of cfgs.
pub fn is_equivalent_to(&self, other: &Self) -> bool {
match (self, other) {
(Self::All(a, _), Self::All(b, _)) | (Self::Any(a, _), Self::Any(b, _)) => {
a.len() == b.len() && a.iter().all(|a| b.iter().any(|b| a.is_equivalent_to(b)))
}
(Self::Not(a, _), Self::Not(b, _)) => a.is_equivalent_to(b),
(Self::Bool(a, _), Self::Bool(b, _)) => a == b,
(
Self::NameValue { name: name1, value: value1, .. },
Self::NameValue { name: name2, value: value2, .. },
) => name1 == name2 && value1 == value2,
(Self::Version(a, _), Self::Version(b, _)) => a == b,
_ => false,
}
}
}
impl fmt::Display for CfgEntry {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fn write_entries(
name: &str,
entries: &[CfgEntry],
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
write!(f, "{name}(")?;
for (nb, entry) in entries.iter().enumerate() {
if nb != 0 {
f.write_str(", ")?;
}
entry.fmt(f)?;
}
f.write_str(")")
}
match self {
Self::All(entries, _) => write_entries("all", entries, f),
Self::Any(entries, _) => write_entries("any", entries, f),
Self::Not(entry, _) => write!(f, "not({entry})"),
Self::Bool(value, _) => write!(f, "{value}"),
Self::NameValue { name, value, .. } => {
match value {
// We use `as_str` and debug display to have characters escaped and `"`
// characters surrounding the string.
Some(value) => write!(f, "{name} = {:?}", value.as_str()),
None => write!(f, "{name}"),
}
}
Self::Version(version, _) => match version {
Some(version) => write!(f, "{version}"),
None => Ok(()),
},
}
}
}
/// Possible values for the `#[linkage]` attribute, allowing to specify the
/// linkage type for a `MonoItem`.
///
@ -713,6 +649,12 @@ pub enum AttributeKind {
span: Span,
},
/// Represents the trace attribute of `#[cfg_attr]`
CfgAttrTrace,
/// Represents the trace attribute of `#[cfg]`
CfgTrace(ThinVec<(CfgEntry, Span)>),
/// Represents `#[cfi_encoding]`
CfiEncoding { encoding: Symbol },
@ -938,6 +880,9 @@ pub enum AttributeKind {
/// Represents `#[rustc_coherence_is_core]`
RustcCoherenceIsCore(Span),
/// Represents `#[rustc_has_incoherent_inherent_impls]`
RustcHasIncoherentInherentImpls,
/// Represents `#[rustc_layout_scalar_valid_range_end]`.
RustcLayoutScalarValidRangeEnd(Box<u128>, Span),

View file

@ -26,6 +26,8 @@ impl AttributeKind {
AsPtr(..) => Yes,
AutomaticallyDerived(..) => Yes,
BodyStability { .. } => No,
CfgAttrTrace => Yes,
CfgTrace(..) => Yes,
CfiEncoding { .. } => Yes,
Coinductive(..) => No,
Cold(..) => No,
@ -93,6 +95,7 @@ impl AttributeKind {
Repr { .. } => No,
RustcBuiltinMacro { .. } => Yes,
RustcCoherenceIsCore(..) => No,
RustcHasIncoherentInherentImpls => Yes,
RustcLayoutScalarValidRangeEnd(..) => Yes,
RustcLayoutScalarValidRangeStart(..) => Yes,
RustcLegacyConstGenerics { .. } => Yes,

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

@ -423,7 +423,7 @@ impl<'hir> ConstItemRhs<'hir> {
pub fn span<'tcx>(&self, tcx: impl crate::intravisit::HirTyCtxt<'tcx>) -> Span {
match self {
ConstItemRhs::Body(body_id) => tcx.hir_body(*body_id).value.span,
ConstItemRhs::TypeConst(ct_arg) => ct_arg.span(),
ConstItemRhs::TypeConst(ct_arg) => ct_arg.span,
}
}
}
@ -440,13 +440,14 @@ impl<'hir> ConstItemRhs<'hir> {
/// versus const args that are literals or have arbitrary computations (e.g., `{ 1 + 3 }`).
///
/// For an explanation of the `Unambig` generic parameter see the dev-guide:
/// <https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html>
/// <https://rustc-dev-guide.rust-lang.org/ambig-unambig-ty-and-consts.html>
#[derive(Clone, Copy, Debug, HashStable_Generic)]
#[repr(C)]
pub struct ConstArg<'hir, Unambig = ()> {
#[stable_hasher(ignore)]
pub hir_id: HirId,
pub kind: ConstArgKind<'hir, Unambig>,
pub span: Span,
}
impl<'hir> ConstArg<'hir, AmbigArg> {
@ -475,7 +476,7 @@ impl<'hir> ConstArg<'hir> {
/// Functions accepting ambiguous consts will not handle the [`ConstArgKind::Infer`] variant, if
/// infer consts are relevant to you then care should be taken to handle them separately.
pub fn try_as_ambig_ct(&self) -> Option<&ConstArg<'hir, AmbigArg>> {
if let ConstArgKind::Infer(_, ()) = self.kind {
if let ConstArgKind::Infer(()) = self.kind {
return None;
}
@ -494,22 +495,13 @@ impl<'hir, Unambig> ConstArg<'hir, Unambig> {
_ => None,
}
}
pub fn span(&self) -> Span {
match self.kind {
ConstArgKind::Struct(path, _) => path.span(),
ConstArgKind::Path(path) => path.span(),
ConstArgKind::Anon(anon) => anon.span,
ConstArgKind::Error(span, _) => span,
ConstArgKind::Infer(span, _) => span,
}
}
}
/// See [`ConstArg`].
#[derive(Clone, Copy, Debug, HashStable_Generic)]
#[repr(u8, C)]
pub enum ConstArgKind<'hir, Unambig = ()> {
Tup(&'hir [&'hir ConstArg<'hir, Unambig>]),
/// **Note:** Currently this is only used for bare const params
/// (`N` where `fn foo<const N: usize>(...)`),
/// not paths to any const (`N` where `const N: usize = ...`).
@ -519,11 +511,14 @@ pub enum ConstArgKind<'hir, Unambig = ()> {
Anon(&'hir AnonConst),
/// Represents construction of struct/struct variants
Struct(QPath<'hir>, &'hir [&'hir ConstArgExprField<'hir>]),
/// Tuple constructor variant
TupleCall(QPath<'hir>, &'hir [&'hir ConstArg<'hir>]),
/// Error const
Error(Span, ErrorGuaranteed),
Error(ErrorGuaranteed),
/// This variant is not always used to represent inference consts, sometimes
/// [`GenericArg::Infer`] is used instead.
Infer(Span, Unambig),
Infer(Unambig),
Literal(LitKind),
}
#[derive(Clone, Copy, Debug, HashStable_Generic)]
@ -569,7 +564,7 @@ impl GenericArg<'_> {
match self {
GenericArg::Lifetime(l) => l.ident.span,
GenericArg::Type(t) => t.span,
GenericArg::Const(c) => c.span(),
GenericArg::Const(c) => c.span,
GenericArg::Infer(i) => i.span,
}
}
@ -1196,7 +1191,7 @@ pub enum AttrArgs {
#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable)]
pub struct AttrPath {
pub segments: Box<[Ident]>,
pub segments: Box<[Symbol]>,
pub span: Span,
}
@ -1212,7 +1207,7 @@ impl AttrPath {
segments: path
.segments
.iter()
.map(|i| Ident { name: i.ident.name, span: lower_span(i.ident.span) })
.map(|i| i.ident.name)
.collect::<Vec<_>>()
.into_boxed_slice(),
span: lower_span(path.span),
@ -1222,7 +1217,11 @@ impl AttrPath {
impl fmt::Display for AttrPath {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", join_path_idents(&self.segments))
write!(
f,
"{}",
join_path_idents(self.segments.iter().map(|i| Ident { name: *i, span: DUMMY_SP }))
)
}
}
@ -1327,7 +1326,7 @@ impl AttributeExt for Attribute {
/// For a single-segment attribute, returns its name; otherwise, returns `None`.
#[inline]
fn ident(&self) -> Option<Ident> {
fn name(&self) -> Option<Symbol> {
match &self {
Attribute::Unparsed(n) => {
if let [ident] = n.path.segments.as_ref() {
@ -1343,7 +1342,7 @@ impl AttributeExt for Attribute {
#[inline]
fn path_matches(&self, name: &[Symbol]) -> bool {
match &self {
Attribute::Unparsed(n) => n.path.segments.iter().map(|ident| &ident.name).eq(name),
Attribute::Unparsed(n) => n.path.segments.iter().eq(name),
_ => false,
}
}
@ -1364,6 +1363,7 @@ impl AttributeExt for Attribute {
// FIXME: should not be needed anymore when all attrs are parsed
Attribute::Parsed(AttributeKind::DocComment { span, .. }) => *span,
Attribute::Parsed(AttributeKind::Deprecation { span, .. }) => *span,
Attribute::Parsed(AttributeKind::CfgTrace(cfgs)) => cfgs[0].1,
a => panic!("can't get the span of an arbitrary parsed attribute: {a:?}"),
}
}
@ -1379,13 +1379,20 @@ impl AttributeExt for Attribute {
}
#[inline]
fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>> {
fn symbol_path(&self) -> Option<SmallVec<[Symbol; 1]>> {
match &self {
Attribute::Unparsed(n) => Some(n.path.segments.iter().copied().collect()),
_ => None,
}
}
fn path_span(&self) -> Option<Span> {
match &self {
Attribute::Unparsed(attr) => Some(attr.path.span),
Attribute::Parsed(_) => None,
}
}
#[inline]
fn doc_str(&self) -> Option<Symbol> {
match &self {
@ -1394,6 +1401,14 @@ impl AttributeExt for Attribute {
}
}
#[inline]
fn deprecation_note(&self) -> Option<Symbol> {
match &self {
Attribute::Parsed(AttributeKind::Deprecation { deprecation, .. }) => deprecation.note,
_ => None,
}
}
fn is_automatically_derived_attr(&self) -> bool {
matches!(self, Attribute::Parsed(AttributeKind::AutomaticallyDerived(..)))
}
@ -1465,11 +1480,6 @@ impl Attribute {
AttributeExt::value_span(self)
}
#[inline]
pub fn ident(&self) -> Option<Ident> {
AttributeExt::ident(self)
}
#[inline]
pub fn path_matches(&self, name: &[Symbol]) -> bool {
AttributeExt::path_matches(self, name)
@ -1505,11 +1515,6 @@ impl Attribute {
AttributeExt::path(self)
}
#[inline]
pub fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>> {
AttributeExt::ident_path(self)
}
#[inline]
pub fn doc_str(&self) -> Option<Symbol> {
AttributeExt::doc_str(self)
@ -2620,6 +2625,12 @@ impl Expr<'_> {
// them being used only for its side-effects.
base.can_have_side_effects()
}
ExprKind::Binary(_, lhs, rhs) => {
// This isn't exactly true for all `Binary`, but we are using this
// method exclusively for diagnostics and there's a *cultural* pressure against
// them being used only for its side-effects.
lhs.can_have_side_effects() || rhs.can_have_side_effects()
}
ExprKind::Struct(_, fields, init) => {
let init_side_effects = match init {
StructTailExpr::Base(init) => init.can_have_side_effects(),
@ -2642,13 +2653,13 @@ impl Expr<'_> {
},
args,
) => args.iter().any(|arg| arg.can_have_side_effects()),
ExprKind::Repeat(arg, _) => arg.can_have_side_effects(),
ExprKind::If(..)
| ExprKind::Match(..)
| ExprKind::MethodCall(..)
| ExprKind::Call(..)
| ExprKind::Closure { .. }
| ExprKind::Block(..)
| ExprKind::Repeat(..)
| ExprKind::Break(..)
| ExprKind::Continue(..)
| ExprKind::Ret(..)
@ -2659,7 +2670,6 @@ impl Expr<'_> {
| ExprKind::InlineAsm(..)
| ExprKind::AssignOp(..)
| ExprKind::ConstBlock(..)
| ExprKind::Binary(..)
| ExprKind::Yield(..)
| ExprKind::DropTemps(..)
| ExprKind::Err(_) => true,
@ -3374,7 +3384,7 @@ pub enum AmbigArg {}
/// Represents a type in the `HIR`.
///
/// For an explanation of the `Unambig` generic parameter see the dev-guide:
/// <https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html>
/// <https://rustc-dev-guide.rust-lang.org/ambig-unambig-ty-and-consts.html>
#[derive(Debug, Clone, Copy, HashStable_Generic)]
#[repr(C)]
pub struct Ty<'hir, Unambig = ()> {
@ -3713,7 +3723,7 @@ pub enum InferDelegationKind {
/// The various kinds of types recognized by the compiler.
///
/// For an explanation of the `Unambig` generic parameter see the dev-guide:
/// <https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html>
/// <https://rustc-dev-guide.rust-lang.org/ambig-unambig-ty-and-consts.html>
// SAFETY: `repr(u8)` is required so that `TyKind<()>` and `TyKind<!>` are layout compatible
#[repr(u8, C)]
#[derive(Debug, Clone, Copy, HashStable_Generic)]

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

@ -1068,8 +1068,8 @@ pub fn walk_unambig_const_arg<'v, V: Visitor<'v>>(
match const_arg.try_as_ambig_ct() {
Some(ambig_ct) => visitor.visit_const_arg(ambig_ct),
None => {
let ConstArg { hir_id, kind: _ } = const_arg;
visitor.visit_infer(*hir_id, const_arg.span(), InferKind::Const(const_arg))
let ConstArg { hir_id, kind: _, span } = const_arg;
visitor.visit_infer(*hir_id, *span, InferKind::Const(const_arg))
}
}
}
@ -1078,9 +1078,13 @@ pub fn walk_const_arg<'v, V: Visitor<'v>>(
visitor: &mut V,
const_arg: &'v ConstArg<'v, AmbigArg>,
) -> V::Result {
let ConstArg { hir_id, kind } = const_arg;
let ConstArg { hir_id, kind, span: _ } = const_arg;
try_visit!(visitor.visit_id(*hir_id));
match kind {
ConstArgKind::Tup(exprs) => {
walk_list!(visitor, visit_const_arg, *exprs);
V::Result::output()
}
ConstArgKind::Struct(qpath, field_exprs) => {
try_visit!(visitor.visit_qpath(qpath, *hir_id, qpath.span()));
@ -1090,9 +1094,17 @@ pub fn walk_const_arg<'v, V: Visitor<'v>>(
V::Result::output()
}
ConstArgKind::TupleCall(qpath, args) => {
try_visit!(visitor.visit_qpath(qpath, *hir_id, qpath.span()));
for arg in *args {
try_visit!(visitor.visit_const_arg_unambig(*arg));
}
V::Result::output()
}
ConstArgKind::Path(qpath) => visitor.visit_qpath(qpath, *hir_id, qpath.span()),
ConstArgKind::Anon(anon) => visitor.visit_anon_const(*anon),
ConstArgKind::Error(_, _) => V::Result::output(), // errors and spans are not important
ConstArgKind::Error(_) => V::Result::output(), // errors and spans are not important
ConstArgKind::Literal(..) => V::Result::output(), // FIXME(mcga)
}
}

View file

@ -278,6 +278,7 @@ language_item_table! {
PartialOrd, sym::partial_ord, partial_ord_trait, Target::Trait, GenericRequirement::Exact(1);
CVoid, sym::c_void, c_void, Target::Enum, GenericRequirement::None;
Type, sym::type_info, type_struct, Target::Struct, GenericRequirement::None;
TypeId, sym::type_id, type_id, Target::Struct, GenericRequirement::None;
// A number of panic-related lang items. The `panic` item corresponds to divide-by-zero and

View file

@ -32,8 +32,7 @@ pub mod lints;
pub mod pat_util;
mod stability;
mod stable_hash_impls;
mod target;
mod version;
pub mod target;
pub mod weak_lang_items;
#[cfg(test)]
@ -42,9 +41,9 @@ mod tests;
#[doc(no_inline)]
pub use hir::*;
pub use lang_items::{LangItem, LanguageItems};
pub use rustc_ast::attr::version::*;
pub use stability::*;
pub use stable_hash_impls::HashStableContext;
pub use target::{MethodKind, Target};
pub use version::*;
arena_types!(rustc_arena::declare_arena);

View file

@ -32,21 +32,21 @@ use crate::errors::{EiiWithGenerics, LifetimesOrBoundsMismatchOnEii};
pub(crate) fn compare_eii_function_types<'tcx>(
tcx: TyCtxt<'tcx>,
external_impl: LocalDefId,
declaration: DefId,
foreign_item: DefId,
eii_name: Symbol,
eii_attr_span: Span,
) -> Result<(), ErrorGuaranteed> {
check_is_structurally_compatible(tcx, external_impl, declaration, eii_name, eii_attr_span)?;
check_is_structurally_compatible(tcx, external_impl, foreign_item, eii_name, eii_attr_span)?;
let external_impl_span = tcx.def_span(external_impl);
let cause = ObligationCause::new(
external_impl_span,
external_impl,
ObligationCauseCode::CompareEii { external_impl, declaration },
ObligationCauseCode::CompareEii { external_impl, declaration: foreign_item },
);
// FIXME(eii): even if we don't support generic functions, we should support explicit outlive bounds here
let param_env = tcx.param_env(declaration);
let param_env = tcx.param_env(foreign_item);
let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
let ocx = ObligationCtxt::new_with_diagnostics(infcx);
@ -62,7 +62,7 @@ pub(crate) fn compare_eii_function_types<'tcx>(
let mut wf_tys = FxIndexSet::default();
let norm_cause = ObligationCause::misc(external_impl_span, external_impl);
let declaration_sig = tcx.fn_sig(declaration).instantiate_identity();
let declaration_sig = tcx.fn_sig(foreign_item).instantiate_identity();
let declaration_sig = tcx.liberate_late_bound_regions(external_impl.into(), declaration_sig);
debug!(?declaration_sig);
@ -103,7 +103,7 @@ pub(crate) fn compare_eii_function_types<'tcx>(
cause,
param_env,
terr,
(declaration, declaration_sig),
(foreign_item, declaration_sig),
(external_impl, external_impl_sig),
eii_attr_span,
eii_name,

View file

@ -213,6 +213,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
| sym::type_id
| sym::type_id_eq
| sym::type_name
| sym::type_of
| sym::ub_checks
| sym::variant_count
| sym::vtable_for
@ -308,13 +309,22 @@ pub(crate) fn check_intrinsic_type(
sym::needs_drop => (1, 0, vec![], tcx.types.bool),
sym::type_name => (1, 0, vec![], Ty::new_static_str(tcx)),
sym::type_id => {
(1, 0, vec![], tcx.type_of(tcx.lang_items().type_id().unwrap()).instantiate_identity())
}
sym::type_id => (
1,
0,
vec![],
tcx.type_of(tcx.lang_items().type_id().unwrap()).no_bound_vars().unwrap(),
),
sym::type_id_eq => {
let type_id = tcx.type_of(tcx.lang_items().type_id().unwrap()).instantiate_identity();
let type_id = tcx.type_of(tcx.lang_items().type_id().unwrap()).no_bound_vars().unwrap();
(0, 0, vec![type_id, type_id], tcx.types.bool)
}
sym::type_of => (
0,
0,
vec![tcx.type_of(tcx.lang_items().type_id().unwrap()).no_bound_vars().unwrap()],
tcx.type_of(tcx.lang_items().type_struct().unwrap()).no_bound_vars().unwrap(),
),
sym::offload => (
3,
0,

View file

@ -6,7 +6,7 @@ use rustc_abi::{ExternAbi, ScalableElt};
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_errors::codes::*;
use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err};
use rustc_hir::attrs::{AttributeKind, EiiDecl, EiiImpl};
use rustc_hir::attrs::{AttributeKind, EiiDecl, EiiImpl, EiiImplResolution};
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::lang_items::LangItem;
@ -1196,27 +1196,28 @@ fn check_item_fn(
fn check_eiis(tcx: TyCtxt<'_>, def_id: LocalDefId) {
// does the function have an EiiImpl attribute? that contains the defid of a *macro*
// that was used to mark the implementation. This is a two step process.
for EiiImpl { eii_macro, span, .. } in
for EiiImpl { resolution, span, .. } in
find_attr!(tcx.get_all_attrs(def_id), AttributeKind::EiiImpls(impls) => impls)
.into_iter()
.flatten()
{
// we expect this macro to have the `EiiMacroFor` attribute, that points to a function
// signature that we'd like to compare the function we're currently checking with
if let Some(eii_extern_target) = find_attr!(tcx.get_all_attrs(*eii_macro), AttributeKind::EiiExternTarget(EiiDecl {eii_extern_target, ..}) => *eii_extern_target)
{
let _ = compare_eii_function_types(
tcx,
def_id,
eii_extern_target,
tcx.item_name(*eii_macro),
*span,
);
} else {
panic!(
"EII impl macro {eii_macro:?} did not have an eii extern target attribute pointing to a foreign function"
)
}
let (foreign_item, name) = match resolution {
EiiImplResolution::Macro(def_id) => {
// we expect this macro to have the `EiiMacroFor` attribute, that points to a function
// signature that we'd like to compare the function we're currently checking with
if let Some(foreign_item) = find_attr!(tcx.get_all_attrs(*def_id), AttributeKind::EiiExternTarget(EiiDecl {eii_extern_target: t, ..}) => *t)
{
(foreign_item, tcx.item_name(*def_id))
} else {
tcx.dcx().span_delayed_bug(*span, "resolved to something that's not an EII");
continue;
}
}
EiiImplResolution::Known(decl) => (decl.eii_extern_target, decl.name.name),
EiiImplResolution::Error(_eg) => continue,
};
let _ = compare_eii_function_types(tcx, def_id, foreign_item, name, *span);
}
}

View file

@ -15,7 +15,7 @@ use rustc_hir::find_attr;
use rustc_middle::bug;
use rustc_middle::ty::fast_reject::{SimplifiedType, TreatParams, simplify_type};
use rustc_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt};
use rustc_span::{ErrorGuaranteed, sym};
use rustc_span::ErrorGuaranteed;
use crate::errors;
@ -79,13 +79,15 @@ impl<'tcx> InherentCollect<'tcx> {
}
if self.tcx.features().rustc_attrs() {
let items = self.tcx.associated_item_def_ids(impl_def_id);
if !self.tcx.has_attr(ty_def_id, sym::rustc_has_incoherent_inherent_impls) {
if !find_attr!(
self.tcx.get_all_attrs(ty_def_id),
AttributeKind::RustcHasIncoherentInherentImpls
) {
let impl_span = self.tcx.def_span(impl_def_id);
return Err(self.tcx.dcx().emit_err(errors::InherentTyOutside { span: impl_span }));
}
let items = self.tcx.associated_item_def_ids(impl_def_id);
for &impl_item in items {
if !find_attr!(
self.tcx.get_all_attrs(impl_item),

View file

@ -1479,23 +1479,27 @@ fn rendered_precise_capturing_args<'tcx>(
fn const_param_default<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
local_def_id: LocalDefId,
) -> ty::EarlyBinder<'tcx, Const<'tcx>> {
let hir::Node::GenericParam(hir::GenericParam {
kind: hir::GenericParamKind::Const { default: Some(default_ct), .. },
..
}) = tcx.hir_node_by_def_id(def_id)
}) = tcx.hir_node_by_def_id(local_def_id)
else {
span_bug!(
tcx.def_span(def_id),
tcx.def_span(local_def_id),
"`const_param_default` expected a generic parameter with a constant"
)
};
let icx = ItemCtxt::new(tcx, def_id);
let identity_args = ty::GenericArgs::identity_for_item(tcx, def_id);
let icx = ItemCtxt::new(tcx, local_def_id);
let def_id = local_def_id.to_def_id();
let identity_args = ty::GenericArgs::identity_for_item(tcx, tcx.parent(def_id));
let ct = icx
.lowerer()
.lower_const_arg(default_ct, FeedConstTy::Param(def_id.to_def_id(), identity_args));
.lower_const_arg(default_ct, FeedConstTy::with_type_of(tcx, def_id, identity_args));
ty::EarlyBinder::bind(ct)
}
@ -1553,7 +1557,7 @@ fn const_of_item<'tcx>(
let identity_args = ty::GenericArgs::identity_for_item(tcx, def_id);
let ct = icx
.lowerer()
.lower_const_arg(ct_arg, FeedConstTy::Param(def_id.to_def_id(), identity_args));
.lower_const_arg(ct_arg, FeedConstTy::with_type_of(tcx, def_id.to_def_id(), identity_args));
if let Err(e) = icx.check_tainted_by_errors()
&& !ct.references_error()
{

View file

@ -420,7 +420,22 @@ fn infer_placeholder_type<'tcx>(
kind: &'static str,
) -> Ty<'tcx> {
let tcx = cx.tcx();
let ty = tcx.typeck(def_id).node_type(hir_id);
// If the type is omitted on a #[type_const] we can't run
// type check on since that requires the const have a body
// which type_consts don't.
let ty = if tcx.is_type_const(def_id.to_def_id()) {
if let Some(trait_item_def_id) = tcx.trait_item_of(def_id.to_def_id()) {
tcx.type_of(trait_item_def_id).instantiate_identity()
} else {
Ty::new_error_with_message(
tcx,
ty_span,
"constant with #[type_const] requires an explicit type",
)
}
} else {
tcx.typeck(def_id).node_type(hir_id)
};
// If this came from a free `const` or `static mut?` item,
// then the user may have written e.g. `const A = 42;`.

View file

@ -610,9 +610,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
AttributeKind::TypeConst(_)
)
{
if tcx.features().min_generic_const_args()
|| tcx.features().associated_const_equality()
{
if tcx.features().min_generic_const_args() {
let mut err = self.dcx().struct_span_err(
constraint.span,
"use of trait associated const without `#[type_const]`",

View file

@ -239,7 +239,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// `trait_object_dummy_self`, so check for that.
let references_self = match pred.skip_binder().term.kind() {
ty::TermKind::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()),
// FIXME(associated_const_equality): We should walk the const instead of not doing anything
// FIXME(mgca): We should walk the const instead of not doing anything
ty::TermKind::Const(_) => false,
};

View file

@ -359,12 +359,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
None
};
// FIXME(associated_const_equality): This has quite a few false positives and negatives.
// FIXME(mgca): This has quite a few false positives and negatives.
let wrap_in_braces_sugg = if let Some(constraint) = constraint
&& let Some(hir_ty) = constraint.ty()
&& let ty = self.lower_ty(hir_ty)
&& (ty.is_enum() || ty.references_error())
&& tcx.features().associated_const_equality()
&& tcx.features().min_generic_const_args()
{
Some(errors::AssocKindMismatchWrapInBracesSugg {
lo: hir_ty.span.shrink_to_lo(),
@ -381,7 +381,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
{
let span = match term {
hir::Term::Ty(ty) => ty.span,
hir::Term::Const(ct) => ct.span(),
hir::Term::Const(ct) => ct.span,
};
(span, Some(ident.span), assoc_item.as_tag(), assoc_tag)
} else {
@ -1466,7 +1466,7 @@ pub fn prohibit_assoc_item_constraint(
hir::AssocItemConstraintKind::Equality { term: hir::Term::Const(c) },
GenericParamDefKind::Const { .. },
) => {
suggest_direct_use(&mut err, c.span());
suggest_direct_use(&mut err, c.span);
}
(hir::AssocItemConstraintKind::Bound { bounds }, _) => {
// Suggest `impl<T: Bound> Trait<T> for Foo` when finding

View file

@ -22,6 +22,7 @@ pub mod generics;
use std::assert_matches::assert_matches;
use std::slice;
use rustc_ast::LitKind;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_errors::codes::*;
use rustc_errors::{
@ -259,17 +260,26 @@ impl AssocItemQSelf {
/// Use this enum with `<dyn HirTyLowerer>::lower_const_arg` to instruct it with the
/// desired behavior.
#[derive(Debug, Clone, Copy)]
pub enum FeedConstTy<'a, 'tcx> {
/// Feed the type.
///
pub enum FeedConstTy<'tcx> {
/// Feed the type to the (anno) const arg.
WithTy(Ty<'tcx>),
/// Don't feed the type.
No,
}
impl<'tcx> FeedConstTy<'tcx> {
/// The `DefId` belongs to the const param that we are supplying
/// this (anon) const arg to.
///
/// The list of generic args is used to instantiate the parameters
/// used by the type of the const param specified by `DefId`.
Param(DefId, &'a [ty::GenericArg<'tcx>]),
/// Don't feed the type.
No,
pub fn with_type_of(
tcx: TyCtxt<'tcx>,
def_id: DefId,
generic_args: &[ty::GenericArg<'tcx>],
) -> Self {
Self::WithTy(tcx.type_of(def_id).instantiate(tcx, generic_args))
}
}
#[derive(Debug, Clone, Copy)]
@ -314,6 +324,7 @@ pub enum PermitVariants {
enum TypeRelativePath<'tcx> {
AssocItem(DefId, GenericArgsRef<'tcx>),
Variant { adt: Ty<'tcx>, variant_did: DefId },
Ctor { ctor_def_id: DefId, args: GenericArgsRef<'tcx> },
}
/// New-typed boolean indicating whether explicit late-bound lifetimes
@ -722,7 +733,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// Ambig portions of `ConstArg` are handled in the match arm below
.lower_const_arg(
ct.as_unambig_ct(),
FeedConstTy::Param(param.def_id, preceding_args),
FeedConstTy::with_type_of(tcx, param.def_id, preceding_args),
)
.into(),
(&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
@ -1375,6 +1386,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let adt = self.check_param_uses_if_mcg(adt, span, false);
Ok((adt, DefKind::Variant, variant_did))
}
TypeRelativePath::Ctor { .. } => {
let e = tcx.dcx().span_err(span, "expected type, found tuple constructor");
Err(e)
}
}
}
@ -1410,6 +1425,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let ct = self.check_param_uses_if_mcg(ct, span, false);
Ok(ct)
}
TypeRelativePath::Ctor { ctor_def_id, args } => match tcx.def_kind(ctor_def_id) {
DefKind::Ctor(_, CtorKind::Fn) => {
Ok(ty::Const::zero_sized(tcx, Ty::new_fn_def(tcx, ctor_def_id, args)))
}
DefKind::Ctor(ctor_of, CtorKind::Const) => {
Ok(self.construct_const_ctor_value(ctor_def_id, ctor_of, args))
}
_ => unreachable!(),
},
// FIXME(mgca): implement support for this once ready to support all adt ctor expressions,
// not just const ctors
TypeRelativePath::Variant { .. } => {
@ -1441,6 +1465,23 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.iter()
.find(|vd| tcx.hygienic_eq(segment.ident, vd.ident(tcx), adt_def.did()));
if let Some(variant_def) = variant_def {
// FIXME(mgca): do we want constructor resolutions to take priority over
// other possible resolutions?
if matches!(mode, LowerTypeRelativePathMode::Const)
&& let Some((_, ctor_def_id)) = variant_def.ctor
{
tcx.check_stability(variant_def.def_id, Some(qpath_hir_id), span, None);
let _ = self.prohibit_generic_args(
slice::from_ref(segment).iter(),
GenericsArgsErrExtend::EnumVariant {
qself: hir_self_ty,
assoc_segment: segment,
adt_def,
},
);
let ty::Adt(_, enum_args) = self_ty.kind() else { unreachable!() };
return Ok(TypeRelativePath::Ctor { ctor_def_id, args: enum_args });
}
if let PermitVariants::Yes = mode.permit_variants() {
tcx.check_stability(variant_def.def_id, Some(qpath_hir_id), span, None);
let _ = self.prohibit_generic_args(
@ -2149,7 +2190,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
);
self.check_param_uses_if_mcg(tcx.types.self_param, span, false)
}
Res::SelfTyAlias { alias_to: def_id, forbid_generic: _, .. } => {
Res::SelfTyAlias { alias_to: def_id, .. } => {
// `Self` in impl (we know the concrete type).
assert_eq!(opt_self_ty, None);
// Try to evaluate any array length constants.
@ -2272,15 +2313,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
pub fn lower_const_arg(
&self,
const_arg: &hir::ConstArg<'tcx>,
feed: FeedConstTy<'_, 'tcx>,
feed: FeedConstTy<'tcx>,
) -> Const<'tcx> {
let tcx = self.tcx();
if let FeedConstTy::Param(param_def_id, args) = feed
if let FeedConstTy::WithTy(anon_const_type) = feed
&& let hir::ConstArgKind::Anon(anon) = &const_arg.kind
{
let anon_const_type = tcx.type_of(param_def_id).instantiate(tcx, args);
// FIXME(generic_const_parameter_types): Ideally we remove these errors below when
// we have the ability to intermix typeck of anon const const args with the parent
// bodies typeck.
@ -2293,7 +2332,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
&& (anon_const_type.has_free_regions() || anon_const_type.has_erased_regions())
{
let e = self.dcx().span_err(
const_arg.span(),
const_arg.span,
"anonymous constants with lifetimes in their type are not yet supported",
);
tcx.feed_anon_const_type(anon.def_id, ty::EarlyBinder::bind(Ty::new_error(tcx, e)));
@ -2304,7 +2343,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// variables otherwise we will ICE.
if anon_const_type.has_non_region_infer() {
let e = self.dcx().span_err(
const_arg.span(),
const_arg.span,
"anonymous constants with inferred types are not yet supported",
);
tcx.feed_anon_const_type(anon.def_id, ty::EarlyBinder::bind(Ty::new_error(tcx, e)));
@ -2314,21 +2353,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// give the anon const any of the generics from the parent.
if anon_const_type.has_non_region_param() {
let e = self.dcx().span_err(
const_arg.span(),
const_arg.span,
"anonymous constants referencing generics are not yet supported",
);
tcx.feed_anon_const_type(anon.def_id, ty::EarlyBinder::bind(Ty::new_error(tcx, e)));
return ty::Const::new_error(tcx, e);
}
tcx.feed_anon_const_type(
anon.def_id,
ty::EarlyBinder::bind(tcx.type_of(param_def_id).instantiate(tcx, args)),
);
tcx.feed_anon_const_type(anon.def_id, ty::EarlyBinder::bind(anon_const_type));
}
let hir_id = const_arg.hir_id;
match const_arg.kind {
hir::ConstArgKind::Tup(exprs) => self.lower_const_arg_tup(exprs, feed, const_arg.span),
hir::ConstArgKind::Path(hir::QPath::Resolved(maybe_qself, path)) => {
debug!(?maybe_qself, ?path);
let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself));
@ -2342,19 +2379,146 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
hir_self_ty,
segment,
hir_id,
const_arg.span(),
const_arg.span,
)
.unwrap_or_else(|guar| Const::new_error(tcx, guar))
}
hir::ConstArgKind::Struct(qpath, inits) => {
self.lower_const_arg_struct(hir_id, qpath, inits, const_arg.span())
self.lower_const_arg_struct(hir_id, qpath, inits, const_arg.span)
}
hir::ConstArgKind::TupleCall(qpath, args) => {
self.lower_const_arg_tuple_call(hir_id, qpath, args, const_arg.span)
}
hir::ConstArgKind::Anon(anon) => self.lower_const_arg_anon(anon),
hir::ConstArgKind::Infer(span, ()) => self.ct_infer(None, span),
hir::ConstArgKind::Error(_, e) => ty::Const::new_error(tcx, e),
hir::ConstArgKind::Infer(()) => self.ct_infer(None, const_arg.span),
hir::ConstArgKind::Error(e) => ty::Const::new_error(tcx, e),
hir::ConstArgKind::Literal(kind) if let FeedConstTy::WithTy(anon_const_type) = feed => {
self.lower_const_arg_literal(&kind, anon_const_type, const_arg.span)
}
hir::ConstArgKind::Literal(..) => {
let e = self.dcx().span_err(const_arg.span, "literal of unknown type");
ty::Const::new_error(tcx, e)
}
}
}
fn lower_const_arg_tuple_call(
&self,
hir_id: HirId,
qpath: hir::QPath<'tcx>,
args: &'tcx [&'tcx hir::ConstArg<'tcx>],
span: Span,
) -> Const<'tcx> {
let tcx = self.tcx();
let non_adt_or_variant_res = || {
let e = tcx.dcx().span_err(span, "tuple constructor with invalid base path");
ty::Const::new_error(tcx, e)
};
let ctor_const = match qpath {
hir::QPath::Resolved(maybe_qself, path) => {
let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself));
self.lower_resolved_const_path(opt_self_ty, path, hir_id)
}
hir::QPath::TypeRelative(hir_self_ty, segment) => {
let self_ty = self.lower_ty(hir_self_ty);
match self.lower_type_relative_const_path(
self_ty,
hir_self_ty,
segment,
hir_id,
span,
) {
Ok(c) => c,
Err(_) => return non_adt_or_variant_res(),
}
}
};
let Some(value) = ctor_const.try_to_value() else {
return non_adt_or_variant_res();
};
let (adt_def, adt_args, variant_did) = match value.ty.kind() {
ty::FnDef(def_id, fn_args)
if let DefKind::Ctor(CtorOf::Variant, _) = tcx.def_kind(*def_id) =>
{
let parent_did = tcx.parent(*def_id);
let enum_did = tcx.parent(parent_did);
(tcx.adt_def(enum_did), fn_args, parent_did)
}
ty::FnDef(def_id, fn_args)
if let DefKind::Ctor(CtorOf::Struct, _) = tcx.def_kind(*def_id) =>
{
let parent_did = tcx.parent(*def_id);
(tcx.adt_def(parent_did), fn_args, parent_did)
}
_ => return non_adt_or_variant_res(),
};
let variant_def = adt_def.variant_with_id(variant_did);
let variant_idx = adt_def.variant_index_with_id(variant_did).as_u32();
if args.len() != variant_def.fields.len() {
let e = tcx.dcx().span_err(
span,
format!(
"tuple constructor has {} arguments but {} were provided",
variant_def.fields.len(),
args.len()
),
);
return ty::Const::new_error(tcx, e);
}
let fields = variant_def
.fields
.iter()
.zip(args)
.map(|(field_def, arg)| {
self.lower_const_arg(arg, FeedConstTy::with_type_of(tcx, field_def.did, adt_args))
})
.collect::<Vec<_>>();
let opt_discr_const = if adt_def.is_enum() {
let valtree = ty::ValTree::from_scalar_int(tcx, variant_idx.into());
Some(ty::Const::new_value(tcx, valtree, tcx.types.u32))
} else {
None
};
let valtree = ty::ValTree::from_branches(tcx, opt_discr_const.into_iter().chain(fields));
let adt_ty = Ty::new_adt(tcx, adt_def, adt_args);
ty::Const::new_value(tcx, valtree, adt_ty)
}
fn lower_const_arg_tup(
&self,
exprs: &'tcx [&'tcx hir::ConstArg<'tcx>],
feed: FeedConstTy<'tcx>,
span: Span,
) -> Const<'tcx> {
let tcx = self.tcx();
let FeedConstTy::WithTy(ty) = feed else {
return Const::new_error_with_message(tcx, span, "unsupported const tuple");
};
let ty::Tuple(tys) = ty.kind() else {
return Const::new_error_with_message(tcx, span, "const tuple must have a tuple type");
};
let exprs = exprs
.iter()
.zip(tys.iter())
.map(|(expr, ty)| self.lower_const_arg(expr, FeedConstTy::WithTy(ty)))
.collect::<Vec<_>>();
let valtree = ty::ValTree::from_branches(tcx, exprs);
ty::Const::new_value(tcx, valtree, ty)
}
fn lower_const_arg_struct(
&self,
hir_id: HirId,
@ -2433,7 +2597,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
return ty::Const::new_error(tcx, e);
}
self.lower_const_arg(expr.expr, FeedConstTy::Param(field_def.did, adt_args))
self.lower_const_arg(
expr.expr,
FeedConstTy::with_type_of(tcx, field_def.did, adt_args),
)
}
None => {
let e = tcx.dcx().span_err(
@ -2478,7 +2645,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
);
self.lower_const_param(def_id, hir_id)
}
Res::Def(DefKind::Const | DefKind::Ctor(_, CtorKind::Const), did) => {
Res::Def(DefKind::Const, did) => {
assert_eq!(opt_self_ty, None);
let [leading_segments @ .., segment] = path.segments else { bug!() };
let _ = self
@ -2486,6 +2653,35 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let args = self.lower_generic_args_of_path_segment(span, did, segment);
ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(did, args))
}
Res::Def(DefKind::Ctor(ctor_of, CtorKind::Const), did) => {
assert_eq!(opt_self_ty, None);
let [leading_segments @ .., segment] = path.segments else { bug!() };
let _ = self
.prohibit_generic_args(leading_segments.iter(), GenericsArgsErrExtend::None);
let parent_did = tcx.parent(did);
let generics_did = match ctor_of {
CtorOf::Variant => tcx.parent(parent_did),
CtorOf::Struct => parent_did,
};
let args = self.lower_generic_args_of_path_segment(span, generics_did, segment);
self.construct_const_ctor_value(did, ctor_of, args)
}
Res::Def(DefKind::Ctor(_, CtorKind::Fn), did) => {
assert_eq!(opt_self_ty, None);
let [leading_segments @ .., segment] = path.segments else { bug!() };
let _ = self
.prohibit_generic_args(leading_segments.iter(), GenericsArgsErrExtend::None);
let parent_did = tcx.parent(did);
let generics_did = if let DefKind::Ctor(CtorOf::Variant, _) = tcx.def_kind(did) {
tcx.parent(parent_did)
} else {
parent_did
};
let args = self.lower_generic_args_of_path_segment(span, generics_did, segment);
ty::Const::zero_sized(tcx, Ty::new_fn_def(tcx, did, args))
}
Res::Def(DefKind::AssocConst, did) => {
let trait_segment = if let [modules @ .., trait_, _item] = path.segments {
let _ = self.prohibit_generic_args(modules.iter(), GenericsArgsErrExtend::None);
@ -2521,9 +2717,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
DefKind::Mod
| DefKind::Enum
| DefKind::Variant
| DefKind::Ctor(CtorOf::Variant, CtorKind::Fn)
| DefKind::Struct
| DefKind::Ctor(CtorOf::Struct, CtorKind::Fn)
| DefKind::OpaqueTy
| DefKind::TyAlias
| DefKind::TraitAlias
@ -2587,6 +2781,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
}
#[instrument(skip(self), level = "debug")]
fn lower_const_arg_literal(&self, kind: &LitKind, ty: Ty<'tcx>, span: Span) -> Const<'tcx> {
let tcx = self.tcx();
let input = LitToConstInput { lit: *kind, ty, neg: false };
tcx.at(span).lit_to_const(input)
}
#[instrument(skip(self), level = "debug")]
fn try_lower_anon_const_lit(
&self,
@ -3043,4 +3244,31 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
Some(r)
}
fn construct_const_ctor_value(
&self,
ctor_def_id: DefId,
ctor_of: CtorOf,
args: GenericArgsRef<'tcx>,
) -> Const<'tcx> {
let tcx = self.tcx();
let parent_did = tcx.parent(ctor_def_id);
let adt_def = tcx.adt_def(match ctor_of {
CtorOf::Variant => tcx.parent(parent_did),
CtorOf::Struct => parent_did,
});
let variant_idx = adt_def.variant_index_with_id(parent_did);
let valtree = if adt_def.is_enum() {
let discr = ty::ValTree::from_scalar_int(tcx, variant_idx.as_u32().into());
ty::ValTree::from_branches(tcx, [ty::Const::new_value(tcx, discr, tcx.types.u32)])
} else {
ty::ValTree::zst(tcx)
};
let adt_ty = Ty::new_adt(tcx, adt_def, args);
ty::Const::new_value(tcx, valtree, adt_ty)
}
}

View file

@ -301,7 +301,7 @@ pub fn lower_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
pub fn lower_const_arg_for_rustdoc<'tcx>(
tcx: TyCtxt<'tcx>,
hir_ct: &hir::ConstArg<'tcx>,
feed: FeedConstTy<'_, 'tcx>,
feed: FeedConstTy<'tcx>,
) -> Const<'tcx> {
let env_def_id = tcx.hir_get_parent_item(hir_ct.hir_id);
collect::ItemCtxt::new(tcx, env_def_id.def_id).lowerer().lower_const_arg(hir_ct, feed)

View file

@ -17,12 +17,12 @@ use rustc_ast_pretty::pprust::state::MacHeader;
use rustc_ast_pretty::pprust::{Comments, PrintState};
use rustc_hir::attrs::{AttributeKind, PrintAttribute};
use rustc_hir::{
BindingMode, ByRef, ConstArgKind, GenericArg, GenericBound, GenericParam, GenericParamKind,
HirId, ImplicitSelfKind, LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term,
TyPatKind,
BindingMode, ByRef, ConstArg, ConstArgExprField, ConstArgKind, GenericArg, GenericBound,
GenericParam, GenericParamKind, HirId, ImplicitSelfKind, LifetimeParamKind, Node, PatKind,
PreciseCapturingArg, RangeEnd, Term, TyPatKind,
};
use rustc_span::source_map::SourceMap;
use rustc_span::{FileName, Ident, Span, Symbol, kw, sym};
use rustc_span::source_map::{SourceMap, Spanned};
use rustc_span::{DUMMY_SP, FileName, Ident, Span, Symbol, kw, sym};
use {rustc_ast as ast, rustc_hir as hir};
pub fn id_to_string(cx: &dyn rustc_hir::intravisit::HirTyCtxt<'_>, hir_id: HirId) -> String {
@ -136,7 +136,11 @@ impl<'a> State<'a> {
.path
.segments
.iter()
.map(|i| ast::PathSegment { ident: *i, args: None, id: DUMMY_NODE_ID })
.map(|i| ast::PathSegment {
ident: Ident { name: *i, span: DUMMY_SP },
args: None,
id: DUMMY_NODE_ID,
})
.collect(),
tokens: None,
};
@ -1137,15 +1141,54 @@ impl<'a> State<'a> {
fn print_const_arg(&mut self, const_arg: &hir::ConstArg<'_>) {
match &const_arg.kind {
// FIXME(mgca): proper printing for struct exprs
ConstArgKind::Struct(..) => self.word("/* STRUCT EXPR */"),
ConstArgKind::Tup(exprs) => {
self.popen();
self.commasep_cmnt(
Inconsistent,
exprs,
|s, arg| s.print_const_arg(arg),
|arg| arg.span,
);
self.pclose();
}
ConstArgKind::Struct(qpath, fields) => self.print_const_struct(qpath, fields),
ConstArgKind::TupleCall(qpath, args) => self.print_const_ctor(qpath, args),
ConstArgKind::Path(qpath) => self.print_qpath(qpath, true),
ConstArgKind::Anon(anon) => self.print_anon_const(anon),
ConstArgKind::Error(_, _) => self.word("/*ERROR*/"),
ConstArgKind::Error(_) => self.word("/*ERROR*/"),
ConstArgKind::Infer(..) => self.word("_"),
ConstArgKind::Literal(node) => {
let span = const_arg.span;
self.print_literal(&Spanned { span, node: *node })
}
}
}
fn print_const_struct(&mut self, qpath: &hir::QPath<'_>, fields: &&[&ConstArgExprField<'_>]) {
self.print_qpath(qpath, true);
self.word(" ");
self.word("{");
if !fields.is_empty() {
self.nbsp();
}
self.commasep(Inconsistent, *fields, |s, field| {
s.word(field.field.as_str().to_string());
s.word(":");
s.nbsp();
s.print_const_arg(field.expr);
});
self.word("}");
}
fn print_const_ctor(&mut self, qpath: &hir::QPath<'_>, args: &&[&ConstArg<'_, ()>]) {
self.print_qpath(qpath, true);
self.word("(");
self.commasep(Inconsistent, *args, |s, arg| {
s.print_const_arg(arg);
});
self.word(")");
}
fn print_call_post(&mut self, args: &[hir::Expr<'_>]) {
self.popen();
self.commasep_exprs(Inconsistent, args);

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