diff options
Diffstat (limited to 'compiler')
457 files changed, 7613 insertions, 5718 deletions
diff --git a/compiler/rustc_abi/src/canon_abi.rs b/compiler/rustc_abi/src/canon_abi.rs index 7c020be6761..13f9a04b286 100644 --- a/compiler/rustc_abi/src/canon_abi.rs +++ b/compiler/rustc_abi/src/canon_abi.rs @@ -63,8 +63,8 @@ impl fmt::Display for CanonAbi { CanonAbi::Custom => ExternAbi::Custom, CanonAbi::Arm(arm_call) => match arm_call { ArmCall::Aapcs => ExternAbi::Aapcs { unwind: false }, - ArmCall::CCmseNonSecureCall => ExternAbi::CCmseNonSecureCall, - ArmCall::CCmseNonSecureEntry => ExternAbi::CCmseNonSecureEntry, + ArmCall::CCmseNonSecureCall => ExternAbi::CmseNonSecureCall, + ArmCall::CCmseNonSecureEntry => ExternAbi::CmseNonSecureEntry, }, CanonAbi::GpuKernel => ExternAbi::GpuKernel, CanonAbi::Interrupt(interrupt_kind) => match interrupt_kind { diff --git a/compiler/rustc_abi/src/extern_abi.rs b/compiler/rustc_abi/src/extern_abi.rs index 7457ae1f033..29a3678abf3 100644 --- a/compiler/rustc_abi/src/extern_abi.rs +++ b/compiler/rustc_abi/src/extern_abi.rs @@ -36,6 +36,10 @@ pub enum ExternAbi { /// Stronger than just `#[cold]` because `fn` pointers might be incompatible. RustCold, + /// An always-invalid ABI that's used to test "this ABI is not supported by this platform" + /// in a platform-agnostic way. + RustInvalid, + /// Unstable impl detail that directly uses Rust types to describe the ABI to LLVM. /// Even normally-compatible Rust types can become ABI-incompatible with this ABI! Unadjusted, @@ -55,9 +59,9 @@ pub enum ExternAbi { unwind: bool, }, /// extremely constrained barely-C ABI for TrustZone - CCmseNonSecureCall, + CmseNonSecureCall, /// extremely constrained barely-C ABI for TrustZone - CCmseNonSecureEntry, + CmseNonSecureEntry, /* gpu */ /// An entry-point function called by the GPU's host @@ -136,8 +140,6 @@ macro_rules! abi_impls { abi_impls! { ExternAbi = { C { unwind: false } =><= "C", - CCmseNonSecureCall =><= "C-cmse-nonsecure-call", - CCmseNonSecureEntry =><= "C-cmse-nonsecure-entry", C { unwind: true } =><= "C-unwind", Rust =><= "Rust", Aapcs { unwind: false } =><= "aapcs", @@ -146,6 +148,8 @@ abi_impls! { AvrNonBlockingInterrupt =><= "avr-non-blocking-interrupt", Cdecl { unwind: false } =><= "cdecl", Cdecl { unwind: true } =><= "cdecl-unwind", + CmseNonSecureCall =><= "cmse-nonsecure-call", + CmseNonSecureEntry =><= "cmse-nonsecure-entry", Custom =><= "custom", EfiApi =><= "efiapi", Fastcall { unwind: false } =><= "fastcall", @@ -157,6 +161,7 @@ abi_impls! { RiscvInterruptS =><= "riscv-interrupt-s", RustCall =><= "rust-call", RustCold =><= "rust-cold", + RustInvalid =><= "rust-invalid", Stdcall { unwind: false } =><= "stdcall", Stdcall { unwind: true } =><= "stdcall-unwind", System { unwind: false } =><= "system", diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 6d729b6919a..0df8921c9b7 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1592,24 +1592,33 @@ pub enum TagEncoding<VariantIdx: Idx> { /// (so converting the tag to the discriminant can require sign extension). Direct, - /// Niche (values invalid for a type) encoding the discriminant: - /// Discriminant and variant index coincide. + /// Niche (values invalid for a type) encoding the discriminant. + /// Note that for this encoding, the discriminant and variant index of each variant coincide! + /// This invariant is codified as part of [`layout_sanity_check`](../rustc_ty_utils/layout/invariant/fn.layout_sanity_check.html). + /// /// The variant `untagged_variant` contains a niche at an arbitrary - /// offset (field `tag_field` of the enum), which for a variant with - /// discriminant `d` is set to - /// `(d - niche_variants.start).wrapping_add(niche_start)` - /// (this is wrapping arithmetic using the type of the niche field). + /// offset (field [`Variants::Multiple::tag_field`] of the enum). + /// For a variant with variant index `i`, such that `i != untagged_variant`, + /// the tag is set to `(i - niche_variants.start).wrapping_add(niche_start)` + /// (this is wrapping arithmetic using the type of the niche field, cf. the + /// [`tag_for_variant`](../rustc_const_eval/interpret/struct.InterpCx.html#method.tag_for_variant) + /// query implementation). + /// To recover the variant index `i` from a `tag`, the above formula has to be reversed, + /// i.e. `i = tag.wrapping_sub(niche_start) + niche_variants.start`. If `i` ends up outside + /// `niche_variants`, the tag must have encoded the `untagged_variant`. /// - /// For example, `Option<(usize, &T)>` is represented such that - /// `None` has a null pointer for the second tuple field, and - /// `Some` is the identity function (with a non-null reference). + /// For example, `Option<(usize, &T)>` is represented such that the tag for + /// `None` is the null pointer in the second tuple field, and + /// `Some` is the identity function (with a non-null reference) + /// and has no additional tag, i.e. the reference being non-null uniquely identifies this variant. /// /// Other variants that are not `untagged_variant` and that are outside the `niche_variants` /// range cannot be represented; they must be uninhabited. + /// Nonetheless, uninhabited variants can also fall into the range of `niche_variants`. Niche { untagged_variant: VariantIdx, - /// This range *may* contain `untagged_variant`; that is then just a "dead value" and - /// not used to encode anything. + /// This range *may* contain `untagged_variant` or uninhabited variants; + /// these are then just "dead values" and not used to encode anything. niche_variants: RangeInclusive<VariantIdx>, /// This is inbounds of the type of the niche field /// (not sign-extended, i.e., all bits beyond the niche field size are 0). diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml index b2d3b90fc44..5de2e69072f 100644 --- a/compiler/rustc_ast/Cargo.toml +++ b/compiler/rustc_ast/Cargo.toml @@ -7,7 +7,7 @@ edition = "2024" # tidy-alphabetical-start bitflags = "2.4.1" memchr = "2.7.4" -rustc-literal-escaper = "0.0.2" +rustc-literal-escaper = "0.0.4" rustc_ast_ir = { path = "../rustc_ast_ir" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_index = { path = "../rustc_index" } diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 11afd359e5a..286bbfb5ae8 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -19,7 +19,6 @@ //! - [`UnOp`], [`BinOp`], and [`BinOpKind`]: Unary and binary operators. use std::borrow::Cow; -use std::sync::Arc; use std::{cmp, fmt}; pub use GenericArgs::*; @@ -32,7 +31,7 @@ use rustc_data_structures::tagged_ptr::Tag; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; pub use rustc_span::AttrId; use rustc_span::source_map::{Spanned, respan}; -use rustc_span::{DUMMY_SP, ErrorGuaranteed, Ident, Span, Symbol, kw, sym}; +use rustc_span::{ByteSymbol, DUMMY_SP, ErrorGuaranteed, Ident, Span, Symbol, kw, sym}; use thin_vec::{ThinVec, thin_vec}; pub use crate::format::*; @@ -323,7 +322,7 @@ impl ParenthesizedArgs { pub use crate::node_id::{CRATE_NODE_ID, DUMMY_NODE_ID, NodeId}; -/// Modifiers on a trait bound like `~const`, `?` and `!`. +/// Modifiers on a trait bound like `[const]`, `?` and `!`. #[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)] pub struct TraitBoundModifiers { pub constness: BoundConstness, @@ -904,6 +903,10 @@ pub enum BorrowKind { /// The resulting type is either `*const T` or `*mut T` /// where `T = typeof($expr)`. Raw, + /// A pinned borrow, `&pin const $expr` or `&pin mut $expr`. + /// The resulting type is either `Pin<&'a T>` or `Pin<&'a mut T>` + /// where `T = typeof($expr)` and `'a` is some lifetime. + Pin, } #[derive(Clone, Copy, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)] @@ -1801,10 +1804,17 @@ pub enum ExprKind { Become(P<Expr>), /// Bytes included via `include_bytes!` + /// /// Added for optimization purposes to avoid the need to escape /// large binary blobs - should always behave like [`ExprKind::Lit`] /// with a `ByteStr` literal. - IncludedBytes(Arc<[u8]>), + /// + /// The value is stored as a `ByteSymbol`. It's unfortunate that we need to + /// intern (hash) the bytes because they're likely to be large and unique. + /// But it's necessary because this will eventually be lowered to + /// `LitKind::ByteStr`, which needs a `ByteSymbol` to impl `Copy` and avoid + /// arena allocation. + IncludedBytes(ByteSymbol), /// A `format_args!()` expression. FormatArgs(P<FormatArgs>), @@ -2062,7 +2072,7 @@ impl YieldKind { } /// A literal in a meta item. -#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] +#[derive(Clone, Copy, Encodable, Decodable, Debug, HashStable_Generic)] pub struct MetaItemLit { /// The original literal as written in the source code. pub symbol: Symbol, @@ -2125,16 +2135,18 @@ pub enum LitFloatType { /// deciding the `LitKind`. This means that float literals like `1f32` are /// classified by this type as `Float`. This is different to `token::LitKind` /// which does *not* consider the suffix. -#[derive(Clone, Encodable, Decodable, Debug, Hash, Eq, PartialEq, HashStable_Generic)] +#[derive(Clone, Copy, Encodable, Decodable, Debug, Hash, Eq, PartialEq, HashStable_Generic)] pub enum LitKind { /// A string literal (`"foo"`). The symbol is unescaped, and so may differ /// from the original token's symbol. Str(Symbol, StrStyle), - /// A byte string (`b"foo"`). Not stored as a symbol because it might be - /// non-utf8, and symbols only allow utf8 strings. - ByteStr(Arc<[u8]>, StrStyle), - /// A C String (`c"foo"`). Guaranteed to only have `\0` at the end. - CStr(Arc<[u8]>, StrStyle), + /// A byte string (`b"foo"`). The symbol is unescaped, and so may differ + /// from the original token's symbol. + ByteStr(ByteSymbol, StrStyle), + /// A C String (`c"foo"`). Guaranteed to only have `\0` at the end. The + /// symbol is unescaped, and so may differ from the original token's + /// symbol. + CStr(ByteSymbol, StrStyle), /// A byte char (`b'f'`). Byte(u8), /// A character literal (`'a'`). @@ -2573,8 +2585,7 @@ pub enum TyPatKind { pub enum TraitObjectSyntax { // SAFETY: When adding new variants make sure to update the `Tag` impl. Dyn = 0, - DynStar = 1, - None = 2, + None = 1, } /// SAFETY: `TraitObjectSyntax` only has 3 data-less variants which means @@ -2590,8 +2601,7 @@ unsafe impl Tag for TraitObjectSyntax { unsafe fn from_usize(tag: usize) -> Self { match tag { 0 => TraitObjectSyntax::Dyn, - 1 => TraitObjectSyntax::DynStar, - 2 => TraitObjectSyntax::None, + 1 => TraitObjectSyntax::None, _ => unreachable!(), } } @@ -3111,7 +3121,7 @@ pub enum BoundConstness { Never, /// `Type: const Trait` Always(Span), - /// `Type: ~const Trait` + /// `Type: [const] Trait` Maybe(Span), } @@ -3120,7 +3130,7 @@ impl BoundConstness { match self { Self::Never => "", Self::Always(_) => "const", - Self::Maybe(_) => "~const", + Self::Maybe(_) => "[const]", } } } @@ -4060,9 +4070,9 @@ mod size_asserts { static_assert_size!(MetaItemLit, 40); static_assert_size!(Param, 40); static_assert_size!(Pat, 72); + static_assert_size!(PatKind, 48); static_assert_size!(Path, 24); static_assert_size!(PathSegment, 24); - static_assert_size!(PatKind, 48); static_assert_size!(Stmt, 32); static_assert_size!(StmtKind, 16); static_assert_size!(Ty, 64); diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 4fc7c7475d7..896d1e1148a 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -16,10 +16,7 @@ #![feature(box_patterns)] #![feature(if_let_guard)] #![feature(macro_metavar_expr)] -#![feature(negative_impls)] -#![feature(never_type)] #![feature(rustdoc_internals)] -#![feature(stmt_expr_attributes)] #![recursion_limit = "256"] // tidy-alphabetical-end diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 54781e8235e..fc816f2cb79 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -893,7 +893,7 @@ impl Token { || self.is_qpath_start() || matches!(self.is_metavar_seq(), Some(MetaVarKind::Path)) || self.is_path_segment_keyword() - || self.is_ident() && !self.is_reserved_ident() + || self.is_non_reserved_ident() } /// Returns `true` if the token is a given keyword, `kw`. @@ -937,6 +937,10 @@ impl Token { self.is_non_raw_ident_where(Ident::is_reserved) } + pub fn is_non_reserved_ident(&self) -> bool { + self.ident().is_some_and(|(id, raw)| raw == IdentIsRaw::Yes || !Ident::is_reserved(id)) + } + /// Returns `true` if the token is the identifier `true` or `false`. pub fn is_bool_lit(&self) -> bool { self.is_non_raw_ident_where(|id| id.name.is_bool_lit()) @@ -1085,6 +1089,7 @@ pub enum NtExprKind { Expr2021 { inferred: bool }, } +/// A macro nonterminal, known in documentation as a fragment specifier. #[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)] pub enum NonterminalKind { Item, diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 3c231be20dc..c60185cdde0 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -634,10 +634,8 @@ impl TokenStream { ( TokenTree::Token(token_left, Spacing::Alone), TokenTree::Token(token_right, _), - ) if ((token_left.is_ident() && !token_left.is_reserved_ident()) - || token_left.is_lit()) - && ((token_right.is_ident() && !token_right.is_reserved_ident()) - || token_right.is_lit()) => + ) if (token_left.is_non_reserved_ident() || token_left.is_lit()) + && (token_right.is_non_reserved_ident() || token_right.is_lit()) => { token_left.span } diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index b8526cf9d95..fa7878873e5 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -3,9 +3,9 @@ use std::{ascii, fmt, str}; use rustc_literal_escaper::{ - MixedUnit, Mode, byte_from_char, unescape_byte, unescape_char, unescape_mixed, unescape_unicode, + MixedUnit, unescape_byte, unescape_byte_str, unescape_c_str, unescape_char, unescape_str, }; -use rustc_span::{Span, Symbol, kw, sym}; +use rustc_span::{ByteSymbol, Span, Symbol, kw, sym}; use tracing::debug; use crate::ast::{self, LitKind, MetaItemLit, StrStyle}; @@ -87,11 +87,10 @@ impl LitKind { // Force-inlining here is aggressive but the closure is // called on every char in the string, so it can be hot in // programs with many long strings containing escapes. - unescape_unicode( + unescape_str( s, - Mode::Str, - &mut #[inline(always)] - |_, c| match c { + #[inline(always)] + |_, res| match res { Ok(c) => buf.push(c), Err(err) => { assert!(!err.is_fatal(), "failed to unescape string literal") @@ -111,24 +110,23 @@ impl LitKind { token::ByteStr => { let s = symbol.as_str(); let mut buf = Vec::with_capacity(s.len()); - unescape_unicode(s, Mode::ByteStr, &mut |_, c| match c { - Ok(c) => buf.push(byte_from_char(c)), + unescape_byte_str(s, |_, res| match res { + Ok(b) => buf.push(b), Err(err) => { assert!(!err.is_fatal(), "failed to unescape string literal") } }); - LitKind::ByteStr(buf.into(), StrStyle::Cooked) + LitKind::ByteStr(ByteSymbol::intern(&buf), StrStyle::Cooked) } token::ByteStrRaw(n) => { - // Raw strings have no escapes so we can convert the symbol - // directly to a `Arc<u8>`. + // Raw byte strings have no escapes so no work is needed here. let buf = symbol.as_str().to_owned().into_bytes(); - LitKind::ByteStr(buf.into(), StrStyle::Raw(n)) + LitKind::ByteStr(ByteSymbol::intern(&buf), StrStyle::Raw(n)) } token::CStr => { let s = symbol.as_str(); let mut buf = Vec::with_capacity(s.len()); - unescape_mixed(s, Mode::CStr, &mut |_span, c| match c { + unescape_c_str(s, |_span, c| match c { Ok(MixedUnit::Char(c)) => { buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes()) } @@ -138,7 +136,7 @@ impl LitKind { } }); buf.push(0); - LitKind::CStr(buf.into(), StrStyle::Cooked) + LitKind::CStr(ByteSymbol::intern(&buf), StrStyle::Cooked) } token::CStrRaw(n) => { // Raw strings have no escapes so we can convert the symbol @@ -146,7 +144,7 @@ impl LitKind { // char. let mut buf = symbol.as_str().to_owned().into_bytes(); buf.push(0); - LitKind::CStr(buf.into(), StrStyle::Raw(n)) + LitKind::CStr(ByteSymbol::intern(&buf), StrStyle::Raw(n)) } token::Err(guar) => LitKind::Err(guar), }) @@ -168,12 +166,12 @@ impl fmt::Display for LitKind { delim = "#".repeat(n as usize), string = sym )?, - LitKind::ByteStr(ref bytes, StrStyle::Cooked) => { - write!(f, "b\"{}\"", escape_byte_str_symbol(bytes))? + LitKind::ByteStr(ref byte_sym, StrStyle::Cooked) => { + write!(f, "b\"{}\"", escape_byte_str_symbol(byte_sym.as_byte_str()))? } - LitKind::ByteStr(ref bytes, StrStyle::Raw(n)) => { + LitKind::ByteStr(ref byte_sym, StrStyle::Raw(n)) => { // Unwrap because raw byte string literals can only contain ASCII. - let symbol = str::from_utf8(bytes).unwrap(); + let symbol = str::from_utf8(byte_sym.as_byte_str()).unwrap(); write!( f, "br{delim}\"{string}\"{delim}", @@ -182,11 +180,11 @@ impl fmt::Display for LitKind { )?; } LitKind::CStr(ref bytes, StrStyle::Cooked) => { - write!(f, "c\"{}\"", escape_byte_str_symbol(bytes))? + write!(f, "c\"{}\"", escape_byte_str_symbol(bytes.as_byte_str()))? } LitKind::CStr(ref bytes, StrStyle::Raw(n)) => { // This can only be valid UTF-8. - let symbol = str::from_utf8(bytes).unwrap(); + let symbol = str::from_utf8(bytes.as_byte_str()).unwrap(); write!(f, "cr{delim}\"{symbol}\"{delim}", delim = "#".repeat(n as usize),)?; } LitKind::Int(n, ty) => { diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml index 6ac258155fe..dc571f5c367 100644 --- a/compiler/rustc_ast_lowering/Cargo.toml +++ b/compiler/rustc_ast_lowering/Cargo.toml @@ -11,6 +11,7 @@ doctest = false rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } +rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index f297bf9f4cf..8747e624a4a 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -4,6 +4,7 @@ use std::sync::Arc; use rustc_ast::ptr::P as AstP; use rustc_ast::*; use rustc_ast_pretty::pprust::expr_to_string; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; use rustc_hir::HirId; @@ -143,11 +144,11 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ExprKind::Unary(op, ohs) } ExprKind::Lit(token_lit) => hir::ExprKind::Lit(self.lower_lit(token_lit, e.span)), - ExprKind::IncludedBytes(bytes) => { - let lit = self.arena.alloc(respan( + ExprKind::IncludedBytes(byte_sym) => { + let lit = respan( self.lower_span(e.span), - LitKind::ByteStr(Arc::clone(bytes), StrStyle::Cooked), - )); + LitKind::ByteStr(*byte_sym, StrStyle::Cooked), + ); hir::ExprKind::Lit(lit) } ExprKind::Cast(expr, ty) => { @@ -420,11 +421,7 @@ impl<'hir> LoweringContext<'_, 'hir> { }) } - pub(crate) fn lower_lit( - &mut self, - token_lit: &token::Lit, - span: Span, - ) -> &'hir Spanned<LitKind> { + pub(crate) fn lower_lit(&mut self, token_lit: &token::Lit, span: Span) -> hir::Lit { let lit_kind = match LitKind::from_token_lit(*token_lit) { Ok(lit_kind) => lit_kind, Err(err) => { @@ -432,7 +429,7 @@ impl<'hir> LoweringContext<'_, 'hir> { LitKind::Err(guar) } }; - self.arena.alloc(respan(self.lower_span(span), lit_kind)) + respan(self.lower_span(span), lit_kind) } fn lower_unop(&mut self, u: UnOp) -> hir::UnOp { @@ -831,7 +828,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) { if self.tcx.features().async_fn_track_caller() && let Some(attrs) = self.attrs.get(&outer_hir_id.local_id) - && attrs.into_iter().any(|attr| attr.has_name(sym::track_caller)) + && find_attr!(*attrs, AttributeKind::TrackCaller(_)) { let unstable_span = self.mark_span_with_reason( DesugaringKind::Async, @@ -2140,10 +2137,10 @@ impl<'hir> LoweringContext<'_, 'hir> { } fn expr_uint(&mut self, sp: Span, ty: ast::UintTy, value: u128) -> hir::Expr<'hir> { - let lit = self.arena.alloc(hir::Lit { + let lit = hir::Lit { span: sp, node: ast::LitKind::Int(value.into(), ast::LitIntType::Unsigned(ty)), - }); + }; self.expr(sp, hir::ExprKind::Lit(lit)) } @@ -2160,9 +2157,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } pub(super) fn expr_str(&mut self, sp: Span, value: Symbol) -> hir::Expr<'hir> { - let lit = self - .arena - .alloc(hir::Lit { span: sp, node: ast::LitKind::Str(value, ast::StrStyle::Cooked) }); + let lit = hir::Lit { span: sp, node: ast::LitKind::Str(value, ast::StrStyle::Cooked) }; self.expr(sp, hir::ExprKind::Lit(lit)) } diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 58dea472f1d..e4440621048 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -390,19 +390,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { allow_paths: bool, ) -> &'hir hir::PatExpr<'hir> { let span = self.lower_span(expr.span); - let err = |guar| hir::PatExprKind::Lit { - lit: self.arena.alloc(respan(span, LitKind::Err(guar))), - negated: false, - }; + let err = + |guar| hir::PatExprKind::Lit { lit: respan(span, LitKind::Err(guar)), negated: false }; let kind = match &expr.kind { ExprKind::Lit(lit) => { hir::PatExprKind::Lit { lit: self.lower_lit(lit, span), negated: false } } ExprKind::ConstBlock(c) => hir::PatExprKind::ConstBlock(self.lower_const_block(c)), - ExprKind::IncludedBytes(bytes) => hir::PatExprKind::Lit { - lit: self - .arena - .alloc(respan(span, LitKind::ByteStr(Arc::clone(bytes), StrStyle::Cooked))), + ExprKind::IncludedBytes(byte_sym) => hir::PatExprKind::Lit { + lit: respan(span, LitKind::ByteStr(*byte_sym, StrStyle::Cooked)), negated: false, }, ExprKind::Err(guar) => err(*guar), diff --git a/compiler/rustc_ast_lowering/src/stability.rs b/compiler/rustc_ast_lowering/src/stability.rs index b8fa2dd3dd6..6752218fa0d 100644 --- a/compiler/rustc_ast_lowering/src/stability.rs +++ b/compiler/rustc_ast_lowering/src/stability.rs @@ -96,6 +96,9 @@ pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> { ExternAbi::RustCold => { Err(UnstableAbi { abi, feature: sym::rust_cold_cc, explain: GateReason::Experimental }) } + ExternAbi::RustInvalid => { + Err(UnstableAbi { abi, feature: sym::rustc_attrs, explain: GateReason::ImplDetail }) + } ExternAbi::GpuKernel => Err(UnstableAbi { abi, feature: sym::abi_gpu_kernel, @@ -124,12 +127,12 @@ pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> { feature: sym::abi_riscv_interrupt, explain: GateReason::Experimental, }), - ExternAbi::CCmseNonSecureCall => Err(UnstableAbi { + ExternAbi::CmseNonSecureCall => Err(UnstableAbi { abi, - feature: sym::abi_c_cmse_nonsecure_call, + feature: sym::abi_cmse_nonsecure_call, explain: GateReason::Experimental, }), - ExternAbi::CCmseNonSecureEntry => Err(UnstableAbi { + ExternAbi::CmseNonSecureEntry => Err(UnstableAbi { abi, feature: sym::cmse_nonsecure_entry, explain: GateReason::Experimental, diff --git a/compiler/rustc_ast_passes/Cargo.toml b/compiler/rustc_ast_passes/Cargo.toml index c738cb2aa2f..1940628b44a 100644 --- a/compiler/rustc_ast_passes/Cargo.toml +++ b/compiler/rustc_ast_passes/Cargo.toml @@ -18,5 +18,6 @@ rustc_macros = { path = "../rustc_macros" } rustc_parse = { path = "../rustc_parse" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } +rustc_target = { path = "../rustc_target" } thin-vec = "0.2.12" # tidy-alphabetical-end diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 9a267501230..4290f7b7ede 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -1,20 +1,25 @@ -ast_passes_abi_custom_coroutine = - functions with the `"custom"` ABI cannot be `{$coroutine_kind_str}` +ast_passes_abi_cannot_be_coroutine = + functions with the {$abi} ABI cannot be `{$coroutine_kind_str}` .suggestion = remove the `{$coroutine_kind_str}` keyword from this definiton -ast_passes_abi_custom_invalid_signature = - invalid signature for `extern "custom"` function - .note = functions with the `"custom"` ABI cannot have any parameters or return type - .suggestion = remove the parameters and return type - ast_passes_abi_custom_safe_foreign_function = - foreign functions with the `"custom"` ABI cannot be safe + foreign functions with the "custom" ABI cannot be safe .suggestion = remove the `safe` keyword from this definition ast_passes_abi_custom_safe_function = - functions with the `"custom"` ABI must be unsafe + functions with the "custom" ABI must be unsafe .suggestion = add the `unsafe` keyword to this definition +ast_passes_abi_must_not_have_parameters_or_return_type= + invalid signature for `extern {$abi}` function + .note = functions with the {$abi} ABI cannot have any parameters or return type + .suggestion = remove the parameters and return type + +ast_passes_abi_must_not_have_return_type= + invalid signature for `extern {$abi}` function + .note = functions with the "custom" ABI cannot have a return type + .help = remove the return type + ast_passes_assoc_const_without_body = associated constant in `impl` without body .suggestion = provide a definition for the constant @@ -232,17 +237,17 @@ ast_passes_static_without_body = free static item without body .suggestion = provide a definition for the static -ast_passes_tilde_const_disallowed = `~const` is not allowed here - .closure = closures cannot have `~const` trait bounds - .function = this function is not `const`, so it cannot have `~const` trait bounds - .trait = this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds - .trait_impl = this impl is not `const`, so it cannot have `~const` trait bounds - .impl = inherent impls cannot have `~const` trait bounds - .trait_assoc_ty = associated types in non-`#[const_trait]` traits cannot have `~const` trait bounds - .trait_impl_assoc_ty = associated types in non-const impls cannot have `~const` trait bounds - .inherent_assoc_ty = inherent associated types cannot have `~const` trait bounds - .object = trait objects cannot have `~const` trait bounds - .item = this item cannot have `~const` trait bounds +ast_passes_tilde_const_disallowed = `[const]` is not allowed here + .closure = closures cannot have `[const]` trait bounds + .function = this function is not `const`, so it cannot have `[const]` trait bounds + .trait = this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds + .trait_impl = this impl is not `const`, so it cannot have `[const]` trait bounds + .impl = inherent impls cannot have `[const]` trait bounds + .trait_assoc_ty = associated types in non-`#[const_trait]` traits cannot have `[const]` trait bounds + .trait_impl_assoc_ty = associated types in non-const impls cannot have `[const]` trait bounds + .inherent_assoc_ty = inherent associated types cannot have `[const]` trait bounds + .object = trait objects cannot have `[const]` trait bounds + .item = this item cannot have `[const]` trait bounds ast_passes_trait_fn_const = functions in {$in_impl -> diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index b69a91e2f5f..da248251203 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -21,7 +21,7 @@ use std::ops::{Deref, DerefMut}; use std::str::FromStr; use itertools::{Either, Itertools}; -use rustc_abi::ExternAbi; +use rustc_abi::{CanonAbi, ExternAbi, InterruptKind}; use rustc_ast::ptr::P; use rustc_ast::visit::{AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor, walk_list}; use rustc_ast::*; @@ -37,6 +37,7 @@ use rustc_session::lint::builtin::{ }; use rustc_session::lint::{BuiltinLintDiag, LintBuffer}; use rustc_span::{Ident, Span, kw, sym}; +use rustc_target::spec::{AbiMap, AbiMapping}; use thin_vec::thin_vec; use crate::errors::{self, TildeConstReason}; @@ -365,31 +366,77 @@ impl<'a> AstValidator<'a> { } } - /// An `extern "custom"` function must be unsafe, and must not have any parameters or return - /// type. - fn check_custom_abi(&self, ctxt: FnCtxt, ident: &Ident, sig: &FnSig) { + /// Check that the signature of this function does not violate the constraints of its ABI. + fn check_extern_fn_signature(&self, abi: ExternAbi, ctxt: FnCtxt, ident: &Ident, sig: &FnSig) { + match AbiMap::from_target(&self.sess.target).canonize_abi(abi, false) { + AbiMapping::Direct(canon_abi) | AbiMapping::Deprecated(canon_abi) => { + match canon_abi { + CanonAbi::C + | CanonAbi::Rust + | CanonAbi::RustCold + | CanonAbi::Arm(_) + | CanonAbi::GpuKernel + | CanonAbi::X86(_) => { /* nothing to check */ } + + CanonAbi::Custom => { + // An `extern "custom"` function must be unsafe. + self.reject_safe_fn(abi, ctxt, sig); + + // An `extern "custom"` function cannot be `async` and/or `gen`. + self.reject_coroutine(abi, sig); + + // An `extern "custom"` function must have type `fn()`. + self.reject_params_or_return(abi, ident, sig); + } + + CanonAbi::Interrupt(interrupt_kind) => { + // An interrupt handler cannot be `async` and/or `gen`. + self.reject_coroutine(abi, sig); + + if let InterruptKind::X86 = interrupt_kind { + // "x86-interrupt" is special because it does have arguments. + // FIXME(workingjubilee): properly lint on acceptable input types. + if let FnRetTy::Ty(ref ret_ty) = sig.decl.output { + self.dcx().emit_err(errors::AbiMustNotHaveReturnType { + span: ret_ty.span, + abi, + }); + } + } else { + // An `extern "interrupt"` function must have type `fn()`. + self.reject_params_or_return(abi, ident, sig); + } + } + } + } + AbiMapping::Invalid => { /* ignore */ } + } + } + + fn reject_safe_fn(&self, abi: ExternAbi, ctxt: FnCtxt, sig: &FnSig) { let dcx = self.dcx(); - // An `extern "custom"` function must be unsafe. match sig.header.safety { Safety::Unsafe(_) => { /* all good */ } Safety::Safe(safe_span) => { - let safe_span = - self.sess.psess.source_map().span_until_non_whitespace(safe_span.to(sig.span)); + let source_map = self.sess.psess.source_map(); + let safe_span = source_map.span_until_non_whitespace(safe_span.to(sig.span)); dcx.emit_err(errors::AbiCustomSafeForeignFunction { span: sig.span, safe_span }); } Safety::Default => match ctxt { FnCtxt::Foreign => { /* all good */ } FnCtxt::Free | FnCtxt::Assoc(_) => { - self.dcx().emit_err(errors::AbiCustomSafeFunction { + dcx.emit_err(errors::AbiCustomSafeFunction { span: sig.span, + abi, unsafe_span: sig.span.shrink_to_lo(), }); } }, } + } - // An `extern "custom"` function cannot be `async` and/or `gen`. + fn reject_coroutine(&self, abi: ExternAbi, sig: &FnSig) { if let Some(coroutine_kind) = sig.header.coroutine_kind { let coroutine_kind_span = self .sess @@ -397,14 +444,16 @@ impl<'a> AstValidator<'a> { .source_map() .span_until_non_whitespace(coroutine_kind.span().to(sig.span)); - self.dcx().emit_err(errors::AbiCustomCoroutine { + self.dcx().emit_err(errors::AbiCannotBeCoroutine { span: sig.span, + abi, coroutine_kind_span, coroutine_kind_str: coroutine_kind.as_str(), }); } + } - // An `extern "custom"` function must not have any parameters or return type. + 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 { spans.push(ret_ty.span); @@ -415,11 +464,12 @@ impl<'a> AstValidator<'a> { let suggestion_span = header_span.shrink_to_hi().to(sig.decl.output.span()); let padding = if header_span.is_empty() { "" } else { " " }; - self.dcx().emit_err(errors::AbiCustomInvalidSignature { + self.dcx().emit_err(errors::AbiMustNotHaveParametersOrReturnType { spans, symbol: ident.name, suggestion_span, padding, + abi, }); } } @@ -1199,9 +1249,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.check_foreign_fn_bodyless(*ident, body.as_deref()); self.check_foreign_fn_headerless(sig.header); self.check_foreign_item_ascii_only(*ident); - if self.extern_mod_abi == Some(ExternAbi::Custom) { - self.check_custom_abi(FnCtxt::Foreign, ident, sig); - } + self.check_extern_fn_signature( + self.extern_mod_abi.unwrap_or(ExternAbi::FALLBACK), + FnCtxt::Foreign, + ident, + sig, + ); } ForeignItemKind::TyAlias(box TyAlias { defaultness, @@ -1411,9 +1464,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { if let FnKind::Fn(ctxt, _, fun) = fk && let Extern::Explicit(str_lit, _) = fun.sig.header.ext - && let Ok(ExternAbi::Custom) = ExternAbi::from_str(str_lit.symbol.as_str()) + && let Ok(abi) = ExternAbi::from_str(str_lit.symbol.as_str()) { - self.check_custom_abi(ctxt, &fun.ident, &fun.sig); + self.check_extern_fn_signature(abi, ctxt, &fun.ident, &fun.sig); } self.check_c_variadic_type(fk); diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index c437e62f4d3..d387a4a310e 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -1,5 +1,6 @@ //! Errors emitted by ast_passes. +use rustc_abi::ExternAbi; use rustc_ast::ParamKindOrd; use rustc_errors::codes::*; use rustc_errors::{Applicability, Diag, EmissionGuarantee, Subdiagnostic}; @@ -845,6 +846,7 @@ pub(crate) struct AbiCustomSafeForeignFunction { pub(crate) struct AbiCustomSafeFunction { #[primary_span] pub span: Span, + pub abi: ExternAbi, #[suggestion( ast_passes_suggestion, @@ -856,10 +858,11 @@ pub(crate) struct AbiCustomSafeFunction { } #[derive(Diagnostic)] -#[diag(ast_passes_abi_custom_coroutine)] -pub(crate) struct AbiCustomCoroutine { +#[diag(ast_passes_abi_cannot_be_coroutine)] +pub(crate) struct AbiCannotBeCoroutine { #[primary_span] pub span: Span, + pub abi: ExternAbi, #[suggestion( ast_passes_suggestion, @@ -872,11 +875,12 @@ pub(crate) struct AbiCustomCoroutine { } #[derive(Diagnostic)] -#[diag(ast_passes_abi_custom_invalid_signature)] +#[diag(ast_passes_abi_must_not_have_parameters_or_return_type)] #[note] -pub(crate) struct AbiCustomInvalidSignature { +pub(crate) struct AbiMustNotHaveParametersOrReturnType { #[primary_span] pub spans: Vec<Span>, + pub abi: ExternAbi, #[suggestion( ast_passes_suggestion, @@ -888,3 +892,13 @@ pub(crate) struct AbiCustomInvalidSignature { pub symbol: Symbol, pub padding: &'static str, } + +#[derive(Diagnostic)] +#[diag(ast_passes_abi_must_not_have_return_type)] +#[note] +pub(crate) struct AbiMustNotHaveReturnType { + #[primary_span] + #[help] + pub span: Span, + pub abi: ExternAbi, +} diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 1ec56868f37..c7f41fc3cb1 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -505,7 +505,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { ); gate_all!(associated_const_equality, "associated const equality is incomplete"); gate_all!(yeet_expr, "`do yeet` expression is experimental"); - gate_all!(dyn_star, "`dyn*` trait objects are experimental"); gate_all!(const_closures, "const closures are experimental"); gate_all!(builtin_syntax, "`builtin #` syntax is unstable"); gate_all!(ergonomic_clones, "ergonomic clones are experimental"); diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 3d738fa31f2..9802ac90c9a 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1303,7 +1303,6 @@ impl<'a> State<'a> { ast::TyKind::TraitObject(bounds, syntax) => { match syntax { ast::TraitObjectSyntax::Dyn => self.word_nbsp("dyn"), - ast::TraitObjectSyntax::DynStar => self.word_nbsp("dyn*"), ast::TraitObjectSyntax::None => {} } self.print_type_bounds(bounds); diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index f6b5ff404db..8a2cb64b2a0 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -357,6 +357,10 @@ impl<'a> State<'a> { self.word_nbsp("raw"); self.print_mutability(mutability, true); } + ast::BorrowKind::Pin => { + self.word_nbsp("pin"); + self.print_mutability(mutability, true); + } } self.print_expr_cond_paren( expr, @@ -465,8 +469,12 @@ impl<'a> State<'a> { ast::ExprKind::Lit(token_lit) => { self.print_token_literal(*token_lit, expr.span); } - ast::ExprKind::IncludedBytes(bytes) => { - let lit = token::Lit::new(token::ByteStr, escape_byte_str_symbol(bytes), None); + ast::ExprKind::IncludedBytes(byte_sym) => { + let lit = token::Lit::new( + token::ByteStr, + escape_byte_str_symbol(byte_sym.as_byte_str()), + None, + ); self.print_token_literal(lit, expr.span) } ast::ExprKind::Cast(expr, ty) => { diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 9227b81f12f..6f4cc83fd10 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -131,6 +131,17 @@ impl Deprecation { } } +/// There are three valid forms of the attribute: +/// `#[used]`, which is semantically equivalent to `#[used(linker)]` except that the latter is currently unstable. +/// `#[used(compiler)]` +/// `#[used(linker)]` +#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(HashStable_Generic, PrintAttribute)] +pub enum UsedBy { + Compiler, + Linker, +} + /// Represents parsed *built-in* inert attributes. /// /// ## Overview @@ -212,6 +223,9 @@ pub enum AttributeKind { first_span: Span, }, + /// Represents `#[const_continue]`. + ConstContinue(Span), + /// Represents `#[rustc_const_stable]` and `#[rustc_const_unstable]`. ConstStability { stability: PartialConstStability, @@ -228,9 +242,26 @@ pub enum AttributeKind { /// Represents [`#[doc]`](https://doc.rust-lang.org/stable/rustdoc/write-documentation/the-doc-attribute.html). DocComment { style: AttrStyle, kind: CommentKind, span: Span, comment: Symbol }, + /// Represents [`#[export_name]`](https://doc.rust-lang.org/reference/abi.html#the-export_name-attribute). + ExportName { + /// The name to export this item with. + /// It may not contain \0 bytes as it will be converted to a null-terminated string. + name: Symbol, + span: Span, + }, + /// Represents `#[inline]` and `#[rustc_force_inline]`. Inline(InlineAttr, Span), + /// Represents `#[link_name]`. + LinkName { name: Symbol, span: Span }, + + /// Represents [`#[link_section]`](https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute) + LinkSection { name: Symbol, span: Span }, + + /// Represents `#[loop_match]`. + LoopMatch(Span), + /// Represents `#[rustc_macro_transparency]`. MacroTransparency(Transparency), @@ -259,11 +290,29 @@ pub enum AttributeKind { /// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations). Repr(ThinVec<(ReprAttr, Span)>), + /// Represents `#[rustc_layout_scalar_valid_range_end]`. + RustcLayoutScalarValidRangeEnd(Box<u128>, Span), + + /// Represents `#[rustc_layout_scalar_valid_range_start]`. + RustcLayoutScalarValidRangeStart(Box<u128>, Span), + + /// Represents `#[rustc_object_lifetime_default]`. + RustcObjectLifetimeDefault, + + /// Represents `#[rustc_skip_during_method_dispatch]`. + SkipDuringMethodDispatch { array: bool, boxed_slice: bool, span: Span }, + /// Represents `#[stable]`, `#[unstable]` and `#[rustc_allowed_through_unstable_modules]`. Stability { stability: Stability, /// Span of the attribute. span: Span, }, + + /// Represents `#[track_caller]` + TrackCaller(Span), + + /// Represents `#[used]` + Used { used_by: UsedBy, span: Span }, // tidy-alphabetical-end } diff --git a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs new file mode 100644 index 00000000000..58ced8e3281 --- /dev/null +++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs @@ -0,0 +1,49 @@ +use crate::AttributeKind; + +#[derive(PartialEq)] +pub enum EncodeCrossCrate { + Yes, + No, +} + +impl AttributeKind { + pub fn encode_cross_crate(&self) -> EncodeCrossCrate { + use AttributeKind::*; + use EncodeCrossCrate::*; + + match self { + Align { .. } => No, + AllowConstFnUnstable(..) => No, + AllowInternalUnstable(..) => Yes, + AsPtr(..) => Yes, + BodyStability { .. } => No, + Confusables { .. } => Yes, + ConstStability { .. } => Yes, + ConstStabilityIndirect => No, + Deprecation { .. } => Yes, + DocComment { .. } => Yes, + ExportName { .. } => Yes, + Inline(..) => No, + LinkSection { .. } => No, + MacroTransparency(..) => Yes, + Repr(..) => No, + Stability { .. } => Yes, + Cold(..) => No, + ConstContinue(..) => No, + LinkName { .. } => Yes, + LoopMatch(..) => No, + MayDangle(..) => No, + MustUse { .. } => Yes, + Naked(..) => No, + NoMangle(..) => No, + Optimize(..) => No, + PubTransparent(..) => Yes, + RustcLayoutScalarValidRangeEnd(..) => Yes, + RustcLayoutScalarValidRangeStart(..) => Yes, + RustcObjectLifetimeDefault => No, + SkipDuringMethodDispatch { .. } => No, + TrackCaller(..) => Yes, + Used { .. } => No, + } + } +} diff --git a/compiler/rustc_attr_data_structures/src/lib.rs b/compiler/rustc_attr_data_structures/src/lib.rs index f8355be09ad..8f8ce575a18 100644 --- a/compiler/rustc_attr_data_structures/src/lib.rs +++ b/compiler/rustc_attr_data_structures/src/lib.rs @@ -9,6 +9,7 @@ // tidy-alphabetical-end mod attributes; +mod encode_cross_crate; mod stability; mod version; @@ -17,6 +18,7 @@ pub mod lints; use std::num::NonZero; pub use attributes::*; +pub use encode_cross_crate::EncodeCrossCrate; use rustc_abi::Align; use rustc_ast::token::CommentKind; use rustc_ast::{AttrStyle, IntTy, UintTy}; @@ -47,6 +49,16 @@ pub trait PrintAttribute { fn print_attribute(&self, p: &mut Printer); } +impl PrintAttribute for u128 { + fn should_render(&self) -> bool { + true + } + + fn print_attribute(&self, p: &mut Printer) { + p.word(self.to_string()) + } +} + impl<T: PrintAttribute> PrintAttribute for &T { fn should_render(&self) -> bool { T::should_render(self) diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 2bb27ede860..9ad46a83f50 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -93,9 +93,14 @@ attr_parsing_naked_functions_incompatible_attribute = attribute incompatible with `#[unsafe(naked)]` .label = the `{$attr}` attribute is incompatible with `#[unsafe(naked)]` .naked_attribute = function marked with `#[unsafe(naked)]` here + attr_parsing_non_ident_feature = 'feature' is not an identifier +attr_parsing_null_on_export = `export_name` may not contain null characters + +attr_parsing_null_on_link_section = `link_section` may not contain null characters + attr_parsing_repr_ident = meta item in `repr` must be an identifier diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 24c40c301fe..7c412d4fa89 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -1,17 +1,17 @@ -use rustc_attr_data_structures::{AttributeKind, OptimizeAttr}; +use rustc_attr_data_structures::{AttributeKind, OptimizeAttr, UsedBy}; use rustc_feature::{AttributeTemplate, template}; use rustc_session::parse::feature_err; -use rustc_span::{Span, sym}; +use rustc_span::{Span, Symbol, sym}; use super::{AcceptMapping, AttributeOrder, AttributeParser, OnDuplicate, SingleAttributeParser}; use crate::context::{AcceptContext, FinalizeContext, Stage}; use crate::parser::ArgParser; -use crate::session_diagnostics::NakedFunctionIncompatibleAttribute; +use crate::session_diagnostics::{NakedFunctionIncompatibleAttribute, NullOnExport}; pub(crate) struct OptimizeParser; impl<S: Stage> SingleAttributeParser<S> for OptimizeParser { - const PATH: &[rustc_span::Symbol] = &[sym::optimize]; + const PATH: &[Symbol] = &[sym::optimize]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError; const TEMPLATE: AttributeTemplate = template!(List: "size|speed|none"); @@ -44,14 +44,14 @@ impl<S: Stage> SingleAttributeParser<S> for OptimizeParser { pub(crate) struct ColdParser; impl<S: Stage> SingleAttributeParser<S> for ColdParser { - const PATH: &[rustc_span::Symbol] = &[sym::cold]; + const PATH: &[Symbol] = &[sym::cold]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn; const TEMPLATE: AttributeTemplate = template!(Word); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { - if !args.no_args() { - cx.expected_no_args(args.span().unwrap_or(cx.attr_span)); + if let Err(span) = args.no_args() { + cx.expected_no_args(span); return None; } @@ -59,6 +59,33 @@ impl<S: Stage> SingleAttributeParser<S> for ColdParser { } } +pub(crate) struct ExportNameParser; + +impl<S: Stage> SingleAttributeParser<S> for ExportNameParser { + const PATH: &[rustc_span::Symbol] = &[sym::export_name]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError; + const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name"); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { + let Some(nv) = args.name_value() else { + cx.expected_name_value(cx.attr_span, None); + return None; + }; + let Some(name) = nv.value_as_str() else { + cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit())); + return None; + }; + if name.as_str().contains('\0') { + // `#[export_name = ...]` will be converted to a null-terminated string, + // so it may not contain any null characters. + cx.emit_err(NullOnExport { span: cx.attr_span }); + return None; + } + Some(AttributeKind::ExportName { name, span: cx.attr_span }) + } +} + #[derive(Default)] pub(crate) struct NakedParser { span: Option<Span>, @@ -67,8 +94,8 @@ pub(crate) struct NakedParser { impl<S: Stage> AttributeParser<S> for NakedParser { const ATTRIBUTES: AcceptMapping<Self, S> = &[(&[sym::naked], template!(Word), |this, cx, args| { - if !args.no_args() { - cx.expected_no_args(args.span().unwrap_or(cx.attr_span)); + if let Err(span) = args.no_args() { + cx.expected_no_args(span); return; } @@ -166,6 +193,24 @@ impl<S: Stage> AttributeParser<S> for NakedParser { } } +pub(crate) struct TrackCallerParser; + +impl<S: Stage> SingleAttributeParser<S> for TrackCallerParser { + const PATH: &[Symbol] = &[sym::track_caller]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn; + const TEMPLATE: AttributeTemplate = template!(Word); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { + if let Err(span) = args.no_args() { + cx.expected_no_args(span); + return None; + } + + Some(AttributeKind::TrackCaller(cx.attr_span)) + } +} + pub(crate) struct NoMangleParser; impl<S: Stage> SingleAttributeParser<S> for NoMangleParser { @@ -175,11 +220,92 @@ impl<S: Stage> SingleAttributeParser<S> for NoMangleParser { const TEMPLATE: AttributeTemplate = template!(Word); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { - if !args.no_args() { - cx.expected_no_args(args.span().unwrap_or(cx.attr_span)); + if let Err(span) = args.no_args() { + cx.expected_no_args(span); return None; - }; + } Some(AttributeKind::NoMangle(cx.attr_span)) } } + +#[derive(Default)] +pub(crate) struct UsedParser { + first_compiler: Option<Span>, + first_linker: Option<Span>, +} + +// A custom `AttributeParser` is used rather than a Simple attribute parser because +// - Specifying two `#[used]` attributes is a warning (but will be an error in the future) +// - But specifying two conflicting attributes: `#[used(compiler)]` and `#[used(linker)]` is already an error today +// We can change this to a Simple parser once the warning becomes an error +impl<S: Stage> AttributeParser<S> for UsedParser { + const ATTRIBUTES: AcceptMapping<Self, S> = &[( + &[sym::used], + template!(Word, List: "compiler|linker"), + |group: &mut Self, cx, args| { + let used_by = match args { + ArgParser::NoArgs => UsedBy::Linker, + ArgParser::List(list) => { + let Some(l) = list.single() else { + cx.expected_single_argument(list.span); + return; + }; + + match l.meta_item().and_then(|i| i.path().word_sym()) { + Some(sym::compiler) => { + if !cx.features().used_with_arg() { + feature_err( + &cx.sess(), + sym::used_with_arg, + cx.attr_span, + "`#[used(compiler)]` is currently unstable", + ) + .emit(); + } + UsedBy::Compiler + } + Some(sym::linker) => { + if !cx.features().used_with_arg() { + feature_err( + &cx.sess(), + sym::used_with_arg, + cx.attr_span, + "`#[used(linker)]` is currently unstable", + ) + .emit(); + } + UsedBy::Linker + } + _ => { + cx.expected_specific_argument(l.span(), vec!["compiler", "linker"]); + return; + } + } + } + ArgParser::NameValue(_) => return, + }; + + let target = match used_by { + UsedBy::Compiler => &mut group.first_compiler, + UsedBy::Linker => &mut group.first_linker, + }; + + let attr_span = cx.attr_span; + if let Some(prev) = *target { + cx.warn_unused_duplicate(prev, attr_span); + } else { + *target = Some(attr_span); + } + }, + )]; + + fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { + // Ratcheting behaviour, if both `linker` and `compiler` are specified, use `linker` + Some(match (self.first_compiler, self.first_linker) { + (_, Some(span)) => AttributeKind::Used { used_by: UsedBy::Linker, span }, + (Some(span), _) => AttributeKind::Used { used_by: UsedBy::Compiler, span }, + (None, None) => return None, + }) + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs new file mode 100644 index 00000000000..e298053ab76 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -0,0 +1,59 @@ +use rustc_attr_data_structures::AttributeKind; +use rustc_attr_data_structures::AttributeKind::{LinkName, LinkSection}; +use rustc_feature::{AttributeTemplate, template}; +use rustc_span::{Symbol, sym}; + +use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; +use crate::context::{AcceptContext, Stage}; +use crate::parser::ArgParser; +use crate::session_diagnostics::NullOnLinkSection; + +pub(crate) struct LinkNameParser; + +impl<S: Stage> SingleAttributeParser<S> for LinkNameParser { + const PATH: &[Symbol] = &[sym::link_name]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError; + const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name"); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { + let Some(nv) = args.name_value() else { + cx.expected_name_value(cx.attr_span, None); + return None; + }; + let Some(name) = nv.value_as_str() else { + cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit())); + return None; + }; + + Some(LinkName { name, span: cx.attr_span }) + } +} + +pub(crate) struct LinkSectionParser; + +impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser { + const PATH: &[Symbol] = &[sym::link_section]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError; + const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name"); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { + let Some(nv) = args.name_value() else { + cx.expected_name_value(cx.attr_span, None); + return None; + }; + let Some(name) = nv.value_as_str() else { + cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit())); + return None; + }; + if name.as_str().contains('\0') { + // `#[link_section = ...]` will be converted to a null-terminated string, + // so it may not contain any null characters. + cx.emit_err(NullOnLinkSection { span: cx.attr_span }); + return None; + } + + Some(LinkSection { name, span: cx.attr_span }) + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs index 4cfd9a82ce8..1c8fc5079da 100644 --- a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs +++ b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs @@ -14,8 +14,10 @@ impl<S: Stage> SingleAttributeParser<S> for AsPtrParser { const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; const TEMPLATE: AttributeTemplate = template!(Word); - fn convert(cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> { - // FIXME: check that there's no args (this is currently checked elsewhere) + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { + if let Err(span) = args.no_args() { + cx.expected_no_args(span); + } Some(AttributeKind::AsPtr(cx.attr_span)) } } @@ -27,8 +29,10 @@ impl<S: Stage> SingleAttributeParser<S> for PubTransparentParser { const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; const TEMPLATE: AttributeTemplate = template!(Word); - fn convert(cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> { - // FIXME: check that there's no args (this is currently checked elsewhere) + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { + if let Err(span) = args.no_args() { + cx.expected_no_args(span); + } Some(AttributeKind::PubTransparent(cx.attr_span)) } } diff --git a/compiler/rustc_attr_parsing/src/attributes/loop_match.rs b/compiler/rustc_attr_parsing/src/attributes/loop_match.rs new file mode 100644 index 00000000000..f6c7ac5e3a3 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/loop_match.rs @@ -0,0 +1,31 @@ +use rustc_attr_data_structures::AttributeKind; +use rustc_feature::{AttributeTemplate, template}; +use rustc_span::{Symbol, sym}; + +use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; +use crate::context::{AcceptContext, Stage}; +use crate::parser::ArgParser; + +pub(crate) struct LoopMatchParser; +impl<S: Stage> SingleAttributeParser<S> for LoopMatchParser { + const PATH: &[Symbol] = &[sym::loop_match]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn; + const TEMPLATE: AttributeTemplate = template!(Word); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> { + Some(AttributeKind::LoopMatch(cx.attr_span)) + } +} + +pub(crate) struct ConstContinueParser; +impl<S: Stage> SingleAttributeParser<S> for ConstContinueParser { + const PATH: &[Symbol] = &[sym::const_continue]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn; + const TEMPLATE: AttributeTemplate = template!(Word); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> { + Some(AttributeKind::ConstContinue(cx.attr_span)) + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 738d8735b69..b3a9c69c055 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -31,11 +31,15 @@ pub(crate) mod codegen_attrs; pub(crate) mod confusables; pub(crate) mod deprecation; pub(crate) mod inline; +pub(crate) mod link_attrs; pub(crate) mod lint_helpers; +pub(crate) mod loop_match; pub(crate) mod must_use; pub(crate) mod repr; +pub(crate) mod rustc_internal; pub(crate) mod semantics; pub(crate) mod stability; +pub(crate) mod traits; pub(crate) mod transparency; pub(crate) mod util; diff --git a/compiler/rustc_attr_parsing/src/attributes/must_use.rs b/compiler/rustc_attr_parsing/src/attributes/must_use.rs index a672d956127..b5eb85f68b4 100644 --- a/compiler/rustc_attr_parsing/src/attributes/must_use.rs +++ b/compiler/rustc_attr_parsing/src/attributes/must_use.rs @@ -21,7 +21,16 @@ impl<S: Stage> SingleAttributeParser<S> for MustUseParser { span: cx.attr_span, reason: match args { ArgParser::NoArgs => None, - ArgParser::NameValue(name_value) => name_value.value_as_str(), + ArgParser::NameValue(name_value) => { + let Some(value_str) = name_value.value_as_str() else { + cx.expected_string_literal( + name_value.value_span, + Some(&name_value.value_as_lit()), + ); + return None; + }; + Some(value_str) + } ArgParser::List(_) => { let suggestions = <Self as SingleAttributeParser<S>>::TEMPLATE.suggestions(false, "must_use"); diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs new file mode 100644 index 00000000000..e6b6a6fe3c9 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -0,0 +1,77 @@ +use rustc_ast::LitKind; +use rustc_attr_data_structures::AttributeKind; +use rustc_feature::{AttributeTemplate, template}; +use rustc_span::{Symbol, sym}; + +use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; +use crate::context::{AcceptContext, Stage}; +use crate::parser::ArgParser; + +pub(crate) struct RustcLayoutScalarValidRangeStart; + +impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeStart { + const PATH: &'static [Symbol] = &[sym::rustc_layout_scalar_valid_range_start]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const TEMPLATE: AttributeTemplate = template!(List: "start"); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { + parse_rustc_layout_scalar_valid_range(cx, args) + .map(|n| AttributeKind::RustcLayoutScalarValidRangeStart(n, cx.attr_span)) + } +} + +pub(crate) struct RustcLayoutScalarValidRangeEnd; + +impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeEnd { + const PATH: &'static [Symbol] = &[sym::rustc_layout_scalar_valid_range_end]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const TEMPLATE: AttributeTemplate = template!(List: "end"); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { + parse_rustc_layout_scalar_valid_range(cx, args) + .map(|n| AttributeKind::RustcLayoutScalarValidRangeEnd(n, cx.attr_span)) + } +} + +fn parse_rustc_layout_scalar_valid_range<S: Stage>( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser<'_>, +) -> Option<Box<u128>> { + let Some(list) = args.list() else { + cx.expected_list(cx.attr_span); + return None; + }; + let Some(single) = list.single() else { + cx.expected_single_argument(list.span); + return None; + }; + let Some(lit) = single.lit() else { + cx.expected_integer_literal(single.span()); + return None; + }; + let LitKind::Int(num, _ty) = lit.kind else { + cx.expected_integer_literal(single.span()); + return None; + }; + Some(Box::new(num.0)) +} + +pub(crate) struct RustcObjectLifetimeDefaultParser; + +impl<S: Stage> SingleAttributeParser<S> for RustcObjectLifetimeDefaultParser { + const PATH: &[rustc_span::Symbol] = &[sym::rustc_object_lifetime_default]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const TEMPLATE: AttributeTemplate = template!(Word); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { + if let Err(span) = args.no_args() { + cx.expected_no_args(span); + return None; + } + + Some(AttributeKind::RustcObjectLifetimeDefault) + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/semantics.rs b/compiler/rustc_attr_parsing/src/attributes/semantics.rs index 071574a5612..54f50445fbd 100644 --- a/compiler/rustc_attr_parsing/src/attributes/semantics.rs +++ b/compiler/rustc_attr_parsing/src/attributes/semantics.rs @@ -13,7 +13,10 @@ impl<S: Stage> SingleAttributeParser<S> for MayDangleParser { const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn; const TEMPLATE: AttributeTemplate = template!(Word); - fn convert(cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { + if let Err(span) = args.no_args() { + cx.expected_no_args(span); + } Some(AttributeKind::MayDangle(cx.attr_span)) } } diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index 6871ff4ec9f..37104855623 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -139,7 +139,10 @@ impl<S: Stage> SingleAttributeParser<S> for ConstStabilityIndirectParser { const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Ignore; const TEMPLATE: AttributeTemplate = template!(Word); - fn convert(_cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { + if let Err(span) = args.no_args() { + cx.expected_no_args(span); + } Some(AttributeKind::ConstStabilityIndirect) } } @@ -361,8 +364,8 @@ pub(crate) fn parse_unstability<S: Stage>( }; } Some(sym::soft) => { - if !param.args().no_args() { - cx.emit_err(session_diagnostics::SoftNoArgs { span: param.span() }); + if let Err(span) = args.no_args() { + cx.emit_err(session_diagnostics::SoftNoArgs { span }); } is_soft = true; } diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs new file mode 100644 index 00000000000..83a98c53c7f --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs @@ -0,0 +1,54 @@ +use core::mem; + +use rustc_attr_data_structures::AttributeKind; +use rustc_feature::{AttributeTemplate, template}; +use rustc_span::{Symbol, sym}; + +use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; +use crate::context::{AcceptContext, Stage}; +use crate::parser::ArgParser; + +pub(crate) struct SkipDuringMethodDispatchParser; + +impl<S: Stage> SingleAttributeParser<S> for SkipDuringMethodDispatchParser { + const PATH: &[Symbol] = &[sym::rustc_skip_during_method_dispatch]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + + const TEMPLATE: AttributeTemplate = template!(List: "array, boxed_slice"); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { + let mut array = false; + let mut boxed_slice = false; + let Some(args) = args.list() else { + cx.expected_list(cx.attr_span); + return None; + }; + if args.is_empty() { + cx.expected_at_least_one_argument(args.span); + return None; + } + for arg in args.mixed() { + let Some(arg) = arg.meta_item() else { + cx.unexpected_literal(arg.span()); + continue; + }; + if let Err(span) = arg.args().no_args() { + cx.expected_no_args(span); + } + let path = arg.path(); + let (key, skip): (Symbol, &mut bool) = match path.word_sym() { + Some(key @ sym::array) => (key, &mut array), + Some(key @ sym::boxed_slice) => (key, &mut boxed_slice), + _ => { + cx.expected_specific_argument(path.span(), vec!["array", "boxed_slice"]); + continue; + } + }; + if mem::replace(skip, true) { + cx.duplicate_key(arg.span(), key); + } + } + Some(AttributeKind::SkipDuringMethodDispatch { array, boxed_slice, span: cx.attr_span }) + } +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 457e073c488..cfba0650932 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -15,17 +15,27 @@ use rustc_session::Session; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser}; -use crate::attributes::codegen_attrs::{ColdParser, NakedParser, NoMangleParser, OptimizeParser}; +use crate::attributes::codegen_attrs::{ + ColdParser, ExportNameParser, NakedParser, NoMangleParser, OptimizeParser, TrackCallerParser, + UsedParser, +}; use crate::attributes::confusables::ConfusablesParser; use crate::attributes::deprecation::DeprecationParser; use crate::attributes::inline::{InlineParser, RustcForceInlineParser}; +use crate::attributes::link_attrs::{LinkNameParser, LinkSectionParser}; use crate::attributes::lint_helpers::{AsPtrParser, PubTransparentParser}; +use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser}; use crate::attributes::must_use::MustUseParser; use crate::attributes::repr::{AlignParser, ReprParser}; +use crate::attributes::rustc_internal::{ + RustcLayoutScalarValidRangeEnd, RustcLayoutScalarValidRangeStart, + RustcObjectLifetimeDefaultParser, +}; use crate::attributes::semantics::MayDangleParser; use crate::attributes::stability::{ BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser, }; +use crate::attributes::traits::SkipDuringMethodDispatchParser; use crate::attributes::transparency::TransparencyParser; use crate::attributes::{AttributeParser as _, Combine, Single}; use crate::parser::{ArgParser, MetaItemParser, PathParser}; @@ -99,6 +109,7 @@ attribute_parsers!( ConstStabilityParser, NakedParser, StabilityParser, + UsedParser, // tidy-alphabetical-end // tidy-alphabetical-start @@ -110,15 +121,25 @@ attribute_parsers!( // tidy-alphabetical-start Single<AsPtrParser>, Single<ColdParser>, + Single<ConstContinueParser>, Single<ConstStabilityIndirectParser>, Single<DeprecationParser>, + Single<ExportNameParser>, Single<InlineParser>, + Single<LinkNameParser>, + Single<LinkSectionParser>, + Single<LoopMatchParser>, Single<MayDangleParser>, Single<MustUseParser>, Single<NoMangleParser>, Single<OptimizeParser>, Single<PubTransparentParser>, Single<RustcForceInlineParser>, + Single<RustcLayoutScalarValidRangeEnd>, + Single<RustcLayoutScalarValidRangeStart>, + Single<RustcObjectLifetimeDefaultParser>, + Single<SkipDuringMethodDispatchParser>, + Single<TrackCallerParser>, Single<TransparencyParser>, // tidy-alphabetical-end ]; @@ -260,6 +281,16 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { }) } + pub(crate) fn expected_integer_literal(&self, span: Span) -> ErrorGuaranteed { + self.emit_err(AttributeParseError { + span, + attr_span: self.attr_span, + template: self.template.clone(), + attribute: self.attr_path.clone(), + reason: AttributeParseErrorReason::ExpectedIntegerLiteral, + }) + } + pub(crate) fn expected_list(&self, span: Span) -> ErrorGuaranteed { self.emit_err(AttributeParseError { span, @@ -325,6 +356,16 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { }) } + pub(crate) fn expected_at_least_one_argument(&self, span: Span) -> ErrorGuaranteed { + self.emit_err(AttributeParseError { + span, + attr_span: self.attr_span, + template: self.template.clone(), + attribute: self.attr_path.clone(), + reason: AttributeParseErrorReason::ExpectedAtLeastOneArgument, + }) + } + pub(crate) fn expected_specific_argument( &self, span: Span, diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index e02dc098127..aecaae947c9 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -169,9 +169,15 @@ impl<'a> ArgParser<'a> { } } - /// Asserts that there are no arguments - pub fn no_args(&self) -> bool { - matches!(self, Self::NoArgs) + /// Assert that there were no args. + /// If there were, get a span to the arguments + /// (to pass to [`AcceptContext::expected_no_args`](crate::context::AcceptContext::expected_no_args)). + pub fn no_args(&self) -> Result<(), Span> { + match self { + Self::NoArgs => Ok(()), + Self::List(args) => Err(args.span), + Self::NameValue(args) => Err(args.eq_span.to(args.value_span)), + } } } diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 808e452799d..6145f1e1d3e 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -446,6 +446,20 @@ pub(crate) struct MustUseIllFormedAttributeInput { } #[derive(Diagnostic)] +#[diag(attr_parsing_null_on_export, code = E0648)] +pub(crate) struct NullOnExport { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(attr_parsing_null_on_link_section, code = E0648)] +pub(crate) struct NullOnLinkSection { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] #[diag(attr_parsing_stability_outside_std, code = E0734)] pub(crate) struct StabilityOutsideStd { #[primary_span] @@ -496,6 +510,8 @@ pub(crate) struct NakedFunctionIncompatibleAttribute { pub(crate) enum AttributeParseErrorReason { ExpectedNoArgs, ExpectedStringLiteral { byte_string: Option<Span> }, + ExpectedIntegerLiteral, + ExpectedAtLeastOneArgument, ExpectedSingleArgument, ExpectedList, UnexpectedLiteral, @@ -535,10 +551,16 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError { diag.span_label(self.span, "expected a string literal here"); } } + AttributeParseErrorReason::ExpectedIntegerLiteral => { + diag.span_label(self.span, "expected an integer literal here"); + } AttributeParseErrorReason::ExpectedSingleArgument => { diag.span_label(self.span, "expected a single argument here"); diag.code(E0805); } + AttributeParseErrorReason::ExpectedAtLeastOneArgument => { + diag.span_label(self.span, "expected at least 1 argument here"); + } AttributeParseErrorReason::ExpectedList => { diag.span_label(self.span, "expected this to be a list"); } @@ -555,10 +577,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError { diag.code(E0565); } AttributeParseErrorReason::ExpectedNameValue(None) => { - diag.span_label( - self.span, - format!("expected this to be of the form `{name} = \"...\"`"), - ); + // The suggestion we add below this match already contains enough information } AttributeParseErrorReason::ExpectedNameValue(Some(name)) => { diag.span_label( diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 98dc898db23..d1dac1c7145 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -518,11 +518,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } = move_spans && can_suggest_clone { - self.suggest_cloning(err, ty, expr, Some(move_spans)); + self.suggest_cloning(err, place.as_ref(), ty, expr, Some(move_spans)); } else if self.suggest_hoisting_call_outside_loop(err, expr) && can_suggest_clone { // The place where the type moves would be misleading to suggest clone. // #121466 - self.suggest_cloning(err, ty, expr, Some(move_spans)); + self.suggest_cloning(err, place.as_ref(), ty, expr, Some(move_spans)); } } @@ -1224,6 +1224,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { pub(crate) fn suggest_cloning( &self, err: &mut Diag<'_>, + place: PlaceRef<'tcx>, ty: Ty<'tcx>, expr: &'tcx hir::Expr<'tcx>, use_spans: Option<UseSpans<'tcx>>, @@ -1238,7 +1239,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } if self.implements_clone(ty) { - self.suggest_cloning_inner(err, ty, expr); + if self.in_move_closure(expr) { + if let Some(name) = self.describe_place(place) { + self.suggest_clone_of_captured_var_in_move_closure(err, &name, use_spans); + } + } else { + self.suggest_cloning_inner(err, ty, expr); + } } else if let ty::Adt(def, args) = ty.kind() && def.did().as_local().is_some() && def.variants().iter().all(|variant| { @@ -1505,7 +1512,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { if let hir::ExprKind::AddrOf(_, _, borrowed_expr) = expr.kind && let Some(ty) = typeck_results.expr_ty_opt(borrowed_expr) { - self.suggest_cloning(&mut err, ty, borrowed_expr, Some(move_spans)); + self.suggest_cloning(&mut err, place.as_ref(), ty, borrowed_expr, Some(move_spans)); } else if typeck_results.expr_adjustments(expr).first().is_some_and(|adj| { matches!( adj.kind, @@ -1518,7 +1525,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ) }) && let Some(ty) = typeck_results.expr_ty_opt(expr) { - self.suggest_cloning(&mut err, ty, expr, Some(move_spans)); + self.suggest_cloning(&mut err, place.as_ref(), ty, expr, Some(move_spans)); } } self.buffer_error(err); diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 095c0df98ac..f9e52239d6f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -71,7 +71,6 @@ impl<'tcx> BorrowExplanation<'tcx> { ) { let tcx = cx.infcx.tcx; let body = cx.body; - let local_names = &cx.local_names; if let Some(span) = borrow_span { let def_id = body.source.def_id(); @@ -220,7 +219,7 @@ impl<'tcx> BorrowExplanation<'tcx> { _ => ("destructor", format!("type `{}`", local_decl.ty)), }; - match local_names[dropped_local] { + match cx.local_name(dropped_local) { Some(local_name) if !local_decl.from_compiler_desugaring() => { let message = format!( "{borrow_desc}borrow might be used here, when `{local_name}` is dropped \ @@ -670,10 +669,10 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { Some(Cause::DropVar(local, location)) => { let mut should_note_order = false; - if self.local_names[local].is_some() + if self.local_name(local).is_some() && let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place && let Some(borrowed_local) = place.as_local() - && self.local_names[borrowed_local].is_some() + && self.local_name(borrowed_local).is_some() && local != borrowed_local { should_note_order = true; @@ -748,7 +747,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { Operand::Copy(place) | Operand::Move(place) => { if let Some(l) = place.as_local() { let local_decl = &self.body.local_decls[l]; - if self.local_names[l].is_none() { + if self.local_name(l).is_none() { local_decl.source_info.span } else { span @@ -793,7 +792,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { Operand::Copy(place) | Operand::Move(place) => { if let Some(l) = place.as_local() { let local_decl = &self.body.local_decls[l]; - if self.local_names[l].is_none() { + if self.local_name(l).is_none() { local_decl.source_info.span } else { span diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 5e3f3ffa2ea..9ad91d605a7 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -7,17 +7,17 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan, listify}; use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::{self as hir, CoroutineKind, LangItem}; -use rustc_index::IndexSlice; +use rustc_index::{IndexSlice, IndexVec}; use rustc_infer::infer::{BoundRegionConversionTime, NllRegionVariableOrigin}; use rustc_infer::traits::SelectionError; -use rustc_middle::bug; use rustc_middle::mir::{ AggregateKind, CallSource, ConstOperand, ConstraintCategory, FakeReadCause, Local, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef, PlaceTy, ProjectionElem, Rvalue, Statement, - StatementKind, Terminator, TerminatorKind, find_self_call, + StatementKind, Terminator, TerminatorKind, VarDebugInfoContents, find_self_call, }; use rustc_middle::ty::print::Print; use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::{bug, span_bug}; use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult, MoveOutIndex}; use rustc_span::def_id::LocalDefId; use rustc_span::source_map::Spanned; @@ -190,6 +190,36 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ) -> Option<&(PlaceRef<'tcx>, Diag<'infcx>)> { self.diags_buffer.buffered_move_errors.get(move_out_indices) } + + /// Uses `body.var_debug_info` to find the symbol + fn local_name(&self, index: Local) -> Option<Symbol> { + *self.local_names().get(index)? + } + + fn local_names(&self) -> &IndexSlice<Local, Option<Symbol>> { + self.local_names.get_or_init(|| { + let mut local_names = IndexVec::from_elem(None, &self.body.local_decls); + for var_debug_info in &self.body.var_debug_info { + if let VarDebugInfoContents::Place(place) = var_debug_info.value { + if let Some(local) = place.as_local() { + if let Some(prev_name) = local_names[local] + && var_debug_info.name != prev_name + { + span_bug!( + var_debug_info.source_info.span, + "local {:?} has many names (`{}` vs `{}`)", + local, + prev_name, + var_debug_info.name + ); + } + local_names[local] = Some(var_debug_info.name); + } + } + } + local_names + }) + } } impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { @@ -430,7 +460,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { /// a name, or its name was generated by the compiler, then `Err` is returned fn append_local_to_string(&self, local: Local, buf: &mut String) -> Result<(), ()> { let decl = &self.body.local_decls[local]; - match self.local_names[local] { + match self.local_name(local) { Some(name) if !decl.from_compiler_desugaring() => { buf.push_str(name.as_str()); Ok(()) @@ -1254,8 +1284,14 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { && !spans.is_empty() { let mut span: MultiSpan = spans.clone().into(); + err.arg("ty", param_ty.to_string()); + let msg = err.dcx.eagerly_translate_to_string( + fluent::borrowck_moved_a_fn_once_in_call_def, + err.args.iter(), + ); + err.remove_arg("ty"); for sp in spans { - span.push_span_label(sp, fluent::borrowck_moved_a_fn_once_in_call_def); + span.push_span_label(sp, msg.clone()); } span.push_span_label( fn_call_span, @@ -1500,4 +1536,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } } } + + /// Skip over locals that begin with an underscore or have no name + pub(crate) fn local_excluded_from_unused_mut_lint(&self, index: Local) -> bool { + self.local_name(index).is_none_or(|name| name.as_str().starts_with('_')) + } } diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 0394a42ea9c..92ca868eb99 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -325,25 +325,17 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { self.cannot_move_out_of(span, &description) } - fn suggest_clone_of_captured_var_in_move_closure( + pub(in crate::diagnostics) fn suggest_clone_of_captured_var_in_move_closure( &self, err: &mut Diag<'_>, - upvar_hir_id: HirId, upvar_name: &str, use_spans: Option<UseSpans<'tcx>>, ) { let tcx = self.infcx.tcx; - let typeck_results = tcx.typeck(self.mir_def_id()); let Some(use_spans) = use_spans else { return }; // We only care about the case where a closure captured a binding. let UseSpans::ClosureUse { args_span, .. } = use_spans else { return }; let Some(body_id) = tcx.hir_node(self.mir_hir_id()).body_id() else { return }; - // Fetch the type of the expression corresponding to the closure-captured binding. - let Some(captured_ty) = typeck_results.node_type_opt(upvar_hir_id) else { return }; - if !self.implements_clone(captured_ty) { - // We only suggest cloning the captured binding if the type can actually be cloned. - return; - }; // Find the closure that captured the binding. let mut expr_finder = FindExprBySpan::new(args_span, tcx); expr_finder.include_closures = true; @@ -396,7 +388,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { .indentation_before(stmt.span) .unwrap_or_else(|| " ".to_string()); err.multipart_suggestion_verbose( - "clone the value before moving it into the closure", + "consider cloning the value before moving it into the closure", vec![ ( stmt.span.shrink_to_lo(), @@ -426,7 +418,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { .indentation_before(closure_expr.span) .unwrap_or_else(|| " ".to_string()); err.multipart_suggestion_verbose( - "clone the value before moving it into the closure", + "consider cloning the value before moving it into the closure", vec![ ( closure_expr.span.shrink_to_lo(), @@ -465,11 +457,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { if let PlaceRef { local, projection: [] } = deref_base { let decl = &self.body.local_decls[local]; + let local_name = self.local_name(local).map(|sym| format!("`{sym}`")); if decl.is_ref_for_guard() { return self .cannot_move_out_of( span, - &format!("`{}` in pattern guard", self.local_names[local].unwrap()), + &format!( + "{} in pattern guard", + local_name.as_deref().unwrap_or("the place") + ), ) .with_note( "variables bound in patterns cannot be moved from \ @@ -519,20 +515,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ); let closure_span = tcx.def_span(def_id); - let mut err = self - .cannot_move_out_of(span, &place_description) + self.cannot_move_out_of(span, &place_description) .with_span_label(upvar_span, "captured outer variable") .with_span_label( closure_span, format!("captured by this `{closure_kind}` closure"), - ); - self.suggest_clone_of_captured_var_in_move_closure( - &mut err, - upvar_hir_id, - &upvar_name, - use_spans, - ); - err + ) } _ => { let source = self.borrowed_content_source(deref_base); @@ -593,7 +581,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { }; if let Some(expr) = self.find_expr(span) { - self.suggest_cloning(err, place_ty, expr, None); + self.suggest_cloning(err, move_from.as_ref(), place_ty, expr, None); } err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label { @@ -625,7 +613,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { }; if let Some(expr) = self.find_expr(use_span) { - self.suggest_cloning(err, place_ty, expr, Some(use_spans)); + self.suggest_cloning( + err, + original_path.as_ref(), + place_ty, + expr, + Some(use_spans), + ); } err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label { @@ -825,16 +819,17 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } if binds_to.len() == 1 { - let place_desc = &format!("`{}`", self.local_names[*local].unwrap()); + let place_desc = self.local_name(*local).map(|sym| format!("`{sym}`")); if let Some(expr) = self.find_expr(binding_span) { - self.suggest_cloning(err, bind_to.ty, expr, None); + let local_place: PlaceRef<'tcx> = (*local).into(); + self.suggest_cloning(err, local_place, bind_to.ty, expr, None); } err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label { is_partial_move: false, ty: bind_to.ty, - place: place_desc, + place: place_desc.as_deref().unwrap_or("the place"), span: binding_span, }); } diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index a5c9bad3ac2..7c69baba62e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -60,7 +60,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { if access_place.as_local().is_some() { reason = ", as it is not declared as mutable".to_string(); } else { - let name = self.local_names[local].expect("immutable unnamed local"); + let name = self.local_name(local).expect("immutable unnamed local"); reason = format!(", as `{name}` is not declared as mutable"); } } @@ -285,7 +285,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { .body .local_decls .get(local) - .is_some_and(|l| mut_borrow_of_mutable_ref(l, self.local_names[local])) => + .is_some_and(|l| mut_borrow_of_mutable_ref(l, self.local_name(local))) => { let decl = &self.body.local_decls[local]; err.span_label(span, format!("cannot {act}")); @@ -481,7 +481,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let (pointer_sigil, pointer_desc) = if local_decl.ty.is_ref() { ("&", "reference") } else { ("*const", "pointer") }; - match self.local_names[local] { + match self.local_name(local) { Some(name) if !local_decl.from_compiler_desugaring() => { err.span_label( span, @@ -1168,6 +1168,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { _, mir::Rvalue::Use(mir::Operand::Copy(place)), )), + .. }) = self.body[location.block].statements.get(location.statement_index) { self.body.local_decls[place.local].source_info.span diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 3bec07afa0f..a611557dc92 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -10,7 +10,7 @@ use rustc_hir::def::Res::Def; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::VisitorExt; use rustc_hir::{PolyTraitRef, TyKind, WhereBoundPredicate}; -use rustc_infer::infer::{NllRegionVariableOrigin, RelateParamBound}; +use rustc_infer::infer::{NllRegionVariableOrigin, SubregionOrigin}; use rustc_middle::bug; use rustc_middle::hir::place::PlaceBase; use rustc_middle::mir::{AnnotationSource, ConstraintCategory, ReturnConstraint}; @@ -329,7 +329,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { self.infcx.tcx, type_test.generic_kind.to_ty(self.infcx.tcx), ); - let origin = RelateParamBound(type_test_span, generic_ty, None); + let origin = + SubregionOrigin::RelateParamBound(type_test_span, generic_ty, None); self.buffer_error(self.infcx.err_ctxt().construct_generic_bound_failure( self.body.source.def_id().expect_local(), type_test_span, @@ -664,14 +665,14 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let fr_name_and_span = self.regioncx.get_var_name_and_span_for_region( self.infcx.tcx, self.body, - &self.local_names, + &self.local_names(), &self.upvars, errci.fr, ); let outlived_fr_name_and_span = self.regioncx.get_var_name_and_span_for_region( self.infcx.tcx, self.body, - &self.local_names, + &self.local_names(), &self.upvars, errci.outlived_fr, ); diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 487f78058a8..1ad629ad167 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -399,7 +399,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { [implicit_inputs + argument_index]; let (_, span) = self.regioncx.get_argument_name_and_span_for_region( self.body, - &self.local_names, + self.local_names(), argument_index, ); @@ -973,7 +973,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { { let (arg_name, arg_span) = self.regioncx.get_argument_name_and_span_for_region( self.body, - &self.local_names, + self.local_names(), arg_index, ); let region_name = self.synthesize_region_name(); diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 4d85f109020..82b300dcb17 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -16,7 +16,7 @@ // tidy-alphabetical-end use std::borrow::Cow; -use std::cell::RefCell; +use std::cell::{OnceCell, RefCell}; use std::marker::PhantomData; use std::ops::{ControlFlow, Deref}; @@ -391,7 +391,7 @@ fn do_mir_borrowck<'tcx>( used_mut_upvars: SmallVec::new(), borrow_set: &borrow_set, upvars: &[], - local_names: IndexVec::from_elem(None, &promoted_body.local_decls), + local_names: OnceCell::from(IndexVec::from_elem(None, &promoted_body.local_decls)), region_names: RefCell::default(), next_region_name: RefCell::new(1), polonius_output: None, @@ -414,26 +414,6 @@ fn do_mir_borrowck<'tcx>( promoted_mbcx.report_move_errors(); } - let mut local_names = IndexVec::from_elem(None, &body.local_decls); - for var_debug_info in &body.var_debug_info { - if let VarDebugInfoContents::Place(place) = var_debug_info.value { - if let Some(local) = place.as_local() { - if let Some(prev_name) = local_names[local] - && var_debug_info.name != prev_name - { - span_bug!( - var_debug_info.source_info.span, - "local {:?} has many names (`{}` vs `{}`)", - local, - prev_name, - var_debug_info.name - ); - } - local_names[local] = Some(var_debug_info.name); - } - } - } - let mut mbcx = MirBorrowckCtxt { root_cx, infcx: &infcx, @@ -450,7 +430,7 @@ fn do_mir_borrowck<'tcx>( used_mut_upvars: SmallVec::new(), borrow_set: &borrow_set, upvars: tcx.closure_captures(def), - local_names, + local_names: OnceCell::new(), region_names: RefCell::default(), next_region_name: RefCell::new(1), move_errors: Vec::new(), @@ -682,7 +662,7 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> { upvars: &'tcx [&'tcx ty::CapturedPlace<'tcx>], /// Names of local (user) variables (extracted from `var_debug_info`). - local_names: IndexVec<Local, Option<Symbol>>, + local_names: OnceCell<IndexVec<Local, Option<Symbol>>>, /// Record the region names generated for each region in the given /// MIR def so that we can reuse them later in help/error messages. @@ -2610,7 +2590,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { }; // Skip over locals that begin with an underscore or have no name - if self.local_names[local].is_none_or(|name| name.as_str().starts_with('_')) { + if self.local_excluded_from_unused_mut_lint(local) { continue; } diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index 0a114467f43..8ed552cfa4f 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -3,7 +3,7 @@ use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_infer::infer::outlives::env::RegionBoundPairs; use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate}; use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound}; -use rustc_infer::infer::{self, InferCtxt, SubregionOrigin}; +use rustc_infer::infer::{InferCtxt, SubregionOrigin}; use rustc_infer::traits::query::type_op::DeeplyNormalize; use rustc_middle::bug; use rustc_middle::ty::{ @@ -172,7 +172,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { ty::Region::new_var(tcx, universal_regions.implicit_region_bound()); // we don't actually use this for anything, but // the `TypeOutlives` code needs an origin. - let origin = infer::RelateParamBound(self.span, t1, None); + let origin = SubregionOrigin::RelateParamBound(self.span, t1, None); TypeOutlives::new( &mut *self, tcx, diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index 0c46e0c0c22..99392ea1915 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -66,10 +66,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Ty::new_tup(self.tcx(), user_provided_sig.inputs()), args.tupled_upvars_ty(), args.coroutine_captures_by_ref_ty(), - self.infcx - .next_region_var(RegionVariableOrigin::MiscVariable(self.body.span), || { - RegionCtxt::Unknown - }), + self.infcx.next_region_var(RegionVariableOrigin::Misc(self.body.span), || { + RegionCtxt::Unknown + }), ); let next_ty_var = || self.infcx.next_ty_var(self.body.span); diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 9b6dcfd17c6..05bcd9f862e 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -16,7 +16,7 @@ use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_infer::infer::outlives::env::RegionBoundPairs; use rustc_infer::infer::region_constraints::RegionConstraintData; use rustc_infer::infer::{ - BoundRegion, BoundRegionConversionTime, InferCtxt, NllRegionVariableOrigin, + BoundRegionConversionTime, InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, }; use rustc_infer::traits::PredicateObligations; use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; @@ -25,9 +25,9 @@ use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::{ - self, Binder, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, CoroutineArgsExt, - Dynamic, GenericArgsRef, OpaqueHiddenType, OpaqueTypeKey, RegionVid, Ty, TyCtxt, - TypeVisitableExt, UserArgs, UserTypeAnnotationIndex, fold_regions, + self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, CoroutineArgsExt, + GenericArgsRef, OpaqueHiddenType, OpaqueTypeKey, RegionVid, Ty, TyCtxt, TypeVisitableExt, + UserArgs, UserTypeAnnotationIndex, fold_regions, }; use rustc_middle::{bug, span_bug}; use rustc_mir_dataflow::move_paths::MoveData; @@ -794,7 +794,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { }; self.infcx.next_region_var( - BoundRegion( + RegionVariableOrigin::BoundRegion( term.source_info.span, br.kind, BoundRegionConversionTime::FnCall, @@ -1233,38 +1233,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ); } - CastKind::PointerCoercion(PointerCoercion::DynStar, coercion_source) => { - // get the constraints from the target type (`dyn* Clone`) - // - // apply them to prove that the source type `Foo` implements `Clone` etc - let (existential_predicates, region) = match ty.kind() { - Dynamic(predicates, region, ty::DynStar) => (predicates, region), - _ => panic!("Invalid dyn* cast_ty"), - }; - - let self_ty = op.ty(self.body, tcx); - - let is_implicit_coercion = coercion_source == CoercionSource::Implicit; - self.prove_predicates( - existential_predicates - .iter() - .map(|predicate| predicate.with_self_ty(tcx, self_ty)), - location.to_locations(), - ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None }, - ); - - let outlives_predicate = tcx.mk_predicate(Binder::dummy( - ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives( - ty::OutlivesPredicate(self_ty, *region), - )), - )); - self.prove_predicate( - outlives_predicate, - location.to_locations(), - ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None }, - ); - } - CastKind::PointerCoercion( PointerCoercion::MutToConstPointer, coercion_source, diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index c5d1f2ad2de..3594c7ec210 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -118,10 +118,6 @@ builtin_macros_concat_bytes_oob = numeric literal is out of bounds builtin_macros_concat_bytestr = cannot concatenate a byte string literal builtin_macros_concat_c_str_lit = cannot concatenate a C string literal -builtin_macros_concat_idents_ident_args = `concat_idents!()` requires ident args - -builtin_macros_concat_idents_missing_args = `concat_idents!()` takes 1 or more arguments -builtin_macros_concat_idents_missing_comma = `concat_idents!()` expecting comma builtin_macros_concat_missing_literal = expected a literal .note = only literals (like `"foo"`, `-42` and `3.14`) can be passed to `concat!()` diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs index 92d011fb9d1..fd2d740c020 100644 --- a/compiler/rustc_builtin_macros/src/concat_bytes.rs +++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs @@ -177,15 +177,15 @@ pub(crate) fn expand_concat_bytes( Ok(LitKind::Byte(val)) => { accumulator.push(val); } - Ok(LitKind::ByteStr(ref bytes, _)) => { - accumulator.extend_from_slice(bytes); + Ok(LitKind::ByteStr(ref byte_sym, _)) => { + accumulator.extend_from_slice(byte_sym.as_byte_str()); } _ => { guar.get_or_insert_with(|| invalid_type_err(cx, token_lit, e.span, false)); } }, - ExprKind::IncludedBytes(bytes) => { - accumulator.extend_from_slice(bytes); + ExprKind::IncludedBytes(byte_sym) => { + accumulator.extend_from_slice(byte_sym.as_byte_str()); } ExprKind::Err(guarantee) => { guar = Some(*guarantee); diff --git a/compiler/rustc_builtin_macros/src/concat_idents.rs b/compiler/rustc_builtin_macros/src/concat_idents.rs deleted file mode 100644 index a721f5b84c5..00000000000 --- a/compiler/rustc_builtin_macros/src/concat_idents.rs +++ /dev/null @@ -1,71 +0,0 @@ -use rustc_ast::ptr::P; -use rustc_ast::token::{self, Token}; -use rustc_ast::tokenstream::{TokenStream, TokenTree}; -use rustc_ast::{AttrVec, DUMMY_NODE_ID, Expr, ExprKind, Path, Ty, TyKind}; -use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult}; -use rustc_span::{Ident, Span, Symbol}; - -use crate::errors; - -pub(crate) fn expand_concat_idents<'cx>( - cx: &'cx mut ExtCtxt<'_>, - sp: Span, - tts: TokenStream, -) -> MacroExpanderResult<'cx> { - if tts.is_empty() { - let guar = cx.dcx().emit_err(errors::ConcatIdentsMissingArgs { span: sp }); - return ExpandResult::Ready(DummyResult::any(sp, guar)); - } - - let mut res_str = String::new(); - for (i, e) in tts.iter().enumerate() { - if i & 1 == 1 { - match e { - TokenTree::Token(Token { kind: token::Comma, .. }, _) => {} - _ => { - let guar = cx.dcx().emit_err(errors::ConcatIdentsMissingComma { span: sp }); - return ExpandResult::Ready(DummyResult::any(sp, guar)); - } - } - } else { - if let TokenTree::Token(token, _) = e { - if let Some((ident, _)) = token.ident() { - res_str.push_str(ident.name.as_str()); - continue; - } - } - - let guar = cx.dcx().emit_err(errors::ConcatIdentsIdentArgs { span: sp }); - return ExpandResult::Ready(DummyResult::any(sp, guar)); - } - } - - let ident = Ident::new(Symbol::intern(&res_str), cx.with_call_site_ctxt(sp)); - - struct ConcatIdentsResult { - ident: Ident, - } - - impl MacResult for ConcatIdentsResult { - fn make_expr(self: Box<Self>) -> Option<P<Expr>> { - Some(P(Expr { - id: DUMMY_NODE_ID, - kind: ExprKind::Path(None, Path::from_ident(self.ident)), - span: self.ident.span, - attrs: AttrVec::new(), - tokens: None, - })) - } - - fn make_ty(self: Box<Self>) -> Option<P<Ty>> { - Some(P(Ty { - id: DUMMY_NODE_ID, - kind: TyKind::Path(None, Path::from_ident(self.ident)), - span: self.ident.span, - tokens: None, - })) - } - } - - ExpandResult::Ready(Box::new(ConcatIdentsResult { ident })) -} diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index b7ecfd2285c..a5ee7349fc6 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -300,27 +300,6 @@ pub(crate) struct ConcatBytesBadRepeat { } #[derive(Diagnostic)] -#[diag(builtin_macros_concat_idents_missing_args)] -pub(crate) struct ConcatIdentsMissingArgs { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_concat_idents_missing_comma)] -pub(crate) struct ConcatIdentsMissingComma { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_concat_idents_ident_args)] -pub(crate) struct ConcatIdentsIdentArgs { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] #[diag(builtin_macros_bad_derive_target, code = E0774)] pub(crate) struct BadDeriveTarget { #[primary_span] @@ -681,6 +660,7 @@ impl Subdiagnostic for FormatUnusedArg { fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) { diag.arg("named", self.named); let msg = diag.eagerly_translate(crate::fluent_generated::builtin_macros_format_unused_arg); + diag.remove_arg("named"); diag.span_label(self.span, msg); } } diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 9e7d0ec9e81..0594f7e86c3 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -5,10 +5,10 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(not(bootstrap), feature(autodiff))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] +#![feature(autodiff)] #![feature(box_patterns)] #![feature(decl_macro)] #![feature(if_let_guard)] @@ -36,7 +36,6 @@ mod cfg_eval; mod compile_error; mod concat; mod concat_bytes; -mod concat_idents; mod define_opaque; mod derive; mod deriving; @@ -84,7 +83,6 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { compile_error: compile_error::expand_compile_error, concat: concat::expand_concat, concat_bytes: concat_bytes::expand_concat_bytes, - concat_idents: concat_idents::expand_concat_idents, const_format_args: format::expand_format_args, core_panic: edition_panic::expand_panic, env: env::expand_env, diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index 8142f1518dd..cebfffa1e16 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -16,7 +16,7 @@ use rustc_parse::parser::{ForceCollect, Parser}; use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal, utf8_error}; use rustc_session::lint::builtin::INCOMPLETE_INCLUDE; use rustc_span::source_map::SourceMap; -use rustc_span::{Pos, Span, Symbol}; +use rustc_span::{ByteSymbol, Pos, Span, Symbol}; use smallvec::SmallVec; use crate::errors; @@ -237,7 +237,7 @@ pub(crate) fn expand_include_bytes( Ok((bytes, _bsp)) => { // Don't care about getting the span for the raw bytes, // because the console can't really show them anyway. - let expr = cx.expr(sp, ast::ExprKind::IncludedBytes(bytes)); + let expr = cx.expr(sp, ast::ExprKind::IncludedBytes(ByteSymbol::intern(&bytes))); MacEager::expr(expr) } Err(dummy) => dummy, diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock index a906bec8b7e..b893a2be9a2 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/Cargo.lock @@ -43,42 +43,42 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cranelift-assembler-x64" -version = "0.120.0" +version = "0.121.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ff8e35182c7372df00447cb90a04e584e032c42b9b9b6e8c50ddaaf0d7900d5" +checksum = "f6f53499803b1607b6ee0ba0de4ba036e6da700c2e489fe8f9d0f683d0b84d31" dependencies = [ "cranelift-assembler-x64-meta", ] [[package]] name = "cranelift-assembler-x64-meta" -version = "0.120.0" +version = "0.121.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14220f9c2698015c3b94dc6b84ae045c1c45509ddc406e43c6139252757fdb7a" +checksum = "1aadaa5bc8430d0e7bb999459369bedd0e5816ad4a82a0e20748341c4e333eda" dependencies = [ "cranelift-srcgen", ] [[package]] name = "cranelift-bforest" -version = "0.120.0" +version = "0.121.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d372ef2777ceefd75829e1390211ac240e9196bc60699218f7ea2419038288ee" +checksum = "2005fda2fc52a2dbce58229b4fb4483b70cbc806ba8ecc11b3f050c1a2d26cac" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-bitset" -version = "0.120.0" +version = "0.121.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56323783e423818fa89ce8078e90a3913d2a6e0810399bfce8ebd7ee87baa81f" +checksum = "56935e02452ca1249d39ad5c45a96304d0b4300a158a391fd113451e0cd4483d" [[package]] name = "cranelift-codegen" -version = "0.120.0" +version = "0.121.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74ffb780aab6186c6e9ba26519654b1ac55a09c0a866f6088a4efbbd84da68ed" +checksum = "62612786bf00e10999f50217d6f455d02b31591155881a45a903d1a95d1a4043" dependencies = [ "bumpalo", "cranelift-assembler-x64", @@ -97,13 +97,14 @@ dependencies = [ "serde", "smallvec", "target-lexicon", + "wasmtime-math", ] [[package]] name = "cranelift-codegen-meta" -version = "0.120.0" +version = "0.121.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c23ef13814d3b39c869650d5961128cbbecad83fbdff4e6836a03ecf6862d7ed" +checksum = "07bae789df91ef236079733af9df11d852256c64af196f0bc6471ea0f5f301be" dependencies = [ "cranelift-assembler-x64-meta", "cranelift-codegen-shared", @@ -112,33 +113,33 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" -version = "0.120.0" +version = "0.121.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f623300657679f847803ce80811454bfff89cea4f6bf684be5c468d4a73631" +checksum = "1be319616d36527782558a8312508757815f64deb19b094c7b8f4337229a9bc6" [[package]] name = "cranelift-control" -version = "0.120.0" +version = "0.121.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f4168af69989aa6b91fab46799ed4df6096f3209f4a6c8fb4358f49c60188f" +checksum = "8810ee1ab5e9bd5cff4c0c8d240e2009cb5c2b79888fde1d5256d605712314b7" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.120.0" +version = "0.121.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6fa9bae1c8de26d71ac2162f069447610fd91e7780cb480ee0d76ac81eabb8" +checksum = "086452c97cfbe116bf17dbe622dc5fdf2ea97299c7d4ce42460f284387c9928a" dependencies = [ "cranelift-bitset", ] [[package]] name = "cranelift-frontend" -version = "0.120.0" +version = "0.121.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8219205608aa0b0e6769b580284a7e055c7e0c323c1041cde7ca078add3e412" +checksum = "4c27947010ab759330f252610c17a8cd64d123358be4f33164233d04fcd77b80" dependencies = [ "cranelift-codegen", "log", @@ -148,15 +149,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.120.0" +version = "0.121.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "588d0c5964f10860b04043e55aab26d7f7a206b0fd4f10c5260e8aa5773832bd" +checksum = "ec67bfb8bd55b1e9760eb9f5186dca8d81bd4d86110f8d5af01154a044c91802" [[package]] name = "cranelift-jit" -version = "0.120.0" +version = "0.121.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56bd917ddc524f84f4066f954062875bdfc0dffea068ee94e906d98de5ac7c33" +checksum = "d67cdfc447f2abdb46bb30a6582cce189539c3c051c1d5330692376e1400edff" dependencies = [ "anyhow", "cranelift-codegen", @@ -174,9 +175,9 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.120.0" +version = "0.121.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a03c057d8a992e06596c871341e446af43ff9224f941e5b8adea39137a5391" +checksum = "e4597eaa52bca1ed111986c7a7f70cdbe192f83d271d627201365078e37b7e84" dependencies = [ "anyhow", "cranelift-codegen", @@ -185,9 +186,9 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.120.0" +version = "0.121.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ed3c94cb97b14f92b6a94a1d45ef8c851f6a2ad9114e5d91d233f7da638fed" +checksum = "75a9b63edea46e013fce459c46e500462cb03a0490fdd9c18fe42b1dd7b93aa1" dependencies = [ "cranelift-codegen", "libc", @@ -196,9 +197,9 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.120.0" +version = "0.121.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a64dacef362a69375a604f6636e5e9a174fb96dba3b273646fcd9fa85c1d0997" +checksum = "ce706f0166d5b7f31693dff521e87cb9858e12adf22ffcde93c4a2826f8f04a9" dependencies = [ "anyhow", "cranelift-codegen", @@ -211,9 +212,9 @@ dependencies = [ [[package]] name = "cranelift-srcgen" -version = "0.120.0" +version = "0.121.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85256fac1519a7d25a040c1d850fba67478f3f021ad5fdf738ba4425ee862dbf" +checksum = "7d5870e266df8237b56cc98b04f5739c228565c92dd629ec6c66efa87271a158" [[package]] name = "crc32fast" @@ -289,6 +290,12 @@ dependencies = [ ] [[package]] +name = "libm" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" + +[[package]] name = "log" version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -446,9 +453,9 @@ checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "wasmtime-jit-icache-coherence" -version = "33.0.0" +version = "34.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "175e924dbc944c185808466d1e90b5a7feb610f3b9abdfe26f8ee25fd1086d1c" +checksum = "2eedc0324e37cf39b049f4dca0c30997eaab49f09006d5f4c1994e64e7b7dba8" dependencies = [ "anyhow", "cfg-if", @@ -457,6 +464,15 @@ dependencies = [ ] [[package]] +name = "wasmtime-math" +version = "34.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd35fae4cf51d2b4a9bd2ef04b0eb309fa1849cab6a6ab5ac27cbd054ea284d" +dependencies = [ + "libm", +] + +[[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml index 94fcbd0a502..9066e4dbbb5 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.toml +++ b/compiler/rustc_codegen_cranelift/Cargo.toml @@ -8,12 +8,12 @@ crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { version = "0.120.0", default-features = false, features = ["std", "timing", "unwind", "all-native-arch"] } -cranelift-frontend = { version = "0.120.0" } -cranelift-module = { version = "0.120.0" } -cranelift-native = { version = "0.120.0" } -cranelift-jit = { version = "0.120.0", optional = true } -cranelift-object = { version = "0.120.0" } +cranelift-codegen = { version = "0.121.0", default-features = false, features = ["std", "timing", "unwind", "all-native-arch"] } +cranelift-frontend = { version = "0.121.0" } +cranelift-module = { version = "0.121.0" } +cranelift-native = { version = "0.121.0" } +cranelift-jit = { version = "0.121.0", optional = true } +cranelift-object = { version = "0.121.0" } target-lexicon = "0.13" gimli = { version = "0.31", default-features = false, features = ["write"] } object = { version = "0.36", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } @@ -24,12 +24,12 @@ smallvec = "1.8.1" [patch.crates-io] # Uncomment to use an unreleased version of cranelift -#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-33.0.0", version = "0.120.0" } -#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-33.0.0", version = "0.120.0" } -#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-33.0.0", version = "0.120.0" } -#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-33.0.0", version = "0.120.0" } -#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-33.0.0", version = "0.120.0" } -#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-33.0.0", version = "0.120.0" } +#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-34.0.0", version = "0.121.0" } +#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-34.0.0", version = "0.121.0" } +#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-34.0.0", version = "0.121.0" } +#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-34.0.0", version = "0.121.0" } +#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-34.0.0", version = "0.121.0" } +#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-34.0.0", version = "0.121.0" } # Uncomment to use local checkout of cranelift #cranelift-codegen = { path = "../wasmtime/cranelift/codegen" } diff --git a/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs b/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs index 674acfbd309..43025137bc6 100644 --- a/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs +++ b/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs @@ -6,8 +6,8 @@ use crate::{CodegenBackend, SysrootKind, build_sysroot}; static ABI_CAFE_REPO: GitRepo = GitRepo::github( "Gankra", "abi-cafe", - "f1220cfd13b57f5c0082c26529163865ee25e115", - "fe93a9acd461425d", + "94d38030419eb00a1ba80e5e2b4d763dcee58db4", + "6efb4457893c8670", "abi-cafe", ); @@ -46,6 +46,10 @@ pub(crate) fn run( let mut cmd = ABI_CAFE.run(bootstrap_host_compiler, dirs); cmd.arg("--"); + cmd.arg("--debug"); + + cmd.arg("--rules").arg(dirs.source_dir.join("scripts/abi-cafe-rules.toml")); + // stdcall, vectorcall and such don't work yet cmd.arg("--conventions").arg("c").arg("--conventions").arg("rust"); diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs index 524ebde1c74..2f53bbf8b79 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs @@ -660,7 +660,7 @@ pub mod intrinsics { #[rustc_intrinsic] pub unsafe fn ctlz_nonzero<T>(x: T) -> u32; #[rustc_intrinsic] - pub fn needs_drop<T: ?::Sized>() -> bool; + pub const fn needs_drop<T: ?::Sized>() -> bool; #[rustc_intrinsic] pub fn bitreverse<T>(x: T) -> T; #[rustc_intrinsic] diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs index 1499f948deb..246bd3104ec 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs @@ -1,4 +1,13 @@ -#![feature(no_core, lang_items, never_type, linkage, extern_types, thread_local, repr_simd)] +#![feature( + no_core, + lang_items, + never_type, + linkage, + extern_types, + thread_local, + repr_simd, + rustc_private +)] #![no_core] #![allow(dead_code, non_camel_case_types, internal_features)] @@ -207,10 +216,14 @@ fn main() { assert_eq!(intrinsics::align_of::<u16>() as u8, 2); assert_eq!(intrinsics::align_of_val(&a) as u8, intrinsics::align_of::<&str>() as u8); - assert!(!intrinsics::needs_drop::<u8>()); - assert!(!intrinsics::needs_drop::<[u8]>()); - assert!(intrinsics::needs_drop::<NoisyDrop>()); - assert!(intrinsics::needs_drop::<NoisyDropUnsized>()); + let u8_needs_drop = const { intrinsics::needs_drop::<u8>() }; + assert!(!u8_needs_drop); + let slice_needs_drop = const { intrinsics::needs_drop::<[u8]>() }; + assert!(!slice_needs_drop); + let noisy_drop = const { intrinsics::needs_drop::<NoisyDrop>() }; + assert!(noisy_drop); + let noisy_unsized_drop = const { intrinsics::needs_drop::<NoisyDropUnsized>() }; + assert!(noisy_unsized_drop); Unique { pointer: NonNull(1 as *mut &str), _marker: PhantomData } as Unique<dyn SomeTrait>; diff --git a/compiler/rustc_codegen_cranelift/patches/0002-abi-cafe-Disable-broken-tests.patch b/compiler/rustc_codegen_cranelift/patches/0002-abi-cafe-Disable-broken-tests.patch deleted file mode 100644 index 01b6a990b72..00000000000 --- a/compiler/rustc_codegen_cranelift/patches/0002-abi-cafe-Disable-broken-tests.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 236df390f3bc4ed69c26f4d51d584bea246da886 Mon Sep 17 00:00:00 2001 -From: bjorn3 <17426603+bjorn3@users.noreply.github.com> -Date: Tue, 9 Jul 2024 11:25:14 +0000 -Subject: [PATCH] Disable broken tests - ---- - src/report.rs | 36 ++++++++++++++++++++++++++++++++++++ - 1 file changed, 36 insertions(+) - -diff --git a/src/toolchains/rust.rs b/src/toolchains/rust.rs -index 0c50f7a..bfde2b1 100644 ---- a/src/toolchains/rust.rs -+++ b/src/toolchains/rust.rs -@@ -83,6 +83,7 @@ impl Toolchain for RustcToolchain { - .arg(out_dir) - .arg("--target") - .arg(built_info::TARGET) -+ .arg("-g") - .arg(format!("-Cmetadata={lib_name}")) - .arg(src_path); - if let Some(codegen_backend) = &self.codegen_backend { -diff --git a/src/report.rs b/src/report.rs -index 958ab43..dcf1044 100644 ---- a/src/report.rs -+++ b/src/report.rs -@@ -48,6 +48,40 @@ pub fn get_test_rules(test: &TestKey, caller: &dyn Toolchain, callee: &dyn Toolc - // - // THIS AREA RESERVED FOR VENDORS TO APPLY PATCHES - -+ if cfg!(all(target_arch = "aarch64", target_os = "linux")) { -+ if test.test == "F32Array" && test.options.convention == CallingConvention::C { -+ result.check = Busted(Check); -+ } -+ } -+ -+ if cfg!(all(target_arch = "aarch64", target_os = "macos")) { -+ if test.test == "SingleVariantUnion" && test.options.convention == CallingConvention::C && test.options.repr == LangRepr::C { -+ result.check = Busted(Check); -+ } -+ -+ if test.test == "OptionU128" && test.caller == "rustc" && test.options.convention == CallingConvention::Rust && test.options.repr == LangRepr::C { -+ result.check = Busted(Run); -+ } -+ -+ if test.test == "OptionU128" && test.caller == "cgclif" && test.options.convention == CallingConvention::Rust && test.options.repr == LangRepr::C { -+ result.check = Busted(Check); -+ } -+ } -+ -+ if cfg!(all(target_arch = "x86_64", windows)) { -+ if test.test == "simple" && test.options.convention == CallingConvention::Rust { -+ result.check = Busted(Check); -+ } -+ -+ if test.test == "simple" && test.options.convention == CallingConvention::Rust && test.caller == "rustc" { -+ result.check = Busted(Run); -+ } -+ } -+ -+ if test.test == "f16" || test.test == "f128" { -+ result.run = Skip; -+ } -+ - // END OF VENDOR RESERVED AREA - // - // --- -2.34.1 - diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain index af4bd6dc6b8..150bb562f74 100644 --- a/compiler/rustc_codegen_cranelift/rust-toolchain +++ b/compiler/rustc_codegen_cranelift/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-05-25" +channel = "nightly-2025-06-24" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" diff --git a/compiler/rustc_codegen_cranelift/scripts/abi-cafe-rules.toml b/compiler/rustc_codegen_cranelift/scripts/abi-cafe-rules.toml new file mode 100644 index 00000000000..54f9445c8e5 --- /dev/null +++ b/compiler/rustc_codegen_cranelift/scripts/abi-cafe-rules.toml @@ -0,0 +1,17 @@ +[target.'cfg(all(target_arch = "aarch64", target_os = "linux"))'] +'F32Array::conv_c'.busted = "check" + +[target.'cfg(all(target_arch = "aarch64", target_os = "macos"))'] +'SingleVariantUnion::conv_c::repr_c'.busted = "check" +'OptionU128::conv_rust::repr_c::rustc_caller'.busted = "run" +'OptionU128::conv_rust::repr_c::cgclif_caller'.busted = "check" + +[target.'cfg(all(target_arch = "x86_64", windows))'] +'simple::conv_rust'.busted = "check" +'simple::conv_rust::rustc_caller'.busted = "run" + +[target.'*'.'f16'] +run = "skip" + +[target.'*'.'f128'] +run = "skip" diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh index 32c71f433b0..7e356b4b462 100755 --- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh +++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh @@ -151,20 +151,6 @@ rm tests/ui/process/process-panic-after-fork.rs # same cp ../dist/bin/rustdoc-clif ../dist/bin/rustdoc # some tests expect bin/rustdoc to exist cat <<EOF | git apply - -diff --git a/tests/run-make/linker-warning/rmake.rs b/tests/run-make/linker-warning/rmake.rs -index 30387af428c..f7895b12961 100644 ---- a/tests/run-make/linker-warning/rmake.rs -+++ b/tests/run-make/linker-warning/rmake.rs -@@ -57,7 +57,8 @@ fn main() { - .actual_text("(linker error)", out.stderr()) -- .normalize(r#"/rustc[^/]*/"#, "/rustc/") -+ .normalize(r#"/tmp/rustc[^/]*/"#, "/tmp/rustc/") -+ .normalize("libpanic_abort", "libpanic_unwind") - .normalize( - regex::escape(run_make_support::build_root().to_str().unwrap()), - "/build-root", - ) - .normalize(r#""[^"]*\/symbols.o""#, "\\"/symbols.o\\"") diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs index 073116933bd..c3e4578204d 100644 --- a/src/tools/compiletest/src/runtest/run_make.rs diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 4c6fd907815..8965e4a944d 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -753,51 +753,6 @@ pub(crate) fn codegen_drop<'tcx>( fx.bcx.ins().call_indirect(sig, drop_fn, &[ptr]); fx.bcx.ins().jump(ret_block, &[]); } - ty::Dynamic(_, _, ty::DynStar) => { - // IN THIS ARM, WE HAVE: - // ty = *mut (dyn* Trait) - // which is: *mut exists<T: sizeof(T) == sizeof(usize)> (T, Vtable<T: Trait>) - // - // args = [ * ] - // | - // v - // ( Data, Vtable ) - // | - // v - // /-------\ - // | ... | - // \-------/ - // - // - // WE CAN CONVERT THIS INTO THE ABOVE LOGIC BY DOING - // - // data = &(*args[0]).0 // gives a pointer to Data above (really the same pointer) - // vtable = (*args[0]).1 // loads the vtable out - // (data, vtable) // an equivalent Rust `*mut dyn Trait` - // - // SO THEN WE CAN USE THE ABOVE CODE. - let (data, vtable) = drop_place.to_cvalue(fx).dyn_star_force_data_on_stack(fx); - let drop_fn = crate::vtable::drop_fn_of_obj(fx, vtable); - - let is_null = fx.bcx.ins().icmp_imm(IntCC::Equal, drop_fn, 0); - let target_block = fx.get_block(target); - let continued = fx.bcx.create_block(); - fx.bcx.ins().brif(is_null, target_block, &[], continued, &[]); - fx.bcx.switch_to_block(continued); - - let virtual_drop = Instance { - def: ty::InstanceKind::Virtual(drop_instance.def_id(), 0), - args: drop_instance.args, - }; - let fn_abi = FullyMonomorphizedLayoutCx(fx.tcx) - .fn_abi_of_instance(virtual_drop, ty::List::empty()); - - let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, &fn_abi); - let sig = fx.bcx.import_signature(sig); - fx.bcx.ins().call_indirect(sig, drop_fn, &[data]); - // FIXME implement cleanup on exceptions - fx.bcx.ins().jump(ret_block, &[]); - } _ => { assert!(!matches!(drop_instance.def, InstanceKind::Virtual(_, _))); diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 0b641ba64b7..bc0a0f034b2 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -407,6 +407,18 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { source_info.span, ) } + AssertKind::InvalidEnumConstruction(source) => { + let source = codegen_operand(fx, source).load_scalar(fx); + let location = fx.get_caller_location(source_info).load_scalar(fx); + + codegen_panic_inner( + fx, + rustc_hir::LangItem::PanicInvalidEnumConstruction, + &[source, location], + *unwind, + source_info.span, + ) + } _ => { let location = fx.get_caller_location(source_info).load_scalar(fx); @@ -778,14 +790,6 @@ fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt: let operand = codegen_operand(fx, operand); crate::unsize::coerce_unsized_into(fx, operand, lval); } - Rvalue::Cast( - CastKind::PointerCoercion(PointerCoercion::DynStar, _), - ref operand, - _, - ) => { - let operand = codegen_operand(fx, operand); - crate::unsize::coerce_dyn_star(fx, operand, lval); - } Rvalue::Cast(CastKind::Transmute, ref operand, _to_ty) => { let operand = codegen_operand(fx, operand); lval.write_cvalue_transmute(fx, operand); diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index c8527c3a57d..ee43eb736e6 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -133,7 +133,7 @@ pub(crate) fn codegen_const_value<'tcx>( } } Scalar::Ptr(ptr, _size) => { - let (prov, offset) = ptr.into_parts(); // we know the `offset` is relative + let (prov, offset) = ptr.prov_and_relative_offset(); let alloc_id = prov.alloc_id(); let base_addr = match fx.tcx.global_alloc(alloc_id) { GlobalAlloc::Memory(alloc) => { @@ -228,7 +228,7 @@ fn pointer_for_allocation<'tcx>( crate::pointer::Pointer::new(global_ptr) } -pub(crate) fn data_id_for_alloc_id( +fn data_id_for_alloc_id( cx: &mut ConstantCx, module: &mut dyn Module, alloc_id: AllocId, diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs index 615f6c47d90..37fbe4be1b0 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs @@ -202,9 +202,10 @@ pub(super) fn codegen_x86_llvm_intrinsic_call<'tcx>( }; let x = codegen_operand(fx, &x.node); let y = codegen_operand(fx, &y.node); - let kind = match &kind.node { - Operand::Constant(const_) => crate::constant::eval_mir_constant(fx, const_).0, - Operand::Copy(_) | Operand::Move(_) => unreachable!("{kind:?}"), + let kind = if let Some(const_) = kind.node.constant() { + crate::constant::eval_mir_constant(fx, const_).0 + } else { + unreachable!("{kind:?}") }; let flt_cc = match kind diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index df5748c34d1..4ff5773a06c 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -812,21 +812,6 @@ fn codegen_regular_intrinsic_call<'tcx>( dest.write_cvalue(fx, val); } - sym::needs_drop | sym::type_id | sym::type_name | sym::variant_count => { - intrinsic_args!(fx, args => (); intrinsic); - - let const_val = fx - .tcx - .const_eval_instance( - ty::TypingEnv::fully_monomorphized(), - instance, - source_info.span, - ) - .unwrap(); - let val = crate::constant::codegen_const_value(fx, const_val, ret.layout().ty); - ret.write_cvalue(fx, val); - } - sym::ptr_offset_from | sym::ptr_offset_from_unsigned => { intrinsic_args!(fx, args => (ptr, base); intrinsic); let ptr = ptr.load_scalar(fx); diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index 46a441488fa..6281089ee24 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -205,9 +205,10 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( // Find a way to reuse `immediate_const_vector` from `codegen_ssa` instead. let indexes = { use rustc_middle::mir::interpret::*; - let idx_const = match &idx.node { - Operand::Constant(const_) => crate::constant::eval_mir_constant(fx, const_).0, - Operand::Copy(_) | Operand::Move(_) => unreachable!("{idx:?}"), + let idx_const = if let Some(const_) = idx.node.constant() { + crate::constant::eval_mir_constant(fx, const_).0 + } else { + unreachable!("{idx:?}") }; let idx_bytes = match idx_const { @@ -495,7 +496,8 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( | sym::simd_flog | sym::simd_flog10 | sym::simd_flog2 - | sym::simd_round => { + | sym::simd_round + | sym::simd_round_ties_even => { intrinsic_args!(fx, args => (a); intrinsic); if !a.layout().ty.is_simd() { @@ -526,6 +528,8 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( (sym::simd_flog2, types::F64) => "log2", (sym::simd_round, types::F32) => "roundf", (sym::simd_round, types::F64) => "round", + (sym::simd_round_ties_even, types::F32) => "rintf", + (sym::simd_round_ties_even, types::F64) => "rint", _ => unreachable!("{:?}", intrinsic), }; fx.lib_call( diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs index df60b05c463..2aee0b2e974 100644 --- a/compiler/rustc_codegen_cranelift/src/unsize.rs +++ b/compiler/rustc_codegen_cranelift/src/unsize.rs @@ -112,21 +112,6 @@ fn unsize_ptr<'tcx>( } } -/// Coerces `src` to `dst_ty` which is guaranteed to be a `dyn*` type. -pub(crate) fn cast_to_dyn_star<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - src: Value, - src_ty_and_layout: TyAndLayout<'tcx>, - dst_ty: Ty<'tcx>, - old_info: Option<Value>, -) -> (Value, Value) { - assert!( - matches!(dst_ty.kind(), ty::Dynamic(_, _, ty::DynStar)), - "destination type must be a dyn*" - ); - (src, unsized_info(fx, src_ty_and_layout.ty, dst_ty, old_info)) -} - /// Coerce `src`, which is a reference to a value of type `src_ty`, /// to a value of type `dst_ty` and store the result in `dst` pub(crate) fn coerce_unsized_into<'tcx>( @@ -174,24 +159,6 @@ pub(crate) fn coerce_unsized_into<'tcx>( } } -pub(crate) fn coerce_dyn_star<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - src: CValue<'tcx>, - dst: CPlace<'tcx>, -) { - let (data, extra) = if let ty::Dynamic(_, _, ty::DynStar) = src.layout().ty.kind() { - let (data, vtable) = src.load_scalar_pair(fx); - (data, Some(vtable)) - } else { - let data = src.load_scalar(fx); - (data, None) - }; - - let (data, vtable) = cast_to_dyn_star(fx, data, src.layout(), dst.layout().ty, extra); - - dst.write_cvalue(fx, CValue::by_val_pair(data, vtable, dst.layout())); -} - // Adapted from https://github.com/rust-lang/rust/blob/2a663555ddf36f6b041445894a8c175cd1bc718c/src/librustc_codegen_ssa/glue.rs pub(crate) fn size_and_align_of<'tcx>( diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index cbfb215a892..9d73f200afe 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -121,43 +121,6 @@ impl<'tcx> CValue<'tcx> { } } - // FIXME remove - /// Forces the data value of a dyn* value to the stack and returns a pointer to it as well as the - /// vtable pointer. - pub(crate) fn dyn_star_force_data_on_stack( - self, - fx: &mut FunctionCx<'_, '_, 'tcx>, - ) -> (Value, Value) { - assert!(self.1.ty.is_dyn_star()); - - match self.0 { - CValueInner::ByRef(ptr, None) => { - let (a_scalar, b_scalar) = match self.1.backend_repr { - BackendRepr::ScalarPair(a, b) => (a, b), - _ => unreachable!("dyn_star_force_data_on_stack({:?})", self), - }; - let b_offset = scalar_pair_calculate_b_offset(fx.tcx, a_scalar, b_scalar); - let clif_ty2 = scalar_to_clif_type(fx.tcx, b_scalar); - let mut flags = MemFlags::new(); - flags.set_notrap(); - let vtable = ptr.offset(fx, b_offset).load(fx, clif_ty2, flags); - (ptr.get_addr(fx), vtable) - } - CValueInner::ByValPair(data, vtable) => { - let data_ptr = fx.create_stack_slot( - u32::try_from(fx.target_config.pointer_type().bytes()).unwrap(), - u32::try_from(fx.target_config.pointer_type().bytes()).unwrap(), - ); - data_ptr.store(fx, data, MemFlags::trusted()); - - (data_ptr.get_addr(fx), vtable) - } - CValueInner::ByRef(_, Some(_)) | CValueInner::ByVal(_) => { - unreachable!("dyn_star_force_data_on_stack({:?})", self) - } - } - } - pub(crate) fn try_to_ptr(self) -> Option<(Pointer, Option<Value>)> { match self.0 { CValueInner::ByRef(ptr, meta) => Some((ptr, meta)), diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs index 1fae56949bc..423cc8d225b 100644 --- a/compiler/rustc_codegen_cranelift/src/vtable.rs +++ b/compiler/rustc_codegen_cranelift/src/vtable.rs @@ -46,34 +46,22 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>( mut arg: CValue<'tcx>, idx: usize, ) -> (Pointer, Value) { - let (ptr, vtable) = 'block: { - if let BackendRepr::Scalar(_) = arg.layout().backend_repr { - while !arg.layout().ty.is_raw_ptr() && !arg.layout().ty.is_ref() { - let (idx, _) = arg - .layout() - .non_1zst_field(fx) - .expect("not exactly one non-1-ZST field in a `DispatchFromDyn` type"); - arg = arg.value_field(fx, idx); - } - } - - if let ty::Ref(_, ty, _) = arg.layout().ty.kind() { - if ty.is_dyn_star() { - let inner_layout = fx.layout_of(arg.layout().ty.builtin_deref(true).unwrap()); - let dyn_star = CPlace::for_ptr(Pointer::new(arg.load_scalar(fx)), inner_layout); - let ptr = dyn_star.place_field(fx, FieldIdx::ZERO).to_ptr(); - let vtable = dyn_star.place_field(fx, FieldIdx::ONE).to_cvalue(fx).load_scalar(fx); - break 'block (ptr, vtable); - } + if let BackendRepr::Scalar(_) = arg.layout().backend_repr { + while !arg.layout().ty.is_raw_ptr() && !arg.layout().ty.is_ref() { + let (idx, _) = arg + .layout() + .non_1zst_field(fx) + .expect("not exactly one non-1-ZST field in a `DispatchFromDyn` type"); + arg = arg.value_field(fx, idx); } + } - if let BackendRepr::ScalarPair(_, _) = arg.layout().backend_repr { - let (ptr, vtable) = arg.load_scalar_pair(fx); - (Pointer::new(ptr), vtable) - } else { - let (ptr, vtable) = arg.try_to_ptr().unwrap(); - (ptr, vtable.unwrap()) - } + let (ptr, vtable) = if let BackendRepr::ScalarPair(_, _) = arg.layout().backend_repr { + let (ptr, vtable) = arg.load_scalar_pair(fx); + (Pointer::new(ptr), vtable) + } else { + let (ptr, vtable) = arg.try_to_ptr().unwrap(); + (ptr, vtable.unwrap()) }; let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes(); diff --git a/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.toml b/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.toml index 931f6097abc..29a3bcec304 100644 --- a/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.toml +++ b/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.toml @@ -6,6 +6,7 @@ resolver = "2" [dependencies] core = { path = "./sysroot_src/library/core" } +compiler_builtins = { path = "./sysroot_src/library/compiler-builtins/compiler-builtins" } alloc = { path = "./sysroot_src/library/alloc" } std = { path = "./sysroot_src/library/std", features = ["panic_unwind", "backtrace"] } test = { path = "./sysroot_src/library/test" } diff --git a/compiler/rustc_codegen_gcc/build_system/src/abi_test.rs b/compiler/rustc_codegen_gcc/build_system/src/abi_test.rs new file mode 100644 index 00000000000..3c1531be27a --- /dev/null +++ b/compiler/rustc_codegen_gcc/build_system/src/abi_test.rs @@ -0,0 +1,65 @@ +use std::ffi::OsStr; +use std::path::Path; + +use crate::utils::run_command_with_output; + +fn show_usage() { + println!( + r#" +`abi-test` command help: + --help : Show this help"# + ); +} + +pub fn run() -> Result<(), String> { + let mut args = std::env::args().skip(2); + // FractalFir: In the future, I'd like to add some more subcommands / options. + // So, this loop ought to stay for that purpose. It should also stay as a while loop(to parse args) + #[allow(clippy::never_loop, clippy::while_let_on_iterator)] + while let Some(arg) = args.next() { + match arg.as_str() { + "--help" => { + show_usage(); + return Ok(()); + } + _ => return Err(format!("Unknown option {arg:?}")), + } + } + // Ensure that we have a cloned version of abi-cafe on hand. + crate::utils::git_clone( + "https://github.com/Gankra/abi-cafe.git", + Some("clones/abi-cafe".as_ref()), + true, + ) + .map_err(|err| (format!("Git clone failed with message: {err:?}!")))?; + // Configure abi-cafe to use the exact same rustc version we use - this is crucial. + // Otherwise, the concept of ABI compatibility becomes meanignless. + std::fs::copy("rust-toolchain", "clones/abi-cafe/rust-toolchain") + .expect("Could not copy toolchain configs!"); + // Get the backend path. + // We will use the *debug* build of the backend - it has more checks enabled. + let backend_path = std::path::absolute("target/debug/librustc_codegen_gcc.so").unwrap(); + let backend_arg = format!("--add-rustc-codegen-backend=cg_gcc:{}", backend_path.display()); + // Run ABI cafe using cargo. + let cmd: &[&dyn AsRef<OsStr>] = &[ + &"cargo", + &"run", + &"--release", + &"--", + &backend_arg, + // Test rust-LLVM to Rust-GCC calls + &"--pairs", + &"rustc_calls_cg_gcc", + &"--pairs", + &"cg_gcc_calls_rustc", + // Test Rust-GCC to C calls + &"--pairs", + &"cg_gcc_calls_c", + &"--pairs", + &"c_calls_cg_gcc", + ]; + // Run ABI cafe. + run_command_with_output(cmd, Some(Path::new("clones/abi-cafe")))?; + + Ok(()) +} diff --git a/compiler/rustc_codegen_gcc/build_system/src/main.rs b/compiler/rustc_codegen_gcc/build_system/src/main.rs index 078a4726ba8..ae975c94fff 100644 --- a/compiler/rustc_codegen_gcc/build_system/src/main.rs +++ b/compiler/rustc_codegen_gcc/build_system/src/main.rs @@ -1,5 +1,6 @@ use std::{env, process}; +mod abi_test; mod build; mod clean; mod clone_gcc; @@ -12,7 +13,6 @@ mod rust_tools; mod rustc_info; mod test; mod utils; - const BUILD_DIR: &str = "build"; macro_rules! arg_error { @@ -44,7 +44,8 @@ Commands: info : Displays information about the build environment and project configuration. clone-gcc : Clones the GCC compiler from a specified source. fmt : Runs rustfmt - fuzz : Fuzzes `cg_gcc` using rustlantis" + fuzz : Fuzzes `cg_gcc` using rustlantis + abi-test : Runs the abi-cafe test suite on the codegen, checking for ABI compatibility with LLVM" ); } @@ -59,6 +60,7 @@ pub enum Command { Info, Fmt, Fuzz, + AbiTest, } fn main() { @@ -77,6 +79,7 @@ fn main() { Some("test") => Command::Test, Some("info") => Command::Info, Some("clone-gcc") => Command::CloneGcc, + Some("abi-test") => Command::AbiTest, Some("fmt") => Command::Fmt, Some("fuzz") => Command::Fuzz, Some("--help") => { @@ -102,6 +105,7 @@ fn main() { Command::CloneGcc => clone_gcc::run(), Command::Fmt => fmt::run(), Command::Fuzz => fuzz::run(), + Command::AbiTest => abi_test::run(), } { eprintln!("Command failed to run: {e}"); process::exit(1); diff --git a/compiler/rustc_codegen_gcc/build_system/src/test.rs b/compiler/rustc_codegen_gcc/build_system/src/test.rs index bcaab0fb526..cbb0f949383 100644 --- a/compiler/rustc_codegen_gcc/build_system/src/test.rs +++ b/compiler/rustc_codegen_gcc/build_system/src/test.rs @@ -9,8 +9,8 @@ use crate::build; use crate::config::{Channel, ConfigInfo}; use crate::utils::{ create_dir, get_sysroot_dir, get_toolchain, git_clone, git_clone_root_dir, remove_file, - run_command, run_command_with_env, run_command_with_output, run_command_with_output_and_env, - rustc_version_info, split_args, walk_dir, + run_command, run_command_with_env, run_command_with_output_and_env, rustc_version_info, + split_args, walk_dir, }; type Env = HashMap<String, String>; @@ -485,30 +485,6 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result<PathBuf, String> { run_command_with_output_and_env(&[&"git", &"checkout"], rust_dir, Some(env))?; } - let mut patches = Vec::new(); - walk_dir( - "patches/tests", - &mut |_| Ok(()), - &mut |file_path: &Path| { - patches.push(file_path.to_path_buf()); - Ok(()) - }, - false, - )?; - patches.sort(); - // TODO: remove duplication with prepare.rs by creating a apply_patch function in the utils - // module. - for file_path in patches { - println!("[GIT] apply `{}`", file_path.display()); - let path = Path::new("../..").join(file_path); - run_command_with_output(&[&"git", &"apply", &path], rust_dir)?; - run_command_with_output(&[&"git", &"add", &"-A"], rust_dir)?; - run_command_with_output( - &[&"git", &"commit", &"--no-gpg-sign", &"-m", &format!("Patch {}", path.display())], - rust_dir, - )?; - } - let cargo = String::from_utf8( run_command_with_env(&[&"rustup", &"which", &"cargo"], rust_dir, Some(env))?.stdout, ) @@ -738,14 +714,7 @@ fn test_libcore(env: &Env, args: &TestArg) -> Result<(), String> { let path = get_sysroot_dir().join("sysroot_src/library/coretests"); let _ = remove_dir_all(path.join("target")); // TODO(antoyo): run in release mode when we fix the failures. - // TODO(antoyo): remove the --skip f16::test_total_cmp when this issue is fixed: - // https://github.com/rust-lang/rust/issues/141503 - run_cargo_command( - &[&"test", &"--", &"--skip", &"f16::test_total_cmp"], - Some(&path), - env, - args, - )?; + run_cargo_command(&[&"test"], Some(&path), env, args)?; Ok(()) } diff --git a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs index c3bd62e5897..6b6f71edaf8 100644 --- a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs @@ -6,6 +6,7 @@ )] #![no_core] #![allow(dead_code, internal_features, non_camel_case_types)] +#![rustfmt::skip] extern crate mini_core; @@ -197,10 +198,10 @@ fn main() { assert_eq!(intrinsics::align_of::<u16>() as u8, 2); assert_eq!(intrinsics::align_of_val(&a) as u8, intrinsics::align_of::<&str>() as u8); - assert!(!intrinsics::needs_drop::<u8>()); - assert!(!intrinsics::needs_drop::<[u8]>()); - assert!(intrinsics::needs_drop::<NoisyDrop>()); - assert!(intrinsics::needs_drop::<NoisyDropUnsized>()); + assert!(!const { intrinsics::needs_drop::<u8>() }); + assert!(!const { intrinsics::needs_drop::<[u8]>() }); + assert!(const { intrinsics::needs_drop::<NoisyDrop>() }); + assert!(const { intrinsics::needs_drop::<NoisyDropUnsized>() }); Unique { pointer: 0 as *const &str, diff --git a/compiler/rustc_codegen_gcc/patches/0001-Pin-compiler_builtins-to-0.1.160.patch b/compiler/rustc_codegen_gcc/patches/0001-Pin-compiler_builtins-to-0.1.160.patch deleted file mode 100644 index 39266e081ed..00000000000 --- a/compiler/rustc_codegen_gcc/patches/0001-Pin-compiler_builtins-to-0.1.160.patch +++ /dev/null @@ -1,39 +0,0 @@ -From cdb3d407740e4f15c3746051f8ba89b8e74e99d3 Mon Sep 17 00:00:00 2001 -From: None <none@example.com> -Date: Fri, 30 May 2025 13:46:22 -0400 -Subject: [PATCH] Pin compiler_builtins to 0.1.160 - ---- - library/alloc/Cargo.toml | 2 +- - library/std/Cargo.toml | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml -index 9d0d957..365c9dc 100644 ---- a/library/alloc/Cargo.toml -+++ b/library/alloc/Cargo.toml -@@ -16,7 +16,7 @@ bench = false - - [dependencies] - core = { path = "../core", public = true } --compiler_builtins = { version = "=0.1.159", features = ['rustc-dep-of-std'] } -+compiler_builtins = { version = "=0.1.160", features = ['rustc-dep-of-std'] } - - [features] - compiler-builtins-mem = ['compiler_builtins/mem'] -diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml -index 4ff4895..31371f0 100644 ---- a/library/std/Cargo.toml -+++ b/library/std/Cargo.toml -@@ -18,7 +18,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } - panic_unwind = { path = "../panic_unwind", optional = true } - panic_abort = { path = "../panic_abort" } - core = { path = "../core", public = true } --compiler_builtins = { version = "=0.1.159" } -+compiler_builtins = { version = "=0.1.160" } - unwind = { path = "../unwind" } - hashbrown = { version = "0.15", default-features = false, features = [ - 'rustc-dep-of-std', --- -2.49.0 - diff --git a/compiler/rustc_codegen_gcc/patches/tests/0001-Workaround-to-make-a-run-make-test-pass.patch b/compiler/rustc_codegen_gcc/patches/tests/0001-Workaround-to-make-a-run-make-test-pass.patch deleted file mode 100644 index a329d09a95e..00000000000 --- a/compiler/rustc_codegen_gcc/patches/tests/0001-Workaround-to-make-a-run-make-test-pass.patch +++ /dev/null @@ -1,25 +0,0 @@ -From a131c69e54b5c02fe3b517e8f3ad23d4f784ffc8 Mon Sep 17 00:00:00 2001 -From: Antoni Boucher <bouanto@zoho.com> -Date: Fri, 13 Jun 2025 20:25:33 -0400 -Subject: [PATCH] Workaround to make a run-make test pass - ---- - tests/run-make/linker-warning/rmake.rs | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/tests/run-make/linker-warning/rmake.rs b/tests/run-make/linker-warning/rmake.rs -index bc21739fefc..0946a7e2a48 100644 ---- a/tests/run-make/linker-warning/rmake.rs -+++ b/tests/run-make/linker-warning/rmake.rs -@@ -55,7 +55,7 @@ fn main() { - diff() - .expected_file("short-error.txt") - .actual_text("(linker error)", out.stderr()) -- .normalize(r#"/rustc[^/]*/"#, "/rustc/") -+ .normalize(r#"/tmp/rustc[^/]*/"#, "/tmp/rustc/") - .normalize( - regex::escape(run_make_support::build_root().to_str().unwrap()), - "/build-root", --- -2.49.0 - diff --git a/compiler/rustc_codegen_gcc/rust-toolchain b/compiler/rustc_codegen_gcc/rust-toolchain index bafe497a2a2..bccbc6cd2c5 100644 --- a/compiler/rustc_codegen_gcc/rust-toolchain +++ b/compiler/rustc_codegen_gcc/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2025-05-21" +channel = "nightly-2025-06-28" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs index 08f3d281904..0b359f1c5c8 100644 --- a/compiler/rustc_codegen_gcc/src/abi.rs +++ b/compiler/rustc_codegen_gcc/src/abi.rs @@ -1,7 +1,9 @@ #[cfg(feature = "master")] use gccjit::FnAttribute; use gccjit::{ToLValue, ToRValue, Type}; -use rustc_abi::{ArmCall, CanonAbi, InterruptKind, Reg, RegKind, X86Call}; +#[cfg(feature = "master")] +use rustc_abi::{ArmCall, CanonAbi, InterruptKind, X86Call}; +use rustc_abi::{Reg, RegKind}; use rustc_codegen_ssa::traits::{AbiBuilderMethods, BaseTypeCodegenMethods}; use rustc_data_structures::fx::FxHashSet; use rustc_middle::bug; diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index a2e34d1f8fb..b1785af444a 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -520,8 +520,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { self.block } - fn append_block(cx: &'a CodegenCx<'gcc, 'tcx>, func: RValue<'gcc>, name: &str) -> Block<'gcc> { - let func = cx.rvalue_as_function(func); + fn append_block(_: &'a CodegenCx<'gcc, 'tcx>, func: Function<'gcc>, name: &str) -> Block<'gcc> { func.new_block(name) } @@ -539,11 +538,6 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn ret(&mut self, mut value: RValue<'gcc>) { - if self.structs_as_pointer.borrow().contains(&value) { - // NOTE: hack to workaround a limitation of the rustc API: see comment on - // CodegenCx.structs_as_pointer - value = value.dereference(self.location).to_rvalue(); - } let expected_return_type = self.current_func().get_return_type(); if !expected_return_type.is_compatible_with(value.get_type()) { // NOTE: due to opaque pointers now being used, we need to cast here. @@ -701,7 +695,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let a = self.gcc_int_cast(a, a_type); let b_type = b.get_type().to_unsigned(self); let b = self.gcc_int_cast(b, b_type); - a / b + self.gcc_udiv(a, b) } fn sdiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { @@ -713,8 +707,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { // FIXME(antoyo): rustc_codegen_ssa::mir::intrinsic uses different types for a and b but they // should be the same. let typ = a.get_type().to_signed(self); - let b = self.context.new_cast(self.location, b, typ); - a / b + let b = self.gcc_int_cast(b, typ); + self.gcc_sdiv(a, b) } fn fdiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { @@ -782,6 +776,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { return self.context.new_call(self.location, fmod, &[a, b]); } TypeKind::FP128 => { + // TODO(antoyo): use get_simple_function_f128_2args. let f128_type = self.type_f128(); let fmodf128 = self.context.new_function( None, @@ -938,22 +933,36 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn load(&mut self, pointee_ty: Type<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> { let block = self.llbb(); let function = block.get_function(); + // NOTE(FractalFir): In some cases, we *should* skip the call to get_aligned. + // For example, calling `get_aligned` on a i8 is pointless(since it can only be 1 aligned) + // Calling get_aligned on a `u128`/`i128` causes the attribute to become "stacked" + // + // From GCCs perspective: + // __int128_t __attribute__((aligned(16))) __attribute__((aligned(16))) + // and: + // __int128_t __attribute__((aligned(16))) + // are 2 distinct, incompatible types. + // + // So, we skip the call to `get_aligned` in such a case. *Ideally*, we could do this for all the types, + // but the GCC APIs to facilitate this just aren't quite there yet. + + // This checks that we only skip `get_aligned` on 128 bit ints if they have the correct alignment. + // Otherwise, this may be an under-aligned load, so we will still call get_aligned. + let mut can_skip_align = (pointee_ty == self.cx.u128_type + || pointee_ty == self.cx.i128_type) + && align == self.int128_align; + // We can skip the call to `get_aligned` for byte-sized types with alignment of 1. + can_skip_align = can_skip_align + || (pointee_ty == self.cx.u8_type || pointee_ty == self.cx.i8_type) + && align.bytes() == 1; + // Skip the call to `get_aligned` when possible. + let aligned_type = + if can_skip_align { pointee_ty } else { pointee_ty.get_aligned(align.bytes()) }; + + let ptr = self.context.new_cast(self.location, ptr, aligned_type.make_pointer()); // NOTE: instead of returning the dereference here, we have to assign it to a variable in // the current basic block. Otherwise, it could be used in another basic block, causing a // dereference after a drop, for instance. - // FIXME(antoyo): this check that we don't call get_aligned() a second time on a type. - // Ideally, we shouldn't need to do this check. - // FractalFir: the `align == self.int128_align` check ensures we *do* call `get_aligned` if - // the alignment of a `u128`/`i128` is not the one mandated by the ABI. This ensures we handle - // under-aligned loads correctly. - let aligned_type = if (pointee_ty == self.cx.u128_type || pointee_ty == self.cx.i128_type) - && align == self.int128_align - { - pointee_ty - } else { - pointee_ty.get_aligned(align.bytes()) - }; - let ptr = self.context.new_cast(self.location, ptr, aligned_type.make_pointer()); let deref = ptr.dereference(self.location).to_rvalue(); let loaded_value = function.new_local( self.location, @@ -1488,16 +1497,6 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { element.get_address(self.location) } else if value_type.dyncast_vector().is_some() { panic!(); - } else if let Some(pointer_type) = value_type.get_pointee() { - if let Some(struct_type) = pointer_type.is_struct() { - // NOTE: hack to workaround a limitation of the rustc API: see comment on - // CodegenCx.structs_as_pointer - aggregate_value - .dereference_field(self.location, struct_type.get_field(idx as i32)) - .to_rvalue() - } else { - panic!("Unexpected type {:?}", value_type); - } } else if let Some(struct_type) = value_type.is_struct() { aggregate_value .access_field(self.location, struct_type.get_field(idx as i32)) @@ -1517,21 +1516,18 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { assert_eq!(idx as usize as u64, idx); let value_type = aggregate_value.get_type(); + let new_val = self.current_func().new_local(None, value_type, "aggregate_value"); + self.block.add_assignment(None, new_val, aggregate_value); + let lvalue = if value_type.dyncast_array().is_some() { let index = self .context .new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); - self.context.new_array_access(self.location, aggregate_value, index) + self.context.new_array_access(self.location, new_val, index) } else if value_type.dyncast_vector().is_some() { panic!(); - } else if let Some(pointer_type) = value_type.get_pointee() { - if let Some(struct_type) = pointer_type.is_struct() { - // NOTE: hack to workaround a limitation of the rustc API: see comment on - // CodegenCx.structs_as_pointer - aggregate_value.dereference_field(self.location, struct_type.get_field(idx as i32)) - } else { - panic!("Unexpected type {:?}", value_type); - } + } else if let Some(struct_type) = value_type.is_struct() { + new_val.access_field(None, struct_type.get_field(idx as i32)) } else { panic!("Unexpected type {:?}", value_type); }; @@ -1548,19 +1544,16 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { self.llbb().add_assignment(self.location, lvalue, value); - aggregate_value + new_val.to_rvalue() } - fn set_personality_fn(&mut self, _personality: RValue<'gcc>) { + fn set_personality_fn(&mut self, _personality: Function<'gcc>) { #[cfg(feature = "master")] - { - let personality = self.rvalue_as_function(_personality); - self.current_func().set_personality_function(personality); - } + self.current_func().set_personality_function(_personality); } #[cfg(feature = "master")] - fn cleanup_landing_pad(&mut self, pers_fn: RValue<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) { + fn cleanup_landing_pad(&mut self, pers_fn: Function<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) { self.set_personality_fn(pers_fn); // NOTE: insert the current block in a variable so that a later call to invoke knows to @@ -1581,7 +1574,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } #[cfg(not(feature = "master"))] - fn cleanup_landing_pad(&mut self, _pers_fn: RValue<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) { + fn cleanup_landing_pad(&mut self, _pers_fn: Function<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) { let value1 = self .current_func() .new_local(self.location, self.u8_type.make_pointer(), "landing_pad0") @@ -1591,9 +1584,9 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { (value1, value2) } - fn filter_landing_pad(&mut self, pers_fn: RValue<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) { + fn filter_landing_pad(&mut self, pers_fn: Function<'gcc>) { // TODO(antoyo): generate the correct landing pad - self.cleanup_landing_pad(pers_fn) + self.cleanup_landing_pad(pers_fn); } #[cfg(feature = "master")] diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index 58ff2f1f8f0..dd582834fac 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -117,15 +117,7 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { fn const_undef(&self, typ: Type<'gcc>) -> RValue<'gcc> { let local = self.current_func.borrow().expect("func").new_local(None, typ, "undefined"); - if typ.is_struct().is_some() { - // NOTE: hack to workaround a limitation of the rustc API: see comment on - // CodegenCx.structs_as_pointer - let pointer = local.get_address(None); - self.structs_as_pointer.borrow_mut().insert(pointer); - pointer - } else { - local.to_rvalue() - } + local.to_rvalue() } fn const_poison(&self, typ: Type<'gcc>) -> RValue<'gcc> { @@ -234,19 +226,6 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { match cv { Scalar::Int(int) => { let data = int.to_bits(layout.size(self)); - - // FIXME(antoyo): there's some issues with using the u128 code that follows, so hard-code - // the paths for floating-point values. - // TODO: Remove this code? - /*if ty == self.float_type { - return self - .context - .new_rvalue_from_double(ty, f32::from_bits(data as u32) as f64); - } - if ty == self.double_type { - return self.context.new_rvalue_from_double(ty, f64::from_bits(data as u64)); - }*/ - let value = self.const_uint_big(self.type_ix(bitsize), data); let bytesize = layout.size(self).bytes(); if bitsize > 1 && ty.is_integral() && bytesize as u32 == ty.get_size() { @@ -261,7 +240,7 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { } } Scalar::Ptr(ptr, _size) => { - let (prov, offset) = ptr.into_parts(); // we know the `offset` is relative + let (prov, offset) = ptr.prov_and_relative_offset(); let alloc_id = prov.alloc_id(); let base_addr = match self.tcx.global_alloc(alloc_id) { GlobalAlloc::Memory(alloc) => { diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index ff141ad365b..665cf22ddba 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -118,19 +118,12 @@ pub struct CodegenCx<'gcc, 'tcx> { /// A counter that is used for generating local symbol names local_gen_sym_counter: Cell<usize>, - eh_personality: Cell<Option<RValue<'gcc>>>, + eh_personality: Cell<Option<Function<'gcc>>>, #[cfg(feature = "master")] pub rust_try_fn: Cell<Option<(Type<'gcc>, Function<'gcc>)>>, pub pointee_infos: RefCell<FxHashMap<(Ty<'tcx>, Size), Option<PointeeInfo>>>, - /// NOTE: a hack is used because the rustc API is not suitable to libgccjit and as such, - /// `const_undef()` returns struct as pointer so that they can later be assigned a value. - /// As such, this set remembers which of these pointers were returned by this function so that - /// they can be dereferenced later. - /// FIXME(antoyo): fix the rustc API to avoid having this hack. - pub structs_as_pointer: RefCell<FxHashSet<RValue<'gcc>>>, - #[cfg(feature = "master")] pub cleanup_blocks: RefCell<FxHashSet<Block<'gcc>>>, /// The alignment of a u128/i128 type. @@ -155,6 +148,13 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(rust_type)) .unwrap(); let align = layout.align.abi.bytes(); + // For types with size 1, the alignment can be 1 and only 1 + // So, we can skip the call to ``get_aligned`. + // In the future, we can add a GCC API to query the type align, + // and call `get_aligned` if and only if that differs from Rust's expectations. + if layout.size.bytes() == 1 { + return context.new_c_type(ctype); + } #[cfg(feature = "master")] { context.new_c_type(ctype).get_aligned(align) @@ -296,7 +296,6 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { #[cfg(feature = "master")] rust_try_fn: Cell::new(None), pointee_infos: Default::default(), - structs_as_pointer: Default::default(), #[cfg(feature = "master")] cleanup_blocks: Default::default(), }; @@ -373,8 +372,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { impl<'gcc, 'tcx> BackendTypes for CodegenCx<'gcc, 'tcx> { type Value = RValue<'gcc>; type Metadata = RValue<'gcc>; - // TODO(antoyo): change to Function<'gcc>. - type Function = RValue<'gcc>; + type Function = Function<'gcc>; type BasicBlock = Block<'gcc>; type Type = Type<'gcc>; @@ -392,11 +390,10 @@ impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { &self.vtables } - fn get_fn(&self, instance: Instance<'tcx>) -> RValue<'gcc> { + fn get_fn(&self, instance: Instance<'tcx>) -> Function<'gcc> { let func = get_fn(self, instance); *self.current_func.borrow_mut() = Some(func); - // FIXME(antoyo): this is a wrong cast. That requires changing the compiler API. - unsafe { std::mem::transmute(func) } + func } fn get_fn_addr(&self, instance: Instance<'tcx>) -> RValue<'gcc> { @@ -420,7 +417,7 @@ impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { ptr } - fn eh_personality(&self) -> RValue<'gcc> { + fn eh_personality(&self) -> Function<'gcc> { // The exception handling personality function. // // If our compilation unit has the `eh_personality` lang item somewhere @@ -458,9 +455,7 @@ impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { let symbol_name = tcx.symbol_name(instance).name; let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty()); self.linkage.set(FunctionType::Extern); - let func = self.declare_fn(symbol_name, fn_abi); - let func: RValue<'gcc> = unsafe { std::mem::transmute(func) }; - func + self.declare_fn(symbol_name, fn_abi) } _ => { let name = if wants_msvc_seh(self.sess()) { @@ -468,8 +463,7 @@ impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } else { "rust_eh_personality" }; - let func = self.declare_func(name, self.type_i32(), &[], true); - unsafe { std::mem::transmute::<Function<'gcc>, RValue<'gcc>>(func) } + self.declare_func(name, self.type_i32(), &[], true) } }; // TODO(antoyo): apply target cpu attributes. @@ -481,11 +475,11 @@ impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { self.tcx.sess } - fn set_frame_pointer_type(&self, _llfn: RValue<'gcc>) { + fn set_frame_pointer_type(&self, _llfn: Function<'gcc>) { // TODO(antoyo) } - fn apply_target_cpu_attr(&self, _llfn: RValue<'gcc>) { + fn apply_target_cpu_attr(&self, _llfn: Function<'gcc>) { // TODO(antoyo) } diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs index 3a265fbc64f..4c8585192a1 100644 --- a/compiler/rustc_codegen_gcc/src/debuginfo.rs +++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs @@ -1,7 +1,7 @@ use std::ops::Range; use std::sync::Arc; -use gccjit::{Location, RValue}; +use gccjit::{Function, Location, RValue}; use rustc_abi::Size; use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext, VariableKind}; use rustc_codegen_ssa::traits::{DebugInfoBuilderMethods, DebugInfoCodegenMethods}; @@ -221,7 +221,7 @@ impl<'gcc, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { &self, instance: Instance<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, - llfn: RValue<'gcc>, + llfn: Function<'gcc>, mir: &mir::Body<'tcx>, ) -> Option<FunctionDebugContext<'tcx, Self::DIScope, Self::DILocation>> { if self.sess().opts.debuginfo == DebugInfo::None { @@ -272,7 +272,7 @@ impl<'gcc, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { &self, _instance: Instance<'tcx>, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, - _maybe_definition_llfn: Option<RValue<'gcc>>, + _maybe_definition_llfn: Option<Function<'gcc>>, ) -> Self::DIScope { // TODO(antoyo): implement. } diff --git a/compiler/rustc_codegen_gcc/src/declare.rs b/compiler/rustc_codegen_gcc/src/declare.rs index bed82073e2c..691fd8729e3 100644 --- a/compiler/rustc_codegen_gcc/src/declare.rs +++ b/compiler/rustc_codegen_gcc/src/declare.rs @@ -94,7 +94,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { _fn_type: Type<'gcc>, #[cfg(feature = "master")] callconv: Option<FnAttribute<'gcc>>, #[cfg(not(feature = "master"))] callconv: Option<()>, - ) -> RValue<'gcc> { + ) -> Function<'gcc> { // TODO(antoyo): use the fn_type parameter. let const_string = self.context.new_type::<u8>().make_pointer().make_pointer(); let return_type = self.type_i32(); @@ -111,8 +111,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { // NOTE: it is needed to set the current_func here as well, because get_fn() is not called // for the main function. *self.current_func.borrow_mut() = Some(func); - // FIXME(antoyo): this is a wrong cast. That requires changing the compiler API. - unsafe { std::mem::transmute(func) } + func } pub fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Function<'gcc> { diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/archs.rs b/compiler/rustc_codegen_gcc/src/intrinsic/archs.rs index f0352c5e6e5..915ed875e32 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/archs.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/archs.rs @@ -1,9 +1,9 @@ // File generated by `rustc_codegen_gcc/tools/generate_intrinsics.py` // DO NOT EDIT IT! /// Translate a given LLVM intrinsic name to an equivalent GCC one. -fn map_arch_intrinsic(name: &str) -> &str { - let Some(name) = name.strip_prefix("llvm.") else { - unimplemented!("***** unsupported LLVM intrinsic {}", name) +fn map_arch_intrinsic(full_name: &str) -> &'static str { + let Some(name) = full_name.strip_prefix("llvm.") else { + unimplemented!("***** unsupported LLVM intrinsic {}", full_name) }; let Some((arch, name)) = name.split_once('.') else { unimplemented!("***** unsupported LLVM intrinsic {}", name) @@ -11,7 +11,7 @@ fn map_arch_intrinsic(name: &str) -> &str { match arch { "AMDGPU" => { #[allow(non_snake_case)] - fn AMDGPU(name: &str) -> &str { + fn AMDGPU(name: &str, full_name: &str) -> &'static str { match name { // AMDGPU "div.fixup.f32" => "__builtin_amdgpu_div_fixup", @@ -42,14 +42,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "trig.preop.f64" => "__builtin_amdgpu_trig_preop", "trig.preop.v2f64" => "__builtin_amdgpu_trig_preop", "trig.preop.v4f32" => "__builtin_amdgpu_trig_preop", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - AMDGPU(name) + AMDGPU(name, full_name) } "aarch64" => { #[allow(non_snake_case)] - fn aarch64(name: &str) -> &str { + fn aarch64(name: &str, full_name: &str) -> &'static str { match name { // aarch64 "chkfeat" => "__builtin_arm_chkfeat", @@ -75,14 +75,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "tcommit" => "__builtin_arm_tcommit", "tstart" => "__builtin_arm_tstart", "ttest" => "__builtin_arm_ttest", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - aarch64(name) + aarch64(name, full_name) } "amdgcn" => { #[allow(non_snake_case)] - fn amdgcn(name: &str) -> &str { + fn amdgcn(name: &str, full_name: &str) -> &'static str { match name { // amdgcn "alignbyte" => "__builtin_amdgcn_alignbyte", @@ -99,6 +99,8 @@ fn map_arch_intrinsic(name: &str) -> &str { "cvt.f32.fp8" => "__builtin_amdgcn_cvt_f32_fp8", "cvt.off.f32.i4" => "__builtin_amdgcn_cvt_off_f32_i4", "cvt.pk.bf8.f32" => "__builtin_amdgcn_cvt_pk_bf8_f32", + "cvt.pk.f16.bf8" => "__builtin_amdgcn_cvt_pk_f16_bf8", + "cvt.pk.f16.fp8" => "__builtin_amdgcn_cvt_pk_f16_fp8", "cvt.pk.f32.bf8" => "__builtin_amdgcn_cvt_pk_f32_bf8", "cvt.pk.f32.fp8" => "__builtin_amdgcn_cvt_pk_f32_fp8", "cvt.pk.fp8.f32" => "__builtin_amdgcn_cvt_pk_fp8_f32", @@ -292,6 +294,7 @@ fn map_arch_intrinsic(name: &str) -> &str { "s.sendmsg" => "__builtin_amdgcn_s_sendmsg", "s.sendmsghalt" => "__builtin_amdgcn_s_sendmsghalt", "s.setprio" => "__builtin_amdgcn_s_setprio", + "s.setprio.inc.wg" => "__builtin_amdgcn_s_setprio_inc_wg", "s.setreg" => "__builtin_amdgcn_s_setreg", "s.sleep" => "__builtin_amdgcn_s_sleep", "s.sleep.var" => "__builtin_amdgcn_s_sleep_var", @@ -356,14 +359,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "workitem.id.x" => "__builtin_amdgcn_workitem_id_x", "workitem.id.y" => "__builtin_amdgcn_workitem_id_y", "workitem.id.z" => "__builtin_amdgcn_workitem_id_z", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - amdgcn(name) + amdgcn(name, full_name) } "arm" => { #[allow(non_snake_case)] - fn arm(name: &str) -> &str { + fn arm(name: &str, full_name: &str) -> &'static str { match name { // arm "cdp" => "__builtin_arm_cdp", @@ -465,14 +468,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "usub8" => "__builtin_arm_usub8", "uxtab16" => "__builtin_arm_uxtab16", "uxtb16" => "__builtin_arm_uxtb16", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - arm(name) + arm(name, full_name) } "bpf" => { #[allow(non_snake_case)] - fn bpf(name: &str) -> &str { + fn bpf(name: &str, full_name: &str) -> &'static str { match name { // bpf "btf.type.id" => "__builtin_bpf_btf_type_id", @@ -487,25 +490,25 @@ fn map_arch_intrinsic(name: &str) -> &str { "preserve.field.info" => "__builtin_bpf_preserve_field_info", "preserve.type.info" => "__builtin_bpf_preserve_type_info", "pseudo" => "__builtin_bpf_pseudo", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - bpf(name) + bpf(name, full_name) } "cuda" => { #[allow(non_snake_case)] - fn cuda(name: &str) -> &str { + fn cuda(name: &str, full_name: &str) -> &'static str { match name { // cuda "syncthreads" => "__syncthreads", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - cuda(name) + cuda(name, full_name) } "hexagon" => { #[allow(non_snake_case)] - fn hexagon(name: &str) -> &str { + fn hexagon(name: &str, full_name: &str) -> &'static str { match name { // hexagon "A2.abs" => "__builtin_HEXAGON_A2_abs", @@ -2479,14 +2482,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "prefetch" => "__builtin_HEXAGON_prefetch", "vmemcpy" => "__builtin_hexagon_vmemcpy", "vmemset" => "__builtin_hexagon_vmemset", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - hexagon(name) + hexagon(name, full_name) } "loongarch" => { #[allow(non_snake_case)] - fn loongarch(name: &str) -> &str { + fn loongarch(name: &str, full_name: &str) -> &'static str { match name { // loongarch "asrtgt.d" => "__builtin_loongarch_asrtgt_d", @@ -3988,14 +3991,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "movfcsr2gr" => "__builtin_loongarch_movfcsr2gr", "movgr2fcsr" => "__builtin_loongarch_movgr2fcsr", "syscall" => "__builtin_loongarch_syscall", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - loongarch(name) + loongarch(name, full_name) } "mips" => { #[allow(non_snake_case)] - fn mips(name: &str) -> &str { + fn mips(name: &str, full_name: &str) -> &'static str { match name { // mips "absq.s.ph" => "__builtin_mips_absq_s_ph", @@ -4669,14 +4672,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "wrdsp" => "__builtin_mips_wrdsp", "xor.v" => "__builtin_msa_xor_v", "xori.b" => "__builtin_msa_xori_b", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - mips(name) + mips(name, full_name) } "nvvm" => { #[allow(non_snake_case)] - fn nvvm(name: &str) -> &str { + fn nvvm(name: &str, full_name: &str) -> &'static str { match name { // nvvm "abs.i" => "__nvvm_abs_i", @@ -5024,6 +5027,7 @@ fn map_arch_intrinsic(name: &str) -> &str { "nanosleep" => "__nvvm_nanosleep", "neg.bf16" => "__nvvm_neg_bf16", "neg.bf16x2" => "__nvvm_neg_bf16x2", + "pm.event.mask" => "__nvvm_pm_event_mask", "popc.i" => "__nvvm_popc_i", "popc.ll" => "__nvvm_popc_ll", "prmt" => "__nvvm_prmt", @@ -5448,14 +5452,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "vote.ballot.sync" => "__nvvm_vote_ballot_sync", "vote.uni" => "__nvvm_vote_uni", "vote.uni.sync" => "__nvvm_vote_uni_sync", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - nvvm(name) + nvvm(name, full_name) } "ppc" => { #[allow(non_snake_case)] - fn ppc(name: &str) -> &str { + fn ppc(name: &str, full_name: &str) -> &'static str { match name { // ppc "addex" => "__builtin_ppc_addex", @@ -5842,7 +5846,10 @@ fn map_arch_intrinsic(name: &str) -> &str { "mulhdu" => "__builtin_ppc_mulhdu", "mulhw" => "__builtin_ppc_mulhw", "mulhwu" => "__builtin_ppc_mulhwu", + "national2packed" => "__builtin_ppc_national2packed", "pack.longdouble" => "__builtin_pack_longdouble", + "packed2national" => "__builtin_ppc_packed2national", + "packed2zoned" => "__builtin_ppc_packed2zoned", "pdepd" => "__builtin_pdepd", "pextd" => "__builtin_pextd", "qpx.qvfabs" => "__builtin_qpx_qvfabs", @@ -6035,14 +6042,15 @@ fn map_arch_intrinsic(name: &str) -> &str { "vsx.xxinsertw" => "__builtin_vsx_xxinsertw", "vsx.xxleqv" => "__builtin_vsx_xxleqv", "vsx.xxpermx" => "__builtin_vsx_xxpermx", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + "zoned2packed" => "__builtin_ppc_zoned2packed", + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - ppc(name) + ppc(name, full_name) } "ptx" => { #[allow(non_snake_case)] - fn ptx(name: &str) -> &str { + fn ptx(name: &str, full_name: &str) -> &'static str { match name { // ptx "bar.sync" => "__builtin_ptx_bar_sync", @@ -6063,14 +6071,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "read.pm3" => "__builtin_ptx_read_pm3", "read.smid" => "__builtin_ptx_read_smid", "read.warpid" => "__builtin_ptx_read_warpid", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - ptx(name) + ptx(name, full_name) } "r600" => { #[allow(non_snake_case)] - fn r600(name: &str) -> &str { + fn r600(name: &str, full_name: &str) -> &'static str { match name { // r600 "group.barrier" => "__builtin_r600_group_barrier", @@ -6088,14 +6096,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "read.tidig.x" => "__builtin_r600_read_tidig_x", "read.tidig.y" => "__builtin_r600_read_tidig_y", "read.tidig.z" => "__builtin_r600_read_tidig_z", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - r600(name) + r600(name, full_name) } "riscv" => { #[allow(non_snake_case)] - fn riscv(name: &str) -> &str { + fn riscv(name: &str, full_name: &str) -> &'static str { match name { // riscv "aes32dsi" => "__builtin_riscv_aes32dsi", @@ -6119,14 +6127,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "sha512sum0r" => "__builtin_riscv_sha512sum0r", "sha512sum1" => "__builtin_riscv_sha512sum1", "sha512sum1r" => "__builtin_riscv_sha512sum1r", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - riscv(name) + riscv(name, full_name) } "s390" => { #[allow(non_snake_case)] - fn s390(name: &str) -> &str { + fn s390(name: &str, full_name: &str) -> &'static str { match name { // s390 "bdepg" => "__builtin_s390_bdepg", @@ -6313,14 +6321,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "vupllf" => "__builtin_s390_vupllf", "vupllg" => "__builtin_s390_vupllg", "vupllh" => "__builtin_s390_vupllh", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - s390(name) + s390(name, full_name) } "ve" => { #[allow(non_snake_case)] - fn ve(name: &str) -> &str { + fn ve(name: &str, full_name: &str) -> &'static str { match name { // ve "vl.andm.MMM" => "__builtin_ve_vl_andm_MMM", @@ -7586,14 +7594,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "vl.vxor.vvvvl" => "__builtin_ve_vl_vxor_vvvvl", "vl.xorm.MMM" => "__builtin_ve_vl_xorm_MMM", "vl.xorm.mmm" => "__builtin_ve_vl_xorm_mmm", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - ve(name) + ve(name, full_name) } "x86" => { #[allow(non_snake_case)] - fn x86(name: &str) -> &str { + fn x86(name: &str, full_name: &str) -> &'static str { match name { // x86 "aadd32" => "__builtin_ia32_aadd32", @@ -10154,25 +10162,25 @@ fn map_arch_intrinsic(name: &str) -> &str { "xresldtrk" => "__builtin_ia32_xresldtrk", "xsusldtrk" => "__builtin_ia32_xsusldtrk", "xtest" => "__builtin_ia32_xtest", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - x86(name) + x86(name, full_name) } "xcore" => { #[allow(non_snake_case)] - fn xcore(name: &str) -> &str { + fn xcore(name: &str, full_name: &str) -> &'static str { match name { // xcore "bitrev" => "__builtin_bitrev", "getid" => "__builtin_getid", "getps" => "__builtin_getps", "setps" => "__builtin_setps", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - xcore(name) + xcore(name, full_name) } - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM architecture {arch}, intrinsic:{full_name}"), } } diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs b/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs index 0b77694f115..39dba28b24c 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs @@ -648,6 +648,11 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( new_args.push(handle); args = new_args.into(); } + "__builtin_ia32_rdtscp" => { + let result = builder.current_func().new_local(None, builder.u32_type, "result"); + let new_args = vec![result.get_address(None).to_rvalue()]; + args = new_args.into(); + } _ => (), } } else { @@ -764,6 +769,14 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( new_args.swap(0, 1); args = new_args.into(); } + "__builtin_ia32_dpps256" => { + let mut new_args = args.to_vec(); + // NOTE: without this cast to u8 (and it needs to be a u8 to fix the issue), we + // would get the following error: + // the last argument must be an 8-bit immediate + new_args[2] = builder.context.new_cast(None, new_args[2], builder.cx.type_u8()); + args = new_args.into(); + } _ => (), } } @@ -935,6 +948,19 @@ pub fn adjust_intrinsic_return_value<'a, 'gcc, 'tcx>( ); return_value = result.to_rvalue(); } + "__builtin_ia32_rdtscp" => { + let field1 = builder.context.new_field(None, return_value.get_type(), "rdtscpField1"); + let return2 = args[0].dereference(None).to_rvalue(); + let field2 = builder.context.new_field(None, return2.get_type(), "rdtscpField2"); + let struct_type = + builder.context.new_struct_type(None, "rdtscpResult", &[field1, field2]); + return_value = builder.context.new_struct_constructor( + None, + struct_type.as_type(), + None, + &[return_value, return2], + ); + } _ => (), } @@ -1529,6 +1555,17 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function "llvm.x86.aesdecwide128kl" => "__builtin_ia32_aesdecwide128kl_u8", "llvm.x86.aesencwide256kl" => "__builtin_ia32_aesencwide256kl_u8", "llvm.x86.aesdecwide256kl" => "__builtin_ia32_aesdecwide256kl_u8", + "llvm.x86.avx512.uitofp.round.v8f16.v8i16" => "__builtin_ia32_vcvtuw2ph128_mask", + "llvm.x86.avx512.uitofp.round.v16f16.v16i16" => "__builtin_ia32_vcvtuw2ph256_mask", + "llvm.x86.avx512.uitofp.round.v32f16.v32i16" => "__builtin_ia32_vcvtuw2ph512_mask_round", + "llvm.x86.avx512.uitofp.round.v8f16.v8i32" => "__builtin_ia32_vcvtudq2ph256_mask", + "llvm.x86.avx512.uitofp.round.v16f16.v16i32" => "__builtin_ia32_vcvtudq2ph512_mask_round", + "llvm.x86.avx512.uitofp.round.v8f16.v8i64" => "__builtin_ia32_vcvtuqq2ph512_mask_round", + "llvm.x86.avx512.uitofp.round.v8f64.v8i64" => "__builtin_ia32_cvtuqq2pd512_mask", + "llvm.x86.avx512.uitofp.round.v2f64.v2i64" => "__builtin_ia32_cvtuqq2pd128_mask", + "llvm.x86.avx512.uitofp.round.v4f64.v4i64" => "__builtin_ia32_cvtuqq2pd256_mask", + "llvm.x86.avx512.uitofp.round.v8f32.v8i64" => "__builtin_ia32_cvtuqq2ps512_mask", + "llvm.x86.avx512.uitofp.round.v4f32.v4i64" => "__builtin_ia32_cvtuqq2ps256_mask", // TODO: support the tile builtins: "llvm.x86.ldtilecfg" => "__builtin_trap", diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 09132c34aae..497605978fe 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -4,7 +4,9 @@ mod simd; #[cfg(feature = "master")] use std::iter; -use gccjit::{ComparisonOp, Function, FunctionType, RValue, ToRValue, Type, UnaryOp}; +#[cfg(feature = "master")] +use gccjit::Type; +use gccjit::{ComparisonOp, Function, FunctionType, RValue, ToRValue, UnaryOp}; #[cfg(feature = "master")] use rustc_abi::ExternAbi; use rustc_abi::{BackendRepr, HasDataLayout}; @@ -112,7 +114,6 @@ fn get_simple_intrinsic<'gcc, 'tcx>( } sym::copysignf32 => "copysignf", sym::copysignf64 => "copysign", - sym::copysignf128 => "copysignl", sym::floorf32 => "floorf", sym::floorf64 => "floor", sym::ceilf32 => "ceilf", @@ -236,6 +237,7 @@ fn get_simple_function_f128_2args<'gcc, 'tcx>( let func_name = match name { sym::maxnumf128 => "fmaxf128", sym::minnumf128 => "fminf128", + sym::copysignf128 => "copysignf128", _ => return None, }; Some(cx.context.new_function( @@ -259,6 +261,7 @@ fn f16_builtin<'gcc, 'tcx>( let f32_type = cx.type_f32(); let builtin_name = match name { sym::ceilf16 => "__builtin_ceilf", + sym::copysignf16 => "__builtin_copysignf", sym::floorf16 => "__builtin_floorf", sym::fmaf16 => "fmaf", sym::maxnumf16 => "__builtin_fmaxf", @@ -300,6 +303,8 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc let fn_args = instance.args; let simple = get_simple_intrinsic(self, name); + // TODO(antoyo): Only call get_simple_function_f128 and get_simple_function_f128_2args when + // it is the symbols for the supported f128 builtins. let simple_func = get_simple_function(self, name) .or_else(|| get_simple_function_f128(self, name)) .or_else(|| get_simple_function_f128_2args(self, name)); @@ -326,6 +331,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc ) } sym::ceilf16 + | sym::copysignf16 | sym::floorf16 | sym::fmaf16 | sym::maxnumf16 @@ -441,7 +447,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc match int_type_width_signed(args[0].layout.ty, self) { Some((width, signed)) => match name { sym::ctlz | sym::cttz => { - let func = self.current_func.borrow().expect("func"); + let func = self.current_func(); let then_block = func.new_block("then"); let else_block = func.new_block("else"); let after_block = func.new_block("after"); @@ -1109,7 +1115,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // for (int counter = 0; value != 0; counter++) { // value &= value - 1; // } - let func = self.current_func.borrow().expect("func"); + let func = self.current_func(); let loop_head = func.new_block("head"); let loop_body = func.new_block("body"); let loop_tail = func.new_block("tail"); @@ -1188,7 +1194,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let result_type = lhs.get_type(); if signed { // Based on algorithm from: https://stackoverflow.com/a/56531252/389119 - let func = self.current_func.borrow().expect("func"); + let func = self.current_func(); let res = func.new_local(self.location, result_type, "saturating_sum"); let supports_native_type = self.is_native_int_type(result_type); let overflow = if supports_native_type { @@ -1259,7 +1265,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let result_type = lhs.get_type(); if signed { // Based on algorithm from: https://stackoverflow.com/a/56531252/389119 - let func = self.current_func.borrow().expect("func"); + let func = self.current_func(); let res = func.new_local(self.location, result_type, "saturating_diff"); let supports_native_type = self.is_native_int_type(result_type); let overflow = if supports_native_type { @@ -1483,10 +1489,9 @@ fn gen_fn<'a, 'gcc, 'tcx>( // FIXME(eddyb) find a nicer way to do this. cx.linkage.set(FunctionType::Internal); let func = cx.declare_fn(name, fn_abi); - let func_val = unsafe { std::mem::transmute::<Function<'gcc>, RValue<'gcc>>(func) }; - cx.set_frame_pointer_type(func_val); - cx.apply_target_cpu_attr(func_val); - let block = Builder::append_block(cx, func_val, "entry-block"); + cx.set_frame_pointer_type(func); + cx.apply_target_cpu_attr(func); + let block = Builder::append_block(cx, func, "entry-block"); let bx = Builder::build(cx, block); codegen(bx); (return_type, func) diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs index 6f6bc93b8b2..2e508813fc3 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs @@ -61,7 +61,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( let (len, _) = args[1].layout.ty.simd_size_and_type(bx.tcx()); let expected_int_bits = (len.max(8) - 1).next_power_of_two(); - let expected_bytes = len / 8 + ((len % 8 > 0) as u64); + let expected_bytes = len / 8 + ((!len.is_multiple_of(8)) as u64); let mask_ty = args[0].layout.ty; let mut mask = match *mask_ty.kind() { @@ -676,7 +676,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( let elem_type = vector_type.get_element_type(); let expected_int_bits = in_len.max(8); - let expected_bytes = expected_int_bits / 8 + ((expected_int_bits % 8 > 0) as u64); + let expected_bytes = + expected_int_bits / 8 + ((!expected_int_bits.is_multiple_of(8)) as u64); // FIXME(antoyo): that's not going to work for masks bigger than 128 bits. let result_type = bx.type_ix(expected_int_bits); @@ -779,6 +780,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( sym::simd_fsin => "sin", sym::simd_fsqrt => "sqrt", sym::simd_round => "round", + sym::simd_round_ties_even => "rint", sym::simd_trunc => "trunc", _ => return_error!(InvalidMonomorphization::UnrecognizedIntrinsic { span, name }), }; @@ -826,6 +828,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( | sym::simd_fsin | sym::simd_fsqrt | sym::simd_round + | sym::simd_round_ties_even | sym::simd_trunc ) { return simd_simple_float_intrinsic(name, in_elem, in_ty, in_len, bx, span, args); diff --git a/compiler/rustc_codegen_gcc/tests/failing-ui-tests.txt b/compiler/rustc_codegen_gcc/tests/failing-ui-tests.txt index d931f0d3b5e..544d0bfc710 100644 --- a/compiler/rustc_codegen_gcc/tests/failing-ui-tests.txt +++ b/compiler/rustc_codegen_gcc/tests/failing-ui-tests.txt @@ -9,6 +9,7 @@ tests/ui/iterators/iter-sum-overflow-debug.rs tests/ui/iterators/iter-sum-overflow-overflow-checks.rs tests/ui/mir/mir_drop_order.rs tests/ui/mir/mir_let_chains_drop_order.rs +tests/ui/mir/mir_match_guard_let_chains_drop_order.rs tests/ui/oom_unwind.rs tests/ui/panic-runtime/abort-link-to-unwinding-crates.rs tests/ui/panic-runtime/abort.rs diff --git a/compiler/rustc_codegen_gcc/tools/generate_intrinsics.py b/compiler/rustc_codegen_gcc/tools/generate_intrinsics.py index ed0ebf00719..88927f39b93 100644 --- a/compiler/rustc_codegen_gcc/tools/generate_intrinsics.py +++ b/compiler/rustc_codegen_gcc/tools/generate_intrinsics.py @@ -176,14 +176,14 @@ def update_intrinsics(llvm_path, llvmint, llvmint2): out.write("// File generated by `rustc_codegen_gcc/tools/generate_intrinsics.py`\n") out.write("// DO NOT EDIT IT!\n") out.write("/// Translate a given LLVM intrinsic name to an equivalent GCC one.\n") - out.write("fn map_arch_intrinsic(name:&str)->&str{\n") - out.write('let Some(name) = name.strip_prefix("llvm.") else { unimplemented!("***** unsupported LLVM intrinsic {}", name) };\n') + out.write("fn map_arch_intrinsic(full_name:&str)->&'static str{\n") + out.write('let Some(name) = full_name.strip_prefix("llvm.") else { unimplemented!("***** unsupported LLVM intrinsic {}", full_name) };\n') out.write('let Some((arch, name)) = name.split_once(\'.\') else { unimplemented!("***** unsupported LLVM intrinsic {}", name) };\n') out.write("match arch {\n") for arch in archs: if len(intrinsics[arch]) == 0: continue - out.write("\"{}\" => {{ #[allow(non_snake_case)] fn {}(name: &str) -> &str {{ match name {{".format(arch,arch)) + out.write("\"{}\" => {{ #[allow(non_snake_case)] fn {}(name: &str,full_name:&str) -> &'static str {{ match name {{".format(arch,arch)) intrinsics[arch].sort(key=lambda x: (x[0], x[2])) out.write(' // {}\n'.format(arch)) for entry in intrinsics[arch]: @@ -196,9 +196,9 @@ def update_intrinsics(llvm_path, llvmint, llvmint2): out.write(' // [INVALID CONVERSION]: "{}" => "{}",\n'.format(llvm_name, entry[1])) else: out.write(' "{}" => "{}",\n'.format(llvm_name, entry[1])) - out.write(' _ => unimplemented!("***** unsupported LLVM intrinsic {}", name),\n') - out.write("}} }} {}(name) }}\n,".format(arch)) - out.write(' _ => unimplemented!("***** unsupported LLVM architecture {}", name),\n') + out.write(' _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"),\n') + out.write("}} }} {}(name,full_name) }}\n,".format(arch)) + out.write(' _ => unimplemented!("***** unsupported LLVM architecture {arch}, intrinsic:{full_name}"),\n') out.write("}\n}") subprocess.call(["rustfmt", output_file]) print("Done!") diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index ee46b49a094..9c62244f3c9 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -587,7 +587,7 @@ fn thin_lto( } fn enable_autodiff_settings(ad: &[config::AutoDiff]) { - for &val in ad { + for val in ad { // We intentionally don't use a wildcard, to not forget handling anything new. match val { config::AutoDiff::PrintPerf => { @@ -599,6 +599,10 @@ fn enable_autodiff_settings(ad: &[config::AutoDiff]) { config::AutoDiff::PrintTA => { llvm::set_print_type(true); } + config::AutoDiff::PrintTAFn(fun) => { + llvm::set_print_type(true); // Enable general type printing + llvm::set_print_type_fun(&fun); // Set specific function to analyze + } config::AutoDiff::Inline => { llvm::set_inline(true); } diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 5e9594dd06b..d0aa7320b4b 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1166,11 +1166,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { (self.extract_value(landing_pad, 0), self.extract_value(landing_pad, 1)) } - fn filter_landing_pad(&mut self, pers_fn: &'ll Value) -> (&'ll Value, &'ll Value) { + fn filter_landing_pad(&mut self, pers_fn: &'ll Value) { let ty = self.type_struct(&[self.type_ptr(), self.type_i32()], false); let landing_pad = self.landing_pad(ty, pers_fn, 1); self.add_clause(landing_pad, self.const_array(self.type_ptr(), &[])); - (self.extract_value(landing_pad, 0), self.extract_value(landing_pad, 1)) } fn resume(&mut self, exn0: &'ll Value, exn1: &'ll Value) { diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index ae5add59322..7cfab25bc50 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -268,7 +268,7 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { } } Scalar::Ptr(ptr, _size) => { - let (prov, offset) = ptr.into_parts(); + let (prov, offset) = ptr.prov_and_relative_offset(); let global_alloc = self.tcx.global_alloc(prov.alloc_id()); let base_addr = match global_alloc { GlobalAlloc::Memory(alloc) => { diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index f7f062849a8..9930eae3fe7 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1537,6 +1537,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( sym::simd_fsin => "llvm.sin", sym::simd_fsqrt => "llvm.sqrt", sym::simd_round => "llvm.round", + sym::simd_round_ties_even => "llvm.rint", sym::simd_trunc => "llvm.trunc", _ => return_error!(InvalidMonomorphization::UnrecognizedIntrinsic { span, name }), }; @@ -1563,6 +1564,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( | sym::simd_fsqrt | sym::simd_relaxed_fma | sym::simd_round + | sym::simd_round_ties_even | sym::simd_trunc ) { return simd_simple_float_intrinsic(name, in_elem, in_ty, in_len, bx, span, args); @@ -2309,7 +2311,13 @@ fn generic_simd_intrinsic<'ll, 'tcx>( // Unary integer intrinsics if matches!( name, - sym::simd_bswap | sym::simd_bitreverse | sym::simd_ctlz | sym::simd_ctpop | sym::simd_cttz + sym::simd_bswap + | sym::simd_bitreverse + | sym::simd_ctlz + | sym::simd_ctpop + | sym::simd_cttz + | sym::simd_funnel_shl + | sym::simd_funnel_shr ) { let vec_ty = bx.cx.type_vector( match *in_elem.kind() { @@ -2330,6 +2338,8 @@ fn generic_simd_intrinsic<'ll, 'tcx>( sym::simd_ctlz => "llvm.ctlz", sym::simd_ctpop => "llvm.ctpop", sym::simd_cttz => "llvm.cttz", + sym::simd_funnel_shl => "llvm.fshl", + sym::simd_funnel_shr => "llvm.fshr", _ => unreachable!(), }; let int_size = in_elem.int_size_and_signed(bx.tcx()).0.bits(); @@ -2350,6 +2360,11 @@ fn generic_simd_intrinsic<'ll, 'tcx>( // simple unary argument cases Ok(bx.call_intrinsic(llvm_intrinsic, &[vec_ty], &[args[0].immediate()])) } + sym::simd_funnel_shl | sym::simd_funnel_shr => Ok(bx.call_intrinsic( + llvm_intrinsic, + &[vec_ty], + &[args[0].immediate(), args[1].immediate(), args[2].immediate()], + )), _ => unreachable!(), }; } diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs index 2ad39fc8538..b94716b89d6 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs @@ -57,14 +57,19 @@ pub(crate) use self::Enzyme_AD::*; #[cfg(llvm_enzyme)] pub(crate) mod Enzyme_AD { + use std::ffi::{CString, c_char}; + use libc::c_void; + unsafe extern "C" { pub(crate) fn EnzymeSetCLBool(arg1: *mut ::std::os::raw::c_void, arg2: u8); + pub(crate) fn EnzymeSetCLString(arg1: *mut ::std::os::raw::c_void, arg2: *const c_char); } unsafe extern "C" { static mut EnzymePrintPerf: c_void; static mut EnzymePrintActivity: c_void; static mut EnzymePrintType: c_void; + static mut EnzymeFunctionToAnalyze: c_void; static mut EnzymePrint: c_void; static mut EnzymeStrictAliasing: c_void; static mut looseTypeAnalysis: c_void; @@ -86,6 +91,15 @@ pub(crate) mod Enzyme_AD { EnzymeSetCLBool(std::ptr::addr_of_mut!(EnzymePrintType), print as u8); } } + pub(crate) fn set_print_type_fun(fun_name: &str) { + let c_fun_name = CString::new(fun_name).unwrap(); + unsafe { + EnzymeSetCLString( + std::ptr::addr_of_mut!(EnzymeFunctionToAnalyze), + c_fun_name.as_ptr() as *const c_char, + ); + } + } pub(crate) fn set_print(print: bool) { unsafe { EnzymeSetCLBool(std::ptr::addr_of_mut!(EnzymePrint), print as u8); @@ -132,6 +146,9 @@ pub(crate) mod Fallback_AD { pub(crate) fn set_print_type(print: bool) { unimplemented!() } + pub(crate) fn set_print_type_fun(fun_name: &str) { + unimplemented!() + } pub(crate) fn set_print(print: bool) { unimplemented!() } diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 6fd07d562af..0fb987bdf82 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -370,10 +370,18 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) { let target_env = sess.target.options.env.as_ref(); let target_abi = sess.target.options.abi.as_ref(); let target_pointer_width = sess.target.pointer_width; + let version = get_version(); cfg.has_reliable_f16 = match (target_arch, target_os) { // Selection failure <https://github.com/llvm/llvm-project/issues/50374> ("s390x", _) => false, + // LLVM crash without neon <https://github.com/llvm/llvm-project/issues/129394> (now fixed) + ("aarch64", _) + if !cfg.target_features.iter().any(|f| f.as_str() == "neon") + && version < (20, 1, 1) => + { + false + } // Unsupported <https://github.com/llvm/llvm-project/issues/94434> ("arm64ec", _) => false, // MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054> diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index b2e86414d90..84d63819343 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -48,8 +48,6 @@ codegen_ssa_error_writing_def_file = codegen_ssa_expected_name_value_pair = expected name value pair -codegen_ssa_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)` - codegen_ssa_extern_funcs_not_found = some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified codegen_ssa_extract_bundled_libs_archive_member = failed to get data from archive member '{$rlib}': {$error} @@ -205,11 +203,6 @@ codegen_ssa_missing_features = add the missing features in a `target_feature` at codegen_ssa_missing_query_depgraph = found CGU-reuse attribute but `-Zquery-dep-graph` was not specified -codegen_ssa_mixed_export_name_and_no_mangle = `{$no_mangle_attr}` attribute may not be used in combination with `#[export_name]` - .label = `{$no_mangle_attr}` is ignored - .note = `#[export_name]` takes precedence - .suggestion = remove the `{$no_mangle_attr}` attribute - codegen_ssa_msvc_missing_linker = the msvc targets depend on the msvc linker but `link.exe` was not found codegen_ssa_multiple_external_func_decl = multiple declarations of external function `{$function}` from library `{$library_name}` have different calling conventions @@ -230,8 +223,6 @@ codegen_ssa_no_natvis_directory = error enumerating natvis directory: {$error} codegen_ssa_no_saved_object_file = cached cgu {$cgu_name} should have an object file, but doesn't -codegen_ssa_null_on_export = `export_name` may not contain null characters - codegen_ssa_out_of_range_integer = integer value out of range .label = value must be between `0` and `255` diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 8882ba359b7..4a2425967e4 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -865,7 +865,7 @@ fn link_natively( command: cmd, escaped_output, verbose: sess.opts.verbose, - sysroot_dir: sess.sysroot.clone(), + sysroot_dir: sess.opts.sysroot.path().to_owned(), }; sess.dcx().emit_err(err); // If MSVC's `link.exe` was expected but the return code @@ -1249,10 +1249,10 @@ fn link_sanitizer_runtime( if path.exists() { sess.target_tlib_path.dir.clone() } else { - let default_sysroot = filesearch::get_or_default_sysroot(); - let default_tlib = - filesearch::make_target_lib_path(&default_sysroot, sess.opts.target_triple.tuple()); - default_tlib + filesearch::make_target_lib_path( + &sess.opts.sysroot.default, + sess.opts.target_triple.tuple(), + ) } } @@ -1758,7 +1758,7 @@ fn detect_self_contained_mingw(sess: &Session, linker: &Path) -> bool { for dir in env::split_paths(&env::var_os("PATH").unwrap_or_default()) { let full_path = dir.join(&linker_with_extension); // If linker comes from sysroot assume self-contained mode - if full_path.is_file() && !full_path.starts_with(&sess.sysroot) { + if full_path.is_file() && !full_path.starts_with(sess.opts.sysroot.path()) { return false; } } diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 8fc83908efb..1896f63bd2d 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -337,7 +337,12 @@ pub(crate) trait Linker { fn debuginfo(&mut self, strip: Strip, natvis_debugger_visualizers: &[PathBuf]); fn no_crt_objects(&mut self); fn no_default_libraries(&mut self); - fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]); + fn export_symbols( + &mut self, + tmpdir: &Path, + crate_type: CrateType, + symbols: &[(String, SymbolExportKind)], + ); fn subsystem(&mut self, subsystem: &str); fn linker_plugin_lto(&mut self); fn add_eh_frame_header(&mut self) {} @@ -770,7 +775,12 @@ impl<'a> Linker for GccLinker<'a> { } } - fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) { + fn export_symbols( + &mut self, + tmpdir: &Path, + crate_type: CrateType, + symbols: &[(String, SymbolExportKind)], + ) { // Symbol visibility in object files typically takes care of this. if crate_type == CrateType::Executable { let should_export_executable_symbols = @@ -799,7 +809,7 @@ impl<'a> Linker for GccLinker<'a> { // Write a plain, newline-separated list of symbols let res: io::Result<()> = try { let mut f = File::create_buffered(&path)?; - for sym in symbols { + for (sym, _) in symbols { debug!(" _{sym}"); writeln!(f, "_{sym}")?; } @@ -814,11 +824,12 @@ impl<'a> Linker for GccLinker<'a> { // .def file similar to MSVC one but without LIBRARY section // because LD doesn't like when it's empty writeln!(f, "EXPORTS")?; - for symbol in symbols { + for (symbol, kind) in symbols { + let kind_marker = if *kind == SymbolExportKind::Data { " DATA" } else { "" }; debug!(" _{symbol}"); // Quote the name in case it's reserved by linker in some way // (this accounts for names with dots in particular). - writeln!(f, " \"{symbol}\"")?; + writeln!(f, " \"{symbol}\"{kind_marker}")?; } }; if let Err(error) = res { @@ -831,7 +842,7 @@ impl<'a> Linker for GccLinker<'a> { writeln!(f, "{{")?; if !symbols.is_empty() { writeln!(f, " global:")?; - for sym in symbols { + for (sym, _) in symbols { debug!(" {sym};"); writeln!(f, " {sym};")?; } @@ -1059,7 +1070,7 @@ impl<'a> Linker for MsvcLinker<'a> { self.link_arg("/PDBALTPATH:%_PDB%"); // This will cause the Microsoft linker to embed .natvis info into the PDB file - let natvis_dir_path = self.sess.sysroot.join("lib\\rustlib\\etc"); + let natvis_dir_path = self.sess.opts.sysroot.path().join("lib\\rustlib\\etc"); if let Ok(natvis_dir) = fs::read_dir(&natvis_dir_path) { for entry in natvis_dir { match entry { @@ -1098,7 +1109,12 @@ impl<'a> Linker for MsvcLinker<'a> { // crates. Upstream rlibs may be linked statically to this dynamic library, // in which case they may continue to transitively be used and hence need // their symbols exported. - fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) { + fn export_symbols( + &mut self, + tmpdir: &Path, + crate_type: CrateType, + symbols: &[(String, SymbolExportKind)], + ) { // Symbol visibility takes care of this typically if crate_type == CrateType::Executable { let should_export_executable_symbols = @@ -1116,9 +1132,10 @@ impl<'a> Linker for MsvcLinker<'a> { // straight to exports. writeln!(f, "LIBRARY")?; writeln!(f, "EXPORTS")?; - for symbol in symbols { + for (symbol, kind) in symbols { + let kind_marker = if *kind == SymbolExportKind::Data { " DATA" } else { "" }; debug!(" _{symbol}"); - writeln!(f, " {symbol}")?; + writeln!(f, " {symbol}{kind_marker}")?; } }; if let Err(error) = res { @@ -1259,14 +1276,19 @@ impl<'a> Linker for EmLinker<'a> { self.cc_arg("-nodefaultlibs"); } - fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { + fn export_symbols( + &mut self, + _tmpdir: &Path, + _crate_type: CrateType, + symbols: &[(String, SymbolExportKind)], + ) { debug!("EXPORTED SYMBOLS:"); self.cc_arg("-s"); let mut arg = OsString::from("EXPORTED_FUNCTIONS="); let encoded = serde_json::to_string( - &symbols.iter().map(|sym| "_".to_owned() + sym).collect::<Vec<_>>(), + &symbols.iter().map(|(sym, _)| "_".to_owned() + sym).collect::<Vec<_>>(), ) .unwrap(); debug!("{encoded}"); @@ -1428,8 +1450,13 @@ impl<'a> Linker for WasmLd<'a> { fn no_default_libraries(&mut self) {} - fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { - for sym in symbols { + fn export_symbols( + &mut self, + _tmpdir: &Path, + _crate_type: CrateType, + symbols: &[(String, SymbolExportKind)], + ) { + for (sym, _) in symbols { self.link_args(&["--export", sym]); } @@ -1563,7 +1590,7 @@ impl<'a> Linker for L4Bender<'a> { self.cc_arg("-nostdlib"); } - fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[String]) { + fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[(String, SymbolExportKind)]) { // ToDo, not implemented, copy from GCC self.sess.dcx().emit_warn(errors::L4BenderExportingSymbolsUnimplemented); } @@ -1720,12 +1747,17 @@ impl<'a> Linker for AixLinker<'a> { fn no_default_libraries(&mut self) {} - fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { + fn export_symbols( + &mut self, + tmpdir: &Path, + _crate_type: CrateType, + symbols: &[(String, SymbolExportKind)], + ) { let path = tmpdir.join("list.exp"); let res: io::Result<()> = try { let mut f = File::create_buffered(&path)?; // FIXME: use llvm-nm to generate export list. - for symbol in symbols { + for (symbol, _) in symbols { debug!(" _{symbol}"); writeln!(f, " {symbol}")?; } @@ -1762,16 +1794,33 @@ fn for_each_exported_symbols_include_dep<'tcx>( for (cnum, dep_format) in deps.iter_enumerated() { // For each dependency that we are linking to statically ... if *dep_format == Linkage::Static { - for &(symbol, info) in tcx.exported_symbols(cnum).iter() { + for &(symbol, info) in tcx.exported_non_generic_symbols(cnum).iter() { + callback(symbol, info, cnum); + } + for &(symbol, info) in tcx.exported_generic_symbols(cnum).iter() { callback(symbol, info, cnum); } } } } -pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> { +pub(crate) fn exported_symbols( + tcx: TyCtxt<'_>, + crate_type: CrateType, +) -> Vec<(String, SymbolExportKind)> { if let Some(ref exports) = tcx.sess.target.override_export_symbols { - return exports.iter().map(ToString::to_string).collect(); + return exports + .iter() + .map(|name| { + ( + name.to_string(), + // FIXME use the correct export kind for this symbol. override_export_symbols + // can't directly specify the SymbolExportKind as it is defined in rustc_middle + // which rustc_target can't depend on. + SymbolExportKind::Text, + ) + }) + .collect(); } if let CrateType::ProcMacro = crate_type { @@ -1781,7 +1830,10 @@ pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<St } } -fn exported_symbols_for_non_proc_macro(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> { +fn exported_symbols_for_non_proc_macro( + tcx: TyCtxt<'_>, + crate_type: CrateType, +) -> Vec<(String, SymbolExportKind)> { let mut symbols = Vec::new(); let export_threshold = symbol_export::crates_export_threshold(&[crate_type]); for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| { @@ -1789,8 +1841,9 @@ fn exported_symbols_for_non_proc_macro(tcx: TyCtxt<'_>, crate_type: CrateType) - // from any cdylib. The latter doesn't work anyway as we use hidden visibility for // compiler-builtins. Most linkers silently ignore it, but ld64 gives a warning. if info.level.is_below_threshold(export_threshold) && !tcx.is_compiler_builtins(cnum) { - symbols.push(symbol_export::exporting_symbol_name_for_instance_in_crate( - tcx, symbol, cnum, + symbols.push(( + symbol_export::exporting_symbol_name_for_instance_in_crate(tcx, symbol, cnum), + info.kind, )); symbol_export::extend_exported_symbols(&mut symbols, tcx, symbol, cnum); } @@ -1799,7 +1852,7 @@ fn exported_symbols_for_non_proc_macro(tcx: TyCtxt<'_>, crate_type: CrateType) - symbols } -fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<String> { +fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<(String, SymbolExportKind)> { // `exported_symbols` will be empty when !should_codegen. if !tcx.sess.opts.output_types.should_codegen() { return Vec::new(); @@ -1809,7 +1862,10 @@ fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<String> { let proc_macro_decls_name = tcx.sess.generate_proc_macro_decls_symbol(stable_crate_id); let metadata_symbol_name = exported_symbols::metadata_symbol_name(tcx); - vec![proc_macro_decls_name, metadata_symbol_name] + vec![ + (proc_macro_decls_name, SymbolExportKind::Data), + (metadata_symbol_name, SymbolExportKind::Data), + ] } pub(crate) fn linked_symbols( @@ -1817,8 +1873,28 @@ pub(crate) fn linked_symbols( crate_type: CrateType, ) -> Vec<(String, SymbolExportKind)> { match crate_type { - CrateType::Executable | CrateType::Cdylib | CrateType::Dylib | CrateType::Sdylib => (), - CrateType::Staticlib | CrateType::ProcMacro | CrateType::Rlib => { + CrateType::Executable + | CrateType::ProcMacro + | CrateType::Cdylib + | CrateType::Dylib + | CrateType::Sdylib => (), + CrateType::Staticlib | CrateType::Rlib => { + // These are not linked, so no need to generate symbols.o for them. + return Vec::new(); + } + } + + match tcx.sess.lto() { + Lto::No | Lto::ThinLocal => {} + Lto::Thin | Lto::Fat => { + // We really only need symbols from upstream rlibs to end up in the linked symbols list. + // The rest are in separate object files which the linker will always link in and + // doesn't have rules around the order in which they need to appear. + // When doing LTO, some of the symbols in the linked symbols list happen to be + // internalized by LTO, which then prevents referencing them from symbols.o. When doing + // LTO, all object files that get linked in will be local object files rather than + // pulled in from rlibs, so an empty linked symbols list works fine to avoid referencing + // all those internalized symbols from symbols.o. return Vec::new(); } } @@ -1829,9 +1905,12 @@ pub(crate) fn linked_symbols( for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| { if info.level.is_below_threshold(export_threshold) && !tcx.is_compiler_builtins(cnum) || info.used + || info.rustc_std_internal_symbol { symbols.push(( - symbol_export::linking_symbol_name_for_instance_in_crate(tcx, symbol, cnum), + symbol_export::linking_symbol_name_for_instance_in_crate( + tcx, symbol, info.kind, cnum, + ), info.kind, )); } @@ -1906,7 +1985,13 @@ impl<'a> Linker for PtxLinker<'a> { fn ehcont_guard(&mut self) {} - fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, _symbols: &[String]) {} + fn export_symbols( + &mut self, + _tmpdir: &Path, + _crate_type: CrateType, + _symbols: &[(String, SymbolExportKind)], + ) { + } fn subsystem(&mut self, _subsystem: &str) {} @@ -1975,10 +2060,15 @@ impl<'a> Linker for LlbcLinker<'a> { fn ehcont_guard(&mut self) {} - fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { + fn export_symbols( + &mut self, + _tmpdir: &Path, + _crate_type: CrateType, + symbols: &[(String, SymbolExportKind)], + ) { match _crate_type { CrateType::Cdylib => { - for sym in symbols { + for (sym, _) in symbols { self.link_args(&["--export-symbol", sym]); } } @@ -2052,11 +2142,16 @@ impl<'a> Linker for BpfLinker<'a> { fn ehcont_guard(&mut self) {} - fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { + fn export_symbols( + &mut self, + tmpdir: &Path, + _crate_type: CrateType, + symbols: &[(String, SymbolExportKind)], + ) { let path = tmpdir.join("symbols"); let res: io::Result<()> = try { let mut f = File::create_buffered(&path)?; - for sym in symbols { + for (sym, _) in symbols { writeln!(f, "{sym}")?; } }; diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index d0b6c7470fb..2f5eca2d6b2 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -131,6 +131,9 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<S used: codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER) || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) || used, + rustc_std_internal_symbol: codegen_attrs + .flags + .contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL), }; (def_id.to_def_id(), info) }) @@ -143,6 +146,7 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<S level: SymbolExportLevel::C, kind: SymbolExportKind::Data, used: false, + rustc_std_internal_symbol: false, }, ); } @@ -164,7 +168,7 @@ fn is_reachable_non_generic_provider_extern(tcx: TyCtxt<'_>, def_id: DefId) -> b tcx.reachable_non_generics(def_id.krate).contains_key(&def_id) } -fn exported_symbols_provider_local<'tcx>( +fn exported_non_generic_symbols_provider_local<'tcx>( tcx: TyCtxt<'tcx>, _: LocalCrate, ) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] { @@ -191,6 +195,7 @@ fn exported_symbols_provider_local<'tcx>( level: info.level, kind: SymbolExportKind::Text, used: info.used, + rustc_std_internal_symbol: info.rustc_std_internal_symbol, }, ) }) @@ -207,6 +212,7 @@ fn exported_symbols_provider_local<'tcx>( level: SymbolExportLevel::C, kind: SymbolExportKind::Text, used: false, + rustc_std_internal_symbol: false, }, )); } @@ -230,6 +236,7 @@ fn exported_symbols_provider_local<'tcx>( level: SymbolExportLevel::Rust, kind: SymbolExportKind::Text, used: false, + rustc_std_internal_symbol: true, }, )); } @@ -250,6 +257,7 @@ fn exported_symbols_provider_local<'tcx>( level: SymbolExportLevel::C, kind: SymbolExportKind::Data, used: false, + rustc_std_internal_symbol: false, }, ) })); @@ -275,6 +283,7 @@ fn exported_symbols_provider_local<'tcx>( level: SymbolExportLevel::C, kind: SymbolExportKind::Data, used: false, + rustc_std_internal_symbol: false, }, ) })); @@ -292,10 +301,27 @@ fn exported_symbols_provider_local<'tcx>( level: SymbolExportLevel::C, kind: SymbolExportKind::Data, used: true, + rustc_std_internal_symbol: false, }, )); } + // Sort so we get a stable incr. comp. hash. + symbols.sort_by_cached_key(|s| s.0.symbol_name_for_local_instance(tcx)); + + tcx.arena.alloc_from_iter(symbols) +} + +fn exported_generic_symbols_provider_local<'tcx>( + tcx: TyCtxt<'tcx>, + _: LocalCrate, +) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] { + if !tcx.sess.opts.output_types.should_codegen() && !tcx.is_sdylib_interface_build() { + return &[]; + } + + let mut symbols: Vec<_> = vec![]; + if tcx.local_crate_exports_generics() { use rustc_middle::mir::mono::{Linkage, MonoItem, Visibility}; use rustc_middle::ty::InstanceKind; @@ -367,6 +393,8 @@ fn exported_symbols_provider_local<'tcx>( } } + // Note: These all set rustc_std_internal_symbol to false as generic functions must not + // be marked with this attribute and we are only handling generic functions here. match *mono_item { MonoItem::Fn(Instance { def: InstanceKind::Item(def), args }) => { let has_generics = args.non_erasable_generics().next().is_some(); @@ -382,6 +410,7 @@ fn exported_symbols_provider_local<'tcx>( level: SymbolExportLevel::Rust, kind: SymbolExportKind::Text, used: false, + rustc_std_internal_symbol: false, }, )); } @@ -404,6 +433,7 @@ fn exported_symbols_provider_local<'tcx>( level: SymbolExportLevel::Rust, kind: SymbolExportKind::Text, used: false, + rustc_std_internal_symbol: false, }, )); } @@ -420,6 +450,7 @@ fn exported_symbols_provider_local<'tcx>( level: SymbolExportLevel::Rust, kind: SymbolExportKind::Text, used: false, + rustc_std_internal_symbol: false, }, )); } @@ -430,6 +461,7 @@ fn exported_symbols_provider_local<'tcx>( level: SymbolExportLevel::Rust, kind: SymbolExportKind::Text, used: false, + rustc_std_internal_symbol: false, }, )); } @@ -458,7 +490,7 @@ fn upstream_monomorphizations_provider( let async_drop_in_place_fn_def_id = tcx.lang_items().async_drop_in_place_fn(); for &cnum in cnums.iter() { - for (exported_symbol, _) in tcx.exported_symbols(cnum).iter() { + for (exported_symbol, _) in tcx.exported_generic_symbols(cnum).iter() { let (def_id, args) = match *exported_symbol { ExportedSymbol::Generic(def_id, args) => (def_id, args), ExportedSymbol::DropGlue(ty) => { @@ -480,10 +512,7 @@ fn upstream_monomorphizations_provider( ExportedSymbol::AsyncDropGlue(def_id, ty) => (def_id, tcx.mk_args(&[ty.into()])), ExportedSymbol::NonGeneric(..) | ExportedSymbol::ThreadLocalShim(..) - | ExportedSymbol::NoDefId(..) => { - // These are no monomorphizations - continue; - } + | ExportedSymbol::NoDefId(..) => unreachable!("{exported_symbol:?}"), }; let args_map = instances.entry(def_id).or_default(); @@ -538,7 +567,8 @@ fn is_unreachable_local_definition_provider(tcx: TyCtxt<'_>, def_id: LocalDefId) pub(crate) fn provide(providers: &mut Providers) { providers.reachable_non_generics = reachable_non_generics_provider; providers.is_reachable_non_generic = is_reachable_non_generic_provider_local; - providers.exported_symbols = exported_symbols_provider_local; + providers.exported_non_generic_symbols = exported_non_generic_symbols_provider_local; + providers.exported_generic_symbols = exported_generic_symbols_provider_local; providers.upstream_monomorphizations = upstream_monomorphizations_provider; providers.is_unreachable_local_definition = is_unreachable_local_definition_provider; providers.upstream_drop_glue_for = upstream_drop_glue_for_provider; @@ -680,6 +710,7 @@ fn calling_convention_for_symbol<'tcx>( pub(crate) fn linking_symbol_name_for_instance_in_crate<'tcx>( tcx: TyCtxt<'tcx>, symbol: ExportedSymbol<'tcx>, + export_kind: SymbolExportKind, instantiating_crate: CrateNum, ) -> String { let mut undecorated = symbol_name_for_instance_in_crate(tcx, symbol, instantiating_crate); @@ -700,8 +731,9 @@ pub(crate) fn linking_symbol_name_for_instance_in_crate<'tcx>( let prefix = match &target.arch[..] { "x86" => Some('_'), "x86_64" => None, - "arm64ec" => Some('#'), - // Only x86/64 use symbol decorations. + // Only functions are decorated for arm64ec. + "arm64ec" if export_kind == SymbolExportKind::Text => Some('#'), + // Only x86/64 and arm64ec use symbol decorations. _ => return undecorated, }; @@ -741,7 +773,7 @@ pub(crate) fn exporting_symbol_name_for_instance_in_crate<'tcx>( /// Add it to the symbols list for all kernel functions, so that it is exported in the linked /// object. pub(crate) fn extend_exported_symbols<'tcx>( - symbols: &mut Vec<String>, + symbols: &mut Vec<(String, SymbolExportKind)>, tcx: TyCtxt<'tcx>, symbol: ExportedSymbol<'tcx>, instantiating_crate: CrateNum, @@ -755,7 +787,9 @@ pub(crate) fn extend_exported_symbols<'tcx>( let undecorated = symbol_name_for_instance_in_crate(tcx, symbol, instantiating_crate); // Add the symbol for the kernel descriptor (with .kd suffix) - symbols.push(format!("{undecorated}.kd")); + // Per https://llvm.org/docs/AMDGPUUsage.html#symbols these will always be `STT_OBJECT` so + // export as data. + symbols.push((format!("{undecorated}.kd"), SymbolExportKind::Data)); } fn maybe_emutls_symbol_name<'tcx>( diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index c3bfe4c13cd..8330e4f7af0 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -1124,8 +1124,9 @@ fn start_executing_work<B: ExtraBackendMethods>( let copy_symbols = |cnum| { let symbols = tcx - .exported_symbols(cnum) + .exported_non_generic_symbols(cnum) .iter() + .chain(tcx.exported_generic_symbols(cnum)) .map(|&(s, lvl)| (symbol_name_for_instance_in_crate(tcx, s, cnum), lvl)) .collect(); Arc::new(symbols) diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index a3d6c73ba85..102d4ea2fa6 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -6,15 +6,15 @@ use std::time::{Duration, Instant}; use itertools::Itertools; use rustc_abi::FIRST_VARIANT; use rustc_ast as ast; -use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, AllocatorKind, global_fn_name}; +use rustc_ast::expand::allocator::AllocatorKind; use rustc_attr_data_structures::OptimizeAttr; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; use rustc_data_structures::sync::{IntoDynSyncSend, par_map}; use rustc_data_structures::unord::UnordMap; -use rustc_hir::ItemId; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::lang_items::LangItem; +use rustc_hir::{ItemId, Target}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType}; use rustc_middle::middle::exported_symbols::{self, SymbolExportKind}; @@ -262,28 +262,6 @@ pub(crate) fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } } -/// Coerces `src` to `dst_ty` which is guaranteed to be a `dyn*` type. -pub(crate) fn cast_to_dyn_star<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - bx: &mut Bx, - src: Bx::Value, - src_ty_and_layout: TyAndLayout<'tcx>, - dst_ty: Ty<'tcx>, - old_info: Option<Bx::Value>, -) -> (Bx::Value, Bx::Value) { - debug!("cast_to_dyn_star: {:?} => {:?}", src_ty_and_layout.ty, dst_ty); - assert!( - matches!(dst_ty.kind(), ty::Dynamic(_, _, ty::DynStar)), - "destination type must be a dyn*" - ); - let src = match bx.cx().type_kind(bx.cx().backend_type(src_ty_and_layout)) { - TypeKind::Pointer => src, - TypeKind::Integer => bx.inttoptr(src, bx.type_ptr()), - // FIXME(dyn-star): We probably have to do a bitcast first, then inttoptr. - kind => bug!("unexpected TypeKind for left-hand side of `dyn*` cast: {kind:?}"), - }; - (src, unsized_info(bx, src_ty_and_layout.ty, dst_ty, old_info)) -} - /// Coerces `src`, which is a reference to a value of type `src_ty`, /// to a value of type `dst_ty`, and stores the result in `dst`. pub(crate) fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( @@ -1003,21 +981,35 @@ impl CrateInfo { // by the compiler, but that's ok because all this stuff is unstable anyway. let target = &tcx.sess.target; if !are_upstream_rust_objects_already_included(tcx.sess) { - let missing_weak_lang_items: FxIndexSet<Symbol> = info + let add_prefix = match (target.is_like_windows, target.arch.as_ref()) { + (true, "x86") => |name: String, _: SymbolExportKind| format!("_{name}"), + (true, "arm64ec") => { + // Only functions are decorated for arm64ec. + |name: String, export_kind: SymbolExportKind| match export_kind { + SymbolExportKind::Text => format!("#{name}"), + _ => name, + } + } + _ => |name: String, _: SymbolExportKind| name, + }; + let missing_weak_lang_items: FxIndexSet<(Symbol, SymbolExportKind)> = info .used_crates .iter() .flat_map(|&cnum| tcx.missing_lang_items(cnum)) .filter(|l| l.is_weak()) .filter_map(|&l| { let name = l.link_name()?; - lang_items::required(tcx, l).then_some(name) + let export_kind = match l.target() { + Target::Fn => SymbolExportKind::Text, + Target::Static => SymbolExportKind::Data, + _ => bug!( + "Don't know what the export kind is for lang item of kind {:?}", + l.target() + ), + }; + lang_items::required(tcx, l).then_some((name, export_kind)) }) .collect(); - let prefix = match (target.is_like_windows, target.arch.as_ref()) { - (true, "x86") => "_", - (true, "arm64ec") => "#", - _ => "", - }; // This loop only adds new items to values of the hash map, so the order in which we // iterate over the values is not important. @@ -1030,35 +1022,18 @@ impl CrateInfo { .for_each(|(_, linked_symbols)| { let mut symbols = missing_weak_lang_items .iter() - .map(|item| { + .map(|(item, export_kind)| { ( - format!("{prefix}{}", mangle_internal_symbol(tcx, item.as_str())), - SymbolExportKind::Text, + add_prefix( + mangle_internal_symbol(tcx, item.as_str()), + *export_kind, + ), + *export_kind, ) }) .collect::<Vec<_>>(); symbols.sort_unstable_by(|a, b| a.0.cmp(&b.0)); linked_symbols.extend(symbols); - if tcx.allocator_kind(()).is_some() { - // At least one crate needs a global allocator. This crate may be placed - // after the crate that defines it in the linker order, in which case some - // linkers return an error. By adding the global allocator shim methods to - // the linked_symbols list, linking the generated symbols.o will ensure that - // circular dependencies involving the global allocator don't lead to linker - // errors. - linked_symbols.extend(ALLOCATOR_METHODS.iter().map(|method| { - ( - format!( - "{prefix}{}", - mangle_internal_symbol( - tcx, - global_fn_name(method.name).as_str() - ) - ), - SymbolExportKind::Text, - ) - })); - } }); } diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index f769b393528..6e2143858de 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -1,15 +1,15 @@ use std::str::FromStr; -use rustc_abi::ExternAbi; +use rustc_abi::{Align, ExternAbi}; use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode}; use rustc_ast::{LitKind, MetaItem, MetaItemInner, attr}; use rustc_attr_data_structures::{ - AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr, ReprAttr, find_attr, + AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr, ReprAttr, UsedBy, find_attr, }; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS; -use rustc_hir::{self as hir, HirId, LangItem, lang_items}; +use rustc_hir::{self as hir, LangItem, lang_items}; use rustc_middle::middle::codegen_fn_attrs::{ CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, }; @@ -87,7 +87,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { let mut link_ordinal_span = None; let mut no_sanitize_span = None; - let mut mixed_export_name_no_mangle_lint_state = MixedExportNameAndNoMangleState::default(); for attr in attrs.iter() { // In some cases, attribute are only valid on functions, but it's the `check_attr` @@ -95,17 +94,15 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { // In these cases, we bail from performing further checks that are only meaningful for // functions (such as calling `fn_sig`, which ICEs if given a non-function). We also // report a delayed bug, just in case `check_attr` isn't doing its job. - let fn_sig = || { + let fn_sig = |attr_span| { use DefKind::*; let def_kind = tcx.def_kind(did); if let Fn | AssocFn | Variant | Ctor(..) = def_kind { Some(tcx.fn_sig(did)) } else { - tcx.dcx().span_delayed_bug( - attr.span(), - "this attribute can only be applied to functions", - ); + tcx.dcx() + .span_delayed_bug(attr_span, "this attribute can only be applied to functions"); None } }; @@ -121,16 +118,18 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { .max(); } AttributeKind::Cold(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD, + AttributeKind::ExportName { name, .. } => { + codegen_fn_attrs.export_name = Some(*name); + } AttributeKind::Naked(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED, AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align), + AttributeKind::LinkName { name, .. } => codegen_fn_attrs.link_name = Some(*name), + AttributeKind::LinkSection { name, .. } => { + codegen_fn_attrs.link_section = Some(*name) + } AttributeKind::NoMangle(attr_span) => { if tcx.opt_item_name(did.to_def_id()).is_some() { codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE; - mixed_export_name_no_mangle_lint_state.track_no_mangle( - *attr_span, - tcx.local_def_id_to_hir_id(did), - attr, - ); } else { tcx.dcx().emit_err(NoMangleNameless { span: *attr_span, @@ -142,6 +141,33 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { }); } } + AttributeKind::TrackCaller(attr_span) => { + let is_closure = tcx.is_closure_like(did.to_def_id()); + + if !is_closure + && let Some(fn_sig) = fn_sig(*attr_span) + && fn_sig.skip_binder().abi() != ExternAbi::Rust + { + tcx.dcx().emit_err(errors::RequiresRustAbi { span: *attr_span }); + } + if is_closure + && !tcx.features().closure_track_caller() + && !attr_span.allows_unstable(sym::closure_track_caller) + { + feature_err( + &tcx.sess, + sym::closure_track_caller, + *attr_span, + "`#[track_caller]` on closures is currently unstable", + ) + .emit(); + } + codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER + } + AttributeKind::Used { used_by, .. } => match used_by { + UsedBy::Compiler => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_COMPILER, + UsedBy::Linker => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER, + }, _ => {} } } @@ -163,79 +189,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { sym::rustc_std_internal_symbol => { codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL } - sym::used => { - let inner = attr.meta_item_list(); - match inner.as_deref() { - Some([item]) if item.has_name(sym::linker) => { - if !tcx.features().used_with_arg() { - feature_err( - &tcx.sess, - sym::used_with_arg, - attr.span(), - "`#[used(linker)]` is currently unstable", - ) - .emit(); - } - codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER; - } - Some([item]) if item.has_name(sym::compiler) => { - if !tcx.features().used_with_arg() { - feature_err( - &tcx.sess, - sym::used_with_arg, - attr.span(), - "`#[used(compiler)]` is currently unstable", - ) - .emit(); - } - codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_COMPILER; - } - Some(_) => { - tcx.dcx().emit_err(errors::ExpectedUsedSymbol { span: attr.span() }); - } - None => { - // Unconditionally using `llvm.used` causes issues in handling - // `.init_array` with the gold linker. Luckily gold has been - // deprecated with GCC 15 and rustc now warns about using gold. - codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER - } - } - } sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL, - sym::track_caller => { - let is_closure = tcx.is_closure_like(did.to_def_id()); - - if !is_closure - && let Some(fn_sig) = fn_sig() - && fn_sig.skip_binder().abi() != ExternAbi::Rust - { - tcx.dcx().emit_err(errors::RequiresRustAbi { span: attr.span() }); - } - if is_closure - && !tcx.features().closure_track_caller() - && !attr.span().allows_unstable(sym::closure_track_caller) - { - feature_err( - &tcx.sess, - sym::closure_track_caller, - attr.span(), - "`#[track_caller]` on closures is currently unstable", - ) - .emit(); - } - codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER - } - sym::export_name => { - if let Some(s) = attr.value_str() { - if s.as_str().contains('\0') { - // `#[export_name = ...]` will be converted to a null-terminated string, - // so it may not contain any null characters. - tcx.dcx().emit_err(errors::NullOnExport { span: attr.span() }); - } - codegen_fn_attrs.export_name = Some(s); - mixed_export_name_no_mangle_lint_state.track_export_name(attr.span()); - } - } sym::target_feature => { let Some(sig) = tcx.hir_node_by_def_id(did).fn_sig() else { tcx.dcx().span_delayed_bug(attr.span(), "target_feature applied to non-fn"); @@ -302,17 +256,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } } } - sym::link_section => { - if let Some(val) = attr.value_str() { - if val.as_str().bytes().any(|b| b == 0) { - let msg = format!("illegal null byte in link_section value: `{val}`"); - tcx.dcx().span_err(attr.span(), msg); - } else { - codegen_fn_attrs.link_section = Some(val); - } - } - } - sym::link_name => codegen_fn_attrs.link_name = attr.value_str(), sym::link_ordinal => { link_ordinal_span = Some(attr.span()); if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) { @@ -446,12 +389,15 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } } - mixed_export_name_no_mangle_lint_state.lint_if_mixed(tcx); - - // Apply the minimum function alignment here, so that individual backends don't have to. + // Apply the minimum function alignment here. This ensures that a function's alignment is + // determined by the `-C` flags of the crate it is defined in, not the `-C` flags of the crate + // it happens to be codegen'd (or const-eval'd) in. codegen_fn_attrs.alignment = Ord::max(codegen_fn_attrs.alignment, tcx.sess.opts.unstable_opts.min_function_alignment); + // On trait methods, inherit the `#[align]` of the trait's method prototype. + codegen_fn_attrs.alignment = Ord::max(codegen_fn_attrs.alignment, tcx.inherited_align(did)); + let inline_span; (codegen_fn_attrs.inline, inline_span) = if let Some((inline_attr, span)) = find_attr!(attrs, AttributeKind::Inline(i, span) => (*i, *span)) @@ -606,17 +552,26 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { codegen_fn_attrs } +/// If the provided DefId is a method in a trait impl, return the DefId of the method prototype. +fn opt_trait_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> { + let impl_item = tcx.opt_associated_item(def_id)?; + match impl_item.container { + ty::AssocItemContainer::Impl => impl_item.trait_item_def_id, + _ => None, + } +} + /// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller /// applied to the method prototype. fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - if let Some(impl_item) = tcx.opt_associated_item(def_id) - && let ty::AssocItemContainer::Impl = impl_item.container - && let Some(trait_item) = impl_item.trait_item_def_id - { - return tcx.codegen_fn_attrs(trait_item).flags.intersects(CodegenFnAttrFlags::TRACK_CALLER); - } + let Some(trait_item) = opt_trait_item(tcx, def_id) else { return false }; + tcx.codegen_fn_attrs(trait_item).flags.intersects(CodegenFnAttrFlags::TRACK_CALLER) +} - false +/// If the provided DefId is a method in a trait impl, return the value of the `#[align]` +/// attribute on the method prototype (if any). +fn inherited_align<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option<Align> { + tcx.codegen_fn_attrs(opt_trait_item(tcx, def_id)?).alignment } fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &hir::Attribute) -> Option<u16> { @@ -674,49 +629,6 @@ fn check_link_name_xor_ordinal( } } -#[derive(Default)] -struct MixedExportNameAndNoMangleState<'a> { - export_name: Option<Span>, - hir_id: Option<HirId>, - no_mangle: Option<Span>, - no_mangle_attr: Option<&'a hir::Attribute>, -} - -impl<'a> MixedExportNameAndNoMangleState<'a> { - fn track_export_name(&mut self, span: Span) { - self.export_name = Some(span); - } - - fn track_no_mangle(&mut self, span: Span, hir_id: HirId, attr_name: &'a hir::Attribute) { - self.no_mangle = Some(span); - self.hir_id = Some(hir_id); - self.no_mangle_attr = Some(attr_name); - } - - /// Emit diagnostics if the lint condition is met. - fn lint_if_mixed(self, tcx: TyCtxt<'_>) { - if let Self { - export_name: Some(export_name), - no_mangle: Some(no_mangle), - hir_id: Some(hir_id), - no_mangle_attr: Some(_), - } = self - { - tcx.emit_node_span_lint( - lint::builtin::UNUSED_ATTRIBUTES, - hir_id, - no_mangle, - errors::MixedExportNameAndNoMangle { - no_mangle, - no_mangle_attr: "#[unsafe(no_mangle)]".to_string(), - export_name, - removal_span: no_mangle, - }, - ); - } - } -} - /// We now check the #\[rustc_autodiff\] attributes which we generated from the #[autodiff(...)] /// macros. There are two forms. The pure one without args to mark primal functions (the functions /// being differentiated). The other form is #[rustc_autodiff(Mode, ActivityList)] on top of the @@ -827,5 +739,6 @@ fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option<AutoDiffAttrs> { } pub(crate) fn provide(providers: &mut Providers) { - *providers = Providers { codegen_fn_attrs, should_inherit_track_caller, ..*providers }; + *providers = + Providers { codegen_fn_attrs, should_inherit_track_caller, inherited_align, ..*providers }; } diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index caac0f83f9d..1950a35b364 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -141,13 +141,6 @@ pub(crate) struct RequiresRustAbi { } #[derive(Diagnostic)] -#[diag(codegen_ssa_null_on_export, code = E0648)] -pub(crate) struct NullOnExport { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] #[diag(codegen_ssa_unsupported_instruction_set, code = E0779)] pub(crate) struct UnsupportedInstructionSet { #[primary_span] @@ -734,13 +727,6 @@ pub struct UnknownArchiveKind<'a> { } #[derive(Diagnostic)] -#[diag(codegen_ssa_expected_used_symbol)] -pub(crate) struct ExpectedUsedSymbol { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] #[diag(codegen_ssa_multiple_main_functions)] #[help] pub(crate) struct MultipleMainFunctions { @@ -1207,18 +1193,6 @@ pub(crate) struct ErrorCreatingImportLibrary<'a> { #[diag(codegen_ssa_aix_strip_not_used)] pub(crate) struct AixStripNotUsed; -#[derive(LintDiagnostic)] -#[diag(codegen_ssa_mixed_export_name_and_no_mangle)] -pub(crate) struct MixedExportNameAndNoMangle { - #[label] - pub no_mangle: Span, - pub no_mangle_attr: String, - #[note] - pub export_name: Span, - #[suggestion(style = "verbose", code = "", applicability = "machine-applicable")] - pub removal_span: Span, -} - #[derive(Diagnostic, Debug)] pub(crate) enum XcrunError { #[diag(codegen_ssa_xcrun_failed_invoking)] diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 523c9f2ad1c..23ed387a3ff 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -218,7 +218,7 @@ pub struct CrateInfo { pub target_cpu: String, pub target_features: Vec<String>, pub crate_types: Vec<CrateType>, - pub exported_symbols: UnordMap<CrateType, Vec<String>>, + pub exported_symbols: UnordMap<CrateType, Vec<(String, SymbolExportKind)>>, pub linked_symbols: FxIndexMap<CrateType, Vec<(String, SymbolExportKind)>>, pub local_crate_name: Symbol, pub compiler_builtins: Option<CrateNum>, diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 3df97429e09..bde63fd501a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -628,50 +628,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { virtual_drop, ) } - ty::Dynamic(_, _, ty::DynStar) => { - // IN THIS ARM, WE HAVE: - // ty = *mut (dyn* Trait) - // which is: *mut exists<T: sizeof(T) == sizeof(usize)> (T, Vtable<T: Trait>) - // - // args = [ * ] - // | - // v - // ( Data, Vtable ) - // | - // v - // /-------\ - // | ... | - // \-------/ - // - // - // WE CAN CONVERT THIS INTO THE ABOVE LOGIC BY DOING - // - // data = &(*args[0]).0 // gives a pointer to Data above (really the same pointer) - // vtable = (*args[0]).1 // loads the vtable out - // (data, vtable) // an equivalent Rust `*mut dyn Trait` - // - // SO THEN WE CAN USE THE ABOVE CODE. - let virtual_drop = Instance { - def: ty::InstanceKind::Virtual(drop_fn.def_id(), 0), // idx 0: the drop function - args: drop_fn.args, - }; - debug!("ty = {:?}", ty); - debug!("drop_fn = {:?}", drop_fn); - debug!("args = {:?}", args); - let fn_abi = bx.fn_abi_of_instance(virtual_drop, ty::List::empty()); - let meta_ptr = place.project_field(bx, 1); - let meta = bx.load_operand(meta_ptr); - // Truncate vtable off of args list - args = &args[..1]; - debug!("args' = {:?}", args); - ( - true, - meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE) - .get_optional_fn(bx, meta.immediate(), ty, fn_abi), - fn_abi, - virtual_drop, - ) - } _ => ( false, bx.get_fn_addr(drop_fn), @@ -776,6 +732,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // `#[track_caller]` adds an implicit argument. (LangItem::PanicNullPointerDereference, vec![location]) } + AssertKind::InvalidEnumConstruction(source) => { + let source = self.codegen_operand(bx, source).immediate(); + // It's `fn panic_invalid_enum_construction(source: u128)`, + // `#[track_caller]` adds an implicit argument. + (LangItem::PanicInvalidEnumConstruction, vec![source, location]) + } _ => { // It's `pub fn panic_...()` and `#[track_caller]` adds an implicit argument. (msg.panic_function(), vec![location]) @@ -1102,33 +1064,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { llargs.push(data_ptr); continue; } - Immediate(_) => { - // See comment above explaining why we peel these newtypes - while !op.layout.ty.is_raw_ptr() && !op.layout.ty.is_ref() { - let (idx, _) = op.layout.non_1zst_field(bx).expect( - "not exactly one non-1-ZST field in a `DispatchFromDyn` type", - ); - op = op.extract_field(self, bx, idx.as_usize()); - } - - // Make sure that we've actually unwrapped the rcvr down - // to a pointer or ref to `dyn* Trait`. - if !op.layout.ty.builtin_deref(true).unwrap().is_dyn_star() { - span_bug!(fn_span, "can't codegen a virtual call on {:#?}", op); - } - let place = op.deref(bx.cx()); - let data_place = place.project_field(bx, 0); - let meta_place = place.project_field(bx, 1); - let meta = bx.load_operand(meta_place); - llfn = Some(meth::VirtualIndex::from_index(idx).get_fn( - bx, - meta.immediate(), - op.layout.ty, - fn_abi, - )); - llargs.push(data_place.val.llval); - continue; - } _ => { span_bug!(fn_span, "can't codegen a virtual call on {:#?}", op); } diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 27fcab8ed2d..fc95f62b4a4 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -1,7 +1,7 @@ use rustc_abi::WrappingRange; -use rustc_middle::bug; use rustc_middle::mir::SourceInfo; use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::{bug, span_bug}; use rustc_session::config::OptLevel; use rustc_span::sym; @@ -98,6 +98,27 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { discr.to_atomic_ordering() }; + if args.is_empty() { + match name { + sym::abort + | sym::unreachable + | sym::cold_path + | sym::breakpoint + | sym::assert_zero_valid + | sym::assert_mem_uninitialized_valid + | sym::assert_inhabited + | sym::ub_checks + | sym::contract_checks + | sym::atomic_fence + | sym::atomic_singlethreadfence + | sym::caller_location => {} + _ => { + span_bug!(span, "nullary intrinsic {name} must either be in a const block or explicitly opted out because it is inherently a runtime intrinsic +"); + } + } + } + let llval = match name { sym::abort => { bx.abort(); @@ -150,10 +171,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } value } - sym::needs_drop | sym::type_id | sym::type_name | sym::variant_count => { - let value = bx.tcx().const_eval_instance(bx.typing_env(), instance, span).unwrap(); - OperandRef::from_const(bx, value, result.layout.ty).immediate_or_packed_pair(bx) - } sym::arith_offset => { let ty = fn_args.type_at(0); let layout = bx.layout_of(ty); diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 66c4af4c935..10b44a1faf0 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -354,15 +354,15 @@ fn optimize_use_clone<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let destination_block = target.unwrap(); - bb.statements.push(mir::Statement { - source_info: bb.terminator().source_info, - kind: mir::StatementKind::Assign(Box::new(( + bb.statements.push(mir::Statement::new( + bb.terminator().source_info, + mir::StatementKind::Assign(Box::new(( *destination, mir::Rvalue::Use(mir::Operand::Copy( arg_place.project_deeper(&[mir::ProjectionElem::Deref], tcx), )), ))), - }); + )); bb.terminator_mut().kind = mir::TerminatorKind::Goto { target: destination_block }; } diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 99957c67708..da615cc9a00 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -479,17 +479,8 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { _ => (tag_imm, bx.cx().immediate_backend_type(tag_op.layout)), }; - // Layout ensures that we only get here for cases where the discriminant + // `layout_sanity_check` ensures that we only get here for cases where the discriminant // value and the variant index match, since that's all `Niche` can encode. - // But for emphasis and debugging, let's double-check one anyway. - debug_assert_eq!( - self.layout - .ty - .discriminant_for_variant(bx.tcx(), untagged_variant) - .unwrap() - .val, - u128::from(untagged_variant.as_u32()), - ); let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32(); diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index e1d8b7546cf..7ef04213d32 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -468,12 +468,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bug!("unexpected non-pair operand"); } } - mir::CastKind::PointerCoercion(PointerCoercion::DynStar, _) => { - let (lldata, llextra) = operand.val.pointer_parts(); - let (lldata, llextra) = - base::cast_to_dyn_star(bx, lldata, operand.layout, cast.ty, llextra); - OperandValue::Pair(lldata, llextra) - } | mir::CastKind::IntToInt | mir::CastKind::FloatToInt | mir::CastKind::FloatToFloat @@ -1123,7 +1117,7 @@ pub(super) fn transmute_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // While optimizations will remove no-op transmutes, they might still be // there in debug or things that aren't no-op in MIR because they change // the Rust type but not the underlying layout/niche. - if from_scalar == to_scalar && from_backend_ty == to_backend_ty { + if from_scalar == to_scalar { return imm; } @@ -1142,7 +1136,13 @@ pub(super) fn transmute_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( assume_scalar_range(bx, imm, from_scalar, from_backend_ty); imm = match (from_scalar.primitive(), to_scalar.primitive()) { - (Int(..) | Float(_), Int(..) | Float(_)) => bx.bitcast(imm, to_backend_ty), + (Int(..) | Float(_), Int(..) | Float(_)) => { + if from_backend_ty == to_backend_ty { + imm + } else { + bx.bitcast(imm, to_backend_ty) + } + } (Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty), (Int(..), Pointer(..)) => bx.ptradd(bx.const_null(bx.type_ptr()), imm), (Pointer(..), Int(..)) => { diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index f35f551d590..d19de6f5d26 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -516,7 +516,7 @@ pub trait BuilderMethods<'a, 'tcx>: // These are used by everyone except msvc fn cleanup_landing_pad(&mut self, pers_fn: Self::Function) -> (Self::Value, Self::Value); - fn filter_landing_pad(&mut self, pers_fn: Self::Function) -> (Self::Value, Self::Value); + fn filter_landing_pad(&mut self, pers_fn: Self::Function); fn resume(&mut self, exn0: Self::Value, exn1: Self::Value); // These are used only by msvc diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 7f9abe8aa8e..22a1894ee72 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -124,16 +124,12 @@ const_eval_incompatible_return_types = const_eval_incompatible_types = calling a function with argument of type {$callee_ty} passing data of type {$caller_ty} -const_eval_interior_mutable_ref_escaping = - {const_eval_const_context}s cannot refer to interior mutable data - .label = this borrow of an interior mutable value may end up in the final value - .help = to fix this, the value can be extracted to a separate `static` item and then referenced - .teach_note = - References that escape into the final value of a constant or static must be immutable. - This is to avoid accidentally creating shared mutable state. - - - If you really want global mutable state, try using an interior mutable `static` or a `static mut`. +const_eval_interior_mutable_borrow_escaping = + interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed + .label = this borrow of an interior mutable value refers to such a temporary + .note = Temporaries in constants and statics can have their lifetime extended until the end of the program + .note2 = To avoid accidentally creating global mutable state, such temporaries must be immutable + .help = If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` const_eval_intern_kind = {$kind -> [static] static @@ -207,33 +203,20 @@ const_eval_long_running = .label = the const evaluator is currently interpreting this expression .help = the constant being evaluated -const_eval_max_num_nodes_in_const = maximum number of nodes exceeded in constant {$global_const_id} - const_eval_memory_exhausted = tried to allocate more memory than available to compiler const_eval_modified_global = modifying a static's initial value from another static's initializer -const_eval_mutable_ptr_in_final = encountered mutable pointer in final value of {const_eval_intern_kind} - -const_eval_mutable_raw_escaping = - raw mutable pointers are not allowed in the final value of {const_eval_const_context}s - .teach_note = - Pointers that escape into the final value of a constant or static must be immutable. - This is to avoid accidentally creating shared mutable state. - +const_eval_mutable_borrow_escaping = + mutable borrows of temporaries that have their lifetime extended until the end of the program are not allowed + .label = this mutable borrow refers to such a temporary + .note = Temporaries in constants and statics can have their lifetime extended until the end of the program + .note2 = To avoid accidentally creating global mutable state, such temporaries must be immutable + .help = If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` - If you really want global mutable state, try using an interior mutable `static` or a `static mut`. - -const_eval_mutable_ref_escaping = - mutable references are not allowed in the final value of {const_eval_const_context}s - .teach_note = - References that escape into the final value of a constant or static must be immutable. - This is to avoid accidentally creating shared mutable state. - - - If you really want global mutable state, try using an interior mutable `static` or a `static mut`. +const_eval_mutable_ptr_in_final = encountered mutable pointer in final value of {const_eval_intern_kind} const_eval_nested_static_in_thread_local = #[thread_local] does not support implicit nested statics, please create explicit static items and refer to them instead @@ -280,9 +263,6 @@ const_eval_non_const_try_block_from_output = const_eval_not_enough_caller_args = calling a function with fewer arguments than it requires -const_eval_nullary_intrinsic_fail = - could not evaluate nullary intrinsic - const_eval_offset_from_different_allocations = `{$name}` called on two different pointers that are not both derived from the same allocation const_eval_offset_from_out_of_bounds = @@ -361,7 +341,7 @@ const_eval_realloc_or_alloc_with_offset = *[other] {""} } {$ptr} which does not point to the beginning of an object -const_eval_recursive_static = encountered static that tried to initialize itself with itself +const_eval_recursive_static = encountered static that tried to access itself during initialization const_eval_remainder_by_zero = calculating the remainder with a divisor of zero @@ -437,9 +417,6 @@ const_eval_unwind_past_top = ## (We'd love to sort this differently to make that more clear but tidy won't let us...) const_eval_validation_box_to_uninhabited = {$front_matter}: encountered a box pointing to uninhabited type {$ty} -const_eval_validation_const_ref_to_extern = {$front_matter}: encountered reference to `extern` static in `const` -const_eval_validation_const_ref_to_mutable = {$front_matter}: encountered reference to mutable memory in `const` - const_eval_validation_dangling_box_no_provenance = {$front_matter}: encountered a dangling box ({$pointer} has no provenance) const_eval_validation_dangling_box_out_of_bounds = {$front_matter}: encountered a dangling box (going beyond the bounds of its allocation) const_eval_validation_dangling_box_use_after_free = {$front_matter}: encountered a dangling box (use-after-free) @@ -479,6 +456,7 @@ const_eval_validation_invalid_ref_meta = {$front_matter}: encountered invalid re const_eval_validation_invalid_ref_slice_meta = {$front_matter}: encountered invalid reference metadata: slice is bigger than largest supported object const_eval_validation_invalid_vtable_ptr = {$front_matter}: encountered {$value}, but expected a vtable pointer const_eval_validation_invalid_vtable_trait = {$front_matter}: wrong trait in wide pointer vtable: expected `{$expected_dyn_type}`, but encountered `{$vtable_dyn_type}` +const_eval_validation_mutable_ref_in_const = {$front_matter}: encountered mutable reference in `const` value const_eval_validation_mutable_ref_to_immutable = {$front_matter}: encountered mutable reference or box pointing to read-only memory const_eval_validation_never_val = {$front_matter}: encountered a value of the never type `!` const_eval_validation_null_box = {$front_matter}: encountered a null box diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 576b174369d..0eb6f28bdb3 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -421,7 +421,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { Some(ConstConditionsHold::Yes) } else { tcx.dcx() - .span_delayed_bug(call_span, "this should have reported a ~const error in HIR"); + .span_delayed_bug(call_span, "this should have reported a [const] error in HIR"); Some(ConstConditionsHold::No) } } @@ -595,11 +595,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { self.const_kind() == hir::ConstContext::Static(hir::Mutability::Mut); if !is_allowed && self.place_may_escape(place) { - self.check_op(ops::EscapingMutBorrow(if matches!(rvalue, Rvalue::Ref(..)) { - hir::BorrowKind::Ref - } else { - hir::BorrowKind::Raw - })); + self.check_op(ops::EscapingMutBorrow); } } @@ -642,14 +638,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // These are all okay; they only change the type, not the data. } - Rvalue::Cast( - CastKind::PointerCoercion(PointerCoercion::Unsize | PointerCoercion::DynStar, _), - _, - _, - ) => { - // Unsizing and `dyn*` coercions are implemented for CTFE. - } - Rvalue::Cast(CastKind::PointerExposeProvenance, _, _) => { self.check_op(ops::RawPtrToIntCast); } diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index 887275e7294..b2e0577cc82 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -149,7 +149,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { debug!(?param_ty); if let Some(generics) = tcx.hir_node_by_def_id(caller).generics() { let constraint = with_no_trimmed_paths!(format!( - "~const {}", + "[const] {}", trait_ref.print_trait_sugared(), )); suggest_constraining_type_param( @@ -567,12 +567,7 @@ impl<'tcx> NonConstOp<'tcx> for EscapingCellBorrow { DiagImportance::Secondary } fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - ccx.dcx().create_err(errors::InteriorMutableRefEscaping { - span, - opt_help: matches!(ccx.const_kind(), hir::ConstContext::Static(_)), - kind: ccx.const_kind(), - teach: ccx.tcx.sess.teach(E0492), - }) + ccx.dcx().create_err(errors::InteriorMutableBorrowEscaping { span, kind: ccx.const_kind() }) } } @@ -580,7 +575,7 @@ impl<'tcx> NonConstOp<'tcx> for EscapingCellBorrow { /// This op is for `&mut` borrows in the trailing expression of a constant /// which uses the "enclosing scopes rule" to leak its locals into anonymous /// static or const items. -pub(crate) struct EscapingMutBorrow(pub hir::BorrowKind); +pub(crate) struct EscapingMutBorrow; impl<'tcx> NonConstOp<'tcx> for EscapingMutBorrow { fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status { @@ -594,18 +589,7 @@ impl<'tcx> NonConstOp<'tcx> for EscapingMutBorrow { } fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - match self.0 { - hir::BorrowKind::Raw => ccx.tcx.dcx().create_err(errors::MutableRawEscaping { - span, - kind: ccx.const_kind(), - teach: ccx.tcx.sess.teach(E0764), - }), - hir::BorrowKind::Ref => ccx.dcx().create_err(errors::MutableRefEscaping { - span, - kind: ccx.const_kind(), - teach: ccx.tcx.sess.teach(E0764), - }), - } + ccx.dcx().create_err(errors::MutableBorrowEscaping { span, kind: ccx.const_kind() }) } } diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index c1a37ab6a83..166491b47a1 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -170,14 +170,14 @@ impl Qualif for NeedsNonConstDrop { #[instrument(level = "trace", skip(cx), ret)] fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool { - // If this doesn't need drop at all, then don't select `~const Destruct`. + // If this doesn't need drop at all, then don't select `[const] Destruct`. if !ty.needs_drop(cx.tcx, cx.typing_env) { return false; } - // We check that the type is `~const Destruct` since that will verify that - // the type is both `~const Drop` (if a drop impl exists for the adt), *and* - // that the components of this type are also `~const Destruct`. This + // We check that the type is `[const] Destruct` since that will verify that + // the type is both `[const] Drop` (if a drop impl exists for the adt), *and* + // that the components of this type are also `[const] Destruct`. This // amounts to verifying that there are no values in this ADT that may have // a non-const drop. let destruct_def_id = cx.tcx.require_lang_item(LangItem::Destruct, cx.body.span); @@ -203,9 +203,9 @@ impl Qualif for NeedsNonConstDrop { fn is_structural_in_adt_value<'tcx>(cx: &ConstCx<'_, 'tcx>, adt: AdtDef<'tcx>) -> bool { // As soon as an ADT has a destructor, then the drop becomes non-structural // in its value since: - // 1. The destructor may have `~const` bounds which are not present on the type. + // 1. The destructor may have `[const]` bounds which are not present on the type. // Someone needs to check that those are satisfied. - // While this could be instead satisfied by checking that the `~const Drop` + // While this could be instead satisfied by checking that the `[const] Drop` // impl holds (i.e. replicating part of the `in_any_value_of_ty` logic above), // even in this case, we have another problem, which is, // 2. The destructor may *modify* the operand being dropped, so even if we diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index be840191547..08e1877f0eb 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -7,7 +7,7 @@ use rustc_hir::def::DefKind; use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo, ReportedErrorInfo}; use rustc_middle::mir::{self, ConstAlloc, ConstValue}; use rustc_middle::query::TyCtxtAt; -use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf}; +use rustc_middle::ty::layout::HasTypingEnv; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, throw_inval}; @@ -20,7 +20,7 @@ use crate::const_eval::CheckAlignment; use crate::interpret::{ CtfeValidationMode, GlobalId, Immediate, InternKind, InternResult, InterpCx, InterpErrorKind, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, StackPopCleanup, create_static_alloc, - eval_nullary_intrinsic, intern_const_alloc_recursive, interp_ok, throw_exhaust, + intern_const_alloc_recursive, interp_ok, throw_exhaust, }; use crate::{CTRL_C_RECEIVED, errors}; @@ -209,9 +209,9 @@ pub(super) fn op_to_const<'tcx>( match immediate { Left(ref mplace) => { - // We know `offset` is relative to the allocation, so we can use `into_parts`. - let (prov, offset) = mplace.ptr().into_parts(); - let alloc_id = prov.expect("cannot have `fake` place for non-ZST type").alloc_id(); + let (prov, offset) = + mplace.ptr().into_pointer_or_addr().unwrap().prov_and_relative_offset(); + let alloc_id = prov.alloc_id(); ConstValue::Indirect { alloc_id, offset } } // see comment on `let force_as_immediate` above @@ -232,9 +232,10 @@ pub(super) fn op_to_const<'tcx>( imm.layout.ty, ); let msg = "`op_to_const` on an immediate scalar pair must only be used on slice references to the beginning of an actual allocation"; - // We know `offset` is relative to the allocation, so we can use `into_parts`. - let (prov, offset) = a.to_pointer(ecx).expect(msg).into_parts(); - let alloc_id = prov.expect(msg).alloc_id(); + let ptr = a.to_pointer(ecx).expect(msg); + let (prov, offset) = + ptr.into_pointer_or_addr().expect(msg).prov_and_relative_offset(); + let alloc_id = prov.alloc_id(); let data = ecx.tcx.global_alloc(alloc_id).unwrap_memory(); assert!(offset == abi::Size::ZERO, "{}", msg); let meta = b.to_target_usize(ecx).expect(msg); @@ -280,34 +281,6 @@ pub fn eval_to_const_value_raw_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>, ) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> { - // We call `const_eval` for zero arg intrinsics, too, in order to cache their value. - // Catch such calls and evaluate them instead of trying to load a constant's MIR. - if let ty::InstanceKind::Intrinsic(def_id) = key.value.instance.def { - let ty = key.value.instance.ty(tcx, key.typing_env); - let ty::FnDef(_, args) = ty.kind() else { - bug!("intrinsic with type {:?}", ty); - }; - return eval_nullary_intrinsic(tcx, key.typing_env, def_id, args).report_err().map_err( - |error| { - let span = tcx.def_span(def_id); - - // FIXME(oli-obk): why don't we have any tests for this code path? - super::report( - tcx, - error.into_kind(), - span, - || (span, vec![]), - |diag, span, _| { - diag.span_label( - span, - crate::fluent_generated::const_eval_nullary_intrinsic_fail, - ); - }, - ) - }, - ); - } - tcx.eval_to_allocation_raw(key).map(|val| turn_into_const_value(tcx, val, key)) } diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index a68dcf29988..317b1229a90 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -62,7 +62,7 @@ pub struct CompileTimeMachine<'tcx> { /// If `Some`, we are evaluating the initializer of the static with the given `LocalDefId`, /// storing the result in the given `AllocId`. - /// Used to prevent reads from a static's base allocation, as that may allow for self-initialization loops. + /// Used to prevent accesses to a static's base allocation, as that may allow for self-initialization loops. pub(crate) static_root_ids: Option<(AllocId, LocalDefId)>, /// A cache of "data range" computations for unions (i.e., the offsets of non-padding bytes). @@ -508,6 +508,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { found: eval_to_int(found)?, }, NullPointerDereference => NullPointerDereference, + InvalidEnumConstruction(source) => InvalidEnumConstruction(eval_to_int(source)?), }; Err(ConstEvalErrKind::AssertFailure(err)).into() } @@ -705,19 +706,27 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { interp_ok(()) } - fn before_alloc_read(ecx: &InterpCx<'tcx, Self>, alloc_id: AllocId) -> InterpResult<'tcx> { + fn before_alloc_access( + tcx: TyCtxtAt<'tcx>, + machine: &Self, + alloc_id: AllocId, + ) -> InterpResult<'tcx> { + if machine.stack.is_empty() { + // Get out of the way for the final copy. + return interp_ok(()); + } // Check if this is the currently evaluated static. - if Some(alloc_id) == ecx.machine.static_root_ids.map(|(id, _)| id) { + if Some(alloc_id) == machine.static_root_ids.map(|(id, _)| id) { return Err(ConstEvalErrKind::RecursiveStatic).into(); } // If this is another static, make sure we fire off the query to detect cycles. // But only do that when checks for static recursion are enabled. - if ecx.machine.static_root_ids.is_some() { - if let Some(GlobalAlloc::Static(def_id)) = ecx.tcx.try_get_global_alloc(alloc_id) { - if ecx.tcx.is_foreign_item(def_id) { + if machine.static_root_ids.is_some() { + if let Some(GlobalAlloc::Static(def_id)) = tcx.try_get_global_alloc(alloc_id) { + if tcx.is_foreign_item(def_id) { throw_unsup!(ExternStatic(def_id)); } - ecx.ctfe_query(|tcx| tcx.eval_static_initializer(def_id))?; + tcx.eval_static_initializer(def_id)?; } } interp_ok(()) diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index 6fd0b9d26e3..d95d552d7d5 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -2,7 +2,6 @@ use rustc_abi::{FieldIdx, VariantIdx}; use rustc_middle::query::Key; -use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, mir}; use tracing::instrument; @@ -26,13 +25,6 @@ pub(crate) use self::valtrees::{eval_to_valtree, valtree_to_const_value}; // We forbid type-level constants that contain more than `VALTREE_MAX_NODES` nodes. const VALTREE_MAX_NODES: usize = 100000; -pub(crate) enum ValTreeCreationError<'tcx> { - NodesOverflow, - /// Values of this type, or this particular value, are not supported as valtrees. - NonSupportedType(Ty<'tcx>), -} -pub(crate) type ValTreeCreationResult<'tcx> = Result<ty::ValTree<'tcx>, ValTreeCreationError<'tcx>>; - #[instrument(skip(tcx), level = "debug")] pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>( tcx: TyCtxt<'tcx>, @@ -74,18 +66,13 @@ pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>( #[instrument(skip(tcx), level = "debug")] pub fn tag_for_variant_provider<'tcx>( tcx: TyCtxt<'tcx>, - (ty, variant_index): (Ty<'tcx>, VariantIdx), + key: ty::PseudoCanonicalInput<'tcx, (Ty<'tcx>, VariantIdx)>, ) -> Option<ty::ScalarInt> { + let (ty, variant_index) = key.value; assert!(ty.is_enum()); - // FIXME: This uses an empty `TypingEnv` even though - // it may be used by a generic CTFE. - let ecx = InterpCx::new( - tcx, - ty.default_span(tcx), - ty::TypingEnv::fully_monomorphized(), - crate::const_eval::DummyMachine, - ); + let ecx = + InterpCx::new(tcx, ty.default_span(tcx), key.typing_env, crate::const_eval::DummyMachine); let layout = ecx.layout_of(ty).unwrap(); ecx.tag_for_variant(layout, variant_index).unwrap().map(|(tag, _tag_field)| tag) diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 58d230af683..5ab72c853c4 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -1,17 +1,16 @@ use rustc_abi::{BackendRepr, FieldIdx, VariantIdx}; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId, ReportedErrorInfo}; -use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout}; +use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId, ValTreeCreationError}; +use rustc_middle::ty::layout::{LayoutCx, TyAndLayout}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, mir}; use rustc_span::DUMMY_SP; use tracing::{debug, instrument, trace}; +use super::VALTREE_MAX_NODES; use super::eval_queries::{mk_eval_cx_to_read_const_val, op_to_const}; use super::machine::CompileTimeInterpCx; -use super::{VALTREE_MAX_NODES, ValTreeCreationError, ValTreeCreationResult}; use crate::const_eval::CanAccessMutGlobal; -use crate::errors::MaxNumNodesInConstErr; use crate::interpret::{ ImmTy, Immediate, InternKind, MPlaceTy, MemPlaceMeta, MemoryKind, PlaceTy, Projectable, Scalar, intern_const_alloc_recursive, @@ -24,7 +23,7 @@ fn branches<'tcx>( field_count: usize, variant: Option<VariantIdx>, num_nodes: &mut usize, -) -> ValTreeCreationResult<'tcx> { +) -> EvalToValTreeResult<'tcx> { let place = match variant { Some(variant) => ecx.project_downcast(place, variant).unwrap(), None => place.clone(), @@ -58,7 +57,7 @@ fn slice_branches<'tcx>( ecx: &CompileTimeInterpCx<'tcx>, place: &MPlaceTy<'tcx>, num_nodes: &mut usize, -) -> ValTreeCreationResult<'tcx> { +) -> EvalToValTreeResult<'tcx> { let n = place.len(ecx).unwrap_or_else(|_| panic!("expected to use len of place {place:?}")); let mut elems = Vec::with_capacity(n as usize); @@ -76,7 +75,7 @@ fn const_to_valtree_inner<'tcx>( ecx: &CompileTimeInterpCx<'tcx>, place: &MPlaceTy<'tcx>, num_nodes: &mut usize, -) -> ValTreeCreationResult<'tcx> { +) -> EvalToValTreeResult<'tcx> { let tcx = *ecx.tcx; let ty = place.layout.ty; debug!("ty kind: {:?}", ty.kind()); @@ -91,7 +90,7 @@ fn const_to_valtree_inner<'tcx>( Ok(ty::ValTree::zst(tcx)) } ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => { - let val = ecx.read_immediate(place).unwrap(); + let val = ecx.read_immediate(place).report_err()?; let val = val.to_scalar_int().unwrap(); *num_nodes += 1; @@ -113,7 +112,7 @@ fn const_to_valtree_inner<'tcx>( // equality at compile-time (see `ptr_guaranteed_cmp`). // However we allow those that are just integers in disguise. // First, get the pointer. Remember it might be wide! - let val = ecx.read_immediate(place).unwrap(); + let val = ecx.read_immediate(place).report_err()?; // We could allow wide raw pointers where both sides are integers in the future, // but for now we reject them. if matches!(val.layout.backend_repr, BackendRepr::ScalarPair(..)) { @@ -134,7 +133,7 @@ fn const_to_valtree_inner<'tcx>( ty::FnPtr(..) => Err(ValTreeCreationError::NonSupportedType(ty)), ty::Ref(_, _, _) => { - let derefd_place = ecx.deref_pointer(place).unwrap(); + let derefd_place = ecx.deref_pointer(place).report_err()?; const_to_valtree_inner(ecx, &derefd_place, num_nodes) } @@ -158,7 +157,7 @@ fn const_to_valtree_inner<'tcx>( bug!("uninhabited types should have errored and never gotten converted to valtree") } - let variant = ecx.read_discriminant(place).unwrap(); + let variant = ecx.read_discriminant(place).report_err()?; branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant), num_nodes) } @@ -249,24 +248,7 @@ pub(crate) fn eval_to_valtree<'tcx>( debug!(?place); let mut num_nodes = 0; - let valtree_result = const_to_valtree_inner(&ecx, &place, &mut num_nodes); - - match valtree_result { - Ok(valtree) => Ok(Ok(valtree)), - Err(err) => { - let did = cid.instance.def_id(); - let global_const_id = cid.display(tcx); - let span = tcx.hir_span_if_local(did); - match err { - ValTreeCreationError::NodesOverflow => { - let handled = - tcx.dcx().emit_err(MaxNumNodesInConstErr { span, global_const_id }); - Err(ReportedErrorInfo::allowed_in_infallible(handled).into()) - } - ValTreeCreationError::NonSupportedType(ty) => Ok(Err(ty)), - } - } - } + const_to_valtree_inner(&ecx, &place, &mut num_nodes) } /// Converts a `ValTree` to a `ConstValue`, which is needed after mir diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 69c71aef9f3..9133a5fc8ef 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -93,14 +93,6 @@ pub(crate) struct PanicNonStrErr { } #[derive(Diagnostic)] -#[diag(const_eval_max_num_nodes_in_const)] -pub(crate) struct MaxNumNodesInConstErr { - #[primary_span] - pub span: Option<Span>, - pub global_const_id: String, -} - -#[derive(Diagnostic)] #[diag(const_eval_unallowed_fn_pointer_call)] pub(crate) struct UnallowedFnPointerCall { #[primary_span] @@ -158,25 +150,18 @@ pub(crate) struct UnmarkedIntrinsicExposed { } #[derive(Diagnostic)] -#[diag(const_eval_mutable_ref_escaping, code = E0764)] -pub(crate) struct MutableRefEscaping { +#[diag(const_eval_mutable_borrow_escaping, code = E0764)] +#[note] +#[note(const_eval_note2)] +#[help] +pub(crate) struct MutableBorrowEscaping { #[primary_span] + #[label] pub span: Span, pub kind: ConstContext, - #[note(const_eval_teach_note)] - pub teach: bool, } #[derive(Diagnostic)] -#[diag(const_eval_mutable_raw_escaping, code = E0764)] -pub(crate) struct MutableRawEscaping { - #[primary_span] - pub span: Span, - pub kind: ConstContext, - #[note(const_eval_teach_note)] - pub teach: bool, -} -#[derive(Diagnostic)] #[diag(const_eval_non_const_fmt_macro_call, code = E0015)] pub(crate) struct NonConstFmtMacroCall { #[primary_span] @@ -233,16 +218,15 @@ pub(crate) struct UnallowedInlineAsm { } #[derive(Diagnostic)] -#[diag(const_eval_interior_mutable_ref_escaping, code = E0492)] -pub(crate) struct InteriorMutableRefEscaping { +#[diag(const_eval_interior_mutable_borrow_escaping, code = E0492)] +#[note] +#[note(const_eval_note2)] +#[help] +pub(crate) struct InteriorMutableBorrowEscaping { #[primary_span] #[label] pub span: Span, - #[help] - pub opt_help: bool, pub kind: ConstContext, - #[note(const_eval_teach_note)] - pub teach: bool, } #[derive(LintDiagnostic)] @@ -291,6 +275,9 @@ impl Subdiagnostic for FrameNote { span.push_span_label(self.span, fluent::const_eval_frame_note_last); } let msg = diag.eagerly_translate(fluent::const_eval_frame_note); + diag.remove_arg("times"); + diag.remove_arg("where_"); + diag.remove_arg("instance"); diag.span_note(span, msg); } } @@ -587,7 +574,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { if addr != 0 { diag.arg( "pointer", - Pointer::<Option<CtfeProvenance>>::from_addr_invalid(addr).to_string(), + Pointer::<Option<CtfeProvenance>>::without_provenance(addr).to_string(), ); } @@ -652,9 +639,8 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { PointerAsInt { .. } => const_eval_validation_pointer_as_int, PartialPointer => const_eval_validation_partial_pointer, - ConstRefToMutable => const_eval_validation_const_ref_to_mutable, - ConstRefToExtern => const_eval_validation_const_ref_to_extern, MutableRefToImmutable => const_eval_validation_mutable_ref_to_immutable, + MutableRefInConst => const_eval_validation_mutable_ref_in_const, NullFnPtr => const_eval_validation_null_fn_ptr, NeverVal => const_eval_validation_never_val, NullablePtrOutOfRange { .. } => const_eval_validation_nullable_ptr_out_of_range, @@ -812,9 +798,8 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { err.arg("expected_dyn_type", expected_dyn_type.to_string()); } NullPtr { .. } - | ConstRefToMutable - | ConstRefToExtern | MutableRefToImmutable + | MutableRefInConst | NullFnPtr | NeverVal | UnsafeCellInImmutable diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index 37677f9e048..ebaa5a97a4a 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -6,7 +6,7 @@ use std::borrow::Cow; use either::{Left, Right}; use rustc_abi::{self as abi, ExternAbi, FieldIdx, Integer, VariantIdx}; use rustc_hir::def_id::DefId; -use rustc_middle::ty::layout::{FnAbiOf, IntegerExt, LayoutOf, TyAndLayout}; +use rustc_middle::ty::layout::{FnAbiOf, IntegerExt, TyAndLayout}; use rustc_middle::ty::{self, AdtDef, Instance, Ty, VariantDef}; use rustc_middle::{bug, mir, span_bug}; use rustc_span::sym; @@ -643,13 +643,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { break self.ref_to_mplace(&val)?; } ty::Dynamic(.., ty::Dyn) => break receiver.assert_mem_place(), // no immediate unsized values - ty::Dynamic(.., ty::DynStar) => { - // Not clear how to handle this, so far we assume the receiver is always a pointer. - span_bug!( - self.cur_span(), - "by-value calls on a `dyn*`... are those a thing?" - ); - } _ => { // Not there yet, search for the only non-ZST field. // (The rules for `DispatchFromDyn` ensure there's exactly one such field.) @@ -662,39 +655,23 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { }; // Obtain the underlying trait we are working on, and the adjusted receiver argument. - let (trait_, dyn_ty, adjusted_recv) = if let ty::Dynamic(data, _, ty::DynStar) = - receiver_place.layout.ty.kind() - { - let recv = self.unpack_dyn_star(&receiver_place, data)?; - - (data.principal(), recv.layout.ty, recv.ptr()) - } else { - // Doesn't have to be a `dyn Trait`, but the unsized tail must be `dyn Trait`. - // (For that reason we also cannot use `unpack_dyn_trait`.) - let receiver_tail = - self.tcx.struct_tail_for_codegen(receiver_place.layout.ty, self.typing_env); - let ty::Dynamic(receiver_trait, _, ty::Dyn) = receiver_tail.kind() else { - span_bug!( - self.cur_span(), - "dynamic call on non-`dyn` type {}", - receiver_tail - ) - }; - assert!(receiver_place.layout.is_unsized()); - - // Get the required information from the vtable. - let vptr = receiver_place.meta().unwrap_meta().to_pointer(self)?; - let dyn_ty = self.get_ptr_vtable_ty(vptr, Some(receiver_trait))?; - - // It might be surprising that we use a pointer as the receiver even if this - // is a by-val case; this works because by-val passing of an unsized `dyn - // Trait` to a function is actually desugared to a pointer. - (receiver_trait.principal(), dyn_ty, receiver_place.ptr()) + // Doesn't have to be a `dyn Trait`, but the unsized tail must be `dyn Trait`. + // (For that reason we also cannot use `unpack_dyn_trait`.) + let receiver_tail = + self.tcx.struct_tail_for_codegen(receiver_place.layout.ty, self.typing_env); + let ty::Dynamic(receiver_trait, _, ty::Dyn) = receiver_tail.kind() else { + span_bug!(self.cur_span(), "dynamic call on non-`dyn` type {}", receiver_tail) }; + assert!(receiver_place.layout.is_unsized()); + + // Get the required information from the vtable. + let vptr = receiver_place.meta().unwrap_meta().to_pointer(self)?; + let dyn_ty = self.get_ptr_vtable_ty(vptr, Some(receiver_trait))?; + let adjusted_recv = receiver_place.ptr(); // Now determine the actual method to call. Usually we use the easy way of just // looking up the method at index `idx`. - let vtable_entries = self.vtable_entries(trait_, dyn_ty); + let vtable_entries = self.vtable_entries(receiver_trait.principal(), dyn_ty); let Some(ty::VtblEntry::Method(fn_inst)) = vtable_entries.get(idx).copied() else { // FIXME(fee1-dead) these could be variants of the UB info enum instead of this throw_ub_custom!(fluent::const_eval_dyn_call_not_a_method); @@ -830,10 +807,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Dropping a trait object. Need to find actual drop fn. self.unpack_dyn_trait(&place, data)? } - ty::Dynamic(data, _, ty::DynStar) => { - // Dropping a `dyn*`. Need to find actual drop fn. - self.unpack_dyn_star(&place, data)? - } _ => { debug_assert_eq!( instance, diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 9e15f4572d7..7a73d70fc85 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -6,7 +6,7 @@ use rustc_apfloat::{Float, FloatConvert}; use rustc_middle::mir::CastKind; use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar}; use rustc_middle::ty::adjustment::PointerCoercion; -use rustc_middle::ty::layout::{IntegerExt, LayoutOf, TyAndLayout}; +use rustc_middle::ty::layout::{IntegerExt, TyAndLayout}; use rustc_middle::ty::{self, FloatTy, Ty}; use rustc_middle::{bug, span_bug}; use tracing::trace; @@ -126,20 +126,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } - CastKind::PointerCoercion(PointerCoercion::DynStar, _) => { - if let ty::Dynamic(data, _, ty::DynStar) = cast_ty.kind() { - // Initial cast from sized to dyn trait - let vtable = self.get_vtable_ptr(src.layout.ty, data)?; - let vtable = Scalar::from_maybe_pointer(vtable, self); - let data = self.read_immediate(src)?.to_scalar(); - let _assert_pointer_like = data.to_pointer(self)?; - let val = Immediate::ScalarPair(data, vtable); - self.write_immediate(val, dest)?; - } else { - bug!() - } - } - CastKind::Transmute => { assert!(src.layout.is_sized()); assert!(dest.layout.is_sized()); diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs index 6c4b000e16b..b7e7f65c95c 100644 --- a/compiler/rustc_const_eval/src/interpret/discriminant.rs +++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs @@ -1,7 +1,7 @@ //! Functions for reading and writing discriminants of multi-variant layouts (enums and coroutines). use rustc_abi::{self as abi, FieldIdx, TagEncoding, VariantIdx, Variants}; -use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt, TyAndLayout}; +use rustc_middle::ty::layout::{PrimitiveExt, TyAndLayout}; use rustc_middle::ty::{self, CoroutineArgsExt, ScalarInt, Ty}; use rustc_middle::{mir, span_bug}; use tracing::{instrument, trace}; diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index b69bc0918be..46c784b41c6 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -7,7 +7,8 @@ use rustc_hir::def_id::DefId; use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo}; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::layout::{ - self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, TyAndLayout, + self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers, + TyAndLayout, }; use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypingEnv, Variance}; use rustc_middle::{mir, span_bug}; @@ -21,7 +22,7 @@ use super::{ MemPlaceMeta, Memory, OpTy, Place, PlaceTy, PointerArithmetic, Projectable, Provenance, err_inval, interp_ok, throw_inval, throw_ub, throw_ub_custom, }; -use crate::{ReportErrorExt, fluent_generated as fluent, util}; +use crate::{ReportErrorExt, enter_trace_span, fluent_generated as fluent, util}; pub struct InterpCx<'tcx, M: Machine<'tcx>> { /// Stores the `Machine` instance. @@ -91,6 +92,20 @@ impl<'tcx, M: Machine<'tcx>> LayoutOfHelpers<'tcx> for InterpCx<'tcx, M> { } } +impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { + /// This inherent method takes priority over the trait method with the same name in LayoutOf, + /// and allows wrapping the actual [LayoutOf::layout_of] with a tracing span. + /// See [LayoutOf::layout_of] for the original documentation. + #[inline] + pub fn layout_of( + &self, + ty: Ty<'tcx>, + ) -> <InterpCx<'tcx, M> as LayoutOfHelpers<'tcx>>::LayoutOfResult { + let _span = enter_trace_span!(M, "InterpCx::layout_of", "ty = {:?}", ty.kind()); + LayoutOf::layout_of(self, ty) + } +} + impl<'tcx, M: Machine<'tcx>> FnAbiOfHelpers<'tcx> for InterpCx<'tcx, M> { type FnAbiOfResult = Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, InterpErrorKind<'tcx>>; @@ -284,6 +299,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { frame: &Frame<'tcx, M::Provenance, M::FrameExtra>, value: T, ) -> Result<T, ErrorHandled> { + let _span = enter_trace_span!( + M, + "instantiate_from_frame_and_normalize_erasing_regions", + "{}", + frame.instance + ); frame .instance .try_instantiate_mir_and_normalize_erasing_regions( @@ -362,7 +383,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Returns the actual dynamic size and alignment of the place at the given type. /// Only the "meta" (metadata) part of the place matters. /// This can fail to provide an answer for extern types. - pub(super) fn size_and_align_of( + pub(super) fn size_and_align_from_meta( &self, metadata: &MemPlaceMeta<M::Provenance>, layout: &TyAndLayout<'tcx>, @@ -388,7 +409,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // adjust alignment and size for them? let field = layout.field(self, layout.fields.count() - 1); let Some((unsized_size, mut unsized_align)) = - self.size_and_align_of(metadata, &field)? + self.size_and_align_from_meta(metadata, &field)? else { // A field with an extern type. We don't know the actual dynamic size // or the alignment. @@ -450,11 +471,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } #[inline] - pub fn size_and_align_of_mplace( + pub fn size_and_align_of_val( &self, - mplace: &MPlaceTy<'tcx, M::Provenance>, + val: &impl Projectable<'tcx, M::Provenance>, ) -> InterpResult<'tcx, Option<(Size, Align)>> { - self.size_and_align_of(&mplace.meta(), &mplace.layout) + self.size_and_align_from_meta(&val.meta(), &val.layout()) } /// Jump to the given block. diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 96c39c7bb32..d7cede71293 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -6,10 +6,9 @@ use std::assert_matches::assert_matches; use rustc_abi::Size; use rustc_apfloat::ieee::{Double, Half, Quad, Single}; -use rustc_hir::def_id::DefId; use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic}; -use rustc_middle::ty::layout::{LayoutOf as _, TyAndLayout, ValidityRequirement}; -use rustc_middle::ty::{GenericArgsRef, Ty, TyCtxt}; +use rustc_middle::ty::layout::{TyAndLayout, ValidityRequirement}; +use rustc_middle::ty::{Ty, TyCtxt}; use rustc_middle::{bug, ty}; use rustc_span::{Symbol, sym}; use tracing::trace; @@ -17,8 +16,8 @@ use tracing::trace; use super::memory::MemoryKind; use super::util::ensure_monomorphic_enough; use super::{ - Allocation, CheckInAllocMsg, ConstAllocation, GlobalId, ImmTy, InterpCx, InterpResult, Machine, - OpTy, PlaceTy, Pointer, PointerArithmetic, Provenance, Scalar, err_inval, err_ub_custom, + Allocation, CheckInAllocMsg, ConstAllocation, ImmTy, InterpCx, InterpResult, Machine, OpTy, + PlaceTy, Pointer, PointerArithmetic, Provenance, Scalar, err_inval, err_ub_custom, err_unsup_format, interp_ok, throw_inval, throw_ub_custom, throw_ub_format, }; use crate::fluent_generated as fluent; @@ -30,73 +29,6 @@ pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAll tcx.mk_const_alloc(alloc) } -/// The logic for all nullary intrinsics is implemented here. These intrinsics don't get evaluated -/// inside an `InterpCx` and instead have their value computed directly from rustc internal info. -pub(crate) fn eval_nullary_intrinsic<'tcx>( - tcx: TyCtxt<'tcx>, - typing_env: ty::TypingEnv<'tcx>, - def_id: DefId, - args: GenericArgsRef<'tcx>, -) -> InterpResult<'tcx, ConstValue<'tcx>> { - let tp_ty = args.type_at(0); - let name = tcx.item_name(def_id); - interp_ok(match name { - sym::type_name => { - ensure_monomorphic_enough(tcx, tp_ty)?; - let alloc = alloc_type_name(tcx, tp_ty); - ConstValue::Slice { data: alloc, meta: alloc.inner().size().bytes() } - } - sym::needs_drop => { - ensure_monomorphic_enough(tcx, tp_ty)?; - ConstValue::from_bool(tp_ty.needs_drop(tcx, typing_env)) - } - sym::type_id => { - ensure_monomorphic_enough(tcx, tp_ty)?; - ConstValue::from_u128(tcx.type_id_hash(tp_ty).as_u128()) - } - sym::variant_count => match match tp_ty.kind() { - // Pattern types have the same number of variants as their base type. - // Even if we restrict e.g. which variants are valid, the variants are essentially just uninhabited. - // And `Result<(), !>` still has two variants according to `variant_count`. - ty::Pat(base, _) => *base, - _ => tp_ty, - } - .kind() - { - // Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough. - ty::Adt(adt, _) => ConstValue::from_target_usize(adt.variants().len() as u64, &tcx), - ty::Alias(..) | ty::Param(_) | ty::Placeholder(_) | ty::Infer(_) => { - throw_inval!(TooGeneric) - } - ty::Pat(..) => unreachable!(), - ty::Bound(_, _) => bug!("bound ty during ctfe"), - ty::Bool - | ty::Char - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Foreign(_) - | ty::Str - | ty::Array(_, _) - | ty::Slice(_) - | ty::RawPtr(_, _) - | ty::Ref(_, _, _) - | ty::FnDef(_, _) - | ty::FnPtr(..) - | ty::Dynamic(_, _, _) - | ty::Closure(_, _) - | ty::CoroutineClosure(_, _) - | ty::Coroutine(_, _) - | ty::CoroutineWitness(..) - | ty::UnsafeBinder(_) - | ty::Never - | ty::Tuple(_) - | ty::Error(_) => ConstValue::from_target_usize(0u64, &tcx), - }, - other => bug!("`{}` is not a zero arg intrinsic", other), - }) -} - impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Returns `true` if emulation happened. /// Here we implement the intrinsics that are common to all Miri instances; individual machines can add their own @@ -110,8 +42,77 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> InterpResult<'tcx, bool> { let instance_args = instance.args; let intrinsic_name = self.tcx.item_name(instance.def_id()); + let tcx = self.tcx.tcx; match intrinsic_name { + sym::type_name => { + let tp_ty = instance.args.type_at(0); + ensure_monomorphic_enough(tcx, tp_ty)?; + let alloc = alloc_type_name(tcx, tp_ty); + let val = ConstValue::Slice { data: alloc, meta: alloc.inner().size().bytes() }; + let val = self.const_val_to_op(val, dest.layout.ty, Some(dest.layout))?; + self.copy_op(&val, dest)?; + } + sym::needs_drop => { + let tp_ty = instance.args.type_at(0); + ensure_monomorphic_enough(tcx, tp_ty)?; + let val = ConstValue::from_bool(tp_ty.needs_drop(tcx, self.typing_env)); + let val = self.const_val_to_op(val, tcx.types.bool, Some(dest.layout))?; + self.copy_op(&val, dest)?; + } + sym::type_id => { + let tp_ty = instance.args.type_at(0); + ensure_monomorphic_enough(tcx, tp_ty)?; + let val = ConstValue::from_u128(tcx.type_id_hash(tp_ty).as_u128()); + let val = self.const_val_to_op(val, dest.layout.ty, Some(dest.layout))?; + self.copy_op(&val, dest)?; + } + sym::variant_count => { + let tp_ty = instance.args.type_at(0); + let ty = match tp_ty.kind() { + // Pattern types have the same number of variants as their base type. + // Even if we restrict e.g. which variants are valid, the variants are essentially just uninhabited. + // And `Result<(), !>` still has two variants according to `variant_count`. + ty::Pat(base, _) => *base, + _ => tp_ty, + }; + let val = match ty.kind() { + // Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough. + ty::Adt(adt, _) => { + ConstValue::from_target_usize(adt.variants().len() as u64, &tcx) + } + ty::Alias(..) | ty::Param(_) | ty::Placeholder(_) | ty::Infer(_) => { + throw_inval!(TooGeneric) + } + ty::Pat(..) => unreachable!(), + ty::Bound(_, _) => bug!("bound ty during ctfe"), + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Foreign(_) + | ty::Str + | ty::Array(_, _) + | ty::Slice(_) + | ty::RawPtr(_, _) + | ty::Ref(_, _, _) + | ty::FnDef(_, _) + | ty::FnPtr(..) + | ty::Dynamic(_, _, _) + | ty::Closure(_, _) + | ty::CoroutineClosure(_, _) + | ty::Coroutine(_, _) + | ty::CoroutineWitness(..) + | ty::UnsafeBinder(_) + | ty::Never + | ty::Tuple(_) + | ty::Error(_) => ConstValue::from_target_usize(0u64, &tcx), + }; + let val = self.const_val_to_op(val, dest.layout.ty, Some(dest.layout))?; + self.copy_op(&val, dest)?; + } + sym::caller_location => { let span = self.find_closest_untracked_caller_location(); let val = self.tcx.span_as_caller_location(span); @@ -125,7 +126,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // dereferenceable! let place = self.ref_to_mplace(&self.read_immediate(&args[0])?)?; let (size, align) = self - .size_and_align_of_mplace(&place)? + .size_and_align_of_val(&place)? .ok_or_else(|| err_unsup_format!("`extern type` does not have known layout"))?; let result = match intrinsic_name { @@ -137,21 +138,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.write_scalar(Scalar::from_target_usize(result, self), dest)?; } - sym::needs_drop | sym::type_id | sym::type_name | sym::variant_count => { - let gid = GlobalId { instance, promoted: None }; - let ty = self - .tcx - .fn_sig(instance.def_id()) - .instantiate(self.tcx.tcx, instance.args) - .output() - .no_bound_vars() - .unwrap(); - let val = self - .ctfe_query(|tcx| tcx.const_eval_global_id(self.typing_env, gid, tcx.span))?; - let val = self.const_val_to_op(val, ty, Some(dest.layout))?; - self.copy_op(&val, dest)?; - } - sym::fadd_algebraic | sym::fsub_algebraic | sym::fmul_algebraic diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index b9e022c9604..35ec303f961 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -443,7 +443,11 @@ pub trait Machine<'tcx>: Sized { /// /// Used to prevent statics from self-initializing by reading from their own memory /// as it is being initialized. - fn before_alloc_read(_ecx: &InterpCx<'tcx, Self>, _alloc_id: AllocId) -> InterpResult<'tcx> { + fn before_alloc_access( + _tcx: TyCtxtAt<'tcx>, + _machine: &Self, + _alloc_id: AllocId, + ) -> InterpResult<'tcx> { interp_ok(()) } @@ -743,7 +747,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) { // Allow these casts, but make the pointer not dereferenceable. // (I.e., they behave like transmutation.) // This is correct because no pointers can ever be exposed in compile-time evaluation. - interp_ok(Pointer::from_addr_invalid(addr)) + interp_ok(Pointer::without_provenance(addr)) } #[inline(always)] @@ -752,8 +756,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) { ptr: Pointer<CtfeProvenance>, _size: i64, ) -> Option<(AllocId, Size, Self::ProvenanceExtra)> { - // We know `offset` is relative to the allocation, so we can use `into_parts`. - let (prov, offset) = ptr.into_parts(); + let (prov, offset) = ptr.prov_and_relative_offset(); Some((prov.alloc_id(), offset, prov.immutable())) } diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 57bf867e389..3b36bb85985 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -720,7 +720,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // do this after `check_and_deref_ptr` to ensure some basic sanity has already been checked. if !self.memory.validation_in_progress.get() { if let Ok((alloc_id, ..)) = self.ptr_try_get_alloc_id(ptr, size_i64) { - M::before_alloc_read(self, alloc_id)?; + M::before_alloc_access(self.tcx, &self.machine, alloc_id)?; } } @@ -821,6 +821,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if let Some((alloc_id, offset, prov, alloc, machine)) = ptr_and_alloc { let range = alloc_range(offset, size); if !validation_in_progress { + // For writes, it's okay to only call those when there actually is a non-zero + // amount of bytes to be written: a zero-sized write doesn't manifest anything. + M::before_alloc_access(tcx, machine, alloc_id)?; M::before_memory_write( tcx, machine, @@ -1396,6 +1399,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let src_parts = self.get_ptr_access(src, size)?; let dest_parts = self.get_ptr_access(dest, size * num_copies)?; // `Size` multiplication + // Similar to `get_ptr_alloc`, we need to call `before_alloc_access` even for zero-sized + // reads. However, just like in `get_ptr_alloc_mut`, the write part is okay to skip for + // zero-sized writes. + if let Ok((alloc_id, ..)) = self.ptr_try_get_alloc_id(src, size.bytes().try_into().unwrap()) + { + M::before_alloc_access(tcx, &self.machine, alloc_id)?; + } + // FIXME: we look up both allocations twice here, once before for the `check_ptr_access` // and once below to get the underlying `&[mut] Allocation`. @@ -1408,12 +1419,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let src_range = alloc_range(src_offset, size); assert!(!self.memory.validation_in_progress.get(), "we can't be copying during validation"); - // Trigger read hooks. - // For the overlapping case, it is crucial that we trigger the read hooks + // Trigger read hook. + // For the overlapping case, it is crucial that we trigger the read hook // before the write hook -- the aliasing model cares about the order. - if let Ok((alloc_id, ..)) = self.ptr_try_get_alloc_id(src, size.bytes() as i64) { - M::before_alloc_read(self, alloc_id)?; - } M::before_memory_read( tcx, &self.machine, @@ -1438,16 +1446,18 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let provenance = src_alloc .provenance() .prepare_copy(src_range, dest_offset, num_copies, self) - .map_err(|e| e.to_interp_error(dest_alloc_id))?; + .map_err(|e| e.to_interp_error(src_alloc_id))?; // Prepare a copy of the initialization mask. let init = src_alloc.init_mask().prepare_copy(src_range); - // Destination alloc preparations and access hooks. - let (dest_alloc, extra) = self.get_alloc_raw_mut(dest_alloc_id)?; + // Destination alloc preparations... + let (dest_alloc, machine) = self.get_alloc_raw_mut(dest_alloc_id)?; let dest_range = alloc_range(dest_offset, size * num_copies); + // ...and access hooks. + M::before_alloc_access(tcx, machine, dest_alloc_id)?; M::before_memory_write( tcx, - extra, + machine, &mut dest_alloc.extra, dest, (dest_alloc_id, dest_prov), @@ -1586,7 +1596,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Some((alloc_id, offset, extra)) => Ok((alloc_id, offset, extra)), None => { assert!(M::Provenance::OFFSET_IS_ADDR); - let (_, addr) = ptr.into_parts(); + // Offset is absolute, as we just asserted. + let (_, addr) = ptr.into_raw_parts(); Err(addr.bytes()) } }, diff --git a/compiler/rustc_const_eval/src/interpret/mod.rs b/compiler/rustc_const_eval/src/interpret/mod.rs index f5792aba207..f8b3c92debb 100644 --- a/compiler/rustc_const_eval/src/interpret/mod.rs +++ b/compiler/rustc_const_eval/src/interpret/mod.rs @@ -29,7 +29,6 @@ pub use self::intern::{ HasStaticRootDefId, InternKind, InternResult, intern_const_alloc_for_constprop, intern_const_alloc_recursive, }; -pub(crate) use self::intrinsics::eval_nullary_intrinsic; pub use self::machine::{AllocMap, Machine, MayLeak, ReturnAction, compile_time_machine}; pub use self::memory::{AllocInfo, AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind}; use self::operand::Operand; diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 77667ba823a..62cbbae24a8 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -8,7 +8,7 @@ use rustc_abi as abi; use rustc_abi::{BackendRepr, HasDataLayout, Size}; use rustc_hir::def::Namespace; use rustc_middle::mir::interpret::ScalarSizeMismatch; -use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout}; +use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, TyAndLayout}; use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter}; use rustc_middle::ty::{ConstInt, ScalarInt, Ty, TyCtxt}; use rustc_middle::{bug, mir, span_bug, ty}; @@ -878,9 +878,9 @@ mod size_asserts { use super::*; // tidy-alphabetical-start - static_assert_size!(Immediate, 48); static_assert_size!(ImmTy<'_>, 64); - static_assert_size!(Operand, 56); + static_assert_size!(Immediate, 48); static_assert_size!(OpTy<'_>, 72); + static_assert_size!(Operand, 56); // tidy-alphabetical-end } diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index 899670aeb62..74f8a0a7b09 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -3,7 +3,7 @@ use rustc_abi::Size; use rustc_apfloat::{Float, FloatConvert}; use rustc_middle::mir::NullOp; use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar}; -use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; +use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{self, FloatTy, ScalarInt, Ty}; use rustc_middle::{bug, mir, span_bug}; use rustc_span::sym; diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index f5d3de7b1b2..a3cd35ff0bb 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -7,7 +7,7 @@ use std::assert_matches::assert_matches; use either::{Either, Left, Right}; use rustc_abi::{BackendRepr, HasDataLayout, Size}; use rustc_middle::ty::Ty; -use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; +use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::{bug, mir, span_bug}; use tracing::{instrument, trace}; @@ -118,7 +118,7 @@ impl<'tcx, Prov: Provenance> MPlaceTy<'tcx, Prov> { pub fn fake_alloc_zst(layout: TyAndLayout<'tcx>) -> Self { assert!(layout.is_zst()); let align = layout.align.abi; - let ptr = Pointer::from_addr_invalid(align.bytes()); // no provenance, absolute address + let ptr = Pointer::without_provenance(align.bytes()); // no provenance, absolute address MPlaceTy { mplace: MemPlace { ptr, meta: MemPlaceMeta::None, misaligned: None }, layout } } @@ -470,7 +470,7 @@ where ) -> InterpResult<'tcx, Option<AllocRef<'_, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>> { let (size, _align) = self - .size_and_align_of_mplace(mplace)? + .size_and_align_of_val(mplace)? .unwrap_or((mplace.layout.size, mplace.layout.align.abi)); // We check alignment separately, and *after* checking everything else. // If an access is both OOB and misaligned, we want to see the bounds error. @@ -486,7 +486,7 @@ where ) -> InterpResult<'tcx, Option<AllocRefMut<'_, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>> { let (size, _align) = self - .size_and_align_of_mplace(mplace)? + .size_and_align_of_val(mplace)? .unwrap_or((mplace.layout.size, mplace.layout.align.abi)); // We check alignment separately, and raise that error *after* checking everything else. // If an access is both OOB and misaligned, we want to see the bounds error. @@ -888,11 +888,11 @@ where trace!("copy_op: {:?} <- {:?}: {}", *dest, src, dest.layout().ty); let dest = dest.force_mplace(self)?; - let Some((dest_size, _)) = self.size_and_align_of_mplace(&dest)? else { + let Some((dest_size, _)) = self.size_and_align_of_val(&dest)? else { span_bug!(self.cur_span(), "copy_op needs (dynamically) sized values") }; if cfg!(debug_assertions) { - let src_size = self.size_and_align_of_mplace(&src)?.unwrap().0; + let src_size = self.size_and_align_of_val(&src)?.unwrap().0; assert_eq!(src_size, dest_size, "Cannot copy differently-sized data"); } else { // As a cheap approximation, we compare the fixed parts of the size. @@ -980,7 +980,7 @@ where kind: MemoryKind<M::MemoryKind>, meta: MemPlaceMeta<M::Provenance>, ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { - let Some((size, align)) = self.size_and_align_of(&meta, &layout)? else { + let Some((size, align)) = self.size_and_align_from_meta(&meta, &layout)? else { span_bug!(self.cur_span(), "cannot allocate space for `extern` type, size is not known") }; let ptr = self.allocate_ptr(size, align, kind, AllocInit::Uninit)?; @@ -1056,9 +1056,9 @@ mod size_asserts { use super::*; // tidy-alphabetical-start + static_assert_size!(MPlaceTy<'_>, 64); static_assert_size!(MemPlace, 48); static_assert_size!(MemPlaceMeta, 24); - static_assert_size!(MPlaceTy<'_>, 64); static_assert_size!(Place, 48); static_assert_size!(PlaceTy<'_>, 64); // tidy-alphabetical-end diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index ad47a19a14d..306697d4ec9 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -12,7 +12,7 @@ use std::ops::Range; use rustc_abi::{self as abi, FieldIdx, Size, VariantIdx}; use rustc_middle::ty::Ty; -use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; +use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::{bug, mir, span_bug, ty}; use tracing::{debug, instrument}; @@ -168,7 +168,7 @@ where // Re-use parent metadata to determine dynamic field layout. // With custom DSTS, this *will* execute user-defined code, but the same // happens at run-time so that's okay. - match self.size_and_align_of(&base_meta, &field_layout)? { + match self.size_and_align_from_meta(&base_meta, &field_layout)? { Some((_, align)) => { // For packed types, we need to cap alignment. let align = if let ty::Adt(def, _) = base.layout().ty.kind() diff --git a/compiler/rustc_const_eval/src/interpret/stack.rs b/compiler/rustc_const_eval/src/interpret/stack.rs index 2a2d1bb2754..543d68d7f45 100644 --- a/compiler/rustc_const_eval/src/interpret/stack.rs +++ b/compiler/rustc_const_eval/src/interpret/stack.rs @@ -7,7 +7,7 @@ use either::{Either, Left, Right}; use rustc_hir as hir; use rustc_hir::definitions::DefPathData; use rustc_index::IndexVec; -use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; +use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, mir}; use rustc_mir_dataflow::impls::always_storage_live_locals; @@ -499,8 +499,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Never - | ty::Error(_) - | ty::Dynamic(_, _, ty::DynStar) => true, + | ty::Error(_) => true, ty::Str | ty::Slice(_) | ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => false, diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs index 7249ef23bf6..e4b5c82853a 100644 --- a/compiler/rustc_const_eval/src/interpret/traits.rs +++ b/compiler/rustc_const_eval/src/interpret/traits.rs @@ -1,6 +1,5 @@ -use rustc_abi::{Align, FieldIdx, Size}; +use rustc_abi::{Align, Size}; use rustc_middle::mir::interpret::{InterpResult, Pointer}; -use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, ExistentialPredicateStableCmpExt, Ty, TyCtxt, VtblEntry}; use tracing::trace; @@ -126,24 +125,4 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { )?; interp_ok(mplace) } - - /// Turn a `dyn* Trait` type into an value with the actual dynamic type. - pub(super) fn unpack_dyn_star<P: Projectable<'tcx, M::Provenance>>( - &self, - val: &P, - expected_trait: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, - ) -> InterpResult<'tcx, P> { - assert!( - matches!(val.layout().ty.kind(), ty::Dynamic(_, _, ty::DynStar)), - "`unpack_dyn_star` only makes sense on `dyn*` types" - ); - let data = self.project_field(val, FieldIdx::ZERO)?; - let vtable = self.project_field(val, FieldIdx::ONE)?; - let vtable = self.read_pointer(&vtable.to_op(self)?)?; - let ty = self.get_ptr_vtable_ty(vtable, Some(expected_trait))?; - // `data` is already the right thing but has the wrong type. So we transmute it. - let layout = self.layout_of(ty)?; - let data = data.transmute(layout, self)?; - interp_ok(data) - } } diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 7d76d925ef2..e26cf0a4900 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -24,7 +24,7 @@ use rustc_middle::mir::interpret::{ ExpectedKind, InterpErrorKind, InvalidMetaKind, Misalignment, PointerKind, Provenance, UnsupportedOpInfo, ValidationErrorInfo, alloc_range, interp_ok, }; -use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout}; +use rustc_middle::ty::layout::{LayoutCx, TyAndLayout}; use rustc_middle::ty::{self, Ty}; use rustc_span::{Symbol, sym}; use tracing::trace; @@ -35,6 +35,7 @@ use super::{ Machine, MemPlaceMeta, PlaceTy, Pointer, Projectable, Scalar, ValueVisitor, err_ub, format_interp_error, }; +use crate::enter_trace_span; // for the validation errors #[rustfmt::skip] @@ -357,9 +358,6 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { // arrays/slices ty::Array(..) | ty::Slice(..) => PathElem::ArrayElem(field), - // dyn* vtables - ty::Dynamic(_, _, ty::DynKind::DynStar) if field == 1 => PathElem::Vtable, - // dyn traits ty::Dynamic(..) => { assert_eq!(field, 0); @@ -493,7 +491,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { } // Make sure this is dereferenceable and all. let size_and_align = try_validation!( - self.ecx.size_and_align_of_mplace(&place), + self.ecx.size_and_align_of_val(&place), self.path, Ub(InvalidMeta(msg)) => match msg { InvalidMetaKind::SliceTooBig => InvalidMetaSliceTooLarge { ptr_kind }, @@ -517,7 +515,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { Ub(DanglingIntPointer { addr: i, .. }) => DanglingPtrNoProvenance { ptr_kind, // FIXME this says "null pointer" when null but we need translate - pointer: format!("{}", Pointer::<Option<AllocId>>::from_addr_invalid(i)) + pointer: format!("{}", Pointer::<Option<AllocId>>::without_provenance(i)) }, Ub(PointerOutOfBounds { .. }) => DanglingPtrOutOfBounds { ptr_kind @@ -570,6 +568,8 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { }; let (size, _align) = global_alloc.size_and_align(*self.ecx.tcx, self.ecx.typing_env); + let alloc_actual_mutbl = + global_alloc.mutability(*self.ecx.tcx, self.ecx.typing_env); if let GlobalAlloc::Static(did) = global_alloc { let DefKind::Static { nested, .. } = self.ecx.tcx.def_kind(did) else { @@ -597,9 +597,11 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { skip_recursive_check = !nested; } CtfeValidationMode::Const { .. } => { - // We can't recursively validate `extern static`, so we better reject them. - if self.ecx.tcx.is_foreign_item(did) { - throw_validation_failure!(self.path, ConstRefToExtern); + // If this is mutable memory or an `extern static`, there's no point in checking it -- we'd + // just get errors trying to read the value. + if alloc_actual_mutbl.is_mut() || self.ecx.tcx.is_foreign_item(did) + { + skip_recursive_check = true; } } } @@ -618,9 +620,6 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { mutbl } }; - // Determine what it actually points to. - let alloc_actual_mutbl = - global_alloc.mutability(*self.ecx.tcx, self.ecx.typing_env); // Mutable pointer to immutable memory is no good. if ptr_expected_mutbl == Mutability::Mut && alloc_actual_mutbl == Mutability::Not @@ -628,12 +627,10 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { // This can actually occur with transmutes. throw_validation_failure!(self.path, MutableRefToImmutable); } - // In a const, everything must be completely immutable. + // In a const, any kind of mutable reference is not good. if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. })) { - if ptr_expected_mutbl == Mutability::Mut - || alloc_actual_mutbl == Mutability::Mut - { - throw_validation_failure!(self.path, ConstRefToMutable); + if ptr_expected_mutbl == Mutability::Mut { + throw_validation_failure!(self.path, MutableRefInConst); } } } @@ -868,7 +865,9 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { fn add_data_range(&mut self, ptr: Pointer<Option<M::Provenance>>, size: Size) { if let Some(data_bytes) = self.data_bytes.as_mut() { // We only have to store the offset, the rest is the same for all pointers here. - let (_prov, offset) = ptr.into_parts(); + // The logic is agnostic to wether the offset is relative or absolute as long as + // it is consistent. + let (_prov, offset) = ptr.into_raw_parts(); // Add this. data_bytes.add_range(offset, size); }; @@ -894,7 +893,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { .as_mplace_or_imm() .expect_left("place must be in memory") .ptr(); - let (_prov, offset) = ptr.into_parts(); + let (_prov, offset) = ptr.into_raw_parts(); offset } @@ -903,10 +902,10 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { // Our value must be in memory, otherwise we would not have set up `data_bytes`. let mplace = self.ecx.force_allocation(place)?; // Determine starting offset and size. - let (_prov, start_offset) = mplace.ptr().into_parts(); + let (_prov, start_offset) = mplace.ptr().into_raw_parts(); let (size, _align) = self .ecx - .size_and_align_of_mplace(&mplace)? + .size_and_align_of_val(&mplace)? .unwrap_or((mplace.layout.size, mplace.layout.align.abi)); // If there is no padding at all, we can skip the rest: check for // a single data range covering the entire value. @@ -1086,8 +1085,10 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, ) -> InterpResult<'tcx> { // Special check for CTFE validation, preventing `UnsafeCell` inside unions in immutable memory. if self.ctfe_mode.is_some_and(|c| !c.allow_immutable_unsafe_cell()) { - if !val.layout.is_zst() && !val.layout.ty.is_freeze(*self.ecx.tcx, self.ecx.typing_env) - { + // Unsized unions are currently not a thing, but let's keep this code consistent with + // the check in `visit_value`. + let zst = self.ecx.size_and_align_of_val(val)?.is_some_and(|(s, _a)| s.bytes() == 0); + if !zst && !val.layout.ty.is_freeze(*self.ecx.tcx, self.ecx.typing_env) { if !self.in_mutable_memory(val) { throw_validation_failure!(self.path, UnsafeCellInImmutable); } @@ -1131,7 +1132,10 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, // Special check preventing `UnsafeCell` in the inner part of constants if self.ctfe_mode.is_some_and(|c| !c.allow_immutable_unsafe_cell()) { - if !val.layout.is_zst() + // Exclude ZST values. We need to compute the dynamic size/align to properly + // handle slices and trait objects. + let zst = self.ecx.size_and_align_of_val(val)?.is_some_and(|(s, _a)| s.bytes() == 0); + if !zst && let Some(def) = val.layout.ty.ty_adt_def() && def.is_unsafe_cell() { @@ -1364,8 +1368,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { }) } - /// This function checks the data at `op` to be const-valid. - /// `op` is assumed to cover valid memory if it is an indirect operand. + /// This function checks the data at `val` to be const-valid. + /// `val` is assumed to cover valid memory if it is an indirect operand. /// It will error if the bits at the destination do not match the ones described by the layout. /// /// `ref_tracking` is used to record references that we encounter so that they @@ -1391,8 +1395,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) } - /// This function checks the data at `op` to be runtime-valid. - /// `op` is assumed to cover valid memory if it is an indirect operand. + /// This function checks the data at `val` to be runtime-valid. + /// `val` is assumed to cover valid memory if it is an indirect operand. /// It will error if the bits at the destination do not match the ones described by the layout. #[inline(always)] pub fn validate_operand( @@ -1401,6 +1405,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { recursive: bool, reset_provenance_and_padding: bool, ) -> InterpResult<'tcx> { + let _span = enter_trace_span!( + M, + "validate_operand", + "recursive={recursive}, reset_provenance_and_padding={reset_provenance_and_padding}, val={val:?}" + ); + // Note that we *could* actually be in CTFE here with `-Zextra-const-ub-checks`, but it's // still correct to not use `ctfe_mode`: that mode is for validation of the final constant // value, it rules out things like `UnsafeCell` in awkward places. diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs index 5aea91233bd..a27b6646131 100644 --- a/compiler/rustc_const_eval/src/interpret/visitor.rs +++ b/compiler/rustc_const_eval/src/interpret/visitor.rs @@ -6,7 +6,6 @@ use std::num::NonZero; use rustc_abi::{FieldIdx, FieldsShape, VariantIdx, Variants}; use rustc_index::IndexVec; use rustc_middle::mir::interpret::InterpResult; -use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Ty}; use tracing::trace; @@ -102,26 +101,6 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized { // recurse with the inner type return self.visit_field(v, 0, &inner_mplace.into()); } - ty::Dynamic(data, _, ty::DynStar) => { - // DynStar types. Very different from a dyn type (but strangely part of the - // same variant in `TyKind`): These are pairs where the 2nd component is the - // vtable, and the first component is the data (which must be ptr-sized). - - // First make sure the vtable can be read at its type. - // The type of this vtable is fake, it claims to be a reference to some actual memory but that isn't true. - // So we transmute it to a raw pointer. - let raw_ptr_ty = Ty::new_mut_ptr(*self.ecx().tcx, self.ecx().tcx.types.unit); - let raw_ptr_ty = self.ecx().layout_of(raw_ptr_ty)?; - let vtable_field = self - .ecx() - .project_field(v, FieldIdx::ONE)? - .transmute(raw_ptr_ty, self.ecx())?; - self.visit_field(v, 1, &vtable_field)?; - - // Then unpack the first field, and continue. - let data = self.ecx().unpack_dyn_star(v, data)?; - return self.visit_field(v, 0, &data); - } // Slices do not need special handling here: they have `Array` field // placement with length 0, so we enter the `Array` case below which // indirectly uses the metadata to determine the actual length. diff --git a/compiler/rustc_const_eval/src/util/caller_location.rs b/compiler/rustc_const_eval/src/util/caller_location.rs index 671214002a0..f489b05fbbd 100644 --- a/compiler/rustc_const_eval/src/util/caller_location.rs +++ b/compiler/rustc_const_eval/src/util/caller_location.rs @@ -1,6 +1,5 @@ use rustc_abi::FieldIdx; use rustc_hir::LangItem; -use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::{bug, mir}; use rustc_span::Symbol; @@ -22,13 +21,14 @@ fn alloc_caller_location<'tcx>( assert!(!filename.as_str().as_bytes().contains(&0)); let loc_details = ecx.tcx.sess.opts.unstable_opts.location_detail; - let file_wide_ptr = { + let filename = { let filename = if loc_details.file { filename.as_str() } else { "<redacted>" }; let filename_with_nul = filename.to_owned() + "\0"; // This can fail if rustc runs out of memory right here. Trying to emit an error would be // pointless, since that would require allocating more memory than these short strings. let file_ptr = ecx.allocate_bytes_dedup(filename_with_nul.as_bytes()).unwrap(); - Immediate::new_slice(file_ptr.into(), filename_with_nul.len().try_into().unwrap(), ecx) + let file_len = u64::try_from(filename.len()).unwrap(); + Immediate::new_slice(file_ptr.into(), file_len, ecx) }; let line = if loc_details.line { Scalar::from_u32(line) } else { Scalar::from_u32(0) }; let col = if loc_details.column { Scalar::from_u32(col) } else { Scalar::from_u32(0) }; @@ -42,11 +42,8 @@ fn alloc_caller_location<'tcx>( let location = ecx.allocate(loc_layout, MemoryKind::CallerLocation).unwrap(); // Initialize fields. - ecx.write_immediate( - file_wide_ptr, - &ecx.project_field(&location, FieldIdx::from_u32(0)).unwrap(), - ) - .expect("writing to memory we just allocated cannot fail"); + ecx.write_immediate(filename, &ecx.project_field(&location, FieldIdx::from_u32(0)).unwrap()) + .expect("writing to memory we just allocated cannot fail"); ecx.write_scalar(line, &ecx.project_field(&location, FieldIdx::from_u32(1)).unwrap()) .expect("writing to memory we just allocated cannot fail"); ecx.write_scalar(col, &ecx.project_field(&location, FieldIdx::from_u32(2)).unwrap()) diff --git a/compiler/rustc_data_structures/src/aligned.rs b/compiler/rustc_data_structures/src/aligned.rs index 111740e5509..bfc7556faf6 100644 --- a/compiler/rustc_data_structures/src/aligned.rs +++ b/compiler/rustc_data_structures/src/aligned.rs @@ -1,7 +1,6 @@ +use std::marker::PointeeSized; use std::ptr::Alignment; -use rustc_serialize::PointeeSized; - /// Returns the ABI-required minimum alignment of a type in bytes. /// /// This is equivalent to [`align_of`], but also works for some unsized diff --git a/compiler/rustc_data_structures/src/flock.rs b/compiler/rustc_data_structures/src/flock.rs index 60ae7ad115a..f33f6b7cac1 100644 --- a/compiler/rustc_data_structures/src/flock.rs +++ b/compiler/rustc_data_structures/src/flock.rs @@ -4,18 +4,7 @@ //! green/native threading. This is just a bare-bones enough solution for //! librustdoc, it is not production quality at all. -// cfg(bootstrap) -macro_rules! cfg_select_dispatch { - ($($tokens:tt)*) => { - #[cfg(bootstrap)] - cfg_match! { $($tokens)* } - - #[cfg(not(bootstrap))] - cfg_select! { $($tokens)* } - }; -} - -cfg_select_dispatch! { +cfg_select! { target_os = "linux" => { mod linux; use linux as imp; diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 0431182e9e2..53178d09348 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -10,9 +10,6 @@ #![allow(internal_features)] #![allow(rustc::default_hash_types)] #![allow(rustc::potential_query_instability)] -#![cfg_attr(bootstrap, feature(cfg_match))] -#![cfg_attr(not(bootstrap), feature(cfg_select))] -#![cfg_attr(not(bootstrap), feature(sized_hierarchy))] #![deny(unsafe_op_in_unsafe_fn)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] @@ -22,6 +19,7 @@ #![feature(ascii_char_variants)] #![feature(assert_matches)] #![feature(auto_traits)] +#![feature(cfg_select)] #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] #![feature(extend_one)] @@ -33,6 +31,7 @@ #![feature(ptr_alignment_type)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] +#![feature(sized_hierarchy)] #![feature(test)] #![feature(thread_id_value)] #![feature(type_alias_impl_trait)] @@ -44,9 +43,6 @@ use std::fmt; pub use atomic_ref::AtomicRef; pub use ena::{snapshot_vec, undo_log, unify}; pub use rustc_index::static_assert_size; -// re-exported for `rustc_smir` -// FIXME(sized_hierarchy): remove with `cfg(bootstrap)`, see `rustc_serialize/src/lib.rs` -pub use rustc_serialize::PointeeSized; pub mod aligned; pub mod base_n; diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs index 4846bc997f1..2be9ba292f9 100644 --- a/compiler/rustc_data_structures/src/marker.rs +++ b/compiler/rustc_data_structures/src/marker.rs @@ -1,6 +1,5 @@ use std::alloc::Allocator; - -use rustc_serialize::PointeeSized; +use std::marker::PointeeSized; #[diagnostic::on_unimplemented(message = "`{Self}` doesn't implement `DynSend`. \ Add it to `rustc_data_structures::marker` or use `IntoDynSyncSend` if it's already `Send`")] diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs index 0cc14d6b0c9..1b4db7adc27 100644 --- a/compiler/rustc_data_structures/src/profiling.rs +++ b/compiler/rustc_data_structures/src/profiling.rs @@ -945,19 +945,8 @@ fn get_thread_id() -> u32 { std::thread::current().id().as_u64().get() as u32 } -// cfg(bootstrap) -macro_rules! cfg_select_dispatch { - ($($tokens:tt)*) => { - #[cfg(bootstrap)] - cfg_match! { $($tokens)* } - - #[cfg(not(bootstrap))] - cfg_select! { $($tokens)* } - }; -} - // Memory reporting -cfg_select_dispatch! { +cfg_select! { windows => { pub fn get_resident_set_size() -> Option<usize> { use windows::{ diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index daeca43169d..18490385455 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -53,13 +53,13 @@ use rustc_metadata::locator; use rustc_middle::ty::TyCtxt; use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal}; use rustc_session::config::{ - CG_OPTIONS, CrateType, ErrorOutputType, Input, OptionDesc, OutFileName, OutputType, + CG_OPTIONS, CrateType, ErrorOutputType, Input, OptionDesc, OutFileName, OutputType, Sysroot, UnstableOptions, Z_OPTIONS, nightly_options, parse_target_triple, }; use rustc_session::getopts::{self, Matches}; use rustc_session::lint::{Lint, LintId}; use rustc_session::output::{CRATE_TYPES, collect_crate_types, invalid_output_for_target}; -use rustc_session::{EarlyDiagCtxt, Session, config, filesearch}; +use rustc_session::{EarlyDiagCtxt, Session, config}; use rustc_span::FileName; use rustc_span::def_id::LOCAL_CRATE; use rustc_target::json::ToJson; @@ -662,7 +662,7 @@ fn print_crate_info( println_info!("{}", targets.join("\n")); } HostTuple => println_info!("{}", rustc_session::config::host_tuple()), - Sysroot => println_info!("{}", sess.sysroot.display()), + Sysroot => println_info!("{}", sess.opts.sysroot.path().display()), TargetLibdir => println_info!("{}", sess.target_tlib_path.dir.display()), TargetSpecJson => { println_info!("{}", serde_json::to_string_pretty(&sess.target.to_json()).unwrap()); @@ -1112,10 +1112,12 @@ fn get_backend_from_raw_matches( matches: &Matches, ) -> Box<dyn CodegenBackend> { let debug_flags = matches.opt_strs("Z"); - let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend=")); + let backend_name = debug_flags + .iter() + .find_map(|x| x.strip_prefix("codegen-backend=").or(x.strip_prefix("codegen_backend="))); let target = parse_target_triple(early_dcx, matches); - let sysroot = filesearch::materialize_sysroot(matches.opt_str("sysroot").map(PathBuf::from)); - let target = config::build_target_config(early_dcx, &target, &sysroot); + let sysroot = Sysroot::new(matches.opt_str("sysroot").map(PathBuf::from)); + let target = config::build_target_config(early_dcx, &target, sysroot.path()); get_codegen_backend(early_dcx, &sysroot, backend_name, &target) } diff --git a/compiler/rustc_error_codes/src/error_codes/E0775.md b/compiler/rustc_error_codes/src/error_codes/E0775.md index efbd51e89ea..9fcd3a6eef7 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0775.md +++ b/compiler/rustc_error_codes/src/error_codes/E0775.md @@ -8,7 +8,7 @@ Erroneous code example: ```ignore (no longer emitted) #![feature(cmse_nonsecure_entry)] -pub extern "C-cmse-nonsecure-entry" fn entry_function() {} +pub extern "cmse-nonsecure-entry" fn entry_function() {} ``` To fix this error, compile your code for a Rust target that supports the diff --git a/compiler/rustc_error_codes/src/error_codes/E0781.md b/compiler/rustc_error_codes/src/error_codes/E0781.md index 7641acfb524..22abe0e3cb1 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0781.md +++ b/compiler/rustc_error_codes/src/error_codes/E0781.md @@ -1,12 +1,12 @@ -The `C-cmse-nonsecure-call` ABI can only be used with function pointers. +The `cmse-nonsecure-call` ABI can only be used with function pointers. Erroneous code example: ```compile_fail,E0781 -#![feature(abi_c_cmse_nonsecure_call)] +#![feature(abi_cmse_nonsecure_call)] -pub extern "C-cmse-nonsecure-call" fn test() {} +pub extern "cmse-nonsecure-call" fn test() {} ``` -The `C-cmse-nonsecure-call` ABI should be used by casting function pointers to +The `cmse-nonsecure-call` ABI should be used by casting function pointers to specific addresses. diff --git a/compiler/rustc_error_codes/src/error_codes/E0798.md b/compiler/rustc_error_codes/src/error_codes/E0798.md index da08cde3010..e5f356ef4d5 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0798.md +++ b/compiler/rustc_error_codes/src/error_codes/E0798.md @@ -1,4 +1,4 @@ -Functions marked as `C-cmse-nonsecure-call` place restrictions on their +Functions marked as `cmse-nonsecure-call` place restrictions on their inputs and outputs. - inputs must fit in the 4 available 32-bit argument registers. Alignment @@ -12,12 +12,12 @@ see [arm's aapcs32](https://github.com/ARM-software/abi-aa/releases). Erroneous code example: -```ignore (only fails on supported targets) -#![feature(abi_c_cmse_nonsecure_call)] +```ignore (host errors will not match for target) +#![feature(abi_cmse_nonsecure_call)] #[no_mangle] pub fn test( - f: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32, u32) -> u32, + f: extern "cmse-nonsecure-call" fn(u32, u32, u32, u32, u32) -> u32, ) -> u32 { f(1, 2, 3, 4, 5) } @@ -27,12 +27,12 @@ Arguments' alignment is respected. In the example below, padding is inserted so that the `u64` argument is passed in registers r2 and r3. There is then no room left for the final `f32` argument -```ignore (only fails on supported targets) -#![feature(abi_c_cmse_nonsecure_call)] +```ignore (host errors will not match for target) +#![feature(abi_cmse_nonsecure_call)] #[no_mangle] pub fn test( - f: extern "C-cmse-nonsecure-call" fn(u32, u64, f32) -> u32, + f: extern "cmse-nonsecure-call" fn(u32, u64, f32) -> u32, ) -> u32 { f(1, 2, 3.0) } diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index 22cc1e894da..0aff1c06e0a 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -690,5 +690,5 @@ E0805: 0805, // E0723, // unstable feature in `const` context // E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`. // E0744, // merged into E0728 -// E0776, // Removed; cmse_nonsecure_entry is now `C-cmse-nonsecure-entry` +// E0776, // Removed; `#[cmse_nonsecure_entry]` is now `extern "cmse-nonsecure-entry"` // E0796, // unused error code. We use `static_mut_refs` lint instead. diff --git a/compiler/rustc_error_messages/Cargo.toml b/compiler/rustc_error_messages/Cargo.toml index 5dc582b9c3a..0951859fa53 100644 --- a/compiler/rustc_error_messages/Cargo.toml +++ b/compiler/rustc_error_messages/Cargo.toml @@ -16,7 +16,6 @@ rustc_data_structures = { path = "../rustc_data_structures" } rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } -smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" unic-langid = { version = "0.9.0", features = ["macros"] } # tidy-alphabetical-end diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 194fc2450ba..4b3ecad307f 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -3,12 +3,11 @@ #![doc(rust_logo)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] -#![feature(type_alias_impl_trait)] // tidy-alphabetical-end use std::borrow::Cow; use std::error::Error; -use std::path::{Path, PathBuf}; +use std::path::Path; use std::sync::{Arc, LazyLock}; use std::{fmt, fs, io}; @@ -21,7 +20,6 @@ use intl_memoizer::concurrent::IntlLangMemoizer; use rustc_data_structures::sync::{DynSend, IntoDynSyncSend}; use rustc_macros::{Decodable, Encodable}; use rustc_span::Span; -use smallvec::SmallVec; use tracing::{instrument, trace}; pub use unic_langid::{LanguageIdentifier, langid}; @@ -107,7 +105,7 @@ impl From<Vec<FluentError>> for TranslationBundleError { /// (overriding any conflicting messages). #[instrument(level = "trace")] pub fn fluent_bundle( - sysroot_candidates: SmallVec<[PathBuf; 2]>, + sysroot_candidates: &[&Path], requested_locale: Option<LanguageIdentifier>, additional_ftl_path: Option<&Path>, with_directionality_markers: bool, @@ -141,7 +139,8 @@ pub fn fluent_bundle( // If the user requests the default locale then don't try to load anything. if let Some(requested_locale) = requested_locale { let mut found_resources = false; - for mut sysroot in sysroot_candidates { + for sysroot in sysroot_candidates { + let mut sysroot = sysroot.to_path_buf(); sysroot.push("share"); sysroot.push("locale"); sysroot.push(requested_locale.to_string()); diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index a11f81b55bb..fe9797026de 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -289,6 +289,9 @@ pub struct DiagInner { pub suggestions: Suggestions, pub args: DiagArgMap, + // This is used to store args and restore them after a subdiagnostic is rendered. + pub reserved_args: DiagArgMap, + /// This is not used for highlighting or rendering any error message. Rather, it can be used /// as a sort key to sort a buffer of diagnostics. By default, it is the primary span of /// `span` if there is one. Otherwise, it is `DUMMY_SP`. @@ -319,6 +322,7 @@ impl DiagInner { children: vec![], suggestions: Suggestions::Enabled(vec![]), args: Default::default(), + reserved_args: Default::default(), sort_span: DUMMY_SP, is_lint: None, long_ty_path: None, @@ -390,7 +394,27 @@ impl DiagInner { } pub(crate) fn arg(&mut self, name: impl Into<DiagArgName>, arg: impl IntoDiagArg) { - self.args.insert(name.into(), arg.into_diag_arg(&mut self.long_ty_path)); + let name = name.into(); + let value = arg.into_diag_arg(&mut self.long_ty_path); + // This assertion is to avoid subdiagnostics overwriting an existing diagnostic arg. + debug_assert!( + !self.args.contains_key(&name) || self.args.get(&name) == Some(&value), + "arg {} already exists", + name + ); + self.args.insert(name, value); + } + + pub fn remove_arg(&mut self, name: &str) { + self.args.swap_remove(name); + } + + pub fn store_args(&mut self) { + self.reserved_args = self.args.clone(); + } + + pub fn restore_args(&mut self) { + self.args = std::mem::take(&mut self.reserved_args); } /// Fields used for Hash, and PartialEq trait. @@ -981,7 +1005,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { /// * may look like "to do xyz, use" or "to do xyz, use abc" /// * may contain a name of a function, variable, or type, but not whole expressions /// - /// See `CodeSuggestion` for more information. + /// See [`CodeSuggestion`] for more information. #[rustc_lint_diagnostics] pub fn span_suggestion( &mut self, @@ -1142,7 +1166,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { /// Prints out a message with a suggested edit of the code. If the suggestion is presented /// inline, it will only show the message and not the suggestion. /// - /// See `CodeSuggestion` for more information. + /// See [`CodeSuggestion`] for more information. #[rustc_lint_diagnostics] pub fn span_suggestion_short( &mut self, @@ -1423,6 +1447,12 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { self.downgrade_to_delayed_bug(); self.emit() } + + pub fn remove_arg(&mut self, name: &str) { + if let Some(diag) = self.diag.as_mut() { + diag.remove_arg(name); + } + } } /// Destructor bomb: every `Diag` must be consumed (emitted, cancelled, etc.) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index e333de4b660..3f5872f34a6 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -2078,7 +2078,9 @@ impl HumanEmitter { // file name, saving in verbosity, but if it *isn't* we do need it, otherwise we're // telling users to make a change but not clarifying *where*. let loc = sm.lookup_char_pos(parts[0].span.lo()); - if loc.file.name != sm.span_to_filename(span) && loc.file.name.is_real() { + if (span.is_dummy() || loc.file.name != sm.span_to_filename(span)) + && loc.file.name.is_real() + { // --> file.rs:line:col // | let arrow = self.file_start(); diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 207aed8c755..69ad15c6081 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -6,8 +6,8 @@ #![allow(incomplete_features)] #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] +#![allow(rustc::direct_use_of_rustc_type_ir)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(not(bootstrap), allow(rustc::direct_use_of_rustc_type_ir))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(array_windows)] diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl index 8b7c47dad99..3fc0fa06191 100644 --- a/compiler/rustc_expand/messages.ftl +++ b/compiler/rustc_expand/messages.ftl @@ -62,7 +62,7 @@ expand_feature_not_allowed = expand_feature_removed = feature has been removed .label = feature has been removed - .note = removed in {$removed_rustc_version} (you are using {$current_rustc_version}){$pull_note} + .note = removed in {$removed_rustc_version}{$pull_note} .reason = {$reason} expand_glob_delegation_outside_impls = @@ -109,9 +109,6 @@ expand_malformed_feature_attribute = expand_meta_var_dif_seq_matchers = {$msg} -expand_meta_var_expr_unrecognized_var = - variable `{$key}` is not recognized in meta-variable expression - expand_missing_fragment_specifier = missing fragment specifier .note = fragment specifiers must be provided .suggestion_add_fragspec = try adding a specifier here @@ -136,6 +133,9 @@ expand_module_multiple_candidates = expand_must_repeat_once = this must repeat at least once +expand_mve_unrecognized_var = + variable `{$key}` is not recognized in meta-variable expression + expand_non_inline_modules_in_proc_macro_input_are_unstable = non-inline modules in proc macro input are unstable diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 7a29f8c9fbd..fe76d9e0b64 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1118,6 +1118,10 @@ pub trait ResolverExpand { trait_def_id: DefId, impl_def_id: LocalDefId, ) -> Result<Vec<(Ident, Option<Ident>)>, Indeterminate>; + + /// Record the name of an opaque `Ty::ImplTrait` pre-expansion so that it can be used + /// to generate an item name later that does not reference placeholder macros. + fn insert_impl_trait_name(&mut self, id: NodeId, name: Symbol); } pub trait LintStoreExpand { diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 9a359e9b031..170ac39d1ec 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -92,7 +92,6 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) - span: mi.span(), reason: f.reason.map(|reason| FeatureRemovedReason { reason }), removed_rustc_version: f.feature.since, - current_rustc_version: sess.cfg_version, pull_note, }); continue; diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index 714ba3bf0f4..fdbc65aff68 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -28,14 +28,6 @@ pub(crate) struct CountRepetitionMisplaced { } #[derive(Diagnostic)] -#[diag(expand_meta_var_expr_unrecognized_var)] -pub(crate) struct MetaVarExprUnrecognizedVar { - #[primary_span] - pub span: Span, - pub key: MacroRulesNormalizedIdent, -} - -#[derive(Diagnostic)] #[diag(expand_var_still_repeating)] pub(crate) struct VarStillRepeating { #[primary_span] @@ -162,7 +154,6 @@ pub(crate) struct FeatureRemoved<'a> { #[subdiagnostic] pub reason: Option<FeatureRemovedReason<'a>>, pub removed_rustc_version: &'a str, - pub current_rustc_version: &'a str, pub pull_note: String, } @@ -444,7 +435,7 @@ pub(crate) struct InvalidFragmentSpecifier { #[primary_span] pub span: Span, pub fragment: Ident, - pub help: String, + pub help: &'static str, } #[derive(Diagnostic)] @@ -500,3 +491,16 @@ pub(crate) struct ProcMacroBackCompat { pub crate_name: String, pub fixed_version: String, } + +pub(crate) use metavar_exprs::*; +mod metavar_exprs { + use super::*; + + #[derive(Diagnostic)] + #[diag(expand_mve_unrecognized_var)] + pub(crate) struct MveUnrecognizedVar { + #[primary_span] + pub span: Span, + pub key: MacroRulesNormalizedIdent, + } +} diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 0474413e762..2de09aa1a28 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1778,6 +1778,16 @@ impl InvocationCollectorNode for ast::Ty { fragment.make_ty() } fn walk(&mut self, collector: &mut InvocationCollector<'_, '_>) { + // Save the pre-expanded name of this `ImplTrait`, so that later when defining + // an APIT we use a name that doesn't have any placeholder fragments in it. + if let ast::TyKind::ImplTrait(..) = self.kind { + // HACK: pprust breaks strings with newlines when the type + // gets too long. We don't want these to show up in compiler + // output or built artifacts, so replace them here... + // Perhaps we should instead format APITs more robustly. + let name = Symbol::intern(&pprust::ty_to_string(self).replace('\n', " ")); + collector.cx.resolver.insert_impl_trait_name(self.id, name); + } walk_ty(collector, self) } fn is_mac_call(&self) -> bool { diff --git a/compiler/rustc_expand/src/mbe.rs b/compiler/rustc_expand/src/mbe.rs index 4ff8c02bcdb..3082c881a7a 100644 --- a/compiler/rustc_expand/src/mbe.rs +++ b/compiler/rustc_expand/src/mbe.rs @@ -78,7 +78,13 @@ enum TokenTree { /// only covers the ident, e.g. `var`.) MetaVar(Span, Ident), /// e.g., `$var:expr`. Only appears on the LHS. - MetaVarDecl(Span, Ident /* name to bind */, Option<NonterminalKind>), + MetaVarDecl { + span: Span, + /// Name to bind. + name: Ident, + /// The fragment specifier. + kind: NonterminalKind, + }, /// A meta-variable expression inside `${...}`. MetaVarExpr(DelimSpan, MetaVarExpr), } @@ -102,7 +108,7 @@ impl TokenTree { match *self { TokenTree::Token(Token { span, .. }) | TokenTree::MetaVar(span, _) - | TokenTree::MetaVarDecl(span, _, _) => span, + | TokenTree::MetaVarDecl { span, .. } => span, TokenTree::Delimited(span, ..) | TokenTree::MetaVarExpr(span, _) | TokenTree::Sequence(span, _) => span.entire(), diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index 698492f42e2..99aa376626d 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -24,6 +24,7 @@ pub(super) fn failed_to_match_macro( arg: TokenStream, lhses: &[Vec<MatcherLoc>], ) -> (Span, ErrorGuaranteed) { + debug!("failed to match macro"); // An error occurred, try the expansion again, tracking the expansion closely for better // diagnostics. let mut tracker = CollectTrackerAndEmitter::new(psess.dcx(), sp); diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs index 3cd803c3e84..dc2d46c4a14 100644 --- a/compiler/rustc_expand/src/mbe/macro_check.rs +++ b/compiler/rustc_expand/src/mbe/macro_check.rs @@ -117,7 +117,6 @@ use rustc_session::parse::ParseSess; use rustc_span::{ErrorGuaranteed, MacroRulesNormalizedIdent, Span, kw}; use smallvec::SmallVec; -use super::quoted::VALID_FRAGMENT_NAMES_MSG; use crate::errors; use crate::mbe::{KleeneToken, TokenTree}; @@ -263,14 +262,7 @@ fn check_binders( } } // Similarly, this can only happen when checking a toplevel macro. - TokenTree::MetaVarDecl(span, name, kind) => { - if kind.is_none() && node_id != DUMMY_NODE_ID { - psess.dcx().emit_err(errors::MissingFragmentSpecifier { - span, - add_span: span.shrink_to_hi(), - valid: VALID_FRAGMENT_NAMES_MSG, - }); - } + TokenTree::MetaVarDecl { span, name, .. } => { if !macros.is_empty() { psess.dcx().span_bug(span, "unexpected MetaVarDecl in nested lhs"); } @@ -339,7 +331,7 @@ fn check_occurrences( ) { match *rhs { TokenTree::Token(..) => {} - TokenTree::MetaVarDecl(span, _name, _kind) => { + TokenTree::MetaVarDecl { span, .. } => { psess.dcx().span_bug(span, "unexpected MetaVarDecl in rhs") } TokenTree::MetaVar(span, name) => { diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index c78beb40688..802e43209a5 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -122,7 +122,7 @@ pub(crate) enum MatcherLoc { MetaVarDecl { span: Span, bind: Ident, - kind: Option<NonterminalKind>, + kind: NonterminalKind, next_metavar: usize, seq_depth: usize, }, @@ -151,12 +151,7 @@ impl Display for MatcherLoc { write!(f, "{}", token_descr(token)) } MatcherLoc::MetaVarDecl { bind, kind, .. } => { - write!(f, "meta-variable `${bind}")?; - if let Some(kind) = kind { - write!(f, ":{kind}")?; - } - write!(f, "`")?; - Ok(()) + write!(f, "meta-variable `${bind}:{kind}`") } MatcherLoc::Eof => f.write_str("end of macro"), @@ -220,7 +215,7 @@ pub(super) fn compute_locs(matcher: &[TokenTree]) -> Vec<MatcherLoc> { seq_depth, }; } - &TokenTree::MetaVarDecl(span, bind, kind) => { + &TokenTree::MetaVarDecl { span, name: bind, kind } => { locs.push(MatcherLoc::MetaVarDecl { span, bind, @@ -330,7 +325,7 @@ pub(super) fn count_metavar_decls(matcher: &[TokenTree]) -> usize { matcher .iter() .map(|tt| match tt { - TokenTree::MetaVarDecl(..) => 1, + TokenTree::MetaVarDecl { .. } => 1, TokenTree::Sequence(_, seq) => seq.num_captures, TokenTree::Delimited(.., delim) => count_metavar_decls(&delim.tts), TokenTree::Token(..) => 0, @@ -551,18 +546,12 @@ impl TtParser { mp.idx = idx_first; self.cur_mps.push(mp); } - &MatcherLoc::MetaVarDecl { span, kind, .. } => { + &MatcherLoc::MetaVarDecl { kind, .. } => { // Built-in nonterminals never start with these tokens, so we can eliminate // them from consideration. We use the span of the metavariable declaration // to determine any edition-specific matching behavior for non-terminals. - if let Some(kind) = kind { - if Parser::nonterminal_may_begin_with(kind, token) { - self.bb_mps.push(mp); - } - } else { - // E.g. `$e` instead of `$e:expr`, reported as a hard error if actually used. - // Both this check and the one in `nameize` are necessary, surprisingly. - return Some(Error(span, "missing fragment specifier".to_string())); + if Parser::nonterminal_may_begin_with(kind, token) { + self.bb_mps.push(mp); } } MatcherLoc::Eof => { @@ -666,11 +655,7 @@ impl TtParser { let mut mp = self.bb_mps.pop().unwrap(); let loc = &matcher[mp.idx]; if let &MatcherLoc::MetaVarDecl { - span, - kind: Some(kind), - next_metavar, - seq_depth, - .. + span, kind, next_metavar, seq_depth, .. } = loc { // We use the span of the metavariable declaration to determine any @@ -715,7 +700,7 @@ impl TtParser { .bb_mps .iter() .map(|mp| match &matcher[mp.idx] { - MatcherLoc::MetaVarDecl { bind, kind: Some(kind), .. } => { + MatcherLoc::MetaVarDecl { bind, kind, .. } => { format!("{kind} ('{bind}')") } _ => unreachable!(), @@ -745,19 +730,13 @@ impl TtParser { // `NamedParseResult`. Otherwise, it's an error. let mut ret_val = FxHashMap::default(); for loc in matcher { - if let &MatcherLoc::MetaVarDecl { span, bind, kind, .. } = loc { - if kind.is_some() { - match ret_val.entry(MacroRulesNormalizedIdent::new(bind)) { - Vacant(spot) => spot.insert(res.next().unwrap()), - Occupied(..) => { - return Error(span, format!("duplicated bind name: {bind}")); - } - }; - } else { - // E.g. `$e` instead of `$e:expr`, reported as a hard error if actually used. - // Both this check and the one in `parse_tt_inner` are necessary, surprisingly. - return Error(span, "missing fragment specifier".to_string()); - } + if let &MatcherLoc::MetaVarDecl { span, bind, .. } = loc { + match ret_val.entry(MacroRulesNormalizedIdent::new(bind)) { + Vacant(spot) => spot.insert(res.next().unwrap()), + Occupied(..) => { + return Error(span, format!("duplicated bind name: {bind}")); + } + }; } } Success(ret_val) diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 783f061ec6c..432ab324740 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -392,7 +392,7 @@ pub fn compile_declarative_macro( let lhs_nm = Ident::new(sym::lhs, span); let rhs_nm = Ident::new(sym::rhs, span); - let tt_spec = Some(NonterminalKind::TT); + let tt_spec = NonterminalKind::TT; let macro_rules = macro_def.macro_rules; // Parse the macro_rules! invocation @@ -407,9 +407,9 @@ pub fn compile_declarative_macro( DelimSpan::dummy(), mbe::SequenceRepetition { tts: vec![ - mbe::TokenTree::MetaVarDecl(span, lhs_nm, tt_spec), + mbe::TokenTree::MetaVarDecl { span, name: lhs_nm, kind: tt_spec }, mbe::TokenTree::token(token::FatArrow, span), - mbe::TokenTree::MetaVarDecl(span, rhs_nm, tt_spec), + mbe::TokenTree::MetaVarDecl { span, name: rhs_nm, kind: tt_spec }, ], separator: Some(Token::new( if macro_rules { token::Semi } else { token::Comma }, @@ -448,6 +448,7 @@ pub fn compile_declarative_macro( match tt_parser.parse_tt(&mut Cow::Owned(parser), &argument_gram, &mut NoopTracker) { Success(m) => m, Failure(()) => { + debug!("failed to parse macro tt"); // The fast `NoopTracker` doesn't have any info on failure, so we need to retry it // with another one that gives us the information we need. // For this we need to reclone the macro body as the previous parser consumed it. @@ -616,7 +617,7 @@ fn is_empty_token_tree(sess: &Session, seq: &mbe::SequenceRepetition) -> bool { let mut iter = seq.tts.iter().peekable(); while let Some(tt) = iter.next() { match tt { - mbe::TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis)) => {} + mbe::TokenTree::MetaVarDecl { kind: NonterminalKind::Vis, .. } => {} mbe::TokenTree::Token(t @ Token { kind: DocComment(..), .. }) => { let mut now = t; while let Some(&mbe::TokenTree::Token( @@ -651,7 +652,7 @@ fn check_redundant_vis_repetition( ) { let is_zero_or_one: bool = seq.kleene.op == KleeneOp::ZeroOrOne; let is_vis = seq.tts.first().map_or(false, |tt| { - matches!(tt, mbe::TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis))) + matches!(tt, mbe::TokenTree::MetaVarDecl { kind: NonterminalKind::Vis, .. }) }); if is_vis && is_zero_or_one { @@ -678,7 +679,7 @@ fn check_lhs_no_empty_seq(sess: &Session, tts: &[mbe::TokenTree]) -> Result<(), match tt { TokenTree::Token(..) | TokenTree::MetaVar(..) - | TokenTree::MetaVarDecl(..) + | TokenTree::MetaVarDecl { .. } | TokenTree::MetaVarExpr(..) => (), TokenTree::Delimited(.., del) => check_lhs_no_empty_seq(sess, &del.tts)?, TokenTree::Sequence(span, seq) => { @@ -777,7 +778,7 @@ impl<'tt> FirstSets<'tt> { match tt { TokenTree::Token(..) | TokenTree::MetaVar(..) - | TokenTree::MetaVarDecl(..) + | TokenTree::MetaVarDecl { .. } | TokenTree::MetaVarExpr(..) => { first.replace_with(TtHandle::TtRef(tt)); } @@ -845,7 +846,7 @@ impl<'tt> FirstSets<'tt> { match tt { TokenTree::Token(..) | TokenTree::MetaVar(..) - | TokenTree::MetaVarDecl(..) + | TokenTree::MetaVarDecl { .. } | TokenTree::MetaVarExpr(..) => { first.add_one(TtHandle::TtRef(tt)); return first; @@ -1084,7 +1085,7 @@ fn check_matcher_core<'tt>( match token { TokenTree::Token(..) | TokenTree::MetaVar(..) - | TokenTree::MetaVarDecl(..) + | TokenTree::MetaVarDecl { .. } | TokenTree::MetaVarExpr(..) => { if token_can_be_followed_by_any(token) { // don't need to track tokens that work with any, @@ -1152,7 +1153,7 @@ fn check_matcher_core<'tt>( // Now `last` holds the complete set of NT tokens that could // end the sequence before SUFFIX. Check that every one works with `suffix`. for tt in &last.tokens { - if let &TokenTree::MetaVarDecl(span, name, Some(kind)) = tt.get() { + if let &TokenTree::MetaVarDecl { span, name, kind } = tt.get() { for next_token in &suffix_first.tokens { let next_token = next_token.get(); @@ -1172,11 +1173,11 @@ fn check_matcher_core<'tt>( ) { // It is suggestion to use pat_param, for example: $x:pat -> $x:pat_param. - let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl( + let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl { span, name, - Some(NonterminalKind::Pat(PatParam { inferred: false })), - )); + kind: NonterminalKind::Pat(PatParam { inferred: false }), + }); sess.psess.buffer_lint( RUST_2021_INCOMPATIBLE_OR_PATTERNS, span, @@ -1212,11 +1213,11 @@ fn check_matcher_core<'tt>( && sess.psess.edition.at_least_rust_2021() && next_token.is_token(&token::Or) { - let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl( + let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl { span, name, - Some(NonterminalKind::Pat(PatParam { inferred: false })), - )); + kind: NonterminalKind::Pat(PatParam { inferred: false }), + }); err.span_suggestion( span, "try a `pat_param` fragment specifier instead", @@ -1254,7 +1255,7 @@ fn check_matcher_core<'tt>( } fn token_can_be_followed_by_any(tok: &mbe::TokenTree) -> bool { - if let mbe::TokenTree::MetaVarDecl(_, _, Some(kind)) = *tok { + if let mbe::TokenTree::MetaVarDecl { kind, .. } = *tok { frag_can_be_followed_by_any(kind) } else { // (Non NT's can always be followed by anything in matchers.) @@ -1367,7 +1368,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow { } _ => IsInFollow::No(TOKENS), }, - TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Block)) => IsInFollow::Yes, + TokenTree::MetaVarDecl { kind: NonterminalKind::Block, .. } => IsInFollow::Yes, _ => IsInFollow::No(TOKENS), } } @@ -1400,11 +1401,10 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow { } } }, - TokenTree::MetaVarDecl( - _, - _, - Some(NonterminalKind::Ident | NonterminalKind::Ty | NonterminalKind::Path), - ) => IsInFollow::Yes, + TokenTree::MetaVarDecl { + kind: NonterminalKind::Ident | NonterminalKind::Ty | NonterminalKind::Path, + .. + } => IsInFollow::Yes, _ => IsInFollow::No(TOKENS), } } @@ -1416,8 +1416,7 @@ fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String { match tt { mbe::TokenTree::Token(token) => pprust::token_to_string(token).into(), mbe::TokenTree::MetaVar(_, name) => format!("${name}"), - mbe::TokenTree::MetaVarDecl(_, name, Some(kind)) => format!("${name}:{kind}"), - mbe::TokenTree::MetaVarDecl(_, name, None) => format!("${name}:"), + mbe::TokenTree::MetaVarDecl { name, kind, .. } => format!("${name}:{kind}"), _ => panic!( "{}", "unexpected mbe::TokenTree::{Sequence or Delimited} \ diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs index 1ccb070f83a..ffd3548019a 100644 --- a/compiler/rustc_expand/src/mbe/metavar_expr.rs +++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs @@ -47,46 +47,7 @@ impl MetaVarExpr { check_trailing_token(&mut iter, psess)?; let mut iter = args.iter(); let rslt = match ident.as_str() { - "concat" => { - let mut result = Vec::new(); - loop { - let is_var = try_eat_dollar(&mut iter); - let token = parse_token(&mut iter, psess, outer_span)?; - let element = if is_var { - MetaVarExprConcatElem::Var(parse_ident_from_token(psess, token)?) - } else if let TokenKind::Literal(Lit { - kind: token::LitKind::Str, - symbol, - suffix: None, - }) = token.kind - { - MetaVarExprConcatElem::Literal(symbol) - } else { - match parse_ident_from_token(psess, token) { - Err(err) => { - err.cancel(); - return Err(psess - .dcx() - .struct_span_err(token.span, UNSUPPORTED_CONCAT_ELEM_ERR)); - } - Ok(elem) => MetaVarExprConcatElem::Ident(elem), - } - }; - result.push(element); - if iter.peek().is_none() { - break; - } - if !try_eat_comma(&mut iter) { - return Err(psess.dcx().struct_span_err(outer_span, "expected comma")); - } - } - if result.len() < 2 { - return Err(psess - .dcx() - .struct_span_err(ident.span, "`concat` must have at least two elements")); - } - MetaVarExpr::Concat(result.into()) - } + "concat" => parse_concat(&mut iter, psess, outer_span, ident.span)?, "count" => parse_count(&mut iter, psess, ident.span)?, "ignore" => { eat_dollar(&mut iter, psess, ident.span)?; @@ -126,6 +87,22 @@ impl MetaVarExpr { } } +// Checks if there are any remaining tokens. For example, `${ignore(ident ... a b c ...)}` +fn check_trailing_token<'psess>( + iter: &mut TokenStreamIter<'_>, + psess: &'psess ParseSess, +) -> PResult<'psess, ()> { + if let Some(tt) = iter.next() { + let mut diag = psess + .dcx() + .struct_span_err(tt.span(), format!("unexpected token: {}", pprust::tt_to_string(tt))); + diag.span_note(tt.span(), "meta-variable expression must not have trailing tokens"); + Err(diag) + } else { + Ok(()) + } +} + /// Indicates what is placed in a `concat` parameter. For example, literals /// (`${concat("foo", "bar")}`) or adhoc identifiers (`${concat(foo, bar)}`). #[derive(Debug, Decodable, Encodable, PartialEq)] @@ -140,20 +117,48 @@ pub(crate) enum MetaVarExprConcatElem { Var(Ident), } -// Checks if there are any remaining tokens. For example, `${ignore(ident ... a b c ...)}` -fn check_trailing_token<'psess>( +/// Parse a meta-variable `concat` expression: `concat($metavar, ident, ...)`. +fn parse_concat<'psess>( iter: &mut TokenStreamIter<'_>, psess: &'psess ParseSess, -) -> PResult<'psess, ()> { - if let Some(tt) = iter.next() { - let mut diag = psess + outer_span: Span, + expr_ident_span: Span, +) -> PResult<'psess, MetaVarExpr> { + let mut result = Vec::new(); + loop { + let is_var = try_eat_dollar(iter); + let token = parse_token(iter, psess, outer_span)?; + let element = if is_var { + MetaVarExprConcatElem::Var(parse_ident_from_token(psess, token)?) + } else if let TokenKind::Literal(Lit { kind: token::LitKind::Str, symbol, suffix: None }) = + token.kind + { + MetaVarExprConcatElem::Literal(symbol) + } else { + match parse_ident_from_token(psess, token) { + Err(err) => { + err.cancel(); + return Err(psess + .dcx() + .struct_span_err(token.span, UNSUPPORTED_CONCAT_ELEM_ERR)); + } + Ok(elem) => MetaVarExprConcatElem::Ident(elem), + } + }; + result.push(element); + if iter.peek().is_none() { + break; + } + if !try_eat_comma(iter) { + return Err(psess.dcx().struct_span_err(outer_span, "expected comma")); + } + } + if result.len() < 2 { + return Err(psess .dcx() - .struct_span_err(tt.span(), format!("unexpected token: {}", pprust::tt_to_string(tt))); - diag.span_note(tt.span(), "meta-variable expression must not have trailing tokens"); - Err(diag) - } else { - Ok(()) + .struct_span_err(expr_ident_span, "`concat` must have at least two elements")); } + Ok(MetaVarExpr::Concat(result.into())) } /// Parse a meta-variable `count` expression: `count(ident[, depth])` diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index 0c2362f23bc..2daa4e71558 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -54,66 +54,78 @@ pub(super) fn parse( // Given the parsed tree, if there is a metavar and we are expecting matchers, actually // parse out the matcher (i.e., in `$id:ident` this would parse the `:` and `ident`). let tree = parse_tree(tree, &mut iter, parsing_patterns, sess, node_id, features, edition); - match tree { - TokenTree::MetaVar(start_sp, ident) if parsing_patterns => { - // Not consuming the next token immediately, as it may not be a colon - let span = match iter.peek() { - Some(&tokenstream::TokenTree::Token( - Token { kind: token::Colon, span: colon_span }, - _, - )) => { - // Consume the colon first - iter.next(); - - // It's ok to consume the next tree no matter how, - // since if it's not a token then it will be an invalid declaration. - match iter.next() { - Some(tokenstream::TokenTree::Token(token, _)) => match token.ident() { - Some((fragment, _)) => { - let span = token.span.with_lo(start_sp.lo()); - let edition = || { - // FIXME(#85708) - once we properly decode a foreign - // crate's `SyntaxContext::root`, then we can replace - // this with just `span.edition()`. A - // `SyntaxContext::root()` from the current crate will - // have the edition of the current crate, and a - // `SyntaxContext::root()` from a foreign crate will - // have the edition of that crate (which we manually - // retrieve via the `edition` parameter). - if !span.from_expansion() { - edition - } else { - span.edition() - } - }; - let kind = NonterminalKind::from_symbol(fragment.name, edition) - .unwrap_or_else(|| { - sess.dcx().emit_err(errors::InvalidFragmentSpecifier { - span, - fragment, - help: VALID_FRAGMENT_NAMES_MSG.into(), - }); - NonterminalKind::Ident - }); - result.push(TokenTree::MetaVarDecl(span, ident, Some(kind))); - continue; - } - _ => token.span, - }, - // Invalid, return a nice source location - _ => colon_span.with_lo(start_sp.lo()), - } - } - // Whether it's none or some other tree, it doesn't belong to - // the current meta variable, returning the original span. - _ => start_sp, - }; - result.push(TokenTree::MetaVarDecl(span, ident, None)); - } + if !parsing_patterns { + // No matchers allowed, nothing to process here + result.push(tree); + continue; + } + + let TokenTree::MetaVar(start_sp, ident) = tree else { + // Not a metavariable, just return the tree + result.push(tree); + continue; + }; - // Not a metavar or no matchers allowed, so just return the tree - _ => result.push(tree), + // Push a metavariable with no fragment specifier at the given span + let mut missing_fragment_specifier = |span| { + sess.dcx().emit_err(errors::MissingFragmentSpecifier { + span, + add_span: span.shrink_to_hi(), + valid: VALID_FRAGMENT_NAMES_MSG, + }); + + // Fall back to a `TokenTree` since that will match anything if we continue expanding. + result.push(TokenTree::MetaVarDecl { span, name: ident, kind: NonterminalKind::TT }); + }; + + // Not consuming the next token immediately, as it may not be a colon + if let Some(peek) = iter.peek() + && let tokenstream::TokenTree::Token(token, _spacing) = peek + && let Token { kind: token::Colon, span: colon_span } = token + { + // Next token is a colon; consume it + iter.next(); + + // It's ok to consume the next tree no matter how, + // since if it's not a token then it will be an invalid declaration. + let Some(tokenstream::TokenTree::Token(token, _)) = iter.next() else { + // Invalid, return a nice source location as `var:` + missing_fragment_specifier(colon_span.with_lo(start_sp.lo())); + continue; + }; + + let Some((fragment, _)) = token.ident() else { + // No identifier for the fragment specifier; + missing_fragment_specifier(token.span); + continue; + }; + + let span = token.span.with_lo(start_sp.lo()); + let edition = || { + // FIXME(#85708) - once we properly decode a foreign + // crate's `SyntaxContext::root`, then we can replace + // this with just `span.edition()`. A + // `SyntaxContext::root()` from the current crate will + // have the edition of the current crate, and a + // `SyntaxContext::root()` from a foreign crate will + // have the edition of that crate (which we manually + // retrieve via the `edition` parameter). + if !span.from_expansion() { edition } else { span.edition() } + }; + let kind = NonterminalKind::from_symbol(fragment.name, edition).unwrap_or_else(|| { + sess.dcx().emit_err(errors::InvalidFragmentSpecifier { + span, + fragment, + help: VALID_FRAGMENT_NAMES_MSG, + }); + NonterminalKind::TT + }); + result.push(TokenTree::MetaVarDecl { span, name: ident, kind }); + } else { + // Whether it's none or some other tree, it doesn't belong to + // the current meta variable, returning the original span. + missing_fragment_specifier(start_sp); } } result diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 0520be5fbae..174844d6ad6 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -17,7 +17,7 @@ use rustc_span::{ use smallvec::{SmallVec, smallvec}; use crate::errors::{ - CountRepetitionMisplaced, MetaVarExprUnrecognizedVar, MetaVarsDifSeqMatchers, MustRepeatOnce, + CountRepetitionMisplaced, MetaVarsDifSeqMatchers, MustRepeatOnce, MveUnrecognizedVar, NoSyntaxVarsExprRepeat, VarStillRepeating, }; use crate::mbe::macro_parser::NamedMatch; @@ -283,7 +283,7 @@ pub(super) fn transcribe<'a>( } // There should be no meta-var declarations in the invocation of a macro. - mbe::TokenTree::MetaVarDecl(..) => panic!("unexpected `TokenTree::MetaVarDecl`"), + mbe::TokenTree::MetaVarDecl { .. } => panic!("unexpected `TokenTree::MetaVarDecl`"), } } } @@ -776,7 +776,7 @@ fn lockstep_iter_size( size.with(lockstep_iter_size(tt, interpolations, repeats)) }) } - TokenTree::MetaVar(_, name) | TokenTree::MetaVarDecl(_, name, _) => { + TokenTree::MetaVar(_, name) | TokenTree::MetaVarDecl { name, .. } => { let name = MacroRulesNormalizedIdent::new(*name); match lookup_cur_matched(name, interpolations, repeats) { Some(matched) => match matched { @@ -879,7 +879,7 @@ where { let span = ident.span; let key = MacroRulesNormalizedIdent::new(ident); - interp.get(&key).ok_or_else(|| dcx.create_err(MetaVarExprUnrecognizedVar { span, key })) + interp.get(&key).ok_or_else(|| dcx.create_err(MveUnrecognizedVar { span, key })) } /// Used by meta-variable expressions when an user input is out of the actual declared bounds. For diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index fb5abaefb57..af91c8b8f00 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -599,8 +599,12 @@ impl server::TokenStream for Rustc<'_, '_> { ast::ExprKind::Lit(token_lit) => { Ok(tokenstream::TokenStream::token_alone(token::Literal(*token_lit), expr.span)) } - ast::ExprKind::IncludedBytes(bytes) => { - let lit = token::Lit::new(token::ByteStr, escape_byte_str_symbol(bytes), None); + ast::ExprKind::IncludedBytes(byte_sym) => { + let lit = token::Lit::new( + token::ByteStr, + escape_byte_str_symbol(byte_sym.as_byte_str()), + None, + ); Ok(tokenstream::TokenStream::token_alone(token::TokenKind::Literal(lit), expr.span)) } ast::ExprKind::Unary(ast::UnOp::Neg, e) => match &e.kind { diff --git a/compiler/rustc_expand/src/stats.rs b/compiler/rustc_expand/src/stats.rs index 6b2ad30dffd..b4c4eac028f 100644 --- a/compiler/rustc_expand/src/stats.rs +++ b/compiler/rustc_expand/src/stats.rs @@ -15,15 +15,11 @@ pub struct MacroStat { /// Number of uses of the macro. pub uses: usize, - /// Net increase in number of lines of code (when pretty-printed), i.e. - /// `lines(output) - lines(invocation)`. Can be negative because a macro - /// output may be smaller than the invocation. - pub lines: isize, - - /// Net increase in number of lines of code (when pretty-printed), i.e. - /// `bytes(output) - bytes(invocation)`. Can be negative because a macro - /// output may be smaller than the invocation. - pub bytes: isize, + /// Number of lines of code (when pretty-printed). + pub lines: usize, + + /// Number of bytes of code (when pretty-printed). + pub bytes: usize, } pub(crate) fn elems_to_string<T>(elems: &SmallVec<[T; 1]>, f: impl Fn(&T) -> String) -> String { @@ -131,16 +127,12 @@ pub(crate) fn update_macro_stats( input: &str, fragment: &AstFragment, ) { - fn lines_and_bytes(s: &str) -> (usize, usize) { - (s.trim_end().split('\n').count(), s.len()) - } - // Measure the size of the output by pretty-printing it and counting // the lines and bytes. let name = Symbol::intern(&pprust::path_to_string(path)); let output = fragment.to_string(); - let (in_l, in_b) = lines_and_bytes(input); - let (out_l, out_b) = lines_and_bytes(&output); + let num_lines = output.trim_end().split('\n').count(); + let num_bytes = output.len(); // This code is useful for debugging `-Zmacro-stats`. For every // invocation it prints the full input and output. @@ -157,7 +149,7 @@ pub(crate) fn update_macro_stats( {name}: [{crate_name}] ({fragment_kind:?}) {span}\n\ -------------------------------\n\ {input}\n\ - -- ({in_l} lines, {in_b} bytes) --> ({out_l} lines, {out_b} bytes) --\n\ + -- {num_lines} lines, {num_bytes} bytes --\n\ {output}\n\ " ); @@ -166,6 +158,6 @@ pub(crate) fn update_macro_stats( // The recorded size is the difference between the input and the output. let entry = ecx.macro_stats.entry((name, macro_kind)).or_insert(MacroStat::default()); entry.uses += 1; - entry.lines += out_l as isize - in_l as isize; - entry.bytes += out_b as isize - in_b as isize; + entry.lines += num_lines; + entry.bytes += num_bytes; } diff --git a/compiler/rustc_feature/Cargo.toml b/compiler/rustc_feature/Cargo.toml index a5ae06473cb..78d7b698b72 100644 --- a/compiler/rustc_feature/Cargo.toml +++ b/compiler/rustc_feature/Cargo.toml @@ -5,8 +5,9 @@ edition = "2024" [dependencies] # tidy-alphabetical-start +rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_span = { path = "../rustc_span" } -serde = { version = "1.0.125", features = [ "derive" ] } +serde = { version = "1.0.125", features = ["derive"] } serde_json = "1.0.59" # tidy-alphabetical-end diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index cfe0f4e5d6c..db67c507b70 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -83,7 +83,7 @@ declare_features! ( /// Allows overloading augmented assignment operations like `a += b`. (accepted, augmented_assignments, "1.8.0", Some(28235)), /// Allows using `avx512*` target features. - (accepted, avx512_target_feature, "CURRENT_RUSTC_VERSION", Some(44839)), + (accepted, avx512_target_feature, "1.89.0", Some(44839)), /// Allows mixing bind-by-move in patterns and references to those identifiers in guards. (accepted, bind_by_move_pattern_guards, "1.39.0", Some(15287)), /// Allows bindings in the subpattern of a binding pattern. @@ -221,7 +221,7 @@ declare_features! ( /// Allows capturing variables in scope using format_args! (accepted, format_args_capture, "1.58.0", Some(67984)), /// Infer generic args for both consts and types. - (accepted, generic_arg_infer, "CURRENT_RUSTC_VERSION", Some(85077)), + (accepted, generic_arg_infer, "1.89.0", Some(85077)), /// Allows associated types to be generic, e.g., `type Foo<T>;` (RFC 1598). (accepted, generic_associated_types, "1.65.0", Some(44265)), /// Allows attributes on lifetime/type formal parameters in generics (RFC 1327). @@ -262,7 +262,7 @@ declare_features! ( /// especially around globs and shadowing (RFC 1560). (accepted, item_like_imports, "1.15.0", Some(35120)), // Allows using the `kl` and `widekl` target features and the associated intrinsics - (accepted, keylocker_x86, "CURRENT_RUSTC_VERSION", Some(134813)), + (accepted, keylocker_x86, "1.89.0", Some(134813)), /// Allows `'a: { break 'a; }`. (accepted, label_break_value, "1.65.0", Some(48594)), /// Allows `let...else` statements. @@ -341,7 +341,7 @@ declare_features! ( (accepted, pattern_parentheses, "1.31.0", Some(51087)), /// Allows `use<'a, 'b, A, B>` in `impl Trait + use<...>` for precise capture of generic args. (accepted, precise_capturing, "1.82.0", Some(123432)), - /// Allows `use<..>` precise capturign on impl Trait in traits. + /// Allows `use<..>` precise capturing on impl Trait in traits. (accepted, precise_capturing_in_traits, "1.87.0", Some(130044)), /// Allows procedural macros in `proc-macro` crates. (accepted, proc_macro, "1.29.0", Some(38356)), @@ -365,7 +365,7 @@ declare_features! ( /// Lessens the requirements for structs to implement `Unsize`. (accepted, relaxed_struct_unsize, "1.58.0", Some(81793)), /// Allows the `#[repr(i128)]` attribute for enums. - (accepted, repr128, "CURRENT_RUSTC_VERSION", Some(56071)), + (accepted, repr128, "1.89.0", Some(56071)), /// Allows `repr(align(16))` struct attribute (RFC 1358). (accepted, repr_align, "1.25.0", Some(33626)), /// Allows using `#[repr(align(X))]` on enums with equivalent semantics @@ -387,8 +387,8 @@ declare_features! ( /// Allows `Self` struct constructor (RFC 2302). (accepted, self_struct_ctor, "1.32.0", Some(51994)), /// Allows use of x86 SHA512, SM3 and SM4 target-features and intrinsics - (accepted, sha512_sm_x86, "CURRENT_RUSTC_VERSION", Some(126624)), - /// Shortern the tail expression lifetime + (accepted, sha512_sm_x86, "1.89.0", Some(126624)), + /// Shorten the tail expression lifetime (accepted, shorter_tail_lifetimes, "1.84.0", Some(123739)), /// Allows using subslice patterns, `[a, .., b]` and `[a, xs @ .., b]`. (accepted, slice_patterns, "1.42.0", Some(62254)), diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 280b33f0723..7d9915d7f68 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -5,6 +5,7 @@ use std::sync::LazyLock; use AttributeDuplicates::*; use AttributeGate::*; use AttributeType::*; +use rustc_attr_data_structures::EncodeCrossCrate; use rustc_data_structures::fx::FxHashMap; use rustc_span::edition::Edition; use rustc_span::{Symbol, sym}; @@ -368,12 +369,6 @@ macro_rules! experimental { }; } -#[derive(PartialEq)] -pub enum EncodeCrossCrate { - Yes, - No, -} - pub struct BuiltinAttribute { pub name: Symbol, /// Whether this attribute is encode cross crate. @@ -657,6 +652,19 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ EncodeCrossCrate::Yes, min_generic_const_args, experimental!(type_const), ), + // The `#[loop_match]` and `#[const_continue]` attributes are part of the + // lang experiment for RFC 3720 tracked in: + // + // - https://github.com/rust-lang/rust/issues/132306 + gated!( + const_continue, Normal, template!(Word), ErrorFollowing, + EncodeCrossCrate::No, loop_match, experimental!(const_continue) + ), + gated!( + loop_match, Normal, template!(Word), ErrorFollowing, + EncodeCrossCrate::No, loop_match, experimental!(loop_match) + ), + // ========================================================================== // Internal attributes: Stability, deprecation, and unsafe: // ========================================================================== @@ -1083,7 +1091,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ "the `#[rustc_main]` attribute is used internally to specify test entry point function", ), rustc_attr!( - rustc_skip_during_method_dispatch, Normal, template!(List: "array, boxed_slice"), WarnFollowing, + rustc_skip_during_method_dispatch, Normal, template!(List: "array, boxed_slice"), ErrorFollowing, EncodeCrossCrate::No, "the `#[rustc_skip_during_method_dispatch]` attribute is used to exclude a trait \ from method dispatch when the receiver is of the following type, for compatibility in \ @@ -1132,6 +1140,10 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ WarnFollowing, EncodeCrossCrate::Yes ), rustc_attr!( + TEST, rustc_no_implicit_bounds, CrateLevel, template!(Word), + WarnFollowing, EncodeCrossCrate::No + ), + rustc_attr!( TEST, rustc_strict_coherence, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes ), diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 0cd090b25a4..7e174c465d5 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -54,6 +54,7 @@ declare_features! ( /// Allows using the `amdgpu-kernel` ABI. (removed, abi_amdgpu_kernel, "1.77.0", Some(51575), None, 120495), + (removed, abi_c_cmse_nonsecure_call, "CURRENT_RUSTC_VERSION", Some(81391), Some("renamed to abi_cmse_nonsecure_call"), 142146), (removed, advanced_slice_patterns, "1.42.0", Some(62254), Some("merged into `#![feature(slice_patterns)]`"), 67712), (removed, allocator, "1.0.0", None, None), @@ -86,7 +87,7 @@ declare_features! ( Some("at compile-time, pointers do not have an integer value, so these casts cannot be properly supported"), 87020), /// Allows `T: ?const Trait` syntax in bounds. (removed, const_trait_bound_opt_out, "1.56.0", Some(67794), - Some("Removed in favor of `~const` bound in #![feature(const_trait_impl)]"), 88328), + Some("Removed in favor of `[const]` bound in #![feature(const_trait_impl)]"), 88328), /// Allows using `crate` as visibility modifier, synonymous with `pub(crate)`. (removed, crate_visibility_modifier, "1.63.0", Some(53120), Some("removed in favor of `pub(crate)`"), 97254), /// Allows using custom attributes (RFC 572). @@ -122,7 +123,10 @@ declare_features! ( /// [^1]: Formerly known as "object safe". (removed, dyn_compatible_for_dispatch, "1.87.0", Some(43561), Some("removed, not used heavily and represented additional complexity in dyn compatibility"), 136522), - /// Uses generic effect parameters for ~const bounds + /// Allows `dyn* Trait` objects. + (removed, dyn_star, "1.65.0", Some(102425), + Some("removed as it was no longer necessary for AFIDT (async fn in dyn trait) support")), + /// Uses generic effect parameters for [const] bounds (removed, effects, "1.84.0", Some(102090), Some("removed, redundant with `#![feature(const_trait_impl)]`"), 132479), /// Allows defining `existential type`s. @@ -221,7 +225,7 @@ declare_features! ( /// Allows exhaustive integer pattern matching with `usize::MAX`/`isize::MIN`/`isize::MAX`. (removed, precise_pointer_size_matching, "1.76.0", Some(56354), Some("removed in favor of half-open ranges"), 118598), - (removed, pref_align_of, "CURRENT_RUSTC_VERSION", Some(91971), + (removed, pref_align_of, "1.89.0", Some(91971), Some("removed due to marginal use and inducing compiler complications")), (removed, proc_macro_expr, "1.27.0", Some(54727), Some("subsumed by `#![feature(proc_macro_hygiene)]`"), 52121), @@ -264,7 +268,7 @@ declare_features! ( (removed, unnamed_fields, "1.83.0", Some(49804), Some("feature needs redesign"), 131045), (removed, unsafe_no_drop_flag, "1.0.0", None, None), /// Allows unsized rvalues at arguments and parameters. - (removed, unsized_locals, "CURRENT_RUSTC_VERSION", Some(48055), Some("removed due to implementation concerns; see https://github.com/rust-lang/rust/issues/111942")), + (removed, unsized_locals, "1.89.0", Some(48055), Some("removed due to implementation concerns; see https://github.com/rust-lang/rust/issues/111942")), (removed, unsized_tuple_coercion, "1.87.0", Some(42877), Some("The feature restricts possible layouts for tuples, and this restriction is not worth it."), 137728), /// Allows `union` fields that don't implement `Copy` as long as they don't have any drop glue. @@ -285,4 +289,18 @@ declare_features! ( // ------------------------------------------------------------------------- // feature-group-end: removed features // ------------------------------------------------------------------------- + + + // ------------------------------------------------------------------------- + // feature-group-start: removed library features + // ------------------------------------------------------------------------- + // + // FIXME(#141617): we should have a better way to track removed library features, but we reuse + // the infrastructure here so users still get hints. The symbols used here can be remove from + // `symbol.rs` when that happens. + (removed, concat_idents, "CURRENT_RUSTC_VERSION", Some(29599), + Some("use the `${concat(..)}` metavariable expression instead"), 142704), + // ------------------------------------------------------------------------- + // feature-group-end: removed library features + // ------------------------------------------------------------------------- ); diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 91715851226..269a9c60d86 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -238,7 +238,7 @@ declare_features! ( /// Allows using `rustc_*` attributes (RFC 572). (internal, rustc_attrs, "1.0.0", None), /// Introduces a hierarchy of `Sized` traits (RFC 3729). - (unstable, sized_hierarchy, "CURRENT_RUSTC_VERSION", None), + (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. @@ -353,10 +353,10 @@ declare_features! ( /// Allows `extern "avr-interrupt" fn()` and `extern "avr-non-blocking-interrupt" fn()`. (unstable, abi_avr_interrupt, "1.45.0", Some(69664)), - /// Allows `extern "C-cmse-nonsecure-call" fn()`. - (unstable, abi_c_cmse_nonsecure_call, "1.51.0", Some(81391)), + /// Allows `extern "cmse-nonsecure-call" fn()`. + (unstable, abi_cmse_nonsecure_call, "CURRENT_RUSTC_VERSION", Some(81391)), /// Allows `extern "custom" fn()`. - (unstable, abi_custom, "CURRENT_RUSTC_VERSION", Some(140829)), + (unstable, abi_custom, "1.89.0", Some(140829)), /// Allows `extern "gpu-kernel" fn()`. (unstable, abi_gpu_kernel, "1.86.0", Some(135467)), /// Allows `extern "msp430-interrupt" fn()`. @@ -376,7 +376,7 @@ declare_features! ( /// Allows inherent and trait methods with arbitrary self types that are raw pointers. (unstable, arbitrary_self_types_pointers, "1.83.0", Some(44874)), /// Allows #[cfg(...)] on inline assembly templates and operands. - (unstable, asm_cfg, "CURRENT_RUSTC_VERSION", Some(140364)), + (unstable, asm_cfg, "1.89.0", Some(140364)), /// Enables experimental inline assembly support for additional architectures. (unstable, asm_experimental_arch, "1.58.0", Some(93335)), /// Enables experimental register support in inline assembly. @@ -431,13 +431,13 @@ declare_features! ( (unstable, closure_lifetime_binder, "1.64.0", Some(97362)), /// Allows `#[track_caller]` on closures and coroutines. (unstable, closure_track_caller, "1.57.0", Some(87417)), - /// Allows `extern "C-cmse-nonsecure-entry" fn()`. + /// Allows `extern "cmse-nonsecure-entry" fn()`. (unstable, cmse_nonsecure_entry, "1.48.0", Some(75835)), /// Allows `async {}` expressions in const contexts. (unstable, const_async_blocks, "1.53.0", Some(85368)), /// Allows `const || {}` closures in const contexts. (incomplete, const_closures, "1.68.0", Some(106003)), - /// Allows using `~const Destruct` bounds and calling drop impls in const contexts. + /// Allows using `[const] Destruct` bounds and calling drop impls in const contexts. (unstable, const_destruct, "1.85.0", Some(133214)), /// Allows `for _ in _` loops in const contexts. (unstable, const_for, "1.56.0", Some(87575)), @@ -481,8 +481,6 @@ declare_features! ( (unstable, doc_cfg_hide, "1.57.0", Some(43781)), /// Allows `#[doc(masked)]`. (unstable, doc_masked, "1.21.0", Some(44027)), - /// Allows `dyn* Trait` objects. - (incomplete, dyn_star, "1.65.0", Some(102425)), /// Allows the .use postfix syntax `x.use` and use closures `use |x| { ... }` (incomplete, ergonomic_clones, "1.87.0", Some(132290)), /// Allows exhaustive pattern matching on types that contain uninhabited types. @@ -557,6 +555,8 @@ declare_features! ( /// Allows using `#[link(kind = "link-arg", name = "...")]` /// to pass custom arguments to the linker. (unstable, link_arg_attribute, "1.76.0", Some(99427)), + /// Allows fused `loop`/`match` for direct intraprocedural jumps. + (incomplete, loop_match, "CURRENT_RUSTC_VERSION", Some(132306)), /// Give access to additional metadata about declarative macro meta-variables. (unstable, macro_metavar_expr, "1.61.0", Some(83527)), /// Provides a way to concatenate identifiers using metavariable expressions. diff --git a/compiler/rustc_hir/src/arena.rs b/compiler/rustc_hir/src/arena.rs index b0dff635a9b..180cb6497e7 100644 --- a/compiler/rustc_hir/src/arena.rs +++ b/compiler/rustc_hir/src/arena.rs @@ -8,7 +8,6 @@ macro_rules! arena_types { [] asm_template: rustc_ast::InlineAsmTemplatePiece, [] attribute: rustc_hir::Attribute, [] owner_info: rustc_hir::OwnerInfo<'tcx>, - [] lit: rustc_hir::Lit, [] macro_def: rustc_ast::MacroDef, ]); ) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 679904c7cfe..c90cd93ff07 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -956,7 +956,7 @@ impl<'hir> Generics<'hir> { && let Some(ret_ty) = segment.args().paren_sugar_output() && let ret_ty = ret_ty.peel_refs() && let TyKind::TraitObject(_, tagged_ptr) = ret_ty.kind - && let TraitObjectSyntax::Dyn | TraitObjectSyntax::DynStar = tagged_ptr.tag() + && let TraitObjectSyntax::Dyn = tagged_ptr.tag() && ret_ty.span.can_be_used_for_suggestions() { Some(ret_ty.span) @@ -1807,7 +1807,7 @@ pub struct PatExpr<'hir> { #[derive(Debug, Clone, Copy, HashStable_Generic)] pub enum PatExprKind<'hir> { Lit { - lit: &'hir Lit, + lit: Lit, // FIXME: move this into `Lit` and handle negated literal expressions // once instead of matching on unop neg expressions everywhere. negated: bool, @@ -2734,7 +2734,7 @@ pub enum ExprKind<'hir> { /// A unary operation (e.g., `!x`, `*x`). Unary(UnOp, &'hir Expr<'hir>), /// A literal (e.g., `1`, `"foo"`). - Lit(&'hir Lit), + Lit(Lit), /// A cast (e.g., `foo as f64`). Cast(&'hir Expr<'hir>, &'hir Ty<'hir>), /// A type ascription (e.g., `x: Foo`). See RFC 3307. @@ -4400,27 +4400,6 @@ impl ItemKind<'_> { _ => return None, }) } - - pub fn descr(&self) -> &'static str { - match self { - ItemKind::ExternCrate(..) => "extern crate", - ItemKind::Use(..) => "`use` import", - ItemKind::Static(..) => "static item", - ItemKind::Const(..) => "constant item", - ItemKind::Fn { .. } => "function", - ItemKind::Macro(..) => "macro", - ItemKind::Mod(..) => "module", - ItemKind::ForeignMod { .. } => "extern block", - ItemKind::GlobalAsm { .. } => "global asm item", - ItemKind::TyAlias(..) => "type alias", - ItemKind::Enum(..) => "enum", - ItemKind::Struct(..) => "struct", - ItemKind::Union(..) => "union", - ItemKind::Trait(..) => "trait", - ItemKind::TraitAlias(..) => "trait alias", - ItemKind::Impl(..) => "implementation", - } - } } /// A reference from an trait to one of its associated items. This @@ -4834,6 +4813,10 @@ impl<'hir> Node<'hir> { ImplItemKind::Type(ty) => Some(ty), _ => None, }, + Node::ForeignItem(it) => match it.kind { + ForeignItemKind::Static(ty, ..) => Some(ty), + _ => None, + }, _ => None, } } @@ -4992,9 +4975,9 @@ mod size_asserts { static_assert_size!(LetStmt<'_>, 72); static_assert_size!(Param<'_>, 32); static_assert_size!(Pat<'_>, 72); + static_assert_size!(PatKind<'_>, 48); static_assert_size!(Path<'_>, 40); static_assert_size!(PathSegment<'_>, 48); - static_assert_size!(PatKind<'_>, 48); static_assert_size!(QPath<'_>, 24); static_assert_size!(Res, 12); static_assert_size!(Stmt<'_>, 32); diff --git a/compiler/rustc_hir/src/hir/tests.rs b/compiler/rustc_hir/src/hir/tests.rs index 1fd793bc161..4f9609fd360 100644 --- a/compiler/rustc_hir/src/hir/tests.rs +++ b/compiler/rustc_hir/src/hir/tests.rs @@ -45,7 +45,6 @@ define_tests! { #[test] fn trait_object_roundtrips() { trait_object_roundtrips_impl(TraitObjectSyntax::Dyn); - trait_object_roundtrips_impl(TraitObjectSyntax::DynStar); trait_object_roundtrips_impl(TraitObjectSyntax::None); } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 57e49625148..a0bc318e2ca 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -347,7 +347,7 @@ pub trait Visitor<'v>: Sized { fn visit_pat_expr(&mut self, expr: &'v PatExpr<'v>) -> Self::Result { walk_pat_expr(self, expr) } - fn visit_lit(&mut self, _hir_id: HirId, _lit: &'v Lit, _negated: bool) -> Self::Result { + fn visit_lit(&mut self, _hir_id: HirId, _lit: Lit, _negated: bool) -> Self::Result { Self::Result::output() } fn visit_anon_const(&mut self, c: &'v AnonConst) -> Self::Result { @@ -786,7 +786,7 @@ pub fn walk_pat_expr<'v, V: Visitor<'v>>(visitor: &mut V, expr: &'v PatExpr<'v>) let PatExpr { hir_id, span, kind } = expr; try_visit!(visitor.visit_id(*hir_id)); match kind { - PatExprKind::Lit { lit, negated } => visitor.visit_lit(*hir_id, lit, *negated), + PatExprKind::Lit { lit, negated } => visitor.visit_lit(*hir_id, *lit, *negated), PatExprKind::ConstBlock(c) => visitor.visit_inline_const(c), PatExprKind::Path(qpath) => visitor.visit_qpath(qpath, *hir_id, *span), } diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 3a08e5ae336..10dd5ff9aa7 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -312,6 +312,7 @@ language_item_table! { PanicAsyncGenFnResumedPanic, sym::panic_const_async_gen_fn_resumed_panic, panic_const_async_gen_fn_resumed_panic, Target::Fn, GenericRequirement::None; PanicGenFnNonePanic, sym::panic_const_gen_fn_none_panic, panic_const_gen_fn_none_panic, Target::Fn, GenericRequirement::None; PanicNullPointerDereference, sym::panic_null_pointer_dereference, panic_null_pointer_dereference, Target::Fn, GenericRequirement::None; + PanicInvalidEnumConstruction, sym::panic_invalid_enum_construction, panic_invalid_enum_construction, Target::Fn, GenericRequirement::None; PanicCoroutineResumedDrop, sym::panic_const_coroutine_resumed_drop, panic_const_coroutine_resumed_drop, Target::Fn, GenericRequirement::None; PanicAsyncFnResumedDrop, sym::panic_const_async_fn_resumed_drop, panic_const_async_fn_resumed_drop, Target::Fn, GenericRequirement::None; PanicAsyncGenFnResumedDrop, sym::panic_const_async_gen_fn_resumed_drop, panic_const_async_gen_fn_resumed_drop, Target::Fn, GenericRequirement::None; diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index bd2252c1bf8..529d3578985 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -1,5 +1,5 @@ hir_analysis_abi_custom_clothed_function = - items with the `"custom"` ABI can only be declared externally or defined via naked functions + items with the "custom" ABI can only be declared externally or defined via naked functions .suggestion = convert this to an `#[unsafe(naked)]` function hir_analysis_ambiguous_assoc_item = ambiguous associated {$assoc_kind} `{$assoc_ident}` in bounds of `{$qself}` @@ -73,10 +73,10 @@ hir_analysis_closure_implicit_hrtb = implicit types in closure signatures are fo .label = `for<...>` is here hir_analysis_cmse_call_generic = - function pointers with the `"C-cmse-nonsecure-call"` ABI cannot contain generics in their type + function pointers with the `"cmse-nonsecure-call"` ABI cannot contain generics in their type hir_analysis_cmse_entry_generic = - functions with the `"C-cmse-nonsecure-entry"` ABI cannot contain generics in their type + functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type hir_analysis_cmse_inputs_stack_spill = arguments for `{$abi}` function too large to pass via registers @@ -447,6 +447,9 @@ hir_analysis_parenthesized_fn_trait_expansion = hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind} .label = not allowed in type signatures + +hir_analysis_pointee_sized_trait_object = `PointeeSized` cannot be used with trait objects + hir_analysis_precise_capture_self_alias = `Self` can't be captured in `use<...>` precise captures list, since it is an alias .label = `Self` is not a generic argument, but an alias to the type of the {$what} diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 485dd1d2204..f4fcb13b1a1 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -10,7 +10,7 @@ use rustc_errors::{EmissionGuarantee, MultiSpan}; use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::{LangItem, Node, intravisit}; use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt}; -use rustc_infer::traits::{Obligation, ObligationCauseCode}; +use rustc_infer::traits::{Obligation, ObligationCauseCode, WellFormedLoc}; use rustc_lint_defs::builtin::{ REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, UNSUPPORTED_CALLING_CONVENTIONS, }; @@ -36,6 +36,10 @@ use {rustc_attr_data_structures as attrs, rustc_hir as hir}; use super::compare_impl_item::check_type_bounds; use super::*; +use crate::check::wfcheck::{ + check_associated_item, check_trait_item, check_variances_for_type_defn, check_where_clauses, + enter_wf_checking_ctxt, +}; fn add_abi_diag_help<T: EmissionGuarantee>(abi: ExternAbi, diag: &mut Diag<'_, T>) { if let ExternAbi::Cdecl { unwind } = abi { @@ -312,7 +316,7 @@ fn check_opaque_meets_bounds<'tcx>( // here rather than using ReErased. let hidden_ty = tcx.type_of(def_id.to_def_id()).instantiate(tcx, args); let hidden_ty = fold_regions(tcx, hidden_ty, |re, _dbi| match re.kind() { - ty::ReErased => infcx.next_region_var(RegionVariableOrigin::MiscVariable(span)), + ty::ReErased => infcx.next_region_var(RegionVariableOrigin::Misc(span)), _ => re, }); @@ -344,7 +348,7 @@ fn check_opaque_meets_bounds<'tcx>( let misc_cause = ObligationCause::misc(span, def_id); // FIXME: We should just register the item bounds here, rather than equating. // FIXME(const_trait_impl): When we do that, please make sure to also register - // the `~const` bounds. + // the `[const]` bounds. match ocx.eq(&misc_cause, param_env, opaque_ty, hidden_ty) { Ok(()) => {} Err(ty_err) => { @@ -729,7 +733,8 @@ fn check_static_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) { } } -pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { +pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> { + let mut res = Ok(()); let generics = tcx.generics_of(def_id); for param in &generics.own_params { @@ -754,15 +759,39 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { } match tcx.def_kind(def_id) { - DefKind::Static { .. } => { - check_static_inhabited(tcx, def_id); - check_static_linkage(tcx, def_id); + def_kind @ (DefKind::Static { .. } | DefKind::Const) => { + tcx.ensure_ok().generics_of(def_id); + tcx.ensure_ok().type_of(def_id); + tcx.ensure_ok().predicates_of(def_id); + match def_kind { + DefKind::Static { .. } => { + check_static_inhabited(tcx, def_id); + check_static_linkage(tcx, def_id); + res = res.and(wfcheck::check_static_item(tcx, def_id)); + + // Only `Node::Item` and `Node::ForeignItem` still have HIR based + // checks. Returning early here does not miss any checks and + // avoids this query from having a direct dependency edge on the HIR + return res; + } + DefKind::Const => {} + _ => unreachable!(), + } } - DefKind::Const => {} DefKind::Enum => { + tcx.ensure_ok().generics_of(def_id); + tcx.ensure_ok().type_of(def_id); + tcx.ensure_ok().predicates_of(def_id); + crate::collect::lower_enum_variant_types(tcx, def_id.to_def_id()); check_enum(tcx, def_id); + check_variances_for_type_defn(tcx, def_id); } DefKind::Fn => { + tcx.ensure_ok().generics_of(def_id); + tcx.ensure_ok().type_of(def_id); + tcx.ensure_ok().predicates_of(def_id); + tcx.ensure_ok().fn_sig(def_id); + tcx.ensure_ok().codegen_fn_attrs(def_id); if let Some(i) = tcx.intrinsic(def_id) { intrinsic::check_intrinsic_type( tcx, @@ -773,17 +802,31 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { } } DefKind::Impl { of_trait } => { + tcx.ensure_ok().generics_of(def_id); + tcx.ensure_ok().type_of(def_id); + tcx.ensure_ok().impl_trait_header(def_id); + tcx.ensure_ok().predicates_of(def_id); + tcx.ensure_ok().associated_items(def_id); if of_trait && let Some(impl_trait_header) = tcx.impl_trait_header(def_id) { - if tcx - .ensure_ok() - .coherent_trait(impl_trait_header.trait_ref.instantiate_identity().def_id) - .is_ok() - { + res = res.and( + tcx.ensure_ok() + .coherent_trait(impl_trait_header.trait_ref.instantiate_identity().def_id), + ); + + if res.is_ok() { + // Checking this only makes sense if the all trait impls satisfy basic + // requirements (see `coherent_trait` query), otherwise + // we run into infinite recursions a lot. check_impl_items_against_trait(tcx, def_id, impl_trait_header); } } } DefKind::Trait => { + tcx.ensure_ok().generics_of(def_id); + tcx.ensure_ok().trait_def(def_id); + tcx.ensure_ok().explicit_super_predicates_of(def_id); + tcx.ensure_ok().predicates_of(def_id); + tcx.ensure_ok().associated_items(def_id); let assoc_items = tcx.associated_items(def_id); check_on_unimplemented(tcx, def_id); @@ -802,11 +845,33 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { } } } - DefKind::Struct => { - check_struct(tcx, def_id); + DefKind::TraitAlias => { + tcx.ensure_ok().generics_of(def_id); + tcx.ensure_ok().explicit_implied_predicates_of(def_id); + tcx.ensure_ok().explicit_super_predicates_of(def_id); + tcx.ensure_ok().predicates_of(def_id); } - DefKind::Union => { - check_union(tcx, def_id); + def_kind @ (DefKind::Struct | DefKind::Union) => { + tcx.ensure_ok().generics_of(def_id); + tcx.ensure_ok().type_of(def_id); + tcx.ensure_ok().predicates_of(def_id); + + let adt = tcx.adt_def(def_id).non_enum_variant(); + for f in adt.fields.iter() { + tcx.ensure_ok().generics_of(f.did); + tcx.ensure_ok().type_of(f.did); + tcx.ensure_ok().predicates_of(f.did); + } + + if let Some((_, ctor_def_id)) = adt.ctor { + crate::collect::lower_variant_ctor(tcx, ctor_def_id.expect_local()); + } + match def_kind { + DefKind::Struct => check_struct(tcx, def_id), + DefKind::Union => check_union(tcx, def_id), + _ => unreachable!(), + } + check_variances_for_type_defn(tcx, def_id); } DefKind::OpaqueTy => { check_opaque_precise_captures(tcx, def_id); @@ -831,14 +896,37 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { tcx.ensure_ok().explicit_implied_const_bounds(def_id); tcx.ensure_ok().const_conditions(def_id); } + + // Only `Node::Item` and `Node::ForeignItem` still have HIR based + // checks. Returning early here does not miss any checks and + // avoids this query from having a direct dependency edge on the HIR + return res; } DefKind::TyAlias => { + tcx.ensure_ok().generics_of(def_id); + tcx.ensure_ok().type_of(def_id); + tcx.ensure_ok().predicates_of(def_id); check_type_alias_type_params_are_used(tcx, def_id); + if tcx.type_alias_is_lazy(def_id) { + res = res.and(enter_wf_checking_ctxt(tcx, def_id, |wfcx| { + let ty = tcx.type_of(def_id).instantiate_identity(); + let span = tcx.def_span(def_id); + let item_ty = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(def_id)), ty); + wfcx.register_wf_obligation( + span, + Some(WellFormedLoc::Ty(def_id)), + item_ty.into(), + ); + check_where_clauses(wfcx, def_id); + Ok(()) + })); + check_variances_for_type_defn(tcx, def_id); + } } DefKind::ForeignMod => { let it = tcx.hir_expect_item(def_id); let hir::ItemKind::ForeignMod { abi, items } = it.kind else { - return; + return Ok(()); }; check_abi(tcx, it.hir_id(), it.span, abi); @@ -877,15 +965,23 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { } let item = tcx.hir_foreign_item(item.id); - match &item.kind { - hir::ForeignItemKind::Fn(sig, _, _) => { + tcx.ensure_ok().generics_of(item.owner_id); + tcx.ensure_ok().type_of(item.owner_id); + tcx.ensure_ok().predicates_of(item.owner_id); + if tcx.is_conditionally_const(def_id) { + tcx.ensure_ok().explicit_implied_const_bounds(def_id); + tcx.ensure_ok().const_conditions(def_id); + } + match item.kind { + hir::ForeignItemKind::Fn(sig, ..) => { + tcx.ensure_ok().codegen_fn_attrs(item.owner_id); + tcx.ensure_ok().fn_sig(item.owner_id); require_c_abi_if_c_variadic(tcx, sig.decl, abi, item.span); } hir::ForeignItemKind::Static(..) => { - check_static_inhabited(tcx, def_id); - check_static_linkage(tcx, def_id); + tcx.ensure_ok().codegen_fn_attrs(item.owner_id); } - _ => {} + _ => (), } } } @@ -897,9 +993,85 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { // We do not call `type_of` for closures here as that // depends on typecheck and would therefore hide // any further errors in case one typeck fails. + + // Only `Node::Item` and `Node::ForeignItem` still have HIR based + // checks. Returning early here does not miss any checks and + // avoids this query from having a direct dependency edge on the HIR + return res; + } + DefKind::AssocFn => { + tcx.ensure_ok().codegen_fn_attrs(def_id); + tcx.ensure_ok().type_of(def_id); + tcx.ensure_ok().fn_sig(def_id); + tcx.ensure_ok().predicates_of(def_id); + res = res.and(check_associated_item(tcx, def_id)); + let assoc_item = tcx.associated_item(def_id); + match assoc_item.container { + ty::AssocItemContainer::Impl => {} + ty::AssocItemContainer::Trait => { + res = res.and(check_trait_item(tcx, def_id)); + } + } + + // Only `Node::Item` and `Node::ForeignItem` still have HIR based + // checks. Returning early here does not miss any checks and + // avoids this query from having a direct dependency edge on the HIR + return res; + } + DefKind::AssocConst => { + tcx.ensure_ok().type_of(def_id); + tcx.ensure_ok().predicates_of(def_id); + res = res.and(check_associated_item(tcx, def_id)); + let assoc_item = tcx.associated_item(def_id); + match assoc_item.container { + ty::AssocItemContainer::Impl => {} + ty::AssocItemContainer::Trait => { + res = res.and(check_trait_item(tcx, def_id)); + } + } + + // Only `Node::Item` and `Node::ForeignItem` still have HIR based + // checks. Returning early here does not miss any checks and + // avoids this query from having a direct dependency edge on the HIR + return res; } + DefKind::AssocTy => { + tcx.ensure_ok().predicates_of(def_id); + res = res.and(check_associated_item(tcx, def_id)); + + let assoc_item = tcx.associated_item(def_id); + let has_type = match assoc_item.container { + ty::AssocItemContainer::Impl => true, + ty::AssocItemContainer::Trait => { + tcx.ensure_ok().item_bounds(def_id); + tcx.ensure_ok().item_self_bounds(def_id); + res = res.and(check_trait_item(tcx, def_id)); + assoc_item.defaultness(tcx).has_value() + } + }; + if has_type { + tcx.ensure_ok().type_of(def_id); + } + + // Only `Node::Item` and `Node::ForeignItem` still have HIR based + // checks. Returning early here does not miss any checks and + // avoids this query from having a direct dependency edge on the HIR + return res; + } + + // Only `Node::Item` and `Node::ForeignItem` still have HIR based + // checks. Returning early here does not miss any checks and + // avoids this query from having a direct dependency edge on the HIR + DefKind::AnonConst | DefKind::InlineConst => return res, _ => {} } + let node = tcx.hir_node_by_def_id(def_id); + res.and(match node { + hir::Node::Crate(_) => bug!("check_well_formed cannot be applied to the crate root"), + hir::Node::Item(item) => wfcheck::check_item(tcx, item), + hir::Node::ForeignItem(item) => wfcheck::check_foreign_item(tcx, item), + _ => unreachable!("{node:?}"), + }) } pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, def_id: LocalDefId) { diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 47681a78ecc..abbe497858b 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -9,7 +9,7 @@ use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, pluralize, struct_ use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::VisitorExt; use rustc_hir::{self as hir, AmbigArg, GenericParamKind, ImplItemKind, intravisit}; -use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; +use rustc_infer::infer::{self, BoundRegionConversionTime, InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::util; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{ @@ -264,9 +264,9 @@ fn compare_method_predicate_entailment<'tcx>( } // If we're within a const implementation, we need to make sure that the method - // does not assume stronger `~const` bounds than the trait definition. + // does not assume stronger `[const]` bounds than the trait definition. // - // This registers the `~const` bounds of the impl method, which we will prove + // This registers the `[const]` bounds of the impl method, which we will prove // using the hybrid param-env that we earlier augmented with the const conditions // from the impl header and trait method declaration. if is_conditionally_const { @@ -311,7 +311,7 @@ fn compare_method_predicate_entailment<'tcx>( let unnormalized_impl_sig = infcx.instantiate_binder_with_fresh_vars( impl_m_span, - infer::HigherRankedType, + BoundRegionConversionTime::HigherRankedType, tcx.fn_sig(impl_m.def_id).instantiate_identity(), ); @@ -518,7 +518,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( param_env, infcx.instantiate_binder_with_fresh_vars( return_span, - infer::HigherRankedType, + BoundRegionConversionTime::HigherRankedType, tcx.fn_sig(impl_m.def_id).instantiate_identity(), ), ); @@ -2335,7 +2335,7 @@ pub(super) fn check_type_bounds<'tcx>( ) .collect(); - // Only in a const implementation do we need to check that the `~const` item bounds hold. + // Only in a const implementation do we need to check that the `[const]` item bounds hold. if tcx.is_conditionally_const(impl_ty_def_id) { obligations.extend(util::elaborate( tcx, diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs index 3bad36da999..b556683e80a 100644 --- a/compiler/rustc_hir_analysis/src/check/entry.rs +++ b/compiler/rustc_hir_analysis/src/check/entry.rs @@ -1,14 +1,15 @@ use std::ops::Not; use rustc_abi::ExternAbi; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_hir as hir; use rustc_hir::Node; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::span_bug; use rustc_middle::ty::{self, TyCtxt, TypingMode}; use rustc_session::config::EntryFnType; +use rustc_span::Span; use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; -use rustc_span::{Span, sym}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; @@ -98,8 +99,10 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { error = true; } - for attr in tcx.get_attrs(main_def_id, sym::track_caller) { - tcx.dcx().emit_err(errors::TrackCallerOnMain { span: attr.span(), annotated: main_span }); + if let Some(attr_span) = + find_attr!(tcx.get_all_attrs(main_def_id), AttributeKind::TrackCaller(span) => *span) + { + tcx.dcx().emit_err(errors::TrackCallerOnMain { span: attr_span, annotated: main_span }); error = true; } diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 060fc51b7bd..cebf7d1b532 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -594,8 +594,9 @@ pub(crate) fn check_intrinsic_type( | sym::simd_ceil | sym::simd_floor | sym::simd_round + | sym::simd_round_ties_even | sym::simd_trunc => (1, 0, vec![param(0)], param(0)), - sym::simd_fma | sym::simd_relaxed_fma => { + sym::simd_fma | sym::simd_relaxed_fma | sym::simd_funnel_shl | sym::simd_funnel_shr => { (1, 0, vec![param(0), param(0), param(0)], param(0)) } sym::simd_gather => (3, 0, vec![param(0), param(1), param(2)], param(0)), diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index d05e381f8c8..ed8d25e9915 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -11,7 +11,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; use rustc_hir::{AmbigArg, ItemKind}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; -use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; +use rustc_infer::infer::{self, InferCtxt, SubregionOrigin, TyCtxtInferExt}; use rustc_lint_defs::builtin::SUPERTRAIT_ITEM_SHADOWING_DEFINITION; use rustc_macros::LintDiagnostic; use rustc_middle::mir::interpret::ErrorHandled; @@ -25,7 +25,7 @@ use rustc_middle::ty::{ }; use rustc_middle::{bug, span_bug}; use rustc_session::parse::feature_err; -use rustc_span::{DUMMY_SP, Ident, Span, sym}; +use rustc_span::{DUMMY_SP, Span, sym}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::regions::{InferCtxtRegionExt, OutlivesEnvironmentBuildExt}; use rustc_trait_selection::traits::misc::{ @@ -46,7 +46,6 @@ use crate::{errors, fluent_generated as fluent}; pub(super) struct WfCheckingCtxt<'a, 'tcx> { pub(super) ocx: ObligationCtxt<'a, 'tcx, FulfillmentError<'tcx>>, - span: Span, body_def_id: LocalDefId, param_env: ty::ParamEnv<'tcx>, } @@ -84,7 +83,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { /// signature types for implied bounds when checking regions. // FIXME(-Znext-solver): This should be removed when we compute implied outlives // bounds using the unnormalized signature of the function we're checking. - fn deeply_normalize<T>(&self, span: Span, loc: Option<WellFormedLoc>, value: T) -> T + pub(super) fn deeply_normalize<T>(&self, span: Span, loc: Option<WellFormedLoc>, value: T) -> T where T: TypeFoldable<TyCtxt<'tcx>>, { @@ -105,7 +104,12 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { } } - fn register_wf_obligation(&self, span: Span, loc: Option<WellFormedLoc>, term: ty::Term<'tcx>) { + pub(super) fn register_wf_obligation( + &self, + span: Span, + loc: Option<WellFormedLoc>, + term: ty::Term<'tcx>, + ) { let cause = traits::ObligationCause::new( span, self.body_def_id, @@ -122,7 +126,6 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { pub(super) fn enter_wf_checking_ctxt<'tcx, F>( tcx: TyCtxt<'tcx>, - span: Span, body_def_id: LocalDefId, f: F, ) -> Result<(), ErrorGuaranteed> @@ -133,7 +136,7 @@ where let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(infcx); - let mut wfcx = WfCheckingCtxt { ocx, span, body_def_id, param_env }; + let mut wfcx = WfCheckingCtxt { ocx, body_def_id, param_env }; if !tcx.features().trivial_bounds() { wfcx.check_false_global_bounds() @@ -187,23 +190,10 @@ where } fn check_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> { - let node = tcx.hir_node_by_def_id(def_id); - let mut res = match node { - hir::Node::Crate(_) => bug!("check_well_formed cannot be applied to the crate root"), - hir::Node::Item(item) => check_item(tcx, item), - hir::Node::TraitItem(item) => check_trait_item(tcx, item), - hir::Node::ImplItem(item) => check_impl_item(tcx, item), - hir::Node::ForeignItem(item) => check_foreign_item(tcx, item), - hir::Node::ConstBlock(_) | hir::Node::Expr(_) | hir::Node::OpaqueTy(_) => { - Ok(crate::check::check::check_item_type(tcx, def_id)) - } - _ => unreachable!("{node:?}"), - }; + let mut res = crate::check::check::check_item_type(tcx, def_id); - if let Some(generics) = node.generics() { - for param in generics.params { - res = res.and(check_param_wf(tcx, param)); - } + for param in &tcx.generics_of(def_id).own_params { + res = res.and(check_param_wf(tcx, param)); } res @@ -223,17 +213,18 @@ fn check_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGua /// not included it frequently leads to confusing errors in fn bodies. So it's better to check /// the types first. #[instrument(skip(tcx), level = "debug")] -fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<(), ErrorGuaranteed> { +pub(super) fn check_item<'tcx>( + tcx: TyCtxt<'tcx>, + item: &'tcx hir::Item<'tcx>, +) -> Result<(), ErrorGuaranteed> { let def_id = item.owner_id.def_id; debug!( ?item.owner_id, item.name = ? tcx.def_path_str(def_id) ); - crate::collect::lower_item(tcx, item.item_id()); - crate::collect::reject_placeholder_type_signatures_in_item(tcx, item); - let res = match item.kind { + match item.kind { // Right now we check that every default trait implementation // has an implementation of itself. Basically, a case like: // @@ -296,57 +287,18 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<() } res } - hir::ItemKind::Fn { ident, sig, .. } => { - check_item_fn(tcx, def_id, ident, item.span, sig.decl) - } - hir::ItemKind::Static(_, _, ty, _) => { - check_static_item(tcx, def_id, ty.span, UnsizedHandling::Forbid) - } - hir::ItemKind::Const(_, _, ty, _) => check_const_item(tcx, def_id, ty.span, item.span), - hir::ItemKind::Struct(_, generics, _) => { - let res = check_type_defn(tcx, item, false); - check_variances_for_type_defn(tcx, item, generics); - res - } - hir::ItemKind::Union(_, generics, _) => { - let res = check_type_defn(tcx, item, true); - check_variances_for_type_defn(tcx, item, generics); - res - } - hir::ItemKind::Enum(_, generics, _) => { - let res = check_type_defn(tcx, item, true); - check_variances_for_type_defn(tcx, item, generics); - res - } + hir::ItemKind::Fn { sig, .. } => check_item_fn(tcx, def_id, sig.decl), + hir::ItemKind::Const(_, _, ty, _) => check_const_item(tcx, def_id, ty.span), + hir::ItemKind::Struct(..) => check_type_defn(tcx, item, false), + hir::ItemKind::Union(..) => check_type_defn(tcx, item, true), + hir::ItemKind::Enum(..) => check_type_defn(tcx, item, true), hir::ItemKind::Trait(..) => check_trait(tcx, item), hir::ItemKind::TraitAlias(..) => check_trait(tcx, item), - // `ForeignItem`s are handled separately. - hir::ItemKind::ForeignMod { .. } => Ok(()), - hir::ItemKind::TyAlias(_, generics, hir_ty) if tcx.type_alias_is_lazy(item.owner_id) => { - let res = enter_wf_checking_ctxt(tcx, item.span, def_id, |wfcx| { - let ty = tcx.type_of(def_id).instantiate_identity(); - let item_ty = - wfcx.deeply_normalize(hir_ty.span, Some(WellFormedLoc::Ty(def_id)), ty); - wfcx.register_wf_obligation( - hir_ty.span, - Some(WellFormedLoc::Ty(def_id)), - item_ty.into(), - ); - check_where_clauses(wfcx, item.span, def_id); - Ok(()) - }); - check_variances_for_type_defn(tcx, item, generics); - res - } _ => Ok(()), - }; - - crate::check::check::check_item_type(tcx, def_id); - - res + } } -fn check_foreign_item<'tcx>( +pub(super) fn check_foreign_item<'tcx>( tcx: TyCtxt<'tcx>, item: &'tcx hir::ForeignItem<'tcx>, ) -> Result<(), ErrorGuaranteed> { @@ -358,43 +310,23 @@ fn check_foreign_item<'tcx>( ); match item.kind { - hir::ForeignItemKind::Fn(sig, ..) => { - check_item_fn(tcx, def_id, item.ident, item.span, sig.decl) - } - hir::ForeignItemKind::Static(ty, ..) => { - check_static_item(tcx, def_id, ty.span, UnsizedHandling::AllowIfForeignTail) - } - hir::ForeignItemKind::Type => Ok(()), + hir::ForeignItemKind::Fn(sig, ..) => check_item_fn(tcx, def_id, sig.decl), + hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => Ok(()), } } -fn check_trait_item<'tcx>( +pub(crate) fn check_trait_item<'tcx>( tcx: TyCtxt<'tcx>, - trait_item: &'tcx hir::TraitItem<'tcx>, + def_id: LocalDefId, ) -> Result<(), ErrorGuaranteed> { - let def_id = trait_item.owner_id.def_id; - - crate::collect::lower_trait_item(tcx, trait_item.trait_item_id()); - - let (method_sig, span) = match trait_item.kind { - hir::TraitItemKind::Fn(ref sig, _) => (Some(sig), trait_item.span), - hir::TraitItemKind::Type(_bounds, Some(ty)) => (None, ty.span), - _ => (None, trait_item.span), - }; - // Check that an item definition in a subtrait is shadowing a supertrait item. lint_item_shadowing_supertrait_item(tcx, def_id); - let mut res = check_associated_item(tcx, def_id, span, method_sig); + let mut res = Ok(()); - if matches!(trait_item.kind, hir::TraitItemKind::Fn(..)) { + if matches!(tcx.def_kind(def_id), DefKind::AssocFn) { for &assoc_ty_def_id in tcx.associated_types_for_impl_traits_in_associated_fn(def_id) { - res = res.and(check_associated_item( - tcx, - assoc_ty_def_id.expect_local(), - tcx.def_span(assoc_ty_def_id), - None, - )); + res = res.and(check_associated_item(tcx, assoc_ty_def_id.expect_local())); } } res @@ -739,7 +671,7 @@ fn ty_known_to_outlive<'tcx>( infcx.register_type_outlives_constraint_inner(infer::TypeOutlivesConstraint { sub_region: region, sup_type: ty, - origin: infer::RelateParamBound(DUMMY_SP, ty, None), + origin: SubregionOrigin::RelateParamBound(DUMMY_SP, ty, None), }); }) } @@ -755,7 +687,11 @@ fn region_known_to_outlive<'tcx>( region_b: ty::Region<'tcx>, ) -> bool { test_region_obligations(tcx, id, param_env, wf_tys, |infcx| { - infcx.sub_regions(infer::RelateRegionParamBound(DUMMY_SP, None), region_b, region_a); + infcx.sub_regions( + SubregionOrigin::RelateRegionParamBound(DUMMY_SP, None), + region_b, + region_a, + ); }) } @@ -869,67 +805,54 @@ fn lint_item_shadowing_supertrait_item<'tcx>(tcx: TyCtxt<'tcx>, trait_item_def_i } } -fn check_impl_item<'tcx>( - tcx: TyCtxt<'tcx>, - impl_item: &'tcx hir::ImplItem<'tcx>, -) -> Result<(), ErrorGuaranteed> { - crate::collect::lower_impl_item(tcx, impl_item.impl_item_id()); - - let (method_sig, span) = match impl_item.kind { - hir::ImplItemKind::Fn(ref sig, _) => (Some(sig), impl_item.span), - // Constrain binding and overflow error spans to `<Ty>` in `type foo = <Ty>`. - hir::ImplItemKind::Type(ty) if ty.span != DUMMY_SP => (None, ty.span), - _ => (None, impl_item.span), - }; - check_associated_item(tcx, impl_item.owner_id.def_id, span, method_sig) -} - -fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), ErrorGuaranteed> { +fn check_param_wf(tcx: TyCtxt<'_>, param: &ty::GenericParamDef) -> Result<(), ErrorGuaranteed> { match param.kind { // We currently only check wf of const params here. - hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => Ok(()), + ty::GenericParamDefKind::Lifetime | ty::GenericParamDefKind::Type { .. } => Ok(()), // Const parameters are well formed if their type is structural match. - hir::GenericParamKind::Const { ty: hir_ty, default: _, synthetic: _ } => { + ty::GenericParamDefKind::Const { .. } => { let ty = tcx.type_of(param.def_id).instantiate_identity(); + let span = tcx.def_span(param.def_id); + let def_id = param.def_id.expect_local(); if tcx.features().unsized_const_params() { - enter_wf_checking_ctxt(tcx, hir_ty.span, tcx.local_parent(param.def_id), |wfcx| { + enter_wf_checking_ctxt(tcx, tcx.local_parent(def_id), |wfcx| { wfcx.register_bound( - ObligationCause::new( - hir_ty.span, - param.def_id, - ObligationCauseCode::ConstParam(ty), - ), + ObligationCause::new(span, def_id, ObligationCauseCode::ConstParam(ty)), wfcx.param_env, ty, - tcx.require_lang_item(LangItem::UnsizedConstParamTy, hir_ty.span), + tcx.require_lang_item(LangItem::UnsizedConstParamTy, span), ); Ok(()) }) } else if tcx.features().adt_const_params() { - enter_wf_checking_ctxt(tcx, hir_ty.span, tcx.local_parent(param.def_id), |wfcx| { + enter_wf_checking_ctxt(tcx, tcx.local_parent(def_id), |wfcx| { wfcx.register_bound( - ObligationCause::new( - hir_ty.span, - param.def_id, - ObligationCauseCode::ConstParam(ty), - ), + ObligationCause::new(span, def_id, ObligationCauseCode::ConstParam(ty)), wfcx.param_env, ty, - tcx.require_lang_item(LangItem::ConstParamTy, hir_ty.span), + tcx.require_lang_item(LangItem::ConstParamTy, span), ); Ok(()) }) } else { + let span = || { + let hir::GenericParamKind::Const { ty: &hir::Ty { span, .. }, .. } = + tcx.hir_node_by_def_id(def_id).expect_generic_param().kind + else { + bug!() + }; + span + }; let mut diag = match ty.kind() { ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Error(_) => return Ok(()), ty::FnPtr(..) => tcx.dcx().struct_span_err( - hir_ty.span, + span(), "using function pointers as const generic parameters is forbidden", ), ty::RawPtr(_, _) => tcx.dcx().struct_span_err( - hir_ty.span, + span(), "using raw pointers as const generic parameters is forbidden", ), _ => { @@ -937,7 +860,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), ty.error_reported()?; tcx.dcx().struct_span_err( - hir_ty.span, + span(), format!( "`{ty}` is forbidden as the type of a const generic parameter", ), @@ -947,7 +870,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), diag.note("the only supported types are integers, `bool`, and `char`"); - let cause = ObligationCause::misc(hir_ty.span, param.def_id); + let cause = ObligationCause::misc(span(), def_id); let adt_const_params_feature_string = " more complex and user defined types".to_string(); let may_suggest_feature = match type_allowed_to_implement_const_param_ty( @@ -1007,15 +930,13 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), } } -#[instrument(level = "debug", skip(tcx, span, sig_if_method))] -fn check_associated_item( +#[instrument(level = "debug", skip(tcx))] +pub(crate) fn check_associated_item( tcx: TyCtxt<'_>, item_id: LocalDefId, - span: Span, - sig_if_method: Option<&hir::FnSig<'_>>, ) -> Result<(), ErrorGuaranteed> { let loc = Some(WellFormedLoc::Ty(item_id)); - enter_wf_checking_ctxt(tcx, span, item_id, |wfcx| { + enter_wf_checking_ctxt(tcx, item_id, |wfcx| { let item = tcx.associated_item(item_id); // Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case @@ -1030,6 +951,8 @@ fn check_associated_item( } }; + let span = tcx.def_span(item_id); + match item.kind { ty::AssocKind::Const { .. } => { let ty = tcx.type_of(item.def_id).instantiate_identity(); @@ -1046,14 +969,9 @@ fn check_associated_item( } ty::AssocKind::Fn { .. } => { let sig = tcx.fn_sig(item.def_id).instantiate_identity(); - let hir_sig = sig_if_method.expect("bad signature for method"); - check_fn_or_method( - wfcx, - item.ident(tcx).span, - sig, - hir_sig.decl, - item.def_id.expect_local(), - ); + let hir_sig = + tcx.hir_node_by_def_id(item_id).fn_sig().expect("bad signature for method"); + check_fn_or_method(wfcx, sig, hir_sig.decl, item_id); check_method_receiver(wfcx, hir_sig, item, self_ty) } ty::AssocKind::Type { .. } => { @@ -1080,7 +998,7 @@ fn check_type_defn<'tcx>( let _ = tcx.representability(item.owner_id.def_id); let adt_def = tcx.adt_def(item.owner_id); - enter_wf_checking_ctxt(tcx, item.span, item.owner_id.def_id, |wfcx| { + enter_wf_checking_ctxt(tcx, item.owner_id.def_id, |wfcx| { let variants = adt_def.variants(); let packed = adt_def.repr().packed(); @@ -1182,7 +1100,7 @@ fn check_type_defn<'tcx>( } } - check_where_clauses(wfcx, item.span, item.owner_id.def_id); + check_where_clauses(wfcx, item.owner_id.def_id); Ok(()) }) } @@ -1212,8 +1130,8 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) -> Result<(), ErrorGuarant } } - let res = enter_wf_checking_ctxt(tcx, item.span, def_id, |wfcx| { - check_where_clauses(wfcx, item.span, def_id); + let res = enter_wf_checking_ctxt(tcx, def_id, |wfcx| { + check_where_clauses(wfcx, def_id); Ok(()) }); @@ -1249,72 +1167,63 @@ fn check_associated_type_bounds(wfcx: &WfCheckingCtxt<'_, '_>, item: ty::AssocIt fn check_item_fn( tcx: TyCtxt<'_>, def_id: LocalDefId, - ident: Ident, - span: Span, decl: &hir::FnDecl<'_>, ) -> Result<(), ErrorGuaranteed> { - enter_wf_checking_ctxt(tcx, span, def_id, |wfcx| { + enter_wf_checking_ctxt(tcx, def_id, |wfcx| { let sig = tcx.fn_sig(def_id).instantiate_identity(); - check_fn_or_method(wfcx, ident.span, sig, decl, def_id); + check_fn_or_method(wfcx, sig, decl, def_id); Ok(()) }) } -enum UnsizedHandling { - Forbid, - AllowIfForeignTail, -} - -#[instrument(level = "debug", skip(tcx, ty_span, unsized_handling))] -fn check_static_item( +#[instrument(level = "debug", skip(tcx))] +pub(super) fn check_static_item( tcx: TyCtxt<'_>, item_id: LocalDefId, - ty_span: Span, - unsized_handling: UnsizedHandling, ) -> Result<(), ErrorGuaranteed> { - enter_wf_checking_ctxt(tcx, ty_span, item_id, |wfcx| { + enter_wf_checking_ctxt(tcx, item_id, |wfcx| { let ty = tcx.type_of(item_id).instantiate_identity(); - let item_ty = wfcx.deeply_normalize(ty_span, Some(WellFormedLoc::Ty(item_id)), ty); - - let forbid_unsized = match unsized_handling { - UnsizedHandling::Forbid => true, - UnsizedHandling::AllowIfForeignTail => { - let tail = - tcx.struct_tail_for_codegen(item_ty, wfcx.infcx.typing_env(wfcx.param_env)); - !matches!(tail.kind(), ty::Foreign(_)) - } + let item_ty = wfcx.deeply_normalize(DUMMY_SP, Some(WellFormedLoc::Ty(item_id)), ty); + + let is_foreign_item = tcx.is_foreign_item(item_id); + + let forbid_unsized = !is_foreign_item || { + let tail = tcx.struct_tail_for_codegen(item_ty, wfcx.infcx.typing_env(wfcx.param_env)); + !matches!(tail.kind(), ty::Foreign(_)) }; - wfcx.register_wf_obligation(ty_span, Some(WellFormedLoc::Ty(item_id)), item_ty.into()); + wfcx.register_wf_obligation(DUMMY_SP, Some(WellFormedLoc::Ty(item_id)), item_ty.into()); if forbid_unsized { + let span = tcx.def_span(item_id); wfcx.register_bound( traits::ObligationCause::new( - ty_span, + span, wfcx.body_def_id, ObligationCauseCode::SizedConstOrStatic, ), wfcx.param_env, item_ty, - tcx.require_lang_item(LangItem::Sized, ty_span), + tcx.require_lang_item(LangItem::Sized, span), ); } // Ensure that the end result is `Sync` in a non-thread local `static`. let should_check_for_sync = tcx.static_mutability(item_id.to_def_id()) == Some(hir::Mutability::Not) - && !tcx.is_foreign_item(item_id.to_def_id()) + && !is_foreign_item && !tcx.is_thread_local_static(item_id.to_def_id()); if should_check_for_sync { + let span = tcx.def_span(item_id); wfcx.register_bound( traits::ObligationCause::new( - ty_span, + span, wfcx.body_def_id, ObligationCauseCode::SharedStatic, ), wfcx.param_env, item_ty, - tcx.require_lang_item(LangItem::Sync, ty_span), + tcx.require_lang_item(LangItem::Sync, span), ); } Ok(()) @@ -1325,9 +1234,8 @@ fn check_const_item( tcx: TyCtxt<'_>, def_id: LocalDefId, ty_span: Span, - item_span: Span, ) -> Result<(), ErrorGuaranteed> { - enter_wf_checking_ctxt(tcx, ty_span, def_id, |wfcx| { + enter_wf_checking_ctxt(tcx, def_id, |wfcx| { let ty = tcx.type_of(def_id).instantiate_identity(); let ty = wfcx.deeply_normalize(ty_span, Some(WellFormedLoc::Ty(def_id)), ty); @@ -1343,7 +1251,7 @@ fn check_const_item( tcx.require_lang_item(LangItem::Sized, ty_span), ); - check_where_clauses(wfcx, item_span, def_id); + check_where_clauses(wfcx, def_id); Ok(()) }) @@ -1356,7 +1264,7 @@ fn check_impl<'tcx>( hir_self_ty: &hir::Ty<'_>, hir_trait_ref: &Option<hir::TraitRef<'_>>, ) -> Result<(), ErrorGuaranteed> { - enter_wf_checking_ctxt(tcx, item.span, item.owner_id.def_id, |wfcx| { + enter_wf_checking_ctxt(tcx, item.owner_id.def_id, |wfcx| { match hir_trait_ref { Some(hir_trait_ref) => { // `#[rustc_reservation_impl]` impls are not real impls and @@ -1399,7 +1307,7 @@ fn check_impl<'tcx>( } } - // Ensure that the `~const` where clauses of the trait hold for the impl. + // Ensure that the `[const]` where clauses of the trait hold for the impl. if tcx.is_conditionally_const(item.owner_id.def_id) { for (bound, _) in tcx.const_conditions(trait_ref.def_id).instantiate(tcx, trait_ref.args) @@ -1440,14 +1348,14 @@ fn check_impl<'tcx>( } } - check_where_clauses(wfcx, item.span, item.owner_id.def_id); + check_where_clauses(wfcx, item.owner_id.def_id); Ok(()) }) } /// Checks where-clauses and inline bounds that are declared on `def_id`. #[instrument(level = "debug", skip(wfcx))] -fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id: LocalDefId) { +pub(super) fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, def_id: LocalDefId) { let infcx = wfcx.infcx; let tcx = wfcx.tcx(); @@ -1491,7 +1399,9 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id ty::ConstKind::Unevaluated(uv) => { infcx.tcx.type_of(uv.def).instantiate(infcx.tcx, uv.args) } - ty::ConstKind::Param(param_ct) => param_ct.find_ty_from_env(wfcx.param_env), + ty::ConstKind::Param(param_ct) => { + param_ct.find_const_ty_from_env(wfcx.param_env) + } }; let param_ty = tcx.type_of(param.def_id).instantiate_identity(); @@ -1600,21 +1510,18 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id let predicates = predicates.instantiate_identity(tcx); - let predicates = wfcx.normalize(span, None, predicates); - - debug!(?predicates.predicates); assert_eq!(predicates.predicates.len(), predicates.spans.len()); let wf_obligations = predicates.into_iter().flat_map(|(p, sp)| { + let p = wfcx.normalize(sp, None, p); traits::wf::clause_obligations(infcx, wfcx.param_env, wfcx.body_def_id, p, sp) }); let obligations: Vec<_> = wf_obligations.chain(default_obligations).collect(); wfcx.register_obligations(obligations); } -#[instrument(level = "debug", skip(wfcx, span, hir_decl))] +#[instrument(level = "debug", skip(wfcx, hir_decl))] fn check_fn_or_method<'tcx>( wfcx: &WfCheckingCtxt<'_, 'tcx>, - span: Span, sig: ty::PolyFnSig<'tcx>, hir_decl: &hir::FnDecl<'_>, def_id: LocalDefId, @@ -1652,7 +1559,7 @@ fn check_fn_or_method<'tcx>( ); } - check_where_clauses(wfcx, span, def_id); + check_where_clauses(wfcx, def_id); if sig.abi == ExternAbi::RustCall { let span = tcx.def_span(def_id); @@ -1741,17 +1648,18 @@ fn check_method_receiver<'tcx>( } let span = fn_sig.decl.inputs[0].span; + let loc = Some(WellFormedLoc::Param { function: method.def_id.expect_local(), param_idx: 0 }); let sig = tcx.fn_sig(method.def_id).instantiate_identity(); let sig = tcx.liberate_late_bound_regions(method.def_id, sig); - let sig = wfcx.normalize(span, None, sig); + let sig = wfcx.normalize(DUMMY_SP, loc, sig); debug!("check_method_receiver: sig={:?}", sig); - let self_ty = wfcx.normalize(span, None, self_ty); + let self_ty = wfcx.normalize(DUMMY_SP, loc, self_ty); let receiver_ty = sig.inputs()[0]; - let receiver_ty = wfcx.normalize(span, None, receiver_ty); + let receiver_ty = wfcx.normalize(DUMMY_SP, loc, receiver_ty); // If the receiver already has errors reported, consider it valid to avoid // unnecessary errors (#58712). @@ -1999,27 +1907,23 @@ fn legacy_receiver_is_implemented<'tcx>( } } -fn check_variances_for_type_defn<'tcx>( - tcx: TyCtxt<'tcx>, - item: &'tcx hir::Item<'tcx>, - hir_generics: &hir::Generics<'tcx>, -) { - match item.kind { - ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => { +pub(super) fn check_variances_for_type_defn<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) { + match tcx.def_kind(def_id) { + DefKind::Enum | DefKind::Struct | DefKind::Union => { // Ok } - ItemKind::TyAlias(..) => { + DefKind::TyAlias => { assert!( - tcx.type_alias_is_lazy(item.owner_id), + tcx.type_alias_is_lazy(def_id), "should not be computing variance of non-free type alias" ); } - kind => span_bug!(item.span, "cannot compute the variances of {kind:?}"), + kind => span_bug!(tcx.def_span(def_id), "cannot compute the variances of {kind:?}"), } - let ty_predicates = tcx.predicates_of(item.owner_id); + let ty_predicates = tcx.predicates_of(def_id); assert_eq!(ty_predicates.parent, None); - let variances = tcx.variances_of(item.owner_id); + let variances = tcx.variances_of(def_id); let mut constrained_parameters: FxHashSet<_> = variances .iter() @@ -2032,8 +1936,10 @@ fn check_variances_for_type_defn<'tcx>( // Lazily calculated because it is only needed in case of an error. let explicitly_bounded_params = LazyCell::new(|| { - let icx = crate::collect::ItemCtxt::new(tcx, item.owner_id.def_id); - hir_generics + let icx = crate::collect::ItemCtxt::new(tcx, def_id); + tcx.hir_node_by_def_id(def_id) + .generics() + .unwrap() .predicates .iter() .filter_map(|predicate| match predicate.kind { @@ -2048,8 +1954,6 @@ fn check_variances_for_type_defn<'tcx>( .collect::<FxHashSet<_>>() }); - let ty_generics = tcx.generics_of(item.owner_id); - for (index, _) in variances.iter().enumerate() { let parameter = Parameter(index as u32); @@ -2057,9 +1961,13 @@ fn check_variances_for_type_defn<'tcx>( continue; } - let ty_param = &ty_generics.own_params[index]; + let node = tcx.hir_node_by_def_id(def_id); + let item = node.expect_item(); + let hir_generics = node.generics().unwrap(); let hir_param = &hir_generics.params[index]; + let ty_param = &tcx.generics_of(item.owner_id).own_params[index]; + if ty_param.def_id != hir_param.def_id.into() { // Valid programs always have lifetimes before types in the generic parameter list. // ty_generics are normalized to be in this required order, and variances are built @@ -2077,7 +1985,7 @@ fn check_variances_for_type_defn<'tcx>( // Look for `ErrorGuaranteed` deeply within this type. if let ControlFlow::Break(ErrorGuaranteed { .. }) = tcx - .type_of(item.owner_id) + .type_of(def_id) .instantiate_identity() .visit_with(&mut HasErrorDeep { tcx, seen: Default::default() }) { @@ -2296,7 +2204,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { #[instrument(level = "debug", skip(self))] fn check_false_global_bounds(&mut self) { let tcx = self.ocx.infcx.tcx; - let mut span = self.span; + let mut span = tcx.def_span(self.body_def_id); let empty_env = ty::ParamEnv::empty(); let predicates_with_span = tcx.predicates_of(self.body_def_id).predicates.iter().copied(); diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 4779f4fb702..734c9c58c08 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -10,7 +10,7 @@ use rustc_hir as hir; use rustc_hir::ItemKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; -use rustc_infer::infer::{self, RegionResolutionError, TyCtxtInferExt}; +use rustc_infer::infer::{self, RegionResolutionError, SubregionOrigin, TyCtxtInferExt}; use rustc_infer::traits::Obligation; use rustc_middle::ty::adjustment::CoerceUnsizedInfo; use rustc_middle::ty::print::PrintTraitRefExt as _; @@ -415,7 +415,7 @@ pub(crate) fn coerce_unsized_info<'tcx>( }; let (source, target, trait_def_id, kind, field_span) = match (source.kind(), target.kind()) { (&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => { - infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a); + infcx.sub_regions(SubregionOrigin::RelateObjectBound(span), r_b, r_a); let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a }; let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b }; check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ref(tcx, r_b, ty)) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 176d955bf03..b10d5b55789 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -21,6 +21,7 @@ use std::ops::Bound; use rustc_abi::ExternAbi; use rustc_ast::Recovered; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::unord::UnordMap; use rustc_errors::{ @@ -28,7 +29,7 @@ use rustc_errors::{ }; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_generics}; +use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt}; use rustc_hir::{self as hir, GenericParamKind, HirId, Node, PreciseCapturingArgKind}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::{DynCompatibilityViolation, ObligationCause}; @@ -153,26 +154,7 @@ impl<'v> Visitor<'v> for HirPlaceholderCollector { } } -/// If there are any placeholder types (`_`), emit an error explaining that this is not allowed -/// and suggest adding type parameters in the appropriate place, taking into consideration any and -/// all already existing generic type parameters to avoid suggesting a name that is already in use. -pub(crate) fn placeholder_type_error<'tcx>( - cx: &dyn HirTyLowerer<'tcx>, - generics: Option<&hir::Generics<'_>>, - placeholder_types: Vec<Span>, - suggest: bool, - hir_ty: Option<&hir::Ty<'_>>, - kind: &'static str, -) { - if placeholder_types.is_empty() { - return; - } - - placeholder_type_error_diag(cx, generics, placeholder_types, vec![], suggest, hir_ty, kind) - .emit(); -} - -pub(crate) fn placeholder_type_error_diag<'cx, 'tcx>( +fn placeholder_type_error_diag<'cx, 'tcx>( cx: &'cx dyn HirTyLowerer<'tcx>, generics: Option<&hir::Generics<'_>>, placeholder_types: Vec<Span>, @@ -244,37 +226,6 @@ pub(crate) fn placeholder_type_error_diag<'cx, 'tcx>( err } -pub(super) fn reject_placeholder_type_signatures_in_item<'tcx>( - tcx: TyCtxt<'tcx>, - item: &'tcx hir::Item<'tcx>, -) { - let (generics, suggest) = match &item.kind { - hir::ItemKind::Union(_, generics, _) - | hir::ItemKind::Enum(_, generics, _) - | hir::ItemKind::TraitAlias(_, generics, _) - | hir::ItemKind::Trait(_, _, _, generics, ..) - | hir::ItemKind::Impl(hir::Impl { generics, .. }) - | hir::ItemKind::Struct(_, generics, _) => (generics, true), - hir::ItemKind::TyAlias(_, generics, _) => (generics, false), - // `static`, `fn` and `const` are handled elsewhere to suggest appropriate type. - _ => return, - }; - - let mut visitor = HirPlaceholderCollector::default(); - visitor.visit_item(item); - - let icx = ItemCtxt::new(tcx, item.owner_id.def_id); - - placeholder_type_error( - icx.lowerer(), - Some(generics), - visitor.spans, - suggest && !visitor.may_contain_const_infer, - None, - item.kind.descr(), - ); -} - /////////////////////////////////////////////////////////////////////////// // Utility types and common code for the above passes. @@ -312,6 +263,44 @@ impl<'tcx> ItemCtxt<'tcx> { None => Ok(()), } } + + fn report_placeholder_type_error( + &self, + placeholder_types: Vec<Span>, + infer_replacements: Vec<(Span, String)>, + ) -> ErrorGuaranteed { + let node = self.tcx.hir_node_by_def_id(self.item_def_id); + let generics = node.generics(); + let kind_id = match node { + Node::GenericParam(_) | Node::WherePredicate(_) | Node::Field(_) => { + self.tcx.local_parent(self.item_def_id) + } + _ => self.item_def_id, + }; + let kind = self.tcx.def_descr(kind_id.into()); + let mut diag = placeholder_type_error_diag( + self, + generics, + placeholder_types, + infer_replacements.iter().map(|&(span, _)| span).collect(), + false, + None, + kind, + ); + if !infer_replacements.is_empty() { + diag.multipart_suggestion( + format!( + "try replacing `_` with the type{} in the corresponding trait method \ + signature", + rustc_errors::pluralize!(infer_replacements.len()), + ), + infer_replacements, + Applicability::MachineApplicable, + ); + } + + diag.emit() + } } impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { @@ -345,10 +334,14 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { } fn ty_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> { + if !self.tcx.dcx().has_stashed_diagnostic(span, StashKey::ItemNoType) { + self.report_placeholder_type_error(vec![span], vec![]); + } Ty::new_error_with_message(self.tcx(), span, "bad placeholder type") } fn ct_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx> { + self.report_placeholder_type_error(vec![span], vec![]); ty::Const::new_error_with_message(self.tcx(), span, "bad placeholder constant") } @@ -523,18 +516,13 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { fn lower_fn_sig( &self, decl: &hir::FnDecl<'tcx>, - generics: Option<&hir::Generics<'_>>, + _generics: Option<&hir::Generics<'_>>, hir_id: rustc_hir::HirId, - hir_ty: Option<&hir::Ty<'_>>, + _hir_ty: Option<&hir::Ty<'_>>, ) -> (Vec<Ty<'tcx>>, Ty<'tcx>) { let tcx = self.tcx(); - // We proactively collect all the inferred type params to emit a single error per fn def. - let mut visitor = HirPlaceholderCollector::default(); - let mut infer_replacements = vec![]; - if let Some(generics) = generics { - walk_generics(&mut visitor, generics); - } + let mut infer_replacements = vec![]; let input_tys = decl .inputs @@ -550,8 +538,6 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { } } - // Only visit the type looking for `_` if we didn't fix the type above - visitor.visit_ty_unambig(a); self.lowerer().lower_ty(a) }) .collect(); @@ -565,42 +551,15 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { infer_replacements.push((output.span, suggested_ty.to_string())); Ty::new_error_with_message(tcx, output.span, suggested_ty.to_string()) } else { - visitor.visit_ty_unambig(output); self.lower_ty(output) } } hir::FnRetTy::DefaultReturn(..) => tcx.types.unit, }; - if !(visitor.spans.is_empty() && infer_replacements.is_empty()) { - // We check for the presence of - // `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`. - - let mut diag = crate::collect::placeholder_type_error_diag( - self, - generics, - visitor.spans, - infer_replacements.iter().map(|(s, _)| *s).collect(), - !visitor.may_contain_const_infer, - hir_ty, - "function", - ); - - if !infer_replacements.is_empty() { - diag.multipart_suggestion( - format!( - "try replacing `_` with the type{} in the corresponding trait method \ - signature", - rustc_errors::pluralize!(infer_replacements.len()), - ), - infer_replacements, - Applicability::MachineApplicable, - ); - } - - diag.emit(); + if !infer_replacements.is_empty() { + self.report_placeholder_type_error(vec![], infer_replacements); } - (input_tys, output_ty) } @@ -646,250 +605,13 @@ fn get_new_lifetime_name<'tcx>( (1..).flat_map(a_to_z_repeat_n).find(|lt| !existing_lifetimes.contains(lt.as_str())).unwrap() } -#[instrument(level = "debug", skip_all)] -pub(super) fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { - let it = tcx.hir_item(item_id); - debug!(item = ?it.kind.ident(), id = %it.hir_id()); - let def_id = item_id.owner_id.def_id; - let icx = ItemCtxt::new(tcx, def_id); - - match &it.kind { - // These don't define types. - hir::ItemKind::ExternCrate(..) - | hir::ItemKind::Use(..) - | hir::ItemKind::Macro(..) - | hir::ItemKind::Mod(..) - | hir::ItemKind::GlobalAsm { .. } => {} - hir::ItemKind::ForeignMod { items, .. } => { - for item in *items { - let item = tcx.hir_foreign_item(item.id); - tcx.ensure_ok().generics_of(item.owner_id); - tcx.ensure_ok().type_of(item.owner_id); - tcx.ensure_ok().predicates_of(item.owner_id); - if tcx.is_conditionally_const(def_id) { - tcx.ensure_ok().explicit_implied_const_bounds(def_id); - tcx.ensure_ok().const_conditions(def_id); - } - match item.kind { - hir::ForeignItemKind::Fn(..) => { - tcx.ensure_ok().codegen_fn_attrs(item.owner_id); - tcx.ensure_ok().fn_sig(item.owner_id) - } - hir::ForeignItemKind::Static(..) => { - tcx.ensure_ok().codegen_fn_attrs(item.owner_id); - let mut visitor = HirPlaceholderCollector::default(); - visitor.visit_foreign_item(item); - placeholder_type_error( - icx.lowerer(), - None, - visitor.spans, - false, - None, - "static variable", - ); - } - _ => (), - } - } - } - hir::ItemKind::Enum(..) => { - tcx.ensure_ok().generics_of(def_id); - tcx.ensure_ok().type_of(def_id); - tcx.ensure_ok().predicates_of(def_id); - lower_enum_variant_types(tcx, def_id.to_def_id()); - } - hir::ItemKind::Impl { .. } => { - tcx.ensure_ok().generics_of(def_id); - tcx.ensure_ok().type_of(def_id); - tcx.ensure_ok().impl_trait_header(def_id); - tcx.ensure_ok().predicates_of(def_id); - tcx.ensure_ok().associated_items(def_id); - } - hir::ItemKind::Trait(..) => { - tcx.ensure_ok().generics_of(def_id); - tcx.ensure_ok().trait_def(def_id); - tcx.at(it.span).explicit_super_predicates_of(def_id); - tcx.ensure_ok().predicates_of(def_id); - tcx.ensure_ok().associated_items(def_id); - } - hir::ItemKind::TraitAlias(..) => { - tcx.ensure_ok().generics_of(def_id); - tcx.at(it.span).explicit_implied_predicates_of(def_id); - tcx.at(it.span).explicit_super_predicates_of(def_id); - tcx.ensure_ok().predicates_of(def_id); - } - hir::ItemKind::Struct(_, _, struct_def) | hir::ItemKind::Union(_, _, struct_def) => { - tcx.ensure_ok().generics_of(def_id); - tcx.ensure_ok().type_of(def_id); - tcx.ensure_ok().predicates_of(def_id); - - for f in struct_def.fields() { - tcx.ensure_ok().generics_of(f.def_id); - tcx.ensure_ok().type_of(f.def_id); - tcx.ensure_ok().predicates_of(f.def_id); - } - - if let Some(ctor_def_id) = struct_def.ctor_def_id() { - lower_variant_ctor(tcx, ctor_def_id); - } - } - - hir::ItemKind::TyAlias(..) => { - tcx.ensure_ok().generics_of(def_id); - tcx.ensure_ok().type_of(def_id); - tcx.ensure_ok().predicates_of(def_id); - } - - hir::ItemKind::Static(_, _, ty, _) | hir::ItemKind::Const(_, _, ty, _) => { - tcx.ensure_ok().generics_of(def_id); - tcx.ensure_ok().type_of(def_id); - tcx.ensure_ok().predicates_of(def_id); - if !ty.is_suggestable_infer_ty() { - let mut visitor = HirPlaceholderCollector::default(); - visitor.visit_item(it); - placeholder_type_error( - icx.lowerer(), - None, - visitor.spans, - false, - None, - it.kind.descr(), - ); - } - } - - hir::ItemKind::Fn { .. } => { - tcx.ensure_ok().generics_of(def_id); - tcx.ensure_ok().type_of(def_id); - tcx.ensure_ok().predicates_of(def_id); - tcx.ensure_ok().fn_sig(def_id); - tcx.ensure_ok().codegen_fn_attrs(def_id); - } - } -} - -pub(crate) fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { - let trait_item = tcx.hir_trait_item(trait_item_id); - let def_id = trait_item_id.owner_id; - tcx.ensure_ok().generics_of(def_id); - let icx = ItemCtxt::new(tcx, def_id.def_id); - - match trait_item.kind { - hir::TraitItemKind::Fn(..) => { - tcx.ensure_ok().codegen_fn_attrs(def_id); - tcx.ensure_ok().type_of(def_id); - tcx.ensure_ok().fn_sig(def_id); - } - - hir::TraitItemKind::Const(ty, body_id) => { - tcx.ensure_ok().type_of(def_id); - if !tcx.dcx().has_stashed_diagnostic(ty.span, StashKey::ItemNoType) - && !(ty.is_suggestable_infer_ty() && body_id.is_some()) - { - // Account for `const C: _;`. - let mut visitor = HirPlaceholderCollector::default(); - visitor.visit_trait_item(trait_item); - placeholder_type_error( - icx.lowerer(), - None, - visitor.spans, - false, - None, - "associated constant", - ); - } - } - - hir::TraitItemKind::Type(_, Some(_)) => { - tcx.ensure_ok().item_bounds(def_id); - tcx.ensure_ok().item_self_bounds(def_id); - tcx.ensure_ok().type_of(def_id); - // Account for `type T = _;`. - let mut visitor = HirPlaceholderCollector::default(); - visitor.visit_trait_item(trait_item); - placeholder_type_error( - icx.lowerer(), - None, - visitor.spans, - false, - None, - "associated type", - ); - } - - hir::TraitItemKind::Type(_, None) => { - tcx.ensure_ok().item_bounds(def_id); - tcx.ensure_ok().item_self_bounds(def_id); - // #74612: Visit and try to find bad placeholders - // even if there is no concrete type. - let mut visitor = HirPlaceholderCollector::default(); - visitor.visit_trait_item(trait_item); - - placeholder_type_error( - icx.lowerer(), - None, - visitor.spans, - false, - None, - "associated type", - ); - } - }; - - tcx.ensure_ok().predicates_of(def_id); -} - -pub(super) fn lower_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) { - let def_id = impl_item_id.owner_id; - tcx.ensure_ok().generics_of(def_id); - tcx.ensure_ok().type_of(def_id); - tcx.ensure_ok().predicates_of(def_id); - let impl_item = tcx.hir_impl_item(impl_item_id); - let icx = ItemCtxt::new(tcx, def_id.def_id); - match impl_item.kind { - hir::ImplItemKind::Fn(..) => { - tcx.ensure_ok().codegen_fn_attrs(def_id); - tcx.ensure_ok().fn_sig(def_id); - } - hir::ImplItemKind::Type(_) => { - // Account for `type T = _;` - let mut visitor = HirPlaceholderCollector::default(); - visitor.visit_impl_item(impl_item); - - placeholder_type_error( - icx.lowerer(), - None, - visitor.spans, - false, - None, - "associated type", - ); - } - hir::ImplItemKind::Const(ty, _) => { - // Account for `const T: _ = ..;` - if !ty.is_suggestable_infer_ty() { - let mut visitor = HirPlaceholderCollector::default(); - visitor.visit_impl_item(impl_item); - placeholder_type_error( - icx.lowerer(), - None, - visitor.spans, - false, - None, - "associated constant", - ); - } - } - } -} - -fn lower_variant_ctor(tcx: TyCtxt<'_>, def_id: LocalDefId) { +pub(super) fn lower_variant_ctor(tcx: TyCtxt<'_>, def_id: LocalDefId) { tcx.ensure_ok().generics_of(def_id); tcx.ensure_ok().type_of(def_id); tcx.ensure_ok().predicates_of(def_id); } -fn lower_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) { +pub(super) fn lower_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) { let def = tcx.adt_def(def_id); let repr_type = def.repr().discr_type(); let initial = repr_type.initial_discriminant(tcx); @@ -1151,22 +873,11 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { let rustc_coinductive = tcx.has_attr(def_id, sym::rustc_coinductive); let is_fundamental = tcx.has_attr(def_id, sym::fundamental); - // FIXME: We could probably do way better attribute validation here. - let mut skip_array_during_method_dispatch = false; - let mut skip_boxed_slice_during_method_dispatch = false; - for attr in tcx.get_attrs(def_id, sym::rustc_skip_during_method_dispatch) { - if let Some(lst) = attr.meta_item_list() { - for item in lst { - if let Some(ident) = item.ident() { - match ident.as_str() { - "array" => skip_array_during_method_dispatch = true, - "boxed_slice" => skip_boxed_slice_during_method_dispatch = true, - _ => (), - } - } - } - } - } + let [skip_array_during_method_dispatch, skip_boxed_slice_during_method_dispatch] = find_attr!( + tcx.get_all_attrs(def_id), + AttributeKind::SkipDuringMethodDispatch { array, boxed_slice, span:_ } => [*array, *boxed_slice] + ) + .unwrap_or([false; 2]); let specialization_kind = if tcx.has_attr(def_id, sym::rustc_unsafe_specialization_marker) { ty::trait_def::TraitSpecializationKind::Marker diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 53c44cdc411..e51ef46afb7 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -54,7 +54,7 @@ fn associated_type_bounds<'tcx>( ); icx.lowerer().add_default_traits(&mut bounds, item_ty, hir_bounds, None, span); } - // `ConstIfConst` is only interested in `~const` bounds. + // `ConstIfConst` is only interested in `[const]` bounds. PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {} } @@ -351,7 +351,7 @@ fn opaque_type_bounds<'tcx>( ); icx.lowerer().add_default_traits(&mut bounds, item_ty, hir_bounds, None, span); } - //`ConstIfConst` is only interested in `~const` bounds. + //`ConstIfConst` is only interested in `[const]` bounds. PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {} } debug!(?bounds); diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index c337765c5fe..a93e58b101f 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -421,7 +421,9 @@ fn const_evaluatable_predicates_of<'tcx>( impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ConstCollector<'tcx> { fn visit_const(&mut self, c: ty::Const<'tcx>) { if let ty::ConstKind::Unevaluated(uv) = c.kind() { - if is_const_param_default(self.tcx, uv.def.expect_local()) { + if let Some(local) = uv.def.as_local() + && is_const_param_default(self.tcx, local) + { // Do not look into const param defaults, // these get checked when they are actually instantiated. // @@ -666,7 +668,7 @@ pub(super) fn implied_predicates_with_filter<'tcx>( item.span, ); } - //`ConstIfConst` is only interested in `~const` bounds. + //`ConstIfConst` is only interested in `[const]` bounds. PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {} } @@ -821,7 +823,7 @@ pub(super) fn assert_only_contains_predicates_from<'tcx>( assert_eq!( pred.constness, ty::BoundConstness::Maybe, - "expected `~const` predicate when computing `{filter:?}` \ + "expected `[const]` predicate when computing `{filter:?}` \ implied bounds: {clause:?}", ); assert_eq!( @@ -1009,7 +1011,7 @@ pub(super) fn const_conditions<'tcx>( } _ => bug!("const_conditions called on wrong item: {def_id:?}"), }, - // While associated types are not really const, we do allow them to have `~const` + // While associated types are not really const, we do allow them to have `[const]` // bounds and where clauses. `const_conditions` is responsible for gathering // these up so we can check them in `compare_type_predicate_entailment`, and // in `HostEffect` goal computation. diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 318aaab50f4..c1c82839212 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -127,6 +127,7 @@ pub(crate) enum AssocItemNotFoundSugg<'a> { SimilarInOtherTrait { #[primary_span] span: Span, + trait_name: &'a str, assoc_kind: &'static str, suggested_name: Symbol, }, @@ -318,6 +319,13 @@ pub(crate) struct TraitObjectDeclaredWithNoTraits { } #[derive(Diagnostic)] +#[diag(hir_analysis_pointee_sized_trait_object)] +pub(crate) struct PointeeSizedTraitObject { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] #[diag(hir_analysis_ambiguous_lifetime_bound, code = E0227)] pub(crate) struct AmbiguousLifetimeBound { #[primary_span] diff --git a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs index a3c8ce620b3..ef789743e06 100644 --- a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs @@ -635,7 +635,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { self.suggest_adding_type_and_const_args(err); } ExcessTypesOrConsts { .. } => { - // this can happen with `~const T` where T isn't a const_trait. + // this can happen with `[const] T` where T isn't a const_trait. } _ => unreachable!(), } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index ea1dfdfd806..d17986d45d2 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -5,14 +5,14 @@ use rustc_errors::codes::*; use rustc_errors::struct_span_code_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; use rustc_hir::{AmbigArg, LangItem, PolyTraitRef}; use rustc_middle::bug; use rustc_middle::ty::{ self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, Upcast, }; -use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw}; +use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, sym}; use rustc_trait_selection::traits; use smallvec::SmallVec; use tracing::{debug, instrument}; @@ -188,6 +188,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) { let tcx = self.tcx(); + // Skip adding any default bounds if `#![rustc_no_implicit_bounds]` + if tcx.has_attr(CRATE_DEF_ID, sym::rustc_no_implicit_bounds) { + return; + } + let meta_sized_did = tcx.require_lang_item(LangItem::MetaSized, span); let pointee_sized_did = tcx.require_lang_item(LangItem::PointeeSized, span); @@ -408,24 +413,21 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let tcx = self.tcx(); let trait_id = tcx.lang_items().get(trait_); if let Some(trait_id) = trait_id - && self.do_not_provide_default_trait_bound( - trait_id, - hir_bounds, - self_ty_where_predicates, - ) + && self.should_add_default_traits(trait_id, hir_bounds, self_ty_where_predicates) { add_trait_bound(tcx, bounds, self_ty, trait_id, span); } } - fn do_not_provide_default_trait_bound<'a>( + /// Returns `true` if default trait bound should be added. + fn should_add_default_traits<'a>( &self, trait_def_id: DefId, hir_bounds: &'a [hir::GenericBound<'tcx>], self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, ) -> bool { let collected = collect_bounds(hir_bounds, self_ty_where_predicates, trait_def_id); - !collected.any() + !self.tcx().has_attr(CRATE_DEF_ID, sym::rustc_no_implicit_bounds) && !collected.any() } /// Lower HIR bounds into `bounds` given the self type `param_ty` and the overarching late-bound vars if any. @@ -492,7 +494,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ); } hir::GenericBound::Outlives(lifetime) => { - // `ConstIfConst` is only interested in `~const` bounds. + // `ConstIfConst` is only interested in `[const]` bounds. if matches!( predicate_filter, PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst @@ -708,7 +710,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } // SelfTraitThatDefines is only interested in trait predicates. PredicateFilter::SelfTraitThatDefines(_) => {} - // `ConstIfConst` is only interested in `~const` bounds. + // `ConstIfConst` is only interested in `[const]` bounds. PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {} } } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs index ebeb3b58208..82e5f65476f 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs @@ -18,7 +18,7 @@ pub(crate) fn validate_cmse_abi<'tcx>( fn_sig: ty::PolyFnSig<'tcx>, ) { match abi { - ExternAbi::CCmseNonSecureCall => { + ExternAbi::CmseNonSecureCall => { let hir_node = tcx.hir_node(hir_id); let hir::Node::Ty(hir::Ty { span: bare_fn_span, @@ -38,7 +38,7 @@ pub(crate) fn validate_cmse_abi<'tcx>( dcx, span, E0781, - "the `\"C-cmse-nonsecure-call\"` ABI is only allowed on function pointers" + "the `\"cmse-nonsecure-call\"` ABI is only allowed on function pointers" ) .emit(); return; @@ -78,7 +78,7 @@ pub(crate) fn validate_cmse_abi<'tcx>( } }; } - ExternAbi::CCmseNonSecureEntry => { + ExternAbi::CmseNonSecureEntry => { let hir_node = tcx.hir_node(hir_id); let Some(hir::FnSig { decl, span: fn_sig_span, .. }) = hir_node.fn_sig() else { // might happen when this ABI is used incorrectly. That will be handled elsewhere @@ -203,11 +203,11 @@ fn should_emit_generic_error<'tcx>(abi: ExternAbi, layout_err: &'tcx LayoutError match layout_err { TooGeneric(ty) => { match abi { - ExternAbi::CCmseNonSecureCall => { + ExternAbi::CmseNonSecureCall => { // prevent double reporting of this error !ty.is_impl_trait() } - ExternAbi::CCmseNonSecureEntry => true, + ExternAbi::CmseNonSecureEntry => true, _ => bug!("invalid ABI: {abi}"), } } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index 05465b47a26..cb106962be1 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -2,6 +2,7 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::struct_span_code_err; use rustc_hir as hir; +use rustc_hir::LangItem; use rustc_hir::def::{DefKind, Res}; use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS; use rustc_middle::ty::elaborate::ClauseWithSupertraitSpan; @@ -69,7 +70,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .into_iter() .partition(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id())); - // We don't support empty trait objects. + // We don't support empty trait objects. if regular_traits.is_empty() && auto_traits.is_empty() { let guar = self.report_trait_object_with_no_traits(span, user_written_bounds.iter().copied()); @@ -80,6 +81,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let guar = self.report_trait_object_addition_traits(®ular_traits); return Ty::new_error(tcx, guar); } + // We don't support `PointeeSized` principals + let pointee_sized_did = tcx.require_lang_item(LangItem::PointeeSized, span); + if regular_traits.iter().any(|(pred, _)| pred.def_id() == pointee_sized_did) { + let guar = self.report_pointee_sized_trait_object(span); + return Ty::new_error(tcx, guar); + } + // Don't create a dyn trait if we have errors in the principal. if let Err(guar) = regular_traits.error_reported() { return Ty::new_error(tcx, guar); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 0e79a8918b0..5d85a3f8455 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -29,7 +29,7 @@ use tracing::debug; use super::InherentAssocCandidate; use crate::errors::{ self, AssocItemConstraintsNotAllowedHere, ManualImplementation, MissingTypeParams, - ParenthesizedFnTraitExpansion, TraitObjectDeclaredWithNoTraits, + ParenthesizedFnTraitExpansion, PointeeSizedTraitObject, TraitObjectDeclaredWithNoTraits, }; use crate::fluent_generated as fluent; use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer}; @@ -309,6 +309,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // change the associated item. err.sugg = Some(errors::AssocItemNotFoundSugg::SimilarInOtherTrait { span: assoc_ident.span, + trait_name: &trait_name, assoc_kind: assoc_kind_str, suggested_name, }); @@ -1409,6 +1410,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span }) } + + pub(super) fn report_pointee_sized_trait_object(&self, span: Span) -> ErrorGuaranteed { + self.dcx().emit_err(PointeeSizedTraitObject { span }) + } } /// Emit an error for the given associated item constraint. diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index baf3b9b5bc9..6b2854d96af 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -80,10 +80,10 @@ pub enum PredicateFilter { /// and `<Self as Tr>::A: B`. SelfAndAssociatedTypeBounds, - /// Filter only the `~const` bounds, which are lowered into `HostEffect` clauses. + /// Filter only the `[const]` bounds, which are lowered into `HostEffect` clauses. ConstIfConst, - /// Filter only the `~const` bounds which are *also* in the supertrait position. + /// Filter only the `[const]` bounds which are *also* in the supertrait position. SelfConstIfConst, } @@ -885,7 +885,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } // On the flip side, when filtering `ConstIfConst` bounds, we only need to convert - // `~const` bounds. All other predicates are handled in their respective queries. + // `[const]` bounds. All other predicates are handled in their respective queries. // // Note that like `PredicateFilter::SelfOnly`, we don't need to do any filtering // here because we only call this on self bounds, and deal with the recursive case @@ -2364,9 +2364,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }; let lit_input = match expr.kind { - hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }), + hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: lit.node, ty, neg: false }), hir::ExprKind::Unary(hir::UnOp::Neg, expr) => match expr.kind { - hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: true }), + hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: lit.node, ty, neg: true }), _ => None, }, _ => None, @@ -2433,7 +2433,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } else { let repr = match repr { TraitObjectSyntax::Dyn | TraitObjectSyntax::None => ty::Dyn, - TraitObjectSyntax::DynStar => ty::DynStar, }; self.lower_trait_object_ty(hir_ty.span, hir_ty.hir_id, bounds, lifetime, repr) } diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 309221f9a12..574d19a5aa5 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -402,22 +402,22 @@ fn check_predicates<'tcx>( /// as some predicate on the base impl (`predicate2`). /// /// This basically just checks syntactic equivalence, but is a little more -/// forgiving since we want to equate `T: Tr` with `T: ~const Tr` so this can work: +/// forgiving since we want to equate `T: Tr` with `T: [const] Tr` so this can work: /// /// ```ignore (illustrative) /// #[rustc_specialization_trait] /// trait Specialize { } /// /// impl<T: Bound> Tr for T { } -/// impl<T: ~const Bound + Specialize> const Tr for T { } +/// impl<T: [const] Bound + Specialize> const Tr for T { } /// ``` /// /// However, we *don't* want to allow the reverse, i.e., when the bound on the /// specializing impl is not as const as the bound on the base impl: /// /// ```ignore (illustrative) -/// impl<T: ~const Bound> const Tr for T { } -/// impl<T: Bound + Specialize> const Tr for T { } // should be T: ~const Bound +/// impl<T: [const] Bound> const Tr for T { } +/// impl<T: Bound + Specialize> const Tr for T { } // should be T: [const] Bound /// ``` /// /// So we make that check in this function and try to raise a helpful error message. diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 76ab2e57a1b..2ff7caef732 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -65,7 +65,6 @@ This API is completely unstable and subject to change. #![feature(debug_closure_helpers)] #![feature(gen_blocks)] #![feature(if_let_guard)] -#![feature(iter_from_coroutine)] #![feature(iter_intersperse)] #![feature(never_type)] #![feature(rustdoc_internals)] diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index d3289e4cc6d..c523a03e012 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -420,7 +420,6 @@ impl<'a> State<'a> { let syntax = lifetime.tag(); match syntax { ast::TraitObjectSyntax::Dyn => self.word_nbsp("dyn"), - ast::TraitObjectSyntax::DynStar => self.word_nbsp("dyn*"), ast::TraitObjectSyntax::None => {} } let mut first = true; @@ -784,7 +783,7 @@ impl<'a> State<'a> { match constness { hir::BoundConstness::Never => {} hir::BoundConstness::Always(_) => self.word("const"), - hir::BoundConstness::Maybe(_) => self.word("~const"), + hir::BoundConstness::Maybe(_) => self.word("[const]"), } match polarity { hir::BoundPolarity::Positive => {} @@ -1335,6 +1334,10 @@ impl<'a> State<'a> { self.word_nbsp("raw"); self.print_mutability(mutability, true); } + hir::BorrowKind::Pin => { + self.word_nbsp("pin"); + self.print_mutability(mutability, true); + } } self.print_expr_cond_paren(expr, self.precedence(expr) < ExprPrecedence::Prefix); } @@ -1476,7 +1479,7 @@ impl<'a> State<'a> { self.print_expr_addr_of(k, m, expr); } hir::ExprKind::Lit(lit) => { - self.print_literal(lit); + self.print_literal(&lit); } hir::ExprKind::Cast(expr, ty) => { self.print_expr_cond_paren(expr, self.precedence(expr) < ExprPrecedence::Cast); diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 258535f3742..c21b16c9f9f 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -79,6 +79,9 @@ hir_typeck_cast_unknown_pointer = cannot cast {$to -> .note = the type information given here is insufficient to check whether the pointer cast is valid .label_from = the type information given here is insufficient to check whether the pointer cast is valid +hir_typeck_const_continue_bad_label = + `#[const_continue]` must break to a labeled block that participates in a `#[loop_match]` + hir_typeck_const_select_must_be_const = this argument must be a `const fn` .help = consult the documentation on `const_eval_select` for more information diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 4ac260cb15f..6467adb54da 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -1,12 +1,12 @@ use rustc_errors::{Applicability, Diag}; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::LocalDefId; -use rustc_hir::{self as hir, ExprKind, PatKind}; +use rustc_hir::{self as hir, ExprKind, HirId, PatKind}; use rustc_hir_pretty::ty_to_string; use rustc_middle::ty::{self, Ty}; use rustc_span::Span; use rustc_trait_selection::traits::{ - IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, + MatchExpressionArmCause, ObligationCause, ObligationCauseCode, }; use tracing::{debug, instrument}; @@ -414,105 +414,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn if_cause( &self, - span: Span, - cond_span: Span, - then_expr: &'tcx hir::Expr<'tcx>, + expr_id: HirId, else_expr: &'tcx hir::Expr<'tcx>, - then_ty: Ty<'tcx>, - else_ty: Ty<'tcx>, tail_defines_return_position_impl_trait: Option<LocalDefId>, ) -> ObligationCause<'tcx> { - let mut outer_span = if self.tcx.sess.source_map().is_multiline(span) { - // The `if`/`else` isn't in one line in the output, include some context to make it - // clear it is an if/else expression: - // ``` - // LL | let x = if true { - // | _____________- - // LL || 10i32 - // || ----- expected because of this - // LL || } else { - // LL || 10u32 - // || ^^^^^ expected `i32`, found `u32` - // LL || }; - // ||_____- `if` and `else` have incompatible types - // ``` - Some(span) - } else { - // The entire expression is in one line, only point at the arms - // ``` - // LL | let x = if true { 10i32 } else { 10u32 }; - // | ----- ^^^^^ expected `i32`, found `u32` - // | | - // | expected because of this - // ``` - None - }; - - let (error_sp, else_id) = if let ExprKind::Block(block, _) = &else_expr.kind { - let block = block.innermost_block(); - - // Avoid overlapping spans that aren't as readable: - // ``` - // 2 | let x = if true { - // | _____________- - // 3 | | 3 - // | | - expected because of this - // 4 | | } else { - // | |____________^ - // 5 | || - // 6 | || }; - // | || ^ - // | ||_____| - // | |______if and else have incompatible types - // | expected integer, found `()` - // ``` - // by not pointing at the entire expression: - // ``` - // 2 | let x = if true { - // | ------- `if` and `else` have incompatible types - // 3 | 3 - // | - expected because of this - // 4 | } else { - // | ____________^ - // 5 | | - // 6 | | }; - // | |_____^ expected integer, found `()` - // ``` - if block.expr.is_none() - && block.stmts.is_empty() - && let Some(outer_span) = &mut outer_span - && let Some(cond_span) = cond_span.find_ancestor_inside(*outer_span) - { - *outer_span = outer_span.with_hi(cond_span.hi()) - } - - (self.find_block_span(block), block.hir_id) - } else { - (else_expr.span, else_expr.hir_id) - }; - - let then_id = if let ExprKind::Block(block, _) = &then_expr.kind { - let block = block.innermost_block(); - // Exclude overlapping spans - if block.expr.is_none() && block.stmts.is_empty() { - outer_span = None; - } - block.hir_id - } else { - then_expr.hir_id - }; + let error_sp = self.find_block_span_from_hir_id(else_expr.hir_id); // Finally construct the cause: self.cause( error_sp, - ObligationCauseCode::IfExpression(Box::new(IfExpressionCause { - else_id, - then_id, - then_ty, - else_ty, - outer_span, - tail_defines_return_position_impl_trait, - })), + ObligationCauseCode::IfExpression { expr_id, tail_defines_return_position_impl_trait }, ) } diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 7a3647df0c4..8c1399aec14 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -7,7 +7,7 @@ use rustc_hir::def::{self, CtorKind, Namespace, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, HirId, LangItem}; use rustc_hir_analysis::autoderef::Autoderef; -use rustc_infer::infer; +use rustc_infer::infer::BoundRegionConversionTime; use rustc_infer::traits::{Obligation, ObligationCause, ObligationCauseCode}; use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, @@ -156,7 +156,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn check_call_abi(&self, abi: ExternAbi, span: Span) { let canon_abi = match AbiMap::from_target(&self.sess().target).canonize_abi(abi, false) { AbiMapping::Direct(canon_abi) | AbiMapping::Deprecated(canon_abi) => canon_abi, - AbiMapping::Invalid => return, + AbiMapping::Invalid => { + // This should be reported elsewhere, but we want to taint this body + // so that we don't try to evaluate calls to ABIs that are invalid. + let guar = self.dcx().span_delayed_bug( + span, + format!("invalid abi for platform should have reported an error: {abi}"), + ); + self.set_tainted_by_errors(guar); + return; + } }; let valid = match canon_abi { @@ -210,7 +219,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let closure_sig = args.as_closure().sig(); let closure_sig = self.instantiate_binder_with_fresh_vars( call_expr.span, - infer::FnCall, + BoundRegionConversionTime::FnCall, closure_sig, ); let adjustments = self.adjust_steps(autoderef); @@ -237,7 +246,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let closure_args = args.as_coroutine_closure(); let coroutine_closure_sig = self.instantiate_binder_with_fresh_vars( call_expr.span, - infer::FnCall, + BoundRegionConversionTime::FnCall, closure_args.coroutine_closure_sig(), ); let tupled_upvars_ty = self.next_ty_var(callee_expr.span); @@ -536,7 +545,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // renormalize the associated types at this point, since they // previously appeared within a `Binder<>` and hence would not // have been normalized before. - let fn_sig = self.instantiate_binder_with_fresh_vars(call_expr.span, infer::FnCall, fn_sig); + let fn_sig = self.instantiate_binder_with_fresh_vars( + call_expr.span, + BoundRegionConversionTime::FnCall, + fn_sig, + ); let fn_sig = self.normalize(call_expr.span, fn_sig); self.check_argument_types( @@ -903,7 +916,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } - // If we have `rustc_do_not_const_check`, do not check `~const` bounds. + // If we have `rustc_do_not_const_check`, do not check `[const]` bounds. if self.tcx.has_attr(self.body_id, sym::rustc_do_not_const_check) { return; } diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 6f8abc1e67d..3eeb0eac023 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -143,7 +143,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | ty::Coroutine(..) | ty::Adt(..) | ty::Never - | ty::Dynamic(_, _, ty::DynStar) | ty::Error(_) => { let guar = self .dcx() @@ -734,14 +733,6 @@ impl<'a, 'tcx> CastCheck<'tcx> { use rustc_middle::ty::cast::CastTy::*; use rustc_middle::ty::cast::IntTy::*; - if self.cast_ty.is_dyn_star() { - // This coercion will fail if the feature is not enabled, OR - // if the coercion is (currently) illegal (e.g. `dyn* Foo + Send` - // to `dyn* Foo`). Report "casting is invalid" rather than - // "non-primitive cast". - return Err(CastError::IllegalCast); - } - let (t_from, t_cast) = match (CastTy::from_ty(self.expr_ty), CastTy::from_ty(self.cast_ty)) { (Some(t_from), Some(t_cast)) => (t_from, t_cast), diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index ac42eebf08c..61239685884 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -58,7 +58,7 @@ pub(super) fn check_fn<'a, 'tcx>( let maybe_va_list = fn_sig.c_variadic.then(|| { let span = body.params.last().unwrap().span; let va_list_did = tcx.require_lang_item(LangItem::VaList, span); - let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span)); + let region = fcx.next_region_var(RegionVariableOrigin::Misc(span)); tcx.type_of(va_list_did).instantiate(tcx, &[region.into()]) }); diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 24092c01125..3ca04ba330b 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -44,10 +44,9 @@ use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; use rustc_infer::infer::relate::RelateResult; -use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult}; +use rustc_infer::infer::{DefineOpaqueTypes, InferOk, InferResult, RegionVariableOrigin}; use rustc_infer::traits::{ - IfExpressionCause, MatchExpressionArmCause, Obligation, PredicateObligation, - PredicateObligations, SelectionError, + MatchExpressionArmCause, Obligation, PredicateObligation, PredicateObligations, SelectionError, }; use rustc_middle::span_bug; use rustc_middle::ty::adjustment::{ @@ -59,7 +58,7 @@ use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Span}; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::{ - self, NormalizeExt, ObligationCause, ObligationCauseCode, ObligationCtxt, + self, ImplSource, NormalizeExt, ObligationCause, ObligationCauseCode, ObligationCtxt, }; use smallvec::{SmallVec, smallvec}; use tracing::{debug, instrument}; @@ -232,9 +231,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { ty::Ref(r_b, _, mutbl_b) => { return self.coerce_borrowed_pointer(a, b, r_b, mutbl_b); } - ty::Dynamic(predicates, region, ty::DynStar) if self.tcx.features().dyn_star() => { - return self.coerce_dyn_star(a, b, predicates, region); - } ty::Adt(pin, _) if self.tcx.features().pin_ergonomics() && self.tcx.is_lang_item(pin.did(), hir::LangItem::Pin) => @@ -279,8 +275,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { /// fall back to subtyping (`unify_and`). fn coerce_from_inference_variable(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { debug!("coerce_from_inference_variable(a={:?}, b={:?})", a, b); - assert!(a.is_ty_var() && self.shallow_resolve(a) == a); - assert!(self.shallow_resolve(b) == b); + debug_assert!(a.is_ty_var() && self.shallow_resolve(a) == a); + debug_assert!(self.shallow_resolve(b) == b); if b.is_ty_var() { // Two unresolved type variables: create a `Coerce` predicate. @@ -324,6 +320,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { mutbl_b: hir::Mutability, ) -> CoerceResult<'tcx> { debug!("coerce_borrowed_pointer(a={:?}, b={:?})", a, b); + debug_assert!(self.shallow_resolve(a) == a); + debug_assert!(self.shallow_resolve(b) == b); // If we have a parameter of type `&M T_a` and the value // provided is `expr`, we will be adding an implicit borrow, @@ -431,7 +429,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } else { if r_borrow_var.is_none() { // create var lazily, at most once - let coercion = Coercion(span); + let coercion = RegionVariableOrigin::Coercion(span); let r = self.next_region_var(coercion); r_borrow_var = Some(r); // [4] above } @@ -515,10 +513,10 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { /// /// [unsized coercion](https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions) #[instrument(skip(self), level = "debug")] - fn coerce_unsized(&self, mut source: Ty<'tcx>, mut target: Ty<'tcx>) -> CoerceResult<'tcx> { - source = self.shallow_resolve(source); - target = self.shallow_resolve(target); + fn coerce_unsized(&self, source: Ty<'tcx>, target: Ty<'tcx>) -> CoerceResult<'tcx> { debug!(?source, ?target); + debug_assert!(self.shallow_resolve(source) == source); + debug_assert!(self.shallow_resolve(target) == target); // We don't apply any coercions incase either the source or target // aren't sufficiently well known but tend to instead just equate @@ -532,6 +530,54 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { return Err(TypeError::Mismatch); } + // This is an optimization because coercion is one of the most common + // operations that we do in typeck, since it happens at every assignment + // and call arg (among other positions). + // + // These targets are known to never be RHS in `LHS: CoerceUnsized<RHS>`. + // That's because these are built-in types for which a core-provided impl + // doesn't exist, and for which a user-written impl is invalid. + // + // This is technically incomplete when users write impossible bounds like + // `where T: CoerceUnsized<usize>`, for example, but that trait is unstable + // and coercion is allowed to be incomplete. The only case where this matters + // is impossible bounds. + // + // Note that some of these types implement `LHS: Unsize<RHS>`, but they + // do not implement *`CoerceUnsized`* which is the root obligation of the + // check below. + match target.kind() { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Str + | ty::Array(_, _) + | ty::Slice(_) + | ty::FnDef(_, _) + | ty::FnPtr(_, _) + | ty::Dynamic(_, _, _) + | ty::Closure(_, _) + | ty::CoroutineClosure(_, _) + | ty::Coroutine(_, _) + | ty::CoroutineWitness(_, _) + | ty::Never + | ty::Tuple(_) => return Err(TypeError::Mismatch), + _ => {} + } + // Additionally, we ignore `&str -> &str` coercions, which happen very + // commonly since strings are one of the most used argument types in Rust, + // we do coercions when type checking call expressions. + if let ty::Ref(_, source_pointee, ty::Mutability::Not) = *source.kind() + && source_pointee.is_str() + && let ty::Ref(_, target_pointee, ty::Mutability::Not) = *target.kind() + && target_pointee.is_str() + { + return Err(TypeError::Mismatch); + } + let traits = (self.tcx.lang_items().unsize_trait(), self.tcx.lang_items().coerce_unsized_trait()); let (Some(unsize_did), Some(coerce_unsized_did)) = traits else { @@ -549,7 +595,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { (&ty::Ref(_, ty_a, mutbl_a), &ty::Ref(_, _, mutbl_b)) => { coerce_mutbls(mutbl_a, mutbl_b)?; - let coercion = Coercion(self.cause.span); + let coercion = RegionVariableOrigin::Coercion(self.cause.span); let r_borrow = self.next_region_var(coercion); // We don't allow two-phase borrows here, at least for initial @@ -672,7 +718,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { return Err(TypeError::Mismatch); } } - Err(traits::Unimplemented) => { + Err(SelectionError::Unimplemented) => { debug!("coerce_unsized: early return - can't prove obligation"); return Err(TypeError::Mismatch); } @@ -704,6 +750,19 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // be silent, as it causes a type mismatch later. } + Ok(Some(ImplSource::UserDefined(impl_source))) => { + queue.extend(impl_source.nested); + // Certain incoherent `CoerceUnsized` implementations may cause ICEs, + // so check the impl's validity. Taint the body so that we don't try + // to evaluate these invalid coercions in CTFE. We only need to do this + // for local impls, since upstream impls should be valid. + if impl_source.impl_def_id.is_local() + && let Err(guar) = + self.tcx.ensure_ok().coerce_unsized_info(impl_source.impl_def_id) + { + self.fcx.set_tainted_by_errors(guar); + } + } Ok(Some(impl_source)) => queue.extend(impl_source.nested_obligations()), } } @@ -711,71 +770,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { Ok(coercion) } - fn coerce_dyn_star( - &self, - a: Ty<'tcx>, - b: Ty<'tcx>, - predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, - b_region: ty::Region<'tcx>, - ) -> CoerceResult<'tcx> { - if !self.tcx.features().dyn_star() { - return Err(TypeError::Mismatch); - } - - // FIXME(dyn_star): We should probably allow things like casting from - // `dyn* Foo + Send` to `dyn* Foo`. - if let ty::Dynamic(a_data, _, ty::DynStar) = a.kind() - && let ty::Dynamic(b_data, _, ty::DynStar) = b.kind() - && a_data.principal_def_id() == b_data.principal_def_id() - { - return self.unify(a, b); - } - - // Check the obligations of the cast -- for example, when casting - // `usize` to `dyn* Clone + 'static`: - let obligations = predicates - .iter() - .map(|predicate| { - // For each existential predicate (e.g., `?Self: Clone`) instantiate - // the type of the expression (e.g., `usize` in our example above) - // and then require that the resulting predicate (e.g., `usize: Clone`) - // holds (it does). - let predicate = predicate.with_self_ty(self.tcx, a); - Obligation::new(self.tcx, self.cause.clone(), self.param_env, predicate) - }) - .chain([ - // Enforce the region bound (e.g., `usize: 'static`, in our example). - Obligation::new( - self.tcx, - self.cause.clone(), - self.param_env, - ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives( - ty::OutlivesPredicate(a, b_region), - ))), - ), - // Enforce that the type is `usize`/pointer-sized. - Obligation::new( - self.tcx, - self.cause.clone(), - self.param_env, - ty::TraitRef::new( - self.tcx, - self.tcx.require_lang_item(hir::LangItem::PointerLike, self.cause.span), - [a], - ), - ), - ]) - .collect(); - - Ok(InferOk { - value: ( - vec![Adjustment { kind: Adjust::Pointer(PointerCoercion::DynStar), target: b }], - b, - ), - obligations, - }) - } - /// Applies reborrowing for `Pin` /// /// We currently only support reborrowing `Pin<&mut T>` as `Pin<&mut T>`. This is accomplished @@ -788,6 +782,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { /// - `Pin<Box<T>>` as `Pin<&mut T>` #[instrument(skip(self), level = "trace")] fn coerce_pin_ref(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { + debug_assert!(self.shallow_resolve(a) == a); + debug_assert!(self.shallow_resolve(b) == b); + // We need to make sure the two types are compatible for coercion. // Then we will build a ReborrowPin adjustment and return that as an InferOk. @@ -836,6 +833,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { b: Ty<'tcx>, adjustment: Option<Adjust>, ) -> CoerceResult<'tcx> { + debug_assert!(self.shallow_resolve(b) == b); + self.commit_if_ok(|snapshot| { let outer_universe = self.infcx.universe(); @@ -876,24 +875,19 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { fn_ty_a: ty::PolyFnSig<'tcx>, b: Ty<'tcx>, ) -> CoerceResult<'tcx> { - //! Attempts to coerce from the type of a Rust function item - //! into a closure or a `proc`. - //! - - let b = self.shallow_resolve(b); debug!(?fn_ty_a, ?b, "coerce_from_fn_pointer"); + debug_assert!(self.shallow_resolve(b) == b); self.coerce_from_safe_fn(fn_ty_a, b, None) } fn coerce_from_fn_item(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { - //! Attempts to coerce from the type of a Rust function item - //! into a closure or a `proc`. + debug!("coerce_from_fn_item(a={:?}, b={:?})", a, b); + debug_assert!(self.shallow_resolve(a) == a); + debug_assert!(self.shallow_resolve(b) == b); - let b = self.shallow_resolve(b); let InferOk { value: b, mut obligations } = self.at(&self.cause, self.param_env).normalize(b); - debug!("coerce_from_fn_item(a={:?}, b={:?})", a, b); match b.kind() { ty::FnPtr(_, b_hdr) => { @@ -943,6 +937,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } } + /// Attempts to coerce from the type of a non-capturing closure + /// into a function pointer. fn coerce_closure_to_fn( &self, a: Ty<'tcx>, @@ -950,11 +946,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { args_a: GenericArgsRef<'tcx>, b: Ty<'tcx>, ) -> CoerceResult<'tcx> { - //! Attempts to coerce from the type of a non-capturing closure - //! into a function pointer. - //! - - let b = self.shallow_resolve(b); + debug_assert!(self.shallow_resolve(a) == a); + debug_assert!(self.shallow_resolve(b) == b); match b.kind() { // At this point we haven't done capture analysis, which means @@ -998,6 +991,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { mutbl_b: hir::Mutability, ) -> CoerceResult<'tcx> { debug!("coerce_raw_ptr(a={:?}, b={:?})", a, b); + debug_assert!(self.shallow_resolve(a) == a); + debug_assert!(self.shallow_resolve(b) == b); let (is_ref, mt_a) = match *a.kind() { ty::Ref(_, ty, mutbl) => (true, ty::TypeAndMut { ty, mutbl }), @@ -1706,14 +1701,17 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { ); } } - ObligationCauseCode::IfExpression(box IfExpressionCause { - then_id, - else_id, - then_ty, - else_ty, + ObligationCauseCode::IfExpression { + expr_id, tail_defines_return_position_impl_trait: Some(rpit_def_id), - .. - }) => { + } => { + let hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::If(_, then_expr, Some(else_expr)), + .. + }) = fcx.tcx.hir_node(expr_id) + else { + unreachable!(); + }; err = fcx.err_ctxt().report_mismatched_types( cause, fcx.param_env, @@ -1721,24 +1719,12 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { found, coercion_error, ); - let then_span = fcx.find_block_span_from_hir_id(then_id); - let else_span = fcx.find_block_span_from_hir_id(else_id); - // don't suggest wrapping either blocks in `if .. {} else {}` - let is_empty_arm = |id| { - let hir::Node::Block(blk) = fcx.tcx.hir_node(id) else { - return false; - }; - if blk.expr.is_some() || !blk.stmts.is_empty() { - return false; - } - let Some((_, hir::Node::Expr(expr))) = - fcx.tcx.hir_parent_iter(id).nth(1) - else { - return false; - }; - matches!(expr.kind, hir::ExprKind::If(..)) - }; - if !is_empty_arm(then_id) && !is_empty_arm(else_id) { + let then_span = fcx.find_block_span_from_hir_id(then_expr.hir_id); + let else_span = fcx.find_block_span_from_hir_id(else_expr.hir_id); + // Don't suggest wrapping whole block in `Box::new`. + if then_span != then_expr.span && else_span != else_expr.span { + let then_ty = fcx.typeck_results.borrow().expr_ty(then_expr); + let else_ty = fcx.typeck_results.borrow().expr_ty(else_expr); self.suggest_boxing_tail_for_return_position_impl_trait( fcx, &mut err, diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 5fea0c62843..3606c778fc4 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -1167,3 +1167,10 @@ pub(crate) struct AbiCannotBeCalled { pub span: Span, pub abi: ExternAbi, } + +#[derive(Diagnostic)] +#[diag(hir_typeck_const_continue_bad_label)] +pub(crate) struct ConstContinueBadLabel { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 672f3bc67ce..067ee0f0eb0 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -22,8 +22,7 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::{ExprKind, HirId, QPath}; use rustc_hir_analysis::NoVariantNamed; use rustc_hir_analysis::hir_ty_lowering::{FeedConstTy, HirTyLowerer as _}; -use rustc_infer::infer; -use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; +use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk, RegionVariableOrigin}; use rustc_infer::traits::query::NoSolution; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase}; use rustc_middle::ty::error::{ExpectedFound, TypeError}; @@ -583,7 +582,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ascribed_ty } ExprKind::If(cond, then_expr, opt_else_expr) => { - self.check_expr_if(cond, then_expr, opt_else_expr, expr.span, expected) + self.check_expr_if(expr.hir_id, cond, then_expr, opt_else_expr, expr.span, expected) } ExprKind::DropTemps(e) => self.check_expr_with_expectation(e, expected), ExprKind::Array(args) => self.check_expr_array(args, expected, expr), @@ -690,7 +689,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_named_place_expr(oprnd); Ty::new_ptr(self.tcx, ty, mutbl) } - hir::BorrowKind::Ref => { + hir::BorrowKind::Ref | hir::BorrowKind::Pin => { // Note: at this point, we cannot say what the best lifetime // is to use for resulting pointer. We want to use the // shortest lifetime possible so as to avoid spurious borrowck @@ -705,8 +704,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // this time with enough precision to check that the value // whose address was taken can actually be made to live as long // as it needs to live. - let region = self.next_region_var(infer::BorrowRegion(expr.span)); - Ty::new_ref(self.tcx, region, ty, mutbl) + let region = self.next_region_var(RegionVariableOrigin::BorrowRegion(expr.span)); + match kind { + hir::BorrowKind::Ref => Ty::new_ref(self.tcx, region, ty, mutbl), + hir::BorrowKind::Pin => Ty::new_pinned_ref(self.tcx, region, ty, mutbl), + _ => unreachable!(), + } } } } @@ -1339,6 +1342,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // or 'if-else' expression. fn check_expr_if( &self, + expr_id: HirId, cond_expr: &'tcx hir::Expr<'tcx>, then_expr: &'tcx hir::Expr<'tcx>, opt_else_expr: Option<&'tcx hir::Expr<'tcx>>, @@ -1378,15 +1382,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let tail_defines_return_position_impl_trait = self.return_position_impl_trait_from_match_expectation(orig_expected); - let if_cause = self.if_cause( - sp, - cond_expr.span, - then_expr, - else_expr, - then_ty, - else_ty, - tail_defines_return_position_impl_trait, - ); + let if_cause = + self.if_cause(expr_id, else_expr, tail_defines_return_position_impl_trait); coerce.coerce(self, &if_cause, else_expr, else_ty); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 2df19cb21d5..58751f232d0 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -281,7 +281,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } Adjust::Deref(None) => { - // FIXME(const_trait_impl): We *could* enforce `&T: ~const Deref` here. + // FIXME(const_trait_impl): We *could* enforce `&T: [const] Deref` here. } Adjust::Pointer(_pointer_coercion) => { // FIXME(const_trait_impl): We should probably enforce these. diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 95c7f251c88..3c53a060f7f 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -11,7 +11,7 @@ use rustc_hir::{ExprKind, HirId, LangItem, Node, QPath}; use rustc_hir_analysis::check::potentially_plural_count; use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, PermitVariants}; use rustc_index::IndexVec; -use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TypeTrace}; +use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk, TypeTrace}; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt, TypeVisitableExt}; @@ -30,7 +30,6 @@ use crate::TupleArgumentsFlag::*; use crate::coercion::CoerceMany; use crate::errors::SuggestPtrNullMut; use crate::fn_ctxt::arg_matrix::{ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx}; -use crate::fn_ctxt::infer::FnCall; use crate::gather_locals::Declaration; use crate::inline_asm::InlineAsmCtxt; use crate::method::probe::IsSuggestion; @@ -657,7 +656,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let args = self.infcx.fresh_args_for_item(call_name.span, assoc.def_id); let fn_sig = tcx.fn_sig(assoc.def_id).instantiate(tcx, args); - self.instantiate_binder_with_fresh_vars(call_name.span, FnCall, fn_sig); + self.instantiate_binder_with_fresh_vars( + call_name.span, + BoundRegionConversionTime::FnCall, + fn_sig, + ); } None }; @@ -1634,7 +1637,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ast::LitKind::ByteStr(ref v, _) => Ty::new_imm_ref( tcx, tcx.lifetimes.re_static, - Ty::new_array(tcx, tcx.types.u8, v.len() as u64), + Ty::new_array(tcx, tcx.types.u8, v.as_byte_str().len() as u64), ), ast::LitKind::Byte(_) => tcx.types.u8, ast::LitKind::Char(_) => tcx.types.char, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 8c18642e54a..0c6226ce71e 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -15,7 +15,7 @@ use rustc_hir::{self as hir, HirId, ItemLocalMap}; use rustc_hir_analysis::hir_ty_lowering::{ HirTyLowerer, InherentAssocCandidate, RegionInferReason, }; -use rustc_infer::infer; +use rustc_infer::infer::{self, RegionVariableOrigin}; use rustc_infer::traits::{DynCompatibilityViolation, Obligation}; use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt}; use rustc_session::Session; @@ -244,8 +244,10 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx> { let v = match reason { - RegionInferReason::Param(def) => infer::RegionParameterDefinition(span, def.name), - _ => infer::MiscVariable(span), + RegionInferReason::Param(def) => { + RegionVariableOrigin::RegionParameterDefinition(span, def.name) + } + _ => RegionVariableOrigin::Misc(span), }; self.next_region_var(v) } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 7e5f1d97a8b..dd6eb73a3a0 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1624,7 +1624,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { node: rustc_ast::LitKind::Int(lit, rustc_ast::LitIntType::Unsuffixed), span, }) => { - let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(*span) else { + let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) else { return false; }; if !(snippet.starts_with("0x") || snippet.starts_with("0X")) { @@ -1683,7 +1683,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We have satisfied all requirements to provide a suggestion. Emit it. err.span_suggestion( - *span, + span, format!("if you meant to create a null pointer, use `{null_path_str}()`"), null_path_str + "()", Applicability::MachineApplicable, diff --git a/compiler/rustc_hir_typeck/src/loops.rs b/compiler/rustc_hir_typeck/src/loops.rs index b06e0704b6f..80eab578f13 100644 --- a/compiler/rustc_hir_typeck/src/loops.rs +++ b/compiler/rustc_hir_typeck/src/loops.rs @@ -2,6 +2,8 @@ use std::collections::BTreeMap; use std::fmt; use Context::*; +use rustc_ast::Label; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; @@ -14,8 +16,9 @@ use rustc_span::hygiene::DesugaringKind; use rustc_span::{BytePos, Span}; use crate::errors::{ - BreakInsideClosure, BreakInsideCoroutine, BreakNonLoop, ContinueLabeledBlock, OutsideLoop, - OutsideLoopSuggestion, UnlabeledCfInWhileCondition, UnlabeledInLabeledBlock, + BreakInsideClosure, BreakInsideCoroutine, BreakNonLoop, ConstContinueBadLabel, + ContinueLabeledBlock, OutsideLoop, OutsideLoopSuggestion, UnlabeledCfInWhileCondition, + UnlabeledInLabeledBlock, }; /// The context in which a block is encountered. @@ -37,6 +40,11 @@ enum Context { AnonConst, /// E.g. `const { ... }`. ConstBlock, + /// E.g. `#[loop_match] loop { state = 'label: { /* ... */ } }`. + LoopMatch { + /// The label of the labeled block (not of the loop itself). + labeled_block: Label, + }, } #[derive(Clone)] @@ -141,7 +149,12 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> { } } hir::ExprKind::Loop(ref b, _, source, _) => { - self.with_context(Loop(source), |v| v.visit_block(b)); + let cx = match self.is_loop_match(e, b) { + Some(labeled_block) => LoopMatch { labeled_block }, + None => Loop(source), + }; + + self.with_context(cx, |v| v.visit_block(b)); } hir::ExprKind::Closure(&hir::Closure { ref fn_decl, body, fn_decl_span, kind, .. @@ -197,6 +210,23 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> { Err(hir::LoopIdError::UnresolvedLabel) => None, }; + // A `#[const_continue]` must break to a block in a `#[loop_match]`. + if find_attr!(self.tcx.hir_attrs(e.hir_id), AttributeKind::ConstContinue(_)) { + if let Some(break_label) = break_label.label { + let is_target_label = |cx: &Context| match cx { + Context::LoopMatch { labeled_block } => { + break_label.ident.name == labeled_block.ident.name + } + _ => false, + }; + + if !self.cx_stack.iter().rev().any(is_target_label) { + let span = break_label.ident.span; + self.tcx.dcx().emit_fatal(ConstContinueBadLabel { span }); + } + } + } + if let Some(Node::Block(_)) = loop_id.map(|id| self.tcx.hir_node(id)) { return; } @@ -299,7 +329,7 @@ impl<'hir> CheckLoopVisitor<'hir> { cx_pos: usize, ) { match self.cx_stack[cx_pos] { - LabeledBlock | Loop(_) => {} + LabeledBlock | Loop(_) | LoopMatch { .. } => {} Closure(closure_span) => { self.tcx.dcx().emit_err(BreakInsideClosure { span, @@ -380,4 +410,36 @@ impl<'hir> CheckLoopVisitor<'hir> { }); } } + + /// Is this a loop annotated with `#[loop_match]` that looks syntactically sound? + fn is_loop_match( + &self, + e: &'hir hir::Expr<'hir>, + body: &'hir hir::Block<'hir>, + ) -> Option<Label> { + if !find_attr!(self.tcx.hir_attrs(e.hir_id), AttributeKind::LoopMatch(_)) { + return None; + } + + // NOTE: Diagnostics are emitted during MIR construction. + + // Accept either `state = expr` or `state = expr;`. + let loop_body_expr = match body.stmts { + [] => match body.expr { + Some(expr) => expr, + None => return None, + }, + [single] if body.expr.is_none() => match single.kind { + hir::StmtKind::Expr(expr) | hir::StmtKind::Semi(expr) => expr, + _ => return None, + }, + [..] => return None, + }; + + let hir::ExprKind::Assign(_, rhs_expr, _) = loop_body_expr.kind else { return None }; + + let hir::ExprKind::Block(_, label) = rhs_expr.kind else { return None }; + + label + } } diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 53b5dff9c6b..9563cf734f6 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -9,7 +9,9 @@ use rustc_hir_analysis::hir_ty_lowering::generics::{ use rustc_hir_analysis::hir_ty_lowering::{ FeedConstTy, GenericArgsLowerer, HirTyLowerer, IsMethodCall, RegionInferReason, }; -use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk}; +use rustc_infer::infer::{ + BoundRegionConversionTime, DefineOpaqueTypes, InferOk, RegionVariableOrigin, +}; use rustc_lint::builtin::SUPERTRAIT_ITEM_SHADOWING_USAGE; use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::adjustment::{ @@ -194,7 +196,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { match pick.autoref_or_ptr_adjustment { Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, unsize }) => { - let region = self.next_region_var(infer::Autoref(self.span)); + let region = self.next_region_var(RegionVariableOrigin::Autoref(self.span)); // Type we're wrapping in a reference, used later for unsizing let base_ty = target; @@ -239,7 +241,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { } Some(probe::AutorefOrPtrAdjustment::ReborrowPin(mutbl)) => { - let region = self.next_region_var(infer::Autoref(self.span)); + let region = self.next_region_var(RegionVariableOrigin::Autoref(self.span)); target = match target.kind() { ty::Adt(pin, args) if self.tcx.is_lang_item(pin.did(), hir::LangItem::Pin) => { @@ -752,6 +754,10 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { where T: TypeFoldable<TyCtxt<'tcx>> + Copy, { - self.fcx.instantiate_binder_with_fresh_vars(self.span, infer::FnCall, value) + self.fcx.instantiate_binder_with_fresh_vars( + self.span, + BoundRegionConversionTime::FnCall, + value, + ) } } diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 34bbb7d7c05..085e7a2f5df 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -11,7 +11,7 @@ use rustc_errors::{Applicability, Diag, SubdiagMessage}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Namespace}; use rustc_hir::def_id::DefId; -use rustc_infer::infer::{self, InferOk}; +use rustc_infer::infer::{BoundRegionConversionTime, InferOk}; use rustc_infer::traits::PredicateObligations; use rustc_middle::query::Providers; use rustc_middle::traits::ObligationCause; @@ -400,8 +400,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // function signature so that normalization does not need to deal // with bound regions. let fn_sig = tcx.fn_sig(def_id).instantiate(self.tcx, args); - let fn_sig = - self.instantiate_binder_with_fresh_vars(obligation.cause.span, infer::FnCall, fn_sig); + let fn_sig = self.instantiate_binder_with_fresh_vars( + obligation.cause.span, + BoundRegionConversionTime::FnCall, + fn_sig, + ); let InferOk { value: fn_sig, obligations: o } = self.at(&obligation.cause, self.param_env).normalize(fn_sig); diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 589dbb53116..be0eb13cace 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -12,7 +12,7 @@ use rustc_hir::HirId; use rustc_hir::def::DefKind; use rustc_hir_analysis::autoderef::{self, Autoderef}; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; -use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk, TyCtxtInferExt}; +use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk, TyCtxtInferExt}; use rustc_infer::traits::ObligationCauseCode; use rustc_middle::middle::stability; use rustc_middle::query::Providers; @@ -995,7 +995,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { ty::AssocKind::Fn { .. } => self.probe(|_| { let args = self.fresh_args_for_item(self.span, method.def_id); let fty = self.tcx.fn_sig(method.def_id).instantiate(self.tcx, args); - let fty = self.instantiate_binder_with_fresh_vars(self.span, infer::FnCall, fty); + let fty = self.instantiate_binder_with_fresh_vars( + self.span, + BoundRegionConversionTime::FnCall, + fty, + ); self.can_eq(self.param_env, fty.output(), expected) }), _ => false, @@ -1756,8 +1760,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { CandidateSource::Trait(candidate.item.container_id(self.tcx)) } TraitCandidate(trait_ref) => self.probe(|_| { - let trait_ref = - self.instantiate_binder_with_fresh_vars(self.span, infer::FnCall, trait_ref); + let trait_ref = self.instantiate_binder_with_fresh_vars( + self.span, + BoundRegionConversionTime::FnCall, + trait_ref, + ); let (xform_self_ty, _) = self.xform_self_ty(candidate.item, trait_ref.self_ty(), trait_ref.args); // Guide the trait selection to show impls that have methods whose type matches @@ -1873,7 +1880,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let trait_ref = self.instantiate_binder_with_fresh_vars( self.span, - infer::FnCall, + BoundRegionConversionTime::FnCall, poly_trait_ref, ); let trait_ref = ocx.normalize(cause, self.param_env, trait_ref); @@ -1936,7 +1943,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { ObjectCandidate(poly_trait_ref) | WhereClauseCandidate(poly_trait_ref) => { let trait_ref = self.instantiate_binder_with_fresh_vars( self.span, - infer::FnCall, + BoundRegionConversionTime::FnCall, poly_trait_ref, ); (xform_self_ty, xform_ret_ty) = diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index b35aef13c52..df1ee0e79c2 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -22,7 +22,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::lang_items::LangItem; use rustc_hir::{self as hir, ExprKind, HirId, Node, PathSegment, QPath}; -use rustc_infer::infer::{self, RegionVariableOrigin}; +use rustc_infer::infer::{BoundRegionConversionTime, RegionVariableOrigin}; use rustc_middle::bug; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, simplify_type}; use rustc_middle::ty::print::{ @@ -1951,7 +1951,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if def_kind == DefKind::AssocFn { let ty_args = self.infcx.fresh_args_for_item(span, similar_candidate.def_id); let fn_sig = tcx.fn_sig(similar_candidate.def_id).instantiate(tcx, ty_args); - let fn_sig = self.instantiate_binder_with_fresh_vars(span, infer::FnCall, fn_sig); + let fn_sig = self.instantiate_binder_with_fresh_vars( + span, + BoundRegionConversionTime::FnCall, + fn_sig, + ); if similar_candidate.is_method() { if let Some(args) = args && fn_sig.inputs()[1..].len() == args.len() @@ -2033,7 +2037,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.fn_sig(inherent_method.def_id).instantiate(self.tcx, args); let fn_sig = self.instantiate_binder_with_fresh_vars( item_name.span, - infer::FnCall, + BoundRegionConversionTime::FnCall, fn_sig, ); let name = inherent_method.name(); @@ -2348,9 +2352,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !arg.is_suggestable(self.tcx, true) { has_unsuggestable_args = true; match arg.kind() { - GenericArgKind::Lifetime(_) => self - .next_region_var(RegionVariableOrigin::MiscVariable(DUMMY_SP)) - .into(), + GenericArgKind::Lifetime(_) => { + self.next_region_var(RegionVariableOrigin::Misc(DUMMY_SP)).into() + } GenericArgKind::Type(_) => self.next_ty_var(DUMMY_SP).into(), GenericArgKind::Const(_) => self.next_const_var(DUMMY_SP).into(), } @@ -3051,7 +3055,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn note_unmet_impls_on_type( &self, err: &mut Diag<'_>, - errors: Vec<FulfillmentError<'tcx>>, + errors: &[FulfillmentError<'tcx>], suggest_derive: bool, ) { let preds: Vec<_> = errors diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index b9d24506986..87a7cd62ae5 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -322,7 +322,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lhs_expr.span, format!("cannot use `{}` on type `{}`", s, lhs_ty_str), ); - self.note_unmet_impls_on_type(&mut err, errors, false); + self.note_unmet_impls_on_type(&mut err, &errors, false); (err, None) } Op::BinOp(bin_op) => { @@ -382,7 +382,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_label(rhs_expr.span, rhs_ty_str); } let suggest_derive = self.can_eq(self.param_env, lhs_ty, rhs_ty); - self.note_unmet_impls_on_type(&mut err, errors, suggest_derive); + self.note_unmet_impls_on_type(&mut err, &errors, suggest_derive); (err, output_def_id) } }; @@ -582,22 +582,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // concatenation (e.g., "Hello " + "World!"). This means // we don't want the note in the else clause to be emitted } else if lhs_ty.has_non_region_param() { - // Look for a TraitPredicate in the Fulfillment errors, - // and use it to generate a suggestion. - // - // Note that lookup_op_method must be called again but - // with a specific rhs_ty instead of a placeholder so - // the resulting predicate generates a more specific - // suggestion for the user. - let errors = self - .lookup_op_method( - (lhs_expr, lhs_ty), - Some((rhs_expr, rhs_ty)), - lang_item_for_binop(self.tcx, op), - op.span(), - expected, - ) - .unwrap_err(); if !errors.is_empty() { for error in errors { if let Some(trait_pred) = @@ -946,7 +930,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Str | ty::Never | ty::Char | ty::Tuple(_) | ty::Array(_, _) => {} ty::Ref(_, lty, _) if *lty.kind() == ty::Str => {} _ => { - self.note_unmet_impls_on_type(&mut err, errors, true); + self.note_unmet_impls_on_type(&mut err, &errors, true); } } } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 432eeae8016..349e72090d3 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -16,7 +16,7 @@ use rustc_hir::{ PatExprKind, PatKind, expr_needs_parens, }; use rustc_hir_analysis::autoderef::report_autoderef_recursion_limit_error; -use rustc_infer::infer; +use rustc_infer::infer::RegionVariableOrigin; use rustc_middle::traits::PatternOriginExpr; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_middle::{bug, span_bug}; @@ -2777,7 +2777,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Create a reference type with a fresh region variable. fn new_ref_ty(&self, span: Span, mutbl: Mutability, ty: Ty<'tcx>) -> Ty<'tcx> { - let region = self.next_region_var(infer::PatternRegion(span)); + let region = self.next_region_var(RegionVariableOrigin::PatternRegion(span)); Ty::new_ref(self.tcx, region, ty, mutbl) } diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs index 5dffedc7099..79a2aa54ef8 100644 --- a/compiler/rustc_infer/src/infer/canonical/mod.rs +++ b/compiler/rustc_infer/src/infer/canonical/mod.rs @@ -128,10 +128,7 @@ impl<'tcx> InferCtxt<'tcx> { } CanonicalVarKind::Region(ui) => self - .next_region_var_in_universe( - RegionVariableOrigin::MiscVariable(span), - universe_map(ui), - ) + .next_region_var_in_universe(RegionVariableOrigin::Misc(span), universe_map(ui)) .into(), CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion { universe, bound }) => { diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index f7c702d321b..bb9c8850093 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -141,7 +141,7 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { } fn next_region_infer(&self) -> ty::Region<'tcx> { - self.next_region_var(RegionVariableOrigin::MiscVariable(DUMMY_SP)) + self.next_region_var(RegionVariableOrigin::Misc(DUMMY_SP)) } fn next_ty_infer(&self) -> Ty<'tcx> { diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs index cae674165f0..ddc0b116806 100644 --- a/compiler/rustc_infer/src/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -110,17 +110,16 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> { fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match r.kind() { - ty::ReBound(..) => { - // leave bound regions alone - r - } + // Leave bound regions alone, since they affect selection via the leak check. + ty::ReBound(..) => r, + // Leave error regions alone, since they affect selection b/c of incompleteness. + ty::ReError(_) => r, ty::ReEarlyParam(..) | ty::ReLateParam(_) | ty::ReVar(_) | ty::RePlaceholder(..) | ty::ReStatic - | ty::ReError(_) | ty::ReErased => self.cx().lifetimes.re_erased, } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index e9b58eb959b..cc3ad921489 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1,9 +1,6 @@ use std::cell::{Cell, RefCell}; use std::fmt; -pub use BoundRegionConversionTime::*; -pub use RegionVariableOrigin::*; -pub use SubregionOrigin::*; pub use at::DefineOpaqueTypes; use free_regions::RegionRelations; pub use freshen::TypeFreshener; @@ -35,7 +32,7 @@ use rustc_middle::ty::{ PseudoCanonicalInput, Term, TermKind, Ty, TyCtxt, TyVid, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, TypeVisitableExt, TypingEnv, TypingMode, fold_regions, }; -use rustc_span::{Span, Symbol}; +use rustc_span::{DUMMY_SP, Span, Symbol}; use snapshot::undo_log::InferCtxtUndoLogs; use tracing::{debug, instrument}; use type_variable::TypeVariableOrigin; @@ -403,7 +400,7 @@ pub enum RegionVariableOrigin { /// Region variables created for ill-categorized reasons. /// /// They mostly indicate places in need of refactoring. - MiscVariable(Span), + Misc(Span), /// Regions created by a `&P` or `[...]` pattern. PatternRegion(Span), @@ -467,21 +464,19 @@ pub struct FixupError { impl fmt::Display for FixupError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use TyOrConstInferVar::*; - match self.unresolved { - TyInt(_) => write!( + TyOrConstInferVar::TyInt(_) => write!( f, "cannot determine the type of this integer; \ add a suffix to specify the type explicitly" ), - TyFloat(_) => write!( + TyOrConstInferVar::TyFloat(_) => write!( f, "cannot determine the type of this number; \ add a suffix to specify the type explicitly" ), - Ty(_) => write!(f, "unconstrained type"), - Const(_) => write!(f, "unconstrained const value"), + TyOrConstInferVar::Ty(_) => write!(f, "unconstrained type"), + TyOrConstInferVar::Const(_) => write!(f, "unconstrained const value"), } } } @@ -865,7 +860,10 @@ impl<'tcx> InferCtxt<'tcx> { GenericParamDefKind::Lifetime => { // Create a region inference variable for the given // region parameter definition. - self.next_region_var(RegionParameterDefinition(span, param.name)).into() + self.next_region_var(RegionVariableOrigin::RegionParameterDefinition( + span, param.name, + )) + .into() } GenericParamDefKind::Type { .. } => { // Create a type inference variable for the given @@ -1046,6 +1044,13 @@ impl<'tcx> InferCtxt<'tcx> { } } + pub fn shallow_resolve_term(&self, term: ty::Term<'tcx>) -> ty::Term<'tcx> { + match term.kind() { + ty::TermKind::Ty(ty) => self.shallow_resolve(ty).into(), + ty::TermKind::Const(ct) => self.shallow_resolve_const(ct).into(), + } + } + pub fn root_var(&self, var: ty::TyVid) -> ty::TyVid { self.inner.borrow_mut().type_variables().root_var(var) } @@ -1172,7 +1177,7 @@ impl<'tcx> InferCtxt<'tcx> { let arg: ty::GenericArg<'_> = match bound_var_kind { ty::BoundVariableKind::Ty(_) => self.next_ty_var(span).into(), ty::BoundVariableKind::Region(br) => { - self.next_region_var(BoundRegion(span, br, lbrct)).into() + self.next_region_var(RegionVariableOrigin::BoundRegion(span, br, lbrct)).into() } ty::BoundVariableKind::Const => self.next_const_var(span).into(), }; @@ -1472,15 +1477,15 @@ impl<'tcx> TypeTrace<'tcx> { impl<'tcx> SubregionOrigin<'tcx> { pub fn span(&self) -> Span { match *self { - Subtype(ref a) => a.span(), - RelateObjectBound(a) => a, - RelateParamBound(a, ..) => a, - RelateRegionParamBound(a, _) => a, - Reborrow(a) => a, - ReferenceOutlivesReferent(_, a) => a, - CompareImplItemObligation { span, .. } => span, - AscribeUserTypeProvePredicate(span) => span, - CheckAssociatedTypeBounds { ref parent, .. } => parent.span(), + SubregionOrigin::Subtype(ref a) => a.span(), + SubregionOrigin::RelateObjectBound(a) => a, + SubregionOrigin::RelateParamBound(a, ..) => a, + SubregionOrigin::RelateRegionParamBound(a, _) => a, + SubregionOrigin::Reborrow(a) => a, + SubregionOrigin::ReferenceOutlivesReferent(_, a) => a, + SubregionOrigin::CompareImplItemObligation { span, .. } => span, + SubregionOrigin::AscribeUserTypeProvePredicate(span) => span, + SubregionOrigin::CheckAssociatedTypeBounds { ref parent, .. } => parent.span(), } } @@ -1528,15 +1533,15 @@ impl<'tcx> SubregionOrigin<'tcx> { impl RegionVariableOrigin { pub fn span(&self) -> Span { match *self { - MiscVariable(a) - | PatternRegion(a) - | BorrowRegion(a) - | Autoref(a) - | Coercion(a) - | RegionParameterDefinition(a, ..) - | BoundRegion(a, ..) - | UpvarRegion(_, a) => a, - Nll(..) => bug!("NLL variable used with `span`"), + RegionVariableOrigin::Misc(a) + | RegionVariableOrigin::PatternRegion(a) + | RegionVariableOrigin::BorrowRegion(a) + | RegionVariableOrigin::Autoref(a) + | RegionVariableOrigin::Coercion(a) + | RegionVariableOrigin::RegionParameterDefinition(a, ..) + | RegionVariableOrigin::BoundRegion(a, ..) + | RegionVariableOrigin::UpvarRegion(_, a) => a, + RegionVariableOrigin::Nll(..) => bug!("NLL variable used with `span`"), } } } @@ -1557,15 +1562,16 @@ impl<'tcx> InferCtxt<'tcx> { } } - /// Given a [`hir::HirId`] for a block, get the span of its last expression - /// or statement, peeling off any inner blocks. + /// Given a [`hir::HirId`] for a block (or an expr of a block), get the span + /// of its last expression or statement, peeling off any inner blocks. pub fn find_block_span_from_hir_id(&self, hir_id: hir::HirId) -> Span { match self.tcx.hir_node(hir_id) { - hir::Node::Block(blk) => self.find_block_span(blk), - // The parser was in a weird state if either of these happen, but - // it's better not to panic. + hir::Node::Block(blk) + | hir::Node::Expr(&hir::Expr { kind: hir::ExprKind::Block(blk, _), .. }) => { + self.find_block_span(blk) + } hir::Node::Expr(e) => e.span, - _ => rustc_span::DUMMY_SP, + _ => DUMMY_SP, } } } diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index 220d5e9bda2..220e025c3f7 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -262,9 +262,7 @@ impl<'tcx> InferCtxt<'tcx> { .type_of_opaque_hir_typeck(opaque_type_key.def_id) .instantiate(self.tcx, opaque_type_key.args); let actual = ty::fold_regions(tcx, actual, |re, _dbi| match re.kind() { - ty::ReErased => { - self.next_region_var(RegionVariableOrigin::MiscVariable(span)) - } + ty::ReErased => self.next_region_var(RegionVariableOrigin::Misc(span)), _ => re, }); actual diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index db937b3e83e..f272052aaa5 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -141,7 +141,7 @@ impl<'tcx> InferCtxt<'tcx> { debug!(?sup_type, ?sub_region, ?cause); let origin = SubregionOrigin::from_obligation_cause(cause, || { - infer::RelateParamBound( + SubregionOrigin::RelateParamBound( cause.span, sup_type, match cause.code().peel_derives() { diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index 40e2e654b2e..f4cb73685d5 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -14,7 +14,7 @@ use tracing::{debug, instrument}; use self::CombineMapType::*; use self::UndoLog::*; -use super::{MiscVariable, RegionVariableOrigin, Rollback, SubregionOrigin}; +use super::{RegionVariableOrigin, Rollback, SubregionOrigin}; use crate::infer::snapshot::undo_log::{InferCtxtUndoLogs, Snapshot}; use crate::infer::unify_key::{RegionVariableValue, RegionVidKey}; @@ -580,7 +580,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { let a_universe = self.universe(a); let b_universe = self.universe(b); let c_universe = cmp::max(a_universe, b_universe); - let c = self.new_region_var(c_universe, MiscVariable(origin.span())); + let c = self.new_region_var(c_universe, RegionVariableOrigin::Misc(origin.span())); self.combine_map(t).insert(vars, c); self.undo_log.push(AddCombination(t, vars)); let new_r = ty::Region::new_var(tcx, c); diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 0e17b100276..9e451f16a9d 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -603,10 +603,9 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> { } } - Ok(self.infcx.next_region_var_in_universe( - RegionVariableOrigin::MiscVariable(self.span), - self.for_universe, - )) + Ok(self + .infcx + .next_region_var_in_universe(RegionVariableOrigin::Misc(self.span), self.for_universe)) } #[instrument(level = "debug", skip(self, c2), ret)] diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index a95f24b5b95..13df23a39b9 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -5,6 +5,7 @@ use rustc_middle::ty::{ }; use super::{FixupError, FixupResult, InferCtxt}; +use crate::infer::TyOrConstInferVar; /////////////////////////////////////////////////////////////////////////// // OPPORTUNISTIC VAR RESOLVER @@ -144,13 +145,17 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for FullTypeResolver<'a, 'tcx> { if !t.has_infer() { Ok(t) // micro-optimize -- if there is nothing in this type that this fold affects... } else { - use super::TyOrConstInferVar::*; - let t = self.infcx.shallow_resolve(t); match *t.kind() { - ty::Infer(ty::TyVar(vid)) => Err(FixupError { unresolved: Ty(vid) }), - ty::Infer(ty::IntVar(vid)) => Err(FixupError { unresolved: TyInt(vid) }), - ty::Infer(ty::FloatVar(vid)) => Err(FixupError { unresolved: TyFloat(vid) }), + ty::Infer(ty::TyVar(vid)) => { + Err(FixupError { unresolved: TyOrConstInferVar::Ty(vid) }) + } + ty::Infer(ty::IntVar(vid)) => { + Err(FixupError { unresolved: TyOrConstInferVar::TyInt(vid) }) + } + ty::Infer(ty::FloatVar(vid)) => { + Err(FixupError { unresolved: TyOrConstInferVar::TyFloat(vid) }) + } ty::Infer(_) => { bug!("Unexpected type in full type resolver: {:?}", t); } diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index 18cee03ba2e..285e2912937 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -15,8 +15,8 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] +#![allow(rustc::direct_use_of_rustc_type_ir)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(not(bootstrap), allow(rustc::direct_use_of_rustc_type_ir))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs index 9e51a53ae95..9a66bd0574c 100644 --- a/compiler/rustc_infer/src/traits/engine.rs +++ b/compiler/rustc_infer/src/traits/engine.rs @@ -19,7 +19,8 @@ pub enum ScrubbedTraitError<'tcx> { TrueError, /// An ambiguity. This goal may hold if further inference is done. Ambiguity, - /// An old-solver-style cycle error, which will fatal. + /// An old-solver-style cycle error, which will fatal. This is not + /// returned by the new solver. Cycle(PredicateObligations<'tcx>), } diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index 6d5ad96e31c..79a4859f286 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -20,8 +20,6 @@ use rustc_middle::ty::{self, Ty, TyCtxt, Upcast}; use rustc_span::Span; use thin_vec::ThinVec; -pub use self::ImplSource::*; -pub use self::SelectionError::*; pub use self::engine::{FromSolverError, ScrubbedTraitError, TraitEngine}; pub(crate) use self::project::UndoLog; pub use self::project::{ diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index d62bf7f85e0..c46e879b976 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -18,7 +18,6 @@ use rustc_parse::parser::attr::AllowLeadingUnsafe; use rustc_query_impl::QueryCtxt; use rustc_query_system::query::print_query_stack; use rustc_session::config::{self, Cfg, CheckCfg, ExpectedValues, Input, OutFileName}; -use rustc_session::filesearch::sysroot_with_fallback; use rustc_session::parse::ParseSess; use rustc_session::{CompilerIO, EarlyDiagCtxt, Session, lint}; use rustc_span::source_map::{FileLoader, RealFileLoader, SourceMapInputs}; @@ -405,8 +404,11 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se crate::callbacks::setup_callbacks(); - let sysroot = config.opts.sysroot.clone(); - let target = config::build_target_config(&early_dcx, &config.opts.target_triple, &sysroot); + let target = config::build_target_config( + &early_dcx, + &config.opts.target_triple, + config.opts.sysroot.path(), + ); let file_loader = config.file_loader.unwrap_or_else(|| Box::new(RealFileLoader)); let path_mapping = config.opts.file_path_mapping(); let hash_kind = config.opts.unstable_opts.src_hash_algorithm(&target); @@ -426,7 +428,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se let codegen_backend = match config.make_codegen_backend { None => util::get_codegen_backend( &early_dcx, - &sysroot, + &config.opts.sysroot, config.opts.unstable_opts.codegen_backend.as_deref(), &target, ), @@ -440,7 +442,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se let temps_dir = config.opts.unstable_opts.temps_dir.as_deref().map(PathBuf::from); let bundle = match rustc_errors::fluent_bundle( - sysroot_with_fallback(&config.opts.sysroot), + &config.opts.sysroot.all_paths().collect::<Vec<_>>(), config.opts.unstable_opts.translate_lang.clone(), config.opts.unstable_opts.translate_additional_ftl.as_deref(), config.opts.unstable_opts.translate_directionality_markers, @@ -469,7 +471,6 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se locale_resources, config.lint_caps, target, - sysroot, util::rustc_version_str().unwrap_or("unknown"), config.ice_file, config.using_internal_features, diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 0b9facfc7af..3fe7c5e4286 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -298,6 +298,16 @@ fn configure_and_expand( fn print_macro_stats(ecx: &ExtCtxt<'_>) { use std::fmt::Write; + let crate_name = ecx.ecfg.crate_name.as_str(); + let crate_name = if crate_name == "build_script_build" { + // This is a build script. Get the package name from the environment. + let pkg_name = + std::env::var("CARGO_PKG_NAME").unwrap_or_else(|_| "<unknown crate>".to_string()); + format!("{pkg_name} build script") + } else { + crate_name.to_string() + }; + // No instability because we immediately sort the produced vector. #[allow(rustc::potential_query_instability)] let mut macro_stats: Vec<_> = ecx @@ -327,7 +337,7 @@ fn print_macro_stats(ecx: &ExtCtxt<'_>) { // non-interleaving, though. let mut s = String::new(); _ = writeln!(s, "{prefix} {}", "=".repeat(banner_w)); - _ = writeln!(s, "{prefix} MACRO EXPANSION STATS: {}", ecx.ecfg.crate_name); + _ = writeln!(s, "{prefix} MACRO EXPANSION STATS: {}", crate_name); _ = writeln!( s, "{prefix} {:<name_w$}{:>uses_w$}{:>lines_w$}{:>avg_lines_w$}{:>bytes_w$}{:>avg_bytes_w$}", @@ -341,23 +351,33 @@ fn print_macro_stats(ecx: &ExtCtxt<'_>) { } for (bytes, lines, uses, name, kind) in macro_stats { let mut name = ExpnKind::Macro(kind, *name).descr(); + let uses_with_underscores = thousands::usize_with_underscores(uses); let avg_lines = lines as f64 / uses as f64; let avg_bytes = bytes as f64 / uses as f64; - if name.len() >= name_w { - // If the name is long, print it on a line by itself, then - // set the name to empty and print things normally, to show the - // stats on the next line. + + // Ensure the "Macro Name" and "Uses" columns are as compact as possible. + let mut uses_w = uses_w; + if name.len() + uses_with_underscores.len() >= name_w + uses_w { + // The name would abut or overlap the uses value. Print the name + // on a line by itself, then set the name to empty and print things + // normally, to show the stats on the next line. _ = writeln!(s, "{prefix} {:<name_w$}", name); name = String::new(); - } + } else if name.len() >= name_w { + // The name won't abut or overlap with the uses value, but it does + // overlap with the empty part of the uses column. Shrink the width + // of the uses column to account for the excess name length. + uses_w = uses_with_underscores.len() + 1 + }; + _ = writeln!( s, "{prefix} {:<name_w$}{:>uses_w$}{:>lines_w$}{:>avg_lines_w$}{:>bytes_w$}{:>avg_bytes_w$}", name, - thousands::usize_with_underscores(uses), - thousands::isize_with_underscores(lines), + uses_with_underscores, + thousands::usize_with_underscores(lines), thousands::f64p1_with_underscores(avg_lines), - thousands::isize_with_underscores(bytes), + thousands::usize_with_underscores(bytes), thousands::f64p1_with_underscores(avg_bytes), ); } @@ -371,7 +391,7 @@ fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) { let mut lint_buffer = resolver.lint_buffer.steal(); if sess.opts.unstable_opts.input_stats { - input_stats::print_ast_stats(krate, "POST EXPANSION AST STATS", "ast-stats"); + input_stats::print_ast_stats(tcx, krate); } // Needs to go *after* expansion to be able to check the results of macro expansion. diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index a0012b04c4f..360b5629e9d 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -41,9 +41,11 @@ where let matches = optgroups().parse(args).unwrap(); let sessopts = build_session_options(&mut early_dcx, &matches); - let sysroot = sessopts.sysroot.clone(); - let target = - rustc_session::config::build_target_config(&early_dcx, &sessopts.target_triple, &sysroot); + let target = rustc_session::config::build_target_config( + &early_dcx, + &sessopts.target_triple, + sessopts.sysroot.path(), + ); let hash_kind = sessopts.unstable_opts.src_hash_algorithm(&target); let checksum_hash_kind = sessopts.unstable_opts.checksum_hash_algorithm(); let sm_inputs = Some(SourceMapInputs { @@ -72,7 +74,6 @@ where vec![], Default::default(), target, - sysroot, "", None, &USING_INTERNAL_FEATURES, diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 8a7d6117265..0ca4fcc66ca 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -11,7 +11,7 @@ use rustc_data_structures::sync; use rustc_metadata::{DylibError, load_symbol_from_dylib}; use rustc_middle::ty::CurrentGcx; use rustc_parse::validate_attr; -use rustc_session::config::{Cfg, OutFileName, OutputFilenames, OutputTypes, host_tuple}; +use rustc_session::config::{Cfg, OutFileName, OutputFilenames, OutputTypes, Sysroot, host_tuple}; use rustc_session::lint::{self, BuiltinLintDiag, LintBuffer}; use rustc_session::output::{CRATE_TYPES, categorize_crate_type}; use rustc_session::{EarlyDiagCtxt, Session, filesearch}; @@ -305,7 +305,7 @@ fn load_backend_from_dylib(early_dcx: &EarlyDiagCtxt, path: &Path) -> MakeBacken /// A name of `None` indicates that the default backend should be used. pub fn get_codegen_backend( early_dcx: &EarlyDiagCtxt, - sysroot: &Path, + sysroot: &Sysroot, backend_name: Option<&str>, target: &Target, ) -> Box<dyn CodegenBackend> { @@ -336,25 +336,24 @@ pub fn get_codegen_backend( // This is used for rustdoc, but it uses similar machinery to codegen backend // loading, so we leave the code here. It is potentially useful for other tools // that want to invoke the rustc binary while linking to rustc as well. -pub fn rustc_path<'a>() -> Option<&'a Path> { +pub fn rustc_path<'a>(sysroot: &Sysroot) -> Option<&'a Path> { static RUSTC_PATH: OnceLock<Option<PathBuf>> = OnceLock::new(); - const BIN_PATH: &str = env!("RUSTC_INSTALL_BINDIR"); - - RUSTC_PATH.get_or_init(|| get_rustc_path_inner(BIN_PATH)).as_deref() -} - -fn get_rustc_path_inner(bin_path: &str) -> Option<PathBuf> { - let candidate = filesearch::get_or_default_sysroot() - .join(bin_path) - .join(if cfg!(target_os = "windows") { "rustc.exe" } else { "rustc" }); - candidate.exists().then_some(candidate) + RUSTC_PATH + .get_or_init(|| { + let candidate = sysroot + .default + .join(env!("RUSTC_INSTALL_BINDIR")) + .join(if cfg!(target_os = "windows") { "rustc.exe" } else { "rustc" }); + candidate.exists().then_some(candidate) + }) + .as_deref() } #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable fn get_codegen_sysroot( early_dcx: &EarlyDiagCtxt, - sysroot: &Path, + sysroot: &Sysroot, backend_name: &str, ) -> MakeBackendFn { // For now we only allow this function to be called once as it'll dlopen a @@ -369,10 +368,9 @@ fn get_codegen_sysroot( ); let target = host_tuple(); - let sysroot_candidates = filesearch::sysroot_with_fallback(&sysroot); - let sysroot = sysroot_candidates - .iter() + let sysroot = sysroot + .all_paths() .map(|sysroot| { filesearch::make_target_lib_path(sysroot, target).with_file_name("codegen-backends") }) @@ -381,8 +379,8 @@ fn get_codegen_sysroot( f.exists() }) .unwrap_or_else(|| { - let candidates = sysroot_candidates - .iter() + let candidates = sysroot + .all_paths() .map(|p| p.display().to_string()) .collect::<Vec<_>>() .join("\n* "); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index ac405277c4e..172f3372483 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -977,9 +977,9 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { }; match it.kind { hir::ItemKind::Fn { generics, .. } => { - if let Some(attr_span) = attr::find_by_name(attrs, sym::export_name) - .map(|at| at.span()) - .or_else(|| find_attr!(attrs, AttributeKind::NoMangle(span) => *span)) + if let Some(attr_span) = + find_attr!(attrs, AttributeKind::ExportName {span, ..} => *span) + .or_else(|| find_attr!(attrs, AttributeKind::NoMangle(span) => *span)) { check_no_mangle_on_generic_fn(attr_span, None, generics, it.span); } @@ -1010,9 +1010,11 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { for it in *items { if let hir::AssocItemKind::Fn { .. } = it.kind { let attrs = cx.tcx.hir_attrs(it.id.hir_id()); - if let Some(attr_span) = attr::find_by_name(attrs, sym::export_name) - .map(|at| at.span()) - .or_else(|| find_attr!(attrs, AttributeKind::NoMangle(span) => *span)) + if let Some(attr_span) = + find_attr!(attrs, AttributeKind::ExportName {span, ..} => *span) + .or_else( + || find_attr!(attrs, AttributeKind::NoMangle(span) => *span), + ) { check_no_mangle_on_generic_fn( attr_span, @@ -1184,11 +1186,11 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller { if fn_kind.asyncness().is_async() && !cx.tcx.features().async_fn_track_caller() // Now, check if the function has the `#[track_caller]` attribute - && let Some(attr) = cx.tcx.get_attr(def_id, sym::track_caller) + && let Some(attr_span) = find_attr!(cx.tcx.get_all_attrs(def_id), AttributeKind::TrackCaller(span) => *span) { cx.emit_span_lint( UNGATED_ASYNC_FN_TRACK_CALLER, - attr.span(), + attr_span, BuiltinUngatedAsyncFnTrackCaller { label: span, session: &cx.tcx.sess }, ); } diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 297b8ef7e76..95663204ec3 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -524,6 +524,20 @@ pub trait LintContext { }); } + /// Emit a lint at `span` from a lazily-constructed lint struct (some type that implements + /// `LintDiagnostic`, typically generated by `#[derive(LintDiagnostic)]`). + fn emit_span_lint_lazy<S: Into<MultiSpan>, L: for<'a> LintDiagnostic<'a, ()>>( + &self, + lint: &'static Lint, + span: S, + decorator: impl FnOnce() -> L, + ) { + self.opt_span_lint(lint, Some(span), |lint| { + let decorator = decorator(); + decorator.decorate_lint(lint); + }); + } + /// Emit a lint at the appropriate level, with an associated span. /// /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs index d0668794198..d6c402d481f 100644 --- a/compiler/rustc_lint/src/foreign_modules.rs +++ b/compiler/rustc_lint/src/foreign_modules.rs @@ -1,4 +1,5 @@ use rustc_abi::FIRST_VARIANT; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_hir as hir; @@ -6,7 +7,7 @@ use rustc_hir::def::DefKind; use rustc_middle::query::Providers; use rustc_middle::ty::{self, AdtDef, Instance, Ty, TyCtxt}; use rustc_session::declare_lint; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{Span, Symbol}; use tracing::{debug, instrument}; use crate::lints::{BuiltinClashingExtern, BuiltinClashingExternSub}; @@ -182,7 +183,11 @@ fn name_of_extern_decl(tcx: TyCtxt<'_>, fi: hir::OwnerId) -> SymbolName { // information, we could have codegen_fn_attrs also give span information back for // where the attribute was defined. However, until this is found to be a // bottleneck, this does just fine. - (overridden_link_name, tcx.get_attr(fi, sym::link_name).unwrap().span()) + ( + overridden_link_name, + find_attr!(tcx.get_all_attrs(fi), AttributeKind::LinkName {span, ..} => *span) + .unwrap(), + ) }) { SymbolName::Link(overridden_link_name, overridden_link_name_span) diff --git a/compiler/rustc_lint/src/invalid_from_utf8.rs b/compiler/rustc_lint/src/invalid_from_utf8.rs index 11eb079ddc0..41b670c92c4 100644 --- a/compiler/rustc_lint/src/invalid_from_utf8.rs +++ b/compiler/rustc_lint/src/invalid_from_utf8.rs @@ -108,8 +108,8 @@ impl<'tcx> LateLintPass<'tcx> for InvalidFromUtf8 { } match init.kind { ExprKind::Lit(Spanned { node: lit, .. }) => { - if let LitKind::ByteStr(bytes, _) = &lit - && let Err(utf8_error) = std::str::from_utf8(bytes) + if let LitKind::ByteStr(byte_sym, _) = &lit + && let Err(utf8_error) = std::str::from_utf8(byte_sym.as_byte_str()) { lint(init.span, utf8_error); } diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index 852bb01c096..c681deea779 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -152,7 +152,7 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas hir_visit::walk_pat(self, p); } - fn visit_lit(&mut self, hir_id: HirId, lit: &'tcx hir::Lit, negated: bool) { + fn visit_lit(&mut self, hir_id: HirId, lit: hir::Lit, negated: bool) { lint_callback!(self, check_lit, hir_id, lit, negated); } diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index c52dbd892bf..c72f8571153 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -482,7 +482,8 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { let name = lint_name.as_str(); let suggestion = RenamedLintSuggestion::WithoutSpan { replace }; let requested_level = RequestedLevel { level, lint_name }; - let lint = RenamedLintFromCommandLine { name, suggestion, requested_level }; + let lint = + RenamedLintFromCommandLine { name, replace, suggestion, requested_level }; self.emit_lint(RENAMED_AND_REMOVED_LINTS, lint); } CheckLintNameResult::Removed(ref reason) => { @@ -824,7 +825,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { RenamedLintSuggestion::WithSpan { suggestion: sp, replace }; let name = tool_ident.map(|tool| format!("{tool}::{name}")).unwrap_or(name); - let lint = RenamedLint { name: name.as_str(), suggestion }; + let lint = RenamedLint { name: name.as_str(), replace, suggestion }; self.emit_span_lint(RENAMED_AND_REMOVED_LINTS, sp.into(), lint); } diff --git a/compiler/rustc_lint/src/lifetime_syntax.rs b/compiler/rustc_lint/src/lifetime_syntax.rs index 95b7b69bd5a..5465968e984 100644 --- a/compiler/rustc_lint/src/lifetime_syntax.rs +++ b/compiler/rustc_lint/src/lifetime_syntax.rs @@ -422,12 +422,12 @@ fn build_mismatch_suggestion( lifetime_name: &str, infos: &[&Info<'_>], ) -> lints::MismatchedLifetimeSyntaxesSuggestion { - let lifetime_name = lifetime_name.to_owned(); + let lifetime_name_sugg = lifetime_name.to_owned(); let suggestions = infos.iter().map(|info| info.suggestion(&lifetime_name)).collect(); lints::MismatchedLifetimeSyntaxesSuggestion::Explicit { - lifetime_name, + lifetime_name_sugg, suggestions, tool_only: false, } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index abdf8e3853b..5e05b58146e 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1089,6 +1089,7 @@ pub(crate) struct DeprecatedLintNameFromCommandLine<'a> { #[diag(lint_renamed_lint)] pub(crate) struct RenamedLint<'a> { pub name: &'a str, + pub replace: &'a str, #[subdiagnostic] pub suggestion: RenamedLintSuggestion<'a>, } @@ -1109,6 +1110,7 @@ pub(crate) enum RenamedLintSuggestion<'a> { #[diag(lint_renamed_lint)] pub(crate) struct RenamedLintFromCommandLine<'a> { pub name: &'a str, + pub replace: &'a str, #[subdiagnostic] pub suggestion: RenamedLintSuggestion<'a>, #[subdiagnostic] @@ -1353,6 +1355,8 @@ pub(crate) struct NonUpperCaseGlobal<'a> { pub name: &'a str, #[subdiagnostic] pub sub: NonUpperCaseGlobalSub, + #[subdiagnostic] + pub usages: Vec<NonUpperCaseGlobalSubTool>, } #[derive(Subdiagnostic)] @@ -1362,14 +1366,29 @@ pub(crate) enum NonUpperCaseGlobalSub { #[primary_span] span: Span, }, - #[suggestion(lint_suggestion, code = "{replace}", applicability = "maybe-incorrect")] + #[suggestion(lint_suggestion, code = "{replace}")] Suggestion { #[primary_span] span: Span, + #[applicability] + applicability: Applicability, replace: String, }, } +#[derive(Subdiagnostic)] +#[suggestion( + lint_suggestion, + code = "{replace}", + applicability = "machine-applicable", + style = "tool-only" +)] +pub(crate) struct NonUpperCaseGlobalSubTool { + #[primary_span] + pub(crate) span: Span, + pub(crate) replace: String, +} + // noop_method_call.rs #[derive(LintDiagnostic)] #[diag(lint_noop_method_call)] @@ -3227,7 +3246,7 @@ pub(crate) enum MismatchedLifetimeSyntaxesSuggestion { }, Explicit { - lifetime_name: String, + lifetime_name_sugg: String, suggestions: Vec<(Span, String)>, tool_only: bool, }, @@ -3261,7 +3280,7 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion { diag.multipart_suggestion_with_style( fluent::lint_mismatched_lifetime_syntaxes_suggestion_implicit, suggestions, - Applicability::MachineApplicable, + Applicability::MaybeIncorrect, style(tool_only), ); } @@ -3276,22 +3295,21 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion { diag.multipart_suggestion_with_style( fluent::lint_mismatched_lifetime_syntaxes_suggestion_mixed, suggestions, - Applicability::MachineApplicable, + Applicability::MaybeIncorrect, style(tool_only), ); } - Explicit { lifetime_name, suggestions, tool_only } => { - diag.arg("lifetime_name", lifetime_name); - + Explicit { lifetime_name_sugg, suggestions, tool_only } => { + diag.arg("lifetime_name_sugg", lifetime_name_sugg); let msg = diag.eagerly_translate( fluent::lint_mismatched_lifetime_syntaxes_suggestion_explicit, ); - + diag.remove_arg("lifetime_name_sugg"); diag.multipart_suggestion_with_style( msg, suggestions, - Applicability::MachineApplicable, + Applicability::MaybeIncorrect, style(tool_only), ); } diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index f39e1506390..97e627f2eb2 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -1,9 +1,12 @@ use rustc_abi::ExternAbi; use rustc_attr_data_structures::{AttributeKind, ReprAttr, find_attr}; use rustc_attr_parsing::AttributeParser; +use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::intravisit::FnKind; +use rustc_hir::def_id::DefId; +use rustc_hir::intravisit::{FnKind, Visitor}; use rustc_hir::{AttrArgs, AttrItem, Attribute, GenericParamKind, PatExprKind, PatKind}; +use rustc_middle::hir::nested_filter::All; use rustc_middle::ty; use rustc_session::config::CrateType; use rustc_session::{declare_lint, declare_lint_pass}; @@ -13,7 +16,7 @@ use {rustc_ast as ast, rustc_hir as hir}; use crate::lints::{ NonCamelCaseType, NonCamelCaseTypeSub, NonSnakeCaseDiag, NonSnakeCaseDiagSub, - NonUpperCaseGlobal, NonUpperCaseGlobalSub, + NonUpperCaseGlobal, NonUpperCaseGlobalSub, NonUpperCaseGlobalSubTool, }; use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; @@ -493,22 +496,82 @@ declare_lint! { declare_lint_pass!(NonUpperCaseGlobals => [NON_UPPER_CASE_GLOBALS]); impl NonUpperCaseGlobals { - fn check_upper_case(cx: &LateContext<'_>, sort: &str, ident: &Ident) { + fn check_upper_case(cx: &LateContext<'_>, sort: &str, did: Option<LocalDefId>, ident: &Ident) { let name = ident.name.as_str(); if name.chars().any(|c| c.is_lowercase()) { let uc = NonSnakeCase::to_snake_case(name).to_uppercase(); + + // If the item is exported, suggesting changing it's name would be breaking-change + // and could break users without a "nice" applicable fix, so let's avoid it. + let can_change_usages = if let Some(did) = did { + !cx.tcx.effective_visibilities(()).is_exported(did) + } else { + false + }; + // We cannot provide meaningful suggestions // if the characters are in the category of "Lowercase Letter". let sub = if *name != uc { - NonUpperCaseGlobalSub::Suggestion { span: ident.span, replace: uc } + NonUpperCaseGlobalSub::Suggestion { + span: ident.span, + replace: uc.clone(), + applicability: if can_change_usages { + Applicability::MachineApplicable + } else { + Applicability::MaybeIncorrect + }, + } } else { NonUpperCaseGlobalSub::Label { span: ident.span } }; - cx.emit_span_lint( - NON_UPPER_CASE_GLOBALS, - ident.span, - NonUpperCaseGlobal { sort, name, sub }, - ); + + struct UsageCollector<'a, 'tcx> { + cx: &'tcx LateContext<'a>, + did: DefId, + collected: Vec<Span>, + } + + impl<'v, 'tcx> Visitor<'v> for UsageCollector<'v, 'tcx> { + type NestedFilter = All; + + fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { + self.cx.tcx + } + + fn visit_path( + &mut self, + path: &rustc_hir::Path<'v>, + _id: rustc_hir::HirId, + ) -> Self::Result { + if let Some(final_seg) = path.segments.last() + && final_seg.res.opt_def_id() == Some(self.did) + { + self.collected.push(final_seg.ident.span); + } + } + } + + cx.emit_span_lint_lazy(NON_UPPER_CASE_GLOBALS, ident.span, || { + // Compute usages lazily as it can expansive and useless when the lint is allowed. + // cf. https://github.com/rust-lang/rust/pull/142645#issuecomment-2993024625 + let usages = if can_change_usages + && *name != uc + && let Some(did) = did + { + let mut usage_collector = + UsageCollector { cx, did: did.to_def_id(), collected: Vec::new() }; + cx.tcx.hir_walk_toplevel_module(&mut usage_collector); + usage_collector + .collected + .into_iter() + .map(|span| NonUpperCaseGlobalSubTool { span, replace: uc.clone() }) + .collect() + } else { + vec![] + }; + + NonUpperCaseGlobal { sort, name, sub, usages } + }); } } } @@ -520,10 +583,20 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals { hir::ItemKind::Static(_, ident, ..) if !find_attr!(attrs, AttributeKind::NoMangle(..)) => { - NonUpperCaseGlobals::check_upper_case(cx, "static variable", &ident); + NonUpperCaseGlobals::check_upper_case( + cx, + "static variable", + Some(it.owner_id.def_id), + &ident, + ); } hir::ItemKind::Const(ident, ..) => { - NonUpperCaseGlobals::check_upper_case(cx, "constant", &ident); + NonUpperCaseGlobals::check_upper_case( + cx, + "constant", + Some(it.owner_id.def_id), + &ident, + ); } _ => {} } @@ -531,7 +604,7 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals { fn check_trait_item(&mut self, cx: &LateContext<'_>, ti: &hir::TraitItem<'_>) { if let hir::TraitItemKind::Const(..) = ti.kind { - NonUpperCaseGlobals::check_upper_case(cx, "associated constant", &ti.ident); + NonUpperCaseGlobals::check_upper_case(cx, "associated constant", None, &ti.ident); } } @@ -539,7 +612,7 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals { if let hir::ImplItemKind::Const(..) = ii.kind && !assoc_item_in_trait_impl(cx, ii) { - NonUpperCaseGlobals::check_upper_case(cx, "associated constant", &ii.ident); + NonUpperCaseGlobals::check_upper_case(cx, "associated constant", None, &ii.ident); } } @@ -555,6 +628,7 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals { NonUpperCaseGlobals::check_upper_case( cx, "constant in pattern", + None, &segment.ident, ); } @@ -564,7 +638,12 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals { fn check_generic_param(&mut self, cx: &LateContext<'_>, param: &hir::GenericParam<'_>) { if let GenericParamKind::Const { .. } = param.kind { - NonUpperCaseGlobals::check_upper_case(cx, "const parameter", ¶m.name.ident()); + NonUpperCaseGlobals::check_upper_case( + cx, + "const parameter", + Some(param.def_id), + ¶m.name.ident(), + ); } } } diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs index 409a23d1da0..affea1b80ec 100644 --- a/compiler/rustc_lint/src/passes.rs +++ b/compiler/rustc_lint/src/passes.rs @@ -23,7 +23,7 @@ macro_rules! late_lint_methods { fn check_stmt(a: &'tcx rustc_hir::Stmt<'tcx>); fn check_arm(a: &'tcx rustc_hir::Arm<'tcx>); fn check_pat(a: &'tcx rustc_hir::Pat<'tcx>); - fn check_lit(hir_id: rustc_hir::HirId, a: &'tcx rustc_hir::Lit, negated: bool); + fn check_lit(hir_id: rustc_hir::HirId, a: rustc_hir::Lit, negated: bool); fn check_expr(a: &'tcx rustc_hir::Expr<'tcx>); fn check_expr_post(a: &'tcx rustc_hir::Expr<'tcx>); fn check_ty(a: &'tcx rustc_hir::Ty<'tcx, rustc_hir::AmbigArg>); diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index aaba0c14b1c..ea5485d8e5d 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -547,18 +547,12 @@ fn lint_fn_pointer<'tcx>( } impl<'tcx> LateLintPass<'tcx> for TypeLimits { - fn check_lit( - &mut self, - cx: &LateContext<'tcx>, - hir_id: HirId, - lit: &'tcx hir::Lit, - negated: bool, - ) { + fn check_lit(&mut self, cx: &LateContext<'tcx>, hir_id: HirId, lit: hir::Lit, negated: bool) { if negated { self.negated_expr_id = Some(hir_id); self.negated_expr_span = Some(lit.span); } - lint_literal(cx, self, hir_id, lit.span, lit, negated); + lint_literal(cx, self, hir_id, lit.span, &lit, negated); } fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx hir::Expr<'tcx>) { diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index a868c887493..a206f71e153 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -183,6 +183,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { let mut op_warned = false; if let Some(must_use_op) = must_use_op { + let span = expr.span.find_oldest_ancestor_in_same_ctxt(); cx.emit_span_lint( UNUSED_MUST_USE, expr.span, @@ -191,11 +192,11 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { label: expr.span, suggestion: if expr_is_from_block { UnusedOpSuggestion::BlockTailExpr { - before_span: expr.span.shrink_to_lo(), - after_span: expr.span.shrink_to_hi(), + before_span: span.shrink_to_lo(), + after_span: span.shrink_to_hi(), } } else { - UnusedOpSuggestion::NormalExpr { span: expr.span.shrink_to_lo() } + UnusedOpSuggestion::NormalExpr { span: span.shrink_to_lo() } }, }, ); @@ -508,9 +509,10 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { ); } MustUsePath::Def(span, def_id, reason) => { + let span = span.find_oldest_ancestor_in_same_ctxt(); cx.emit_span_lint( UNUSED_MUST_USE, - *span, + span, UnusedDef { pre: descr_pre, post: descr_post, diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 5fa00fcc4a0..10ac14a2fbf 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -131,8 +131,8 @@ declare_lint_pass! { UNUSED_IMPORTS, UNUSED_LABELS, UNUSED_LIFETIMES, - UNUSED_MACRO_RULES, UNUSED_MACROS, + UNUSED_MACRO_RULES, UNUSED_MUT, UNUSED_QUALIFICATIONS, UNUSED_UNSAFE, diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index bc9516b2e0c..dcd0116d804 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -600,7 +600,12 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { calls.extend(call); } - + let store_args = quote! { + #diag.store_args(); + }; + let restore_args = quote! { + #diag.restore_args(); + }; let plain_args: TokenStream = self .variant .bindings() @@ -610,12 +615,21 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { .collect(); let formatting_init = &self.formatting_init; + + // For #[derive(Subdiagnostic)] + // + // - Store args of the main diagnostic for later restore. + // - Add args of subdiagnostic. + // - Generate the calls, such as note, label, etc. + // - Restore the arguments for allowing main and subdiagnostic share the same fields. Ok(quote! { #init #formatting_init #attr_args + #store_args #plain_args #calls + #restore_args }) } } diff --git a/compiler/rustc_macros/src/symbols.rs b/compiler/rustc_macros/src/symbols.rs index 2b00b7dd27a..78a4d47ca33 100644 --- a/compiler/rustc_macros/src/symbols.rs +++ b/compiler/rustc_macros/src/symbols.rs @@ -190,17 +190,6 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) { let mut symbols_stream = quote! {}; let mut prefill_stream = quote! {}; let mut entries = Entries::with_capacity(input.keywords.len() + input.symbols.len() + 10); - let mut prev_key: Option<(Span, String)> = None; - - let mut check_order = |span: Span, s: &str, errors: &mut Errors| { - if let Some((prev_span, ref prev_str)) = prev_key { - if s < prev_str { - errors.error(span, format!("Symbol `{s}` must precede `{prev_str}`")); - errors.error(prev_span, format!("location of previous symbol `{prev_str}`")); - } - } - prev_key = Some((span, s.to_string())); - }; // Generate the listed keywords. for keyword in input.keywords.iter() { @@ -219,7 +208,6 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) { // Generate the listed symbols. for symbol in input.symbols.iter() { let name = &symbol.name; - check_order(symbol.name.span(), &name.to_string(), &mut errors); let value = match &symbol.value { Value::SameAsName => name.to_string(), diff --git a/compiler/rustc_macros/src/symbols/tests.rs b/compiler/rustc_macros/src/symbols/tests.rs index 9c53453df5b..f0a7a2106be 100644 --- a/compiler/rustc_macros/src/symbols/tests.rs +++ b/compiler/rustc_macros/src/symbols/tests.rs @@ -84,18 +84,3 @@ fn check_dup_symbol_and_keyword() { }; test_symbols_macro(input, &["Symbol `splat` is duplicated", "location of previous definition"]); } - -#[test] -fn check_symbol_order() { - let input = quote! { - Keywords {} - Symbols { - zebra, - aardvark, - } - }; - test_symbols_macro( - input, - &["Symbol `aardvark` must precede `zebra`", "location of previous symbol `zebra`"], - ); -} diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index de19c10bc57..2c882b84c58 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -1,7 +1,6 @@ //! Validates all used crates and extern libraries and loads their metadata use std::error::Error; -use std::ops::Fn; use std::path::Path; use std::str::FromStr; use std::time::Duration; @@ -276,12 +275,6 @@ impl CStore { .filter_map(|(cnum, data)| data.as_deref().map(|data| (cnum, data))) } - fn iter_crate_data_mut(&mut self) -> impl Iterator<Item = (CrateNum, &mut CrateMetadata)> { - self.metas - .iter_enumerated_mut() - .filter_map(|(cnum, data)| data.as_deref_mut().map(|data| (cnum, data))) - } - fn push_dependencies_in_postorder(&self, deps: &mut IndexSet<CrateNum>, cnum: CrateNum) { if !deps.contains(&cnum) { let data = self.get_crate_data(cnum); @@ -307,13 +300,6 @@ impl CStore { deps } - fn crate_dependencies_in_reverse_postorder( - &self, - cnum: CrateNum, - ) -> impl Iterator<Item = CrateNum> { - self.crate_dependencies_in_postorder(cnum).into_iter().rev() - } - pub(crate) fn injected_panic_runtime(&self) -> Option<CrateNum> { self.injected_panic_runtime } @@ -966,47 +952,27 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { // If we need a panic runtime, we try to find an existing one here. At // the same time we perform some general validation of the DAG we've got // going such as ensuring everything has a compatible panic strategy. - // - // The logic for finding the panic runtime here is pretty much the same - // as the allocator case with the only addition that the panic strategy - // compilation mode also comes into play. - let desired_strategy = self.sess.panic_strategy(); - let mut runtime_found = false; let mut needs_panic_runtime = attr::contains_name(&krate.attrs, sym::needs_panic_runtime); - - let mut panic_runtimes = Vec::new(); - for (cnum, data) in self.cstore.iter_crate_data() { - needs_panic_runtime = needs_panic_runtime || data.needs_panic_runtime(); - if data.is_panic_runtime() { - // Inject a dependency from all #![needs_panic_runtime] to this - // #![panic_runtime] crate. - panic_runtimes.push(cnum); - runtime_found = runtime_found || data.dep_kind() == CrateDepKind::Explicit; - } - } - for cnum in panic_runtimes { - self.inject_dependency_if(cnum, "a panic runtime", &|data| data.needs_panic_runtime()); + for (_cnum, data) in self.cstore.iter_crate_data() { + needs_panic_runtime |= data.needs_panic_runtime(); } - // If an explicitly linked and matching panic runtime was found, or if - // we just don't need one at all, then we're done here and there's - // nothing else to do. - if !needs_panic_runtime || runtime_found { + // If we just don't need a panic runtime at all, then we're done here + // and there's nothing else to do. + if !needs_panic_runtime { return; } - // By this point we know that we (a) need a panic runtime and (b) no - // panic runtime was explicitly linked. Here we just load an appropriate - // default runtime for our panic strategy and then inject the - // dependencies. + // By this point we know that we need a panic runtime. Here we just load + // an appropriate default runtime for our panic strategy. // // We may resolve to an already loaded crate (as the crate may not have - // been explicitly linked prior to this) and we may re-inject - // dependencies again, but both of those situations are fine. + // been explicitly linked prior to this), but this is fine. // // Also note that we have yet to perform validation of the crate graph // in terms of everyone has a compatible panic runtime format, that's // performed later as part of the `dependency_format` module. + let desired_strategy = self.sess.panic_strategy(); let name = match desired_strategy { PanicStrategy::Unwind => sym::panic_unwind, PanicStrategy::Abort => sym::panic_abort, @@ -1031,7 +997,6 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { } self.cstore.injected_panic_runtime = Some(cnum); - self.inject_dependency_if(cnum, "a panic runtime", &|data| data.needs_panic_runtime()); } fn inject_profiler_runtime(&mut self) { @@ -1212,45 +1177,6 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { } } - fn inject_dependency_if( - &mut self, - krate: CrateNum, - what: &str, - needs_dep: &dyn Fn(&CrateMetadata) -> bool, - ) { - // Don't perform this validation if the session has errors, as one of - // those errors may indicate a circular dependency which could cause - // this to stack overflow. - if self.dcx().has_errors().is_some() { - return; - } - - // Before we inject any dependencies, make sure we don't inject a - // circular dependency by validating that this crate doesn't - // transitively depend on any crates satisfying `needs_dep`. - for dep in self.cstore.crate_dependencies_in_reverse_postorder(krate) { - let data = self.cstore.get_crate_data(dep); - if needs_dep(&data) { - self.dcx().emit_err(errors::NoTransitiveNeedsDep { - crate_name: self.cstore.get_crate_data(krate).name(), - needs_crate_name: what, - deps_crate_name: data.name(), - }); - } - } - - // All crates satisfying `needs_dep` do not explicitly depend on the - // crate provided for this compile, but in order for this compilation to - // be successfully linked we need to inject a dependency (to order the - // crates on the command line correctly). - for (cnum, data) in self.cstore.iter_crate_data_mut() { - if needs_dep(data) { - info!("injecting a dep from {} to {}", cnum, krate); - data.add_dependency(krate); - } - } - } - fn report_unused_deps(&mut self, krate: &ast::Crate) { // Make a point span rather than covering the whole file let span = krate.spans.inner_span.shrink_to_lo(); diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs index fcae33c73c9..fb9c2e23b71 100644 --- a/compiler/rustc_metadata/src/dependency_format.rs +++ b/compiler/rustc_metadata/src/dependency_format.rs @@ -314,7 +314,7 @@ fn add_library( crate_name: tcx.crate_name(cnum), non_static_deps: unavailable_as_static .drain(..) - .map(|cnum| NonStaticCrateDep { crate_name: tcx.crate_name(cnum) }) + .map(|cnum| NonStaticCrateDep { crate_name_: tcx.crate_name(cnum) }) .collect(), rustc_driver_help: linking_to_rustc_driver.then_some(RustcDriverHelp), }); @@ -370,15 +370,15 @@ fn attempt_static(tcx: TyCtxt<'_>, unavailable: &mut Vec<CrateNum>) -> Option<De Some(ret) } -// Given a list of how to link upstream dependencies so far, ensure that an -// injected dependency is activated. This will not do anything if one was -// transitively included already (e.g., via a dylib or explicitly so). -// -// If an injected dependency was not found then we're guaranteed the -// metadata::creader module has injected that dependency (not listed as -// a required dependency) in one of the session's field. If this field is not -// set then this compilation doesn't actually need the dependency and we can -// also skip this step entirely. +/// Given a list of how to link upstream dependencies so far, ensure that an +/// injected dependency is activated. This will not do anything if one was +/// transitively included already (e.g., via a dylib or explicitly so). +/// +/// If an injected dependency was not found then we're guaranteed the +/// metadata::creader module has injected that dependency (not listed as +/// a required dependency) in one of the session's field. If this field is not +/// set then this compilation doesn't actually need the dependency and we can +/// also skip this step entirely. fn activate_injected_dep( injected: Option<CrateNum>, list: &mut DependencyList, diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index 71da4290174..4a3b43167cf 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -45,7 +45,8 @@ pub struct CrateDepMultiple { #[derive(Subdiagnostic)] #[note(metadata_crate_dep_not_static)] pub struct NonStaticCrateDep { - pub crate_name: Symbol, + /// It's different from `crate_name` in main Diagnostic. + pub crate_name_: Symbol, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 23ffb1e487f..3e50689b5ac 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -7,7 +7,6 @@ #![feature(file_buffered)] #![feature(gen_blocks)] #![feature(if_let_guard)] -#![feature(iter_from_coroutine)] #![feature(macro_metavar_expr)] #![feature(min_specialization)] #![feature(never_type)] diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 259bcb1b96d..941f16bd960 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -321,7 +321,7 @@ impl<'a> CrateLocator<'a> { CrateLocator { only_needs_metadata, - sysroot: &sess.sysroot, + sysroot: sess.opts.sysroot.path(), metadata_loader, cfg_version: sess.cfg_version, crate_name, diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index d886f25247f..e6aedc61338 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -32,7 +32,9 @@ use rustc_session::Session; use rustc_session::config::TargetModifier; use rustc_session::cstore::{CrateSource, ExternCrate}; use rustc_span::hygiene::HygieneDecodeContext; -use rustc_span::{BytePos, DUMMY_SP, Pos, SpanData, SpanDecoder, SyntaxContext, kw}; +use rustc_span::{ + BytePos, ByteSymbol, DUMMY_SP, Pos, SpanData, SpanDecoder, Symbol, SyntaxContext, kw, +}; use tracing::debug; use crate::creader::CStore; @@ -384,6 +386,28 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> { fn read_raw_bytes(&mut self, len: usize) -> &[u8] { self.opaque.read_raw_bytes(len) } + + fn decode_symbol_or_byte_symbol<S>( + &mut self, + new_from_index: impl Fn(u32) -> S, + read_and_intern_str_or_byte_str_this: impl Fn(&mut Self) -> S, + read_and_intern_str_or_byte_str_opaque: impl Fn(&mut MemDecoder<'a>) -> S, + ) -> S { + let tag = self.read_u8(); + + match tag { + SYMBOL_STR => read_and_intern_str_or_byte_str_this(self), + SYMBOL_OFFSET => { + // read str offset + let pos = self.read_usize(); + + // move to str offset and read + self.opaque.with_position(pos, |d| read_and_intern_str_or_byte_str_opaque(d)) + } + SYMBOL_PREDEFINED => new_from_index(self.read_u32()), + _ => unreachable!(), + } + } } impl<'a, 'tcx> TyDecoder<'tcx> for DecodeContext<'a, 'tcx> { @@ -545,29 +569,19 @@ impl<'a, 'tcx> SpanDecoder for DecodeContext<'a, 'tcx> { } fn decode_symbol(&mut self) -> Symbol { - let tag = self.read_u8(); - - match tag { - SYMBOL_STR => { - let s = self.read_str(); - Symbol::intern(s) - } - SYMBOL_OFFSET => { - // read str offset - let pos = self.read_usize(); + self.decode_symbol_or_byte_symbol( + Symbol::new, + |this| Symbol::intern(this.read_str()), + |opaque| Symbol::intern(opaque.read_str()), + ) + } - // move to str offset and read - self.opaque.with_position(pos, |d| { - let s = d.read_str(); - Symbol::intern(s) - }) - } - SYMBOL_PREDEFINED => { - let symbol_index = self.read_u32(); - Symbol::new(symbol_index) - } - _ => unreachable!(), - } + fn decode_byte_symbol(&mut self) -> ByteSymbol { + self.decode_symbol_or_byte_symbol( + ByteSymbol::new, + |this| ByteSymbol::intern(this.read_byte_str()), + |opaque| ByteSymbol::intern(opaque.read_byte_str()), + ) } } @@ -1496,11 +1510,18 @@ impl<'a> CrateMetadataRef<'a> { .map(move |v| (self.local_def_id(v.0), v.1)) } - fn exported_symbols<'tcx>( + fn exported_non_generic_symbols<'tcx>( self, tcx: TyCtxt<'tcx>, ) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] { - tcx.arena.alloc_from_iter(self.root.exported_symbols.decode((self, tcx))) + tcx.arena.alloc_from_iter(self.root.exported_non_generic_symbols.decode((self, tcx))) + } + + fn exported_generic_symbols<'tcx>( + self, + tcx: TyCtxt<'tcx>, + ) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] { + tcx.arena.alloc_from_iter(self.root.exported_generic_symbols.decode((self, tcx))) } fn get_macro(self, id: DefIndex, sess: &Session) -> ast::MacroDef { @@ -1912,10 +1933,6 @@ impl CrateMetadata { self.dependencies.iter().copied() } - pub(crate) fn add_dependency(&mut self, cnum: CrateNum) { - self.dependencies.push(cnum); - } - pub(crate) fn target_modifiers(&self) -> TargetModifiers { self.root.decode_target_modifiers(&self.blob).collect() } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 375928c2245..6943d4198df 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -358,7 +358,7 @@ provide! { tcx, def_id, other, cdata, specialization_enabled_in => { cdata.root.specialization_enabled_in } reachable_non_generics => { let reachable_non_generics = tcx - .exported_symbols(cdata.cnum) + .exported_non_generic_symbols(cdata.cnum) .iter() .filter_map(|&(exported_symbol, export_info)| { if let ExportedSymbol::NonGeneric(def_id) = exported_symbol { @@ -408,15 +408,8 @@ provide! { tcx, def_id, other, cdata, exportable_items => { tcx.arena.alloc_from_iter(cdata.get_exportable_items()) } stable_order_of_exportable_impls => { tcx.arena.alloc(cdata.get_stable_order_of_exportable_impls().collect()) } - exported_symbols => { - let syms = cdata.exported_symbols(tcx); - - // FIXME rust-lang/rust#64319, rust-lang/rust#64872: We want - // to block export of generics from dylibs, but we must fix - // rust-lang/rust#65890 before we can do that robustly. - - syms - } + exported_non_generic_symbols => { cdata.exported_non_generic_symbols(tcx) } + exported_generic_symbols => { cdata.exported_generic_symbols(tcx) } crate_extern_paths => { cdata.source().paths().cloned().collect() } expn_that_defined => { cdata.get_expn_that_defined(def_id.index, tcx.sess) } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 00bd32eb0eb..90bc427a19a 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -5,7 +5,7 @@ use std::io::{Read, Seek, Write}; use std::path::{Path, PathBuf}; use std::sync::Arc; -use rustc_ast::attr::AttributeExt; +use rustc_attr_data_structures::EncodeCrossCrate; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::memmap::{Mmap, MmapMut}; use rustc_data_structures::sync::{join, par_for_each_in}; @@ -29,8 +29,8 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder, opaque}; use rustc_session::config::{CrateType, OptLevel, TargetModifier}; use rustc_span::hygiene::HygieneEncodeContext; use rustc_span::{ - ExternalSource, FileName, SourceFile, SpanData, SpanEncoder, StableSourceFileId, SyntaxContext, - sym, + ByteSymbol, ExternalSource, FileName, SourceFile, SpanData, SpanEncoder, StableSourceFileId, + Symbol, SyntaxContext, sym, }; use tracing::{debug, instrument, trace}; @@ -63,7 +63,8 @@ pub(super) struct EncodeContext<'a, 'tcx> { required_source_files: Option<FxIndexSet<usize>>, is_proc_macro: bool, hygiene_ctxt: &'a HygieneEncodeContext, - symbol_table: FxHashMap<Symbol, usize>, + // Used for both `Symbol`s and `ByteSymbol`s. + symbol_index_table: FxHashMap<u32, usize>, } /// If the current crate is a proc-macro, returns early with `LazyArray::default()`. @@ -200,27 +201,14 @@ impl<'a, 'tcx> SpanEncoder for EncodeContext<'a, 'tcx> { } } - fn encode_symbol(&mut self, symbol: Symbol) { - // if symbol predefined, emit tag and symbol index - if symbol.is_predefined() { - self.opaque.emit_u8(SYMBOL_PREDEFINED); - self.opaque.emit_u32(symbol.as_u32()); - } else { - // otherwise write it as string or as offset to it - match self.symbol_table.entry(symbol) { - Entry::Vacant(o) => { - self.opaque.emit_u8(SYMBOL_STR); - let pos = self.opaque.position(); - o.insert(pos); - self.emit_str(symbol.as_str()); - } - Entry::Occupied(o) => { - let x = *o.get(); - self.emit_u8(SYMBOL_OFFSET); - self.emit_usize(x); - } - } - } + fn encode_symbol(&mut self, sym: Symbol) { + self.encode_symbol_or_byte_symbol(sym.as_u32(), |this| this.emit_str(sym.as_str())); + } + + fn encode_byte_symbol(&mut self, byte_sym: ByteSymbol) { + self.encode_symbol_or_byte_symbol(byte_sym.as_u32(), |this| { + this.emit_byte_str(byte_sym.as_byte_str()) + }); } } @@ -492,6 +480,33 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { LazyArray::from_position_and_num_elems(pos, len) } + fn encode_symbol_or_byte_symbol( + &mut self, + index: u32, + emit_str_or_byte_str: impl Fn(&mut Self), + ) { + // if symbol/byte symbol is predefined, emit tag and symbol index + if Symbol::is_predefined(index) { + self.opaque.emit_u8(SYMBOL_PREDEFINED); + self.opaque.emit_u32(index); + } else { + // otherwise write it as string or as offset to it + match self.symbol_index_table.entry(index) { + Entry::Vacant(o) => { + self.opaque.emit_u8(SYMBOL_STR); + let pos = self.opaque.position(); + o.insert(pos); + emit_str_or_byte_str(self); + } + Entry::Occupied(o) => { + let x = *o.get(); + self.emit_u8(SYMBOL_OFFSET); + self.emit_usize(x); + } + } + } + } + fn encode_def_path_table(&mut self) { let table = self.tcx.def_path_table(); if self.is_proc_macro { @@ -677,9 +692,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { stat!("exportable-items", || self.encode_stable_order_of_exportable_impls()); // Encode exported symbols info. This is prefetched in `encode_metadata`. - let exported_symbols = stat!("exported-symbols", || { - self.encode_exported_symbols(tcx.exported_symbols(LOCAL_CRATE)) - }); + let (exported_non_generic_symbols, exported_generic_symbols) = + stat!("exported-symbols", || { + ( + self.encode_exported_symbols(tcx.exported_non_generic_symbols(LOCAL_CRATE)), + self.encode_exported_symbols(tcx.exported_generic_symbols(LOCAL_CRATE)), + ) + }); // Encode the hygiene data. // IMPORTANT: this *must* be the last thing that we encode (other than `SourceMap`). The @@ -745,7 +764,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { incoherent_impls, exportable_items, stable_order_of_exportable_impls, - exported_symbols, + exported_non_generic_symbols, + exported_generic_symbols, interpret_alloc_index, tables, syntax_contexts, @@ -762,6 +782,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { assert_eq!(total_bytes, computed_total_bytes); if tcx.sess.opts.unstable_opts.meta_stats { + use std::fmt::Write; + self.opaque.flush(); // Rewind and re-read all the metadata to count the zero bytes we wrote. @@ -777,31 +799,44 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { assert_eq!(self.opaque.file().stream_position().unwrap(), pos_before_rewind); stats.sort_by_key(|&(_, usize)| usize); + stats.reverse(); // bigger items first let prefix = "meta-stats"; let perc = |bytes| (bytes * 100) as f64 / total_bytes as f64; - eprintln!("{prefix} METADATA STATS"); - eprintln!("{} {:<23}{:>10}", prefix, "Section", "Size"); - eprintln!("{prefix} ----------------------------------------------------------------"); + let section_w = 23; + let size_w = 10; + let banner_w = 64; + + // We write all the text into a string and print it with a single + // `eprint!`. This is an attempt to minimize interleaved text if multiple + // rustc processes are printing macro-stats at the same time (e.g. with + // `RUSTFLAGS='-Zmeta-stats' cargo build`). It still doesn't guarantee + // non-interleaving, though. + let mut s = String::new(); + _ = writeln!(s, "{prefix} {}", "=".repeat(banner_w)); + _ = writeln!(s, "{prefix} METADATA STATS: {}", tcx.crate_name(LOCAL_CRATE)); + _ = writeln!(s, "{prefix} {:<section_w$}{:>size_w$}", "Section", "Size"); + _ = writeln!(s, "{prefix} {}", "-".repeat(banner_w)); for (label, size) in stats { - eprintln!( - "{} {:<23}{:>10} ({:4.1}%)", - prefix, + _ = writeln!( + s, + "{prefix} {:<section_w$}{:>size_w$} ({:4.1}%)", label, usize_with_underscores(size), perc(size) ); } - eprintln!("{prefix} ----------------------------------------------------------------"); - eprintln!( - "{} {:<23}{:>10} (of which {:.1}% are zero bytes)", - prefix, + _ = writeln!(s, "{prefix} {}", "-".repeat(banner_w)); + _ = writeln!( + s, + "{prefix} {:<section_w$}{:>size_w$} (of which {:.1}% are zero bytes)", "Total", usize_with_underscores(total_bytes), perc(zero_bytes) ); - eprintln!("{prefix}"); + _ = writeln!(s, "{prefix} {}", "=".repeat(banner_w)); + eprint!("{s}"); } root @@ -824,9 +859,13 @@ struct AnalyzeAttrState<'a> { /// visibility: this is a piece of data that can be computed once per defid, and not once per /// attribute. Some attributes would only be usable downstream if they are public. #[inline] -fn analyze_attr(attr: &impl AttributeExt, state: &mut AnalyzeAttrState<'_>) -> bool { +fn analyze_attr(attr: &hir::Attribute, state: &mut AnalyzeAttrState<'_>) -> bool { let mut should_encode = false; - if let Some(name) = attr.name() + if let hir::Attribute::Parsed(p) = attr + && p.encode_cross_crate() == EncodeCrossCrate::No + { + // Attributes not marked encode-cross-crate don't need to be encoded for downstream crates. + } else if let Some(name) = attr.name() && !rustc_feature::encode_cross_crate(name) { // Attributes not marked encode-cross-crate don't need to be encoded for downstream crates. @@ -2341,7 +2380,13 @@ pub fn encode_metadata(tcx: TyCtxt<'_>, path: &Path, ref_path: Option<&Path>) { // Prefetch some queries used by metadata encoding. // This is not necessary for correctness, but is only done for performance reasons. // It can be removed if it turns out to cause trouble or be detrimental to performance. - join(|| prefetch_mir(tcx), || tcx.exported_symbols(LOCAL_CRATE)); + join( + || prefetch_mir(tcx), + || { + let _ = tcx.exported_non_generic_symbols(LOCAL_CRATE); + let _ = tcx.exported_generic_symbols(LOCAL_CRATE); + }, + ); } with_encode_metadata_header(tcx, path, |ecx| { @@ -2408,7 +2453,7 @@ fn with_encode_metadata_header( required_source_files, is_proc_macro: tcx.crate_types().contains(&CrateType::ProcMacro), hygiene_ctxt: &hygiene_ctxt, - symbol_table: Default::default(), + symbol_index_table: Default::default(), }; // Encode the rustc version string in a predictable location. diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 077835283e9..a962a787a42 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -282,7 +282,8 @@ pub(crate) struct CrateRoot { exportable_items: LazyArray<DefIndex>, stable_order_of_exportable_impls: LazyArray<(DefIndex, usize)>, - exported_symbols: LazyArray<(ExportedSymbol<'static>, SymbolExportInfo)>, + exported_non_generic_symbols: LazyArray<(ExportedSymbol<'static>, SymbolExportInfo)>, + exported_generic_symbols: LazyArray<(ExportedSymbol<'static>, SymbolExportInfo)>, syntax_contexts: SyntaxContextTable, expn_data: ExpnDataTable, diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl index 3d27e587b6c..69aa4383f13 100644 --- a/compiler/rustc_middle/messages.ftl +++ b/compiler/rustc_middle/messages.ftl @@ -17,6 +17,9 @@ middle_assert_gen_resume_after_drop = `gen` fn or block cannot be further iterat middle_assert_gen_resume_after_panic = `gen` fn or block cannot be further iterated on after it panicked +middle_assert_invalid_enum_construction = + trying to construct an enum from an invalid value `{$source}` + middle_assert_misaligned_ptr_deref = misaligned pointer dereference: address must be a multiple of {$required} but is {$found} @@ -78,6 +81,11 @@ middle_erroneous_constant = erroneous constant encountered middle_failed_writing_file = failed to write file {$path}: {$error}" +# Note: We only mention patterns here since the error can only occur with references, and those +# are forbidden in const generics. +middle_invalid_const_in_valtree = constant {$global_const_id} cannot be used as pattern + .note = constants that reference mutable or external memory cannot be used as pattern + middle_layout_cycle = a cycle occurred during layout computation @@ -95,6 +103,8 @@ middle_layout_too_generic = the type `{$ty}` does not have a fixed layout middle_layout_unknown = the type `{$ty}` has an unknown layout +middle_max_num_nodes_in_valtree = maximum number of nodes exceeded in constant {$global_const_id} + middle_opaque_hidden_type_mismatch = concrete type differs from previous defining opaque type use .label = expected `{$self_ty}`, got `{$other_ty}` diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index 6c6b12fed67..f36ae831653 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -170,3 +170,20 @@ pub(crate) struct TypeLengthLimit { pub path: PathBuf, pub type_length: usize, } + +#[derive(Diagnostic)] +#[diag(middle_max_num_nodes_in_valtree)] +pub(crate) struct MaxNumNodesInValtree { + #[primary_span] + pub span: Span, + pub global_const_id: String, +} + +#[derive(Diagnostic)] +#[diag(middle_invalid_const_in_valtree)] +#[note] +pub(crate) struct InvalidConstInValtree { + #[primary_span] + pub span: Span, + pub global_const_id: String, +} diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index ce2cb33c173..803b645c8f7 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -27,9 +27,8 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] +#![allow(rustc::direct_use_of_rustc_type_ir)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(not(bootstrap), allow(rustc::direct_use_of_rustc_type_ir))] -#![cfg_attr(not(bootstrap), feature(sized_hierarchy))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(allocator_api)] @@ -48,7 +47,6 @@ #![feature(gen_blocks)] #![feature(if_let_guard)] #![feature(intra_doc_pointers)] -#![feature(iter_from_coroutine)] #![feature(min_specialization)] #![feature(negative_impls)] #![feature(never_type)] @@ -56,6 +54,7 @@ #![feature(round_char_boundary)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] +#![feature(sized_hierarchy)] #![feature(try_blocks)] #![feature(try_trait_v2)] #![feature(try_trait_v2_yeet)] diff --git a/compiler/rustc_middle/src/middle/exported_symbols.rs b/compiler/rustc_middle/src/middle/exported_symbols.rs index 1d67d0fe3bb..c70ff398cea 100644 --- a/compiler/rustc_middle/src/middle/exported_symbols.rs +++ b/compiler/rustc_middle/src/middle/exported_symbols.rs @@ -22,7 +22,7 @@ impl SymbolExportLevel { } /// Kind of exported symbols. -#[derive(Eq, PartialEq, Debug, Copy, Clone, Encodable, Decodable, HashStable)] +#[derive(Eq, PartialEq, Debug, Copy, Clone, Encodable, Decodable, HashStable, Hash)] pub enum SymbolExportKind { Text, Data, @@ -31,11 +31,17 @@ pub enum SymbolExportKind { /// The `SymbolExportInfo` of a symbols specifies symbol-related information /// that is relevant to code generation and linking. +/// +/// The difference between `used` and `rustc_std_internal_symbol` is that the +/// former is exported by LTO while the latter isn't. #[derive(Eq, PartialEq, Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)] pub struct SymbolExportInfo { pub level: SymbolExportLevel, pub kind: SymbolExportKind, + /// Was the symbol marked as `#[used(compiler)]` or `#[used(linker)]`? pub used: bool, + /// Was the symbol marked as `#[rustc_std_internal_symbol]`? + pub rustc_std_internal_symbol: bool, } #[derive(Eq, PartialEq, Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)] diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index ab6a65ed526..99faba7b2c0 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -620,7 +620,7 @@ impl<'tcx> TyCtxt<'tcx> { /// instead of regular stability. /// /// This enforces *syntactical* const stability of const traits. In other words, - /// it enforces the ability to name `~const`/`const` traits in trait bounds in various + /// it enforces the ability to name `[const]`/`const` traits in trait bounds in various /// syntax positions in HIR (including in the trait of an impl header). pub fn check_const_stability(self, def_id: DefId, span: Span, const_kw_span: Span) { let is_staged_api = self.lookup_stability(def_id.krate.as_def_id()).is_some(); diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index 2b2ffa71628..16edc240544 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -168,8 +168,9 @@ impl<'tcx> ConstValue<'tcx> { return Some(&[]); } // Non-empty slice, must have memory. We know this is a relative pointer. - let (inner_prov, offset) = ptr.into_parts(); - let data = tcx.global_alloc(inner_prov?.alloc_id()).unwrap_memory(); + let (inner_prov, offset) = + ptr.into_pointer_or_addr().ok()?.prov_and_relative_offset(); + let data = tcx.global_alloc(inner_prov.alloc_id()).unwrap_memory(); (data, offset.bytes(), offset.bytes() + len) } }; diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index dd55d039794..4198b198ab1 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -526,7 +526,7 @@ impl Allocation { let ptr_bytes = &mut bytes[idx..idx + ptr_size]; let bits = read_target_uint(endian, ptr_bytes).unwrap(); let (ptr_prov, ptr_offset) = - adjust_ptr(Pointer::new(alloc_id, Size::from_bytes(bits)))?.into_parts(); + adjust_ptr(Pointer::new(alloc_id, Size::from_bytes(bits)))?.into_raw_parts(); write_target_uint(endian, ptr_bytes, ptr_offset.bytes().into()).unwrap(); new_provenance.push((offset, ptr_prov)); } @@ -769,7 +769,7 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes> // as-is into memory. This also double-checks that `val.size()` matches `range.size`. let (bytes, provenance) = match val.to_bits_or_ptr_internal(range.size)? { Right(ptr) => { - let (provenance, offset) = ptr.into_parts(); + let (provenance, offset) = ptr.into_raw_parts(); (u128::from(offset.bytes()), Some(provenance)) } Left(data) => (data, None), diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 6ff3cac049b..41a166083d0 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -35,7 +35,7 @@ impl From<ReportedErrorInfo> for ErrorHandled { } impl ErrorHandled { - pub fn with_span(self, span: Span) -> Self { + pub(crate) fn with_span(self, span: Span) -> Self { match self { ErrorHandled::Reported(err, _span) => ErrorHandled::Reported(err, span), ErrorHandled::TooGeneric(_span) => ErrorHandled::TooGeneric(span), @@ -94,14 +94,51 @@ impl From<ReportedErrorInfo> for ErrorGuaranteed { } } +/// An error type for the `const_to_valtree` query. Some error should be reported with a "use-site span", +/// which means the query cannot emit the error, so those errors are represented as dedicated variants here. +#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] +pub enum ValTreeCreationError<'tcx> { + /// The constant is too big to be valtree'd. + NodesOverflow, + /// The constant references mutable or external memory, so it cannot be valtree'd. + InvalidConst, + /// Values of this type, or this particular value, are not supported as valtrees. + NonSupportedType(Ty<'tcx>), + /// The error has already been handled by const evaluation. + ErrorHandled(ErrorHandled), +} + +impl<'tcx> From<ErrorHandled> for ValTreeCreationError<'tcx> { + fn from(err: ErrorHandled) -> Self { + ValTreeCreationError::ErrorHandled(err) + } +} + +impl<'tcx> From<InterpErrorInfo<'tcx>> for ValTreeCreationError<'tcx> { + fn from(err: InterpErrorInfo<'tcx>) -> Self { + // An error ocurred outside the const-eval query, as part of constructing the valtree. We + // don't currently preserve the details of this error, since `InterpErrorInfo` cannot be put + // into a query result and it can only be access of some mutable or external memory. + let (_kind, backtrace) = err.into_parts(); + backtrace.print_backtrace(); + ValTreeCreationError::InvalidConst + } +} + +impl<'tcx> ValTreeCreationError<'tcx> { + pub(crate) fn with_span(self, span: Span) -> Self { + use ValTreeCreationError::*; + match self { + ErrorHandled(handled) => ErrorHandled(handled.with_span(span)), + other => other, + } + } +} + pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>; pub type EvalStaticInitializerRawResult<'tcx> = Result<ConstAllocation<'tcx>, ErrorHandled>; pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>; -/// `Ok(Err(ty))` indicates the constant was fine, but the valtree couldn't be constructed -/// because the value contains something of type `ty` that is not valtree-compatible. -/// The caller can then show an appropriate error; the query does not have the -/// necessary context to give good user-facing errors for this case. -pub type EvalToValTreeResult<'tcx> = Result<Result<ValTree<'tcx>, Ty<'tcx>>, ErrorHandled>; +pub type EvalToValTreeResult<'tcx> = Result<ValTree<'tcx>, ValTreeCreationError<'tcx>>; #[cfg(target_pointer_width = "64")] rustc_data_structures::static_assert_size!(InterpErrorInfo<'_>, 8); @@ -450,10 +487,9 @@ pub enum ValidationErrorKind<'tcx> { ptr_kind: PointerKind, ty: Ty<'tcx>, }, - ConstRefToMutable, - ConstRefToExtern, MutableRefToImmutable, UnsafeCellInImmutable, + MutableRefInConst, NullFnPtr, NeverVal, NullablePtrOutOfRange { diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index c2438af6a1e..da9e5bdbadd 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -38,8 +38,8 @@ pub use self::error::{ EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, ExpectedKind, InterpErrorInfo, InterpErrorKind, InterpResult, InvalidMetaKind, InvalidProgramInfo, MachineStopType, Misalignment, PointerKind, ReportedErrorInfo, ResourceExhaustionInfo, - ScalarSizeMismatch, UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo, - ValidationErrorKind, interp_ok, + ScalarSizeMismatch, UndefinedBehaviorInfo, UnsupportedOpInfo, ValTreeCreationError, + ValidationErrorInfo, ValidationErrorKind, interp_ok, }; pub use self::pointer::{CtfeProvenance, Pointer, PointerArithmetic, Provenance}; pub use self::value::Scalar; @@ -77,7 +77,7 @@ impl<'tcx> GlobalId<'tcx> { #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, HashStable)] pub struct LitToConstInput<'tcx> { /// The absolute value of the resultant constant. - pub lit: &'tcx LitKind, + pub lit: LitKind, /// The type of the constant. pub ty: Ty<'tcx>, /// If the constant is negative. diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs index 25c7c26ddd9..0ff14f15c13 100644 --- a/compiler/rustc_middle/src/mir/interpret/pointer.rs +++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs @@ -288,7 +288,7 @@ impl From<CtfeProvenance> for Pointer { impl<Prov> From<Pointer<Prov>> for Pointer<Option<Prov>> { #[inline(always)] fn from(ptr: Pointer<Prov>) -> Self { - let (prov, offset) = ptr.into_parts(); + let (prov, offset) = ptr.into_raw_parts(); Pointer::new(Some(prov), offset) } } @@ -314,19 +314,17 @@ impl<Prov> Pointer<Option<Prov>> { assert!(Prov::OFFSET_IS_ADDR); self.offset } -} -impl<Prov> Pointer<Option<Prov>> { /// Creates a pointer to the given address, with invalid provenance (i.e., cannot be used for /// any memory access). #[inline(always)] - pub fn from_addr_invalid(addr: u64) -> Self { + pub fn without_provenance(addr: u64) -> Self { Pointer { provenance: None, offset: Size::from_bytes(addr) } } #[inline(always)] pub fn null() -> Self { - Pointer::from_addr_invalid(0) + Pointer::without_provenance(0) } } @@ -336,11 +334,11 @@ impl<Prov> Pointer<Prov> { Pointer { provenance, offset } } - /// Obtain the constituents of this pointer. Not that the meaning of the offset depends on the type `Prov`! - /// This function must only be used in the implementation of `Machine::ptr_get_alloc`, - /// and when a `Pointer` is taken apart to be stored efficiently in an `Allocation`. + /// Obtain the constituents of this pointer. Note that the meaning of the offset depends on the + /// type `Prov`! This is a low-level function that should only be used when absolutely + /// necessary. Prefer `prov_and_relative_offset` if possible. #[inline(always)] - pub fn into_parts(self) -> (Prov, Size) { + pub fn into_raw_parts(self) -> (Prov, Size) { (self.provenance, self.offset) } @@ -361,3 +359,12 @@ impl<Prov> Pointer<Prov> { self.wrapping_offset(Size::from_bytes(i as u64), cx) } } + +impl Pointer<CtfeProvenance> { + /// Return the provenance and relative offset stored in this pointer. Safer alternative to + /// `into_raw_parts` since the type ensures that the offset is indeed relative. + #[inline(always)] + pub fn prov_and_relative_offset(self) -> (CtfeProvenance, Size) { + (self.provenance, self.offset) + } +} diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index 97db45a70d7..e25f35c59c2 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -5,11 +5,11 @@ use rustc_span::{DUMMY_SP, Span}; use tracing::{debug, instrument}; use super::{ - ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, GlobalId, - ReportedErrorInfo, + ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult, GlobalId, ReportedErrorInfo, }; -use crate::mir; -use crate::ty::{self, GenericArgs, TyCtxt, TypeVisitableExt}; +use crate::mir::interpret::ValTreeCreationError; +use crate::ty::{self, ConstToValTreeResult, GenericArgs, TyCtxt, TypeVisitableExt}; +use crate::{error, mir}; impl<'tcx> TyCtxt<'tcx> { /// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts @@ -92,7 +92,7 @@ impl<'tcx> TyCtxt<'tcx> { typing_env: ty::TypingEnv<'tcx>, ct: ty::UnevaluatedConst<'tcx>, span: Span, - ) -> EvalToValTreeResult<'tcx> { + ) -> ConstToValTreeResult<'tcx> { // Cannot resolve `Unevaluated` constants that contain inference // variables. We reject those here since `resolve` // would fail otherwise. @@ -103,47 +103,54 @@ impl<'tcx> TyCtxt<'tcx> { bug!("did not expect inference variables here"); } - match ty::Instance::try_resolve(self, typing_env, ct.def, ct.args) { - Ok(Some(instance)) => { - let cid = GlobalId { instance, promoted: None }; - self.const_eval_global_id_for_typeck(typing_env, cid, span).inspect(|_| { - // We are emitting the lint here instead of in `is_const_evaluatable` - // as we normalize obligations before checking them, and normalization - // uses this function to evaluate this constant. - // - // @lcnr believes that successfully evaluating even though there are - // used generic parameters is a bug of evaluation, so checking for it - // here does feel somewhat sensible. - if !self.features().generic_const_exprs() - && ct.args.has_non_region_param() - // We only FCW for anon consts as repeat expr counts with anon consts are the only place - // that we have a back compat hack for. We don't need to check this is a const argument - // as only anon consts as const args should get evaluated "for the type system". - // - // If we don't *only* FCW anon consts we can wind up incorrectly FCW'ing uses of assoc - // consts in pattern positions. #140447 - && self.def_kind(instance.def_id()) == DefKind::AnonConst - { - let mir_body = self.mir_for_ctfe(instance.def_id()); - if mir_body.is_polymorphic { - let Some(local_def_id) = ct.def.as_local() else { return }; - self.node_span_lint( - lint::builtin::CONST_EVALUATABLE_UNCHECKED, - self.local_def_id_to_hir_id(local_def_id), - self.def_span(ct.def), - |lint| { lint.primary_message("cannot use constants which depend on generic parameters in types"); }, - ) - } - } - }) - } + let cid = match ty::Instance::try_resolve(self, typing_env, ct.def, ct.args) { + Ok(Some(instance)) => GlobalId { instance, promoted: None }, // For errors during resolution, we deliberately do not point at the usage site of the constant, // since for these errors the place the constant is used shouldn't matter. - Ok(None) => Err(ErrorHandled::TooGeneric(DUMMY_SP)), + Ok(None) => return Err(ErrorHandled::TooGeneric(DUMMY_SP).into()), Err(err) => { - Err(ErrorHandled::Reported(ReportedErrorInfo::non_const_eval_error(err), DUMMY_SP)) + return Err(ErrorHandled::Reported( + ReportedErrorInfo::non_const_eval_error(err), + DUMMY_SP, + ) + .into()); } - } + }; + + self.const_eval_global_id_for_typeck(typing_env, cid, span).inspect(|_| { + // We are emitting the lint here instead of in `is_const_evaluatable` + // as we normalize obligations before checking them, and normalization + // uses this function to evaluate this constant. + // + // @lcnr believes that successfully evaluating even though there are + // used generic parameters is a bug of evaluation, so checking for it + // here does feel somewhat sensible. + if !self.features().generic_const_exprs() + && ct.args.has_non_region_param() + // We only FCW for anon consts as repeat expr counts with anon consts are the only place + // that we have a back compat hack for. We don't need to check this is a const argument + // as only anon consts as const args should get evaluated "for the type system". + // + // If we don't *only* FCW anon consts we can wind up incorrectly FCW'ing uses of assoc + // consts in pattern positions. #140447 + && self.def_kind(cid.instance.def_id()) == DefKind::AnonConst + { + let mir_body = self.mir_for_ctfe(cid.instance.def_id()); + if mir_body.is_polymorphic { + let Some(local_def_id) = ct.def.as_local() else { return }; + self.node_span_lint( + lint::builtin::CONST_EVALUATABLE_UNCHECKED, + self.local_def_id_to_hir_id(local_def_id), + self.def_span(ct.def), + |lint| { + lint.primary_message( + "cannot use constants which depend on generic parameters in types", + ); + }, + ) + } + } + }) } pub fn const_eval_instance( @@ -182,17 +189,42 @@ impl<'tcx> TyCtxt<'tcx> { typing_env: ty::TypingEnv<'tcx>, cid: GlobalId<'tcx>, span: Span, - ) -> EvalToValTreeResult<'tcx> { + ) -> ConstToValTreeResult<'tcx> { // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should // improve caching of queries. let inputs = self.erase_regions(typing_env.with_post_analysis_normalized(self).as_query_input(cid)); debug!(?inputs); - if !span.is_dummy() { + let res = if !span.is_dummy() { // The query doesn't know where it is being invoked, so we need to fix the span. self.at(span).eval_to_valtree(inputs).map_err(|e| e.with_span(span)) } else { self.eval_to_valtree(inputs) + }; + match res { + Ok(valtree) => Ok(Ok(valtree)), + Err(err) => { + match err { + // Let the caller decide how to handle this. + ValTreeCreationError::NonSupportedType(ty) => Ok(Err(ty)), + // Report the others. + ValTreeCreationError::NodesOverflow => { + let handled = self.dcx().emit_err(error::MaxNumNodesInValtree { + span, + global_const_id: cid.display(self), + }); + Err(ReportedErrorInfo::allowed_in_infallible(handled).into()) + } + ValTreeCreationError::InvalidConst => { + let handled = self.dcx().emit_err(error::InvalidConstInValtree { + span, + global_const_id: cid.display(self), + }); + Err(ReportedErrorInfo::allowed_in_infallible(handled).into()) + } + ValTreeCreationError::ErrorHandled(handled) => Err(handled), + } + } } } } diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index 7ba0e5b5e07..8092f634dc8 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -109,7 +109,7 @@ impl<Prov> Scalar<Prov> { /// Create a Scalar from a pointer with an `Option<_>` provenance (where `None` represents a /// plain integer / "invalid" pointer). pub fn from_maybe_pointer(ptr: Pointer<Option<Prov>>, cx: &impl HasDataLayout) -> Self { - match ptr.into_parts() { + match ptr.into_raw_parts() { (Some(prov), offset) => Scalar::from_pointer(Pointer::new(prov, offset), cx), (None, offset) => { Scalar::Int(ScalarInt::try_from_uint(offset.bytes(), cx.pointer_size()).unwrap()) @@ -276,7 +276,7 @@ impl<'tcx, Prov: Provenance> Scalar<Prov> { Right(ptr) => interp_ok(ptr.into()), Left(bits) => { let addr = u64::try_from(bits).unwrap(); - interp_ok(Pointer::from_addr_invalid(addr)) + interp_ok(Pointer::without_provenance(addr)) } } } @@ -299,7 +299,7 @@ impl<'tcx, Prov: Provenance> Scalar<Prov> { Ok(ScalarInt::try_from_uint(ptr.offset.bytes(), Size::from_bytes(sz)).unwrap()) } else { // We know `offset` is relative, since `OFFSET_IS_ADDR == false`. - let (prov, offset) = ptr.into_parts(); + let (prov, offset) = ptr.into_raw_parts(); // Because `OFFSET_IS_ADDR == false`, this unwrap can never fail. Err(Scalar::Ptr(Pointer::new(prov.get_alloc_id().unwrap(), offset), sz)) } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index adc100941a3..33e97766a02 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1336,6 +1336,7 @@ impl BasicBlock { /// /// See [`BasicBlock`] for documentation on what basic blocks are at a high level. #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] +#[non_exhaustive] pub struct BasicBlockData<'tcx> { /// List of statements in this block. pub statements: Vec<Statement<'tcx>>, @@ -1359,7 +1360,15 @@ pub struct BasicBlockData<'tcx> { impl<'tcx> BasicBlockData<'tcx> { pub fn new(terminator: Option<Terminator<'tcx>>, is_cleanup: bool) -> BasicBlockData<'tcx> { - BasicBlockData { statements: vec![], terminator, is_cleanup } + BasicBlockData::new_stmts(Vec::new(), terminator, is_cleanup) + } + + pub fn new_stmts( + statements: Vec<Statement<'tcx>>, + terminator: Option<Terminator<'tcx>>, + is_cleanup: bool, + ) -> BasicBlockData<'tcx> { + BasicBlockData { statements, terminator, is_cleanup } } /// Accessor for terminator. diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index d98b40f0fcf..683d7b48617 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -11,17 +11,22 @@ use crate::ty::CoroutineArgsExt; /// A statement in a basic block, including information about its source code. #[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] +#[non_exhaustive] pub struct Statement<'tcx> { pub source_info: SourceInfo, pub kind: StatementKind<'tcx>, } -impl Statement<'_> { +impl<'tcx> Statement<'tcx> { /// Changes a statement to a nop. This is both faster than deleting instructions and avoids /// invalidating statement indices in `Location`s. pub fn make_nop(&mut self) { self.kind = StatementKind::Nop } + + pub fn new(source_info: SourceInfo, kind: StatementKind<'tcx>) -> Self { + Statement { source_info, kind } + } } impl<'tcx> StatementKind<'tcx> { diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 56f19d7929d..92eefd89848 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -284,15 +284,15 @@ pub enum FakeBorrowKind { /// /// This is used when lowering deref patterns, where shallow borrows wouldn't prevent something /// like: - // ```compile_fail - // let mut b = Box::new(false); - // match b { - // deref!(true) => {} // not reached because `*b == false` - // _ if { *b = true; false } => {} // not reached because the guard is `false` - // deref!(false) => {} // not reached because the guard changed it - // // UB because we reached the unreachable. - // } - // ``` + /// ```compile_fail + /// let mut b = Box::new(false); + /// match b { + /// deref!(true) => {} // not reached because `*b == false` + /// _ if { *b = true; false } => {} // not reached because the guard is `false` + /// deref!(false) => {} // not reached because the guard changed it + /// // UB because we reached the unreachable. + /// } + /// ``` Deep, } @@ -1075,6 +1075,7 @@ pub enum AssertKind<O> { ResumedAfterDrop(CoroutineKind), MisalignedPointerDereference { required: O, found: O }, NullPointerDereference, + InvalidEnumConstruction(O), } #[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 0834fa8844c..4034a3a06e9 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -208,6 +208,7 @@ impl<O> AssertKind<O> { LangItem::PanicGenFnNonePanic } NullPointerDereference => LangItem::PanicNullPointerDereference, + InvalidEnumConstruction(_) => LangItem::PanicInvalidEnumConstruction, ResumedAfterDrop(CoroutineKind::Coroutine(_)) => LangItem::PanicCoroutineResumedDrop, ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => { LangItem::PanicAsyncFnResumedDrop @@ -284,6 +285,9 @@ impl<O> AssertKind<O> { ) } NullPointerDereference => write!(f, "\"null pointer dereference occurred\""), + InvalidEnumConstruction(source) => { + write!(f, "\"trying to construct an enum from an invalid value {{}}\", {source:?}") + } ResumedAfterReturn(CoroutineKind::Coroutine(_)) => { write!(f, "\"coroutine resumed after completion\"") } @@ -367,6 +371,7 @@ impl<O> AssertKind<O> { middle_assert_coroutine_resume_after_panic } NullPointerDereference => middle_assert_null_ptr_deref, + InvalidEnumConstruction(_) => middle_assert_invalid_enum_construction, ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => { middle_assert_async_resume_after_drop } @@ -420,6 +425,9 @@ impl<O> AssertKind<O> { add!("required", format!("{required:#?}")); add!("found", format!("{found:#?}")); } + InvalidEnumConstruction(source) => { + add!("source", format!("{source:#?}")); + } } } } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 1777756174b..929ebe1aee1 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -642,7 +642,7 @@ macro_rules! make_mir_visitor { self.visit_operand(l, location); self.visit_operand(r, location); } - OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) => { + OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) | InvalidEnumConstruction(op) => { self.visit_operand(op, location); } ResumedAfterReturn(_) | ResumedAfterPanic(_) | NullPointerDereference | ResumedAfterDrop(_) => { diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 7c998761a9d..f138c5ca039 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -4,6 +4,7 @@ use std::mem::MaybeUninit; use rustc_span::ErrorGuaranteed; +use crate::mir::interpret::EvalToValTreeResult; use crate::query::CyclePlaceholder; use crate::ty::adjustment::CoerceUnsizedInfo; use crate::ty::{self, Ty, TyCtxt}; @@ -156,10 +157,8 @@ impl EraseType for Result<mir::ConstValue<'_>, mir::interpret::ErrorHandled> { type Result = [u8; size_of::<Result<mir::ConstValue<'static>, mir::interpret::ErrorHandled>>()]; } -impl EraseType for Result<Result<ty::ValTree<'_>, Ty<'_>>, mir::interpret::ErrorHandled> { - type Result = [u8; size_of::< - Result<Result<ty::ValTree<'static>, Ty<'static>>, mir::interpret::ErrorHandled>, - >()]; +impl EraseType for EvalToValTreeResult<'_> { + type Result = [u8; size_of::<EvalToValTreeResult<'static>>()]; } impl EraseType for Result<&'_ ty::List<Ty<'_>>, ty::util::AlwaysRequiresDrop> { @@ -267,6 +266,7 @@ trivial! { Option<rustc_target::spec::PanicStrategy>, Option<usize>, Option<rustc_middle::ty::IntrinsicDef>, + Option<rustc_abi::Align>, Result<(), rustc_errors::ErrorGuaranteed>, Result<(), rustc_middle::traits::query::NoSolution>, Result<rustc_middle::traits::EvaluationResult, rustc_middle::traits::OverflowError>, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 3668f4e12f5..3e68f0f784e 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -67,6 +67,7 @@ use std::mem; use std::path::PathBuf; use std::sync::Arc; +use rustc_abi::Align; use rustc_arena::TypedArena; use rustc_ast::expand::StrippedCfgItem; use rustc_ast::expand::allocator::AllocatorKind; @@ -850,14 +851,14 @@ rustc_queries! { } /// Compute the conditions that need to hold for a conditionally-const item to be const. - /// That is, compute the set of `~const` where clauses for a given item. + /// That is, compute the set of `[const]` where clauses for a given item. /// - /// This can be thought of as the `~const` equivalent of `predicates_of`. These are the + /// This can be thought of as the `[const]` equivalent of `predicates_of`. These are the /// predicates that need to be proven at usage sites, and can be assumed at definition. /// - /// This query also computes the `~const` where clauses for associated types, which are - /// not "const", but which have item bounds which may be `~const`. These must hold for - /// the `~const` item bound to hold. + /// This query also computes the `[const]` where clauses for associated types, which are + /// not "const", but which have item bounds which may be `[const]`. These must hold for + /// the `[const]` item bound to hold. query const_conditions( key: DefId ) -> ty::ConstConditions<'tcx> { @@ -869,13 +870,13 @@ rustc_queries! { /// Compute the const bounds that are implied for a conditionally-const item. /// - /// This can be though of as the `~const` equivalent of `explicit_item_bounds`. These + /// This can be though of as the `[const]` equivalent of `explicit_item_bounds`. These /// are the predicates that need to proven at definition sites, and can be assumed at /// usage sites. query explicit_implied_const_bounds( key: DefId ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::PolyTraitRef<'tcx>, Span)]> { - desc { |tcx| "computing the implied `~const` bounds for `{}`", + desc { |tcx| "computing the implied `[const]` bounds for `{}`", tcx.def_path_str(key) } separate_provide_extern @@ -1283,15 +1284,15 @@ rustc_queries! { return_result_from_ensure_ok } - /// Check whether the function has any recursion that could cause the inliner to trigger - /// a cycle. - query mir_callgraph_reachable(key: (ty::Instance<'tcx>, LocalDefId)) -> bool { + /// Return the set of (transitive) callees that may result in a recursive call to `key`. + query mir_callgraph_cyclic(key: LocalDefId) -> &'tcx UnordSet<LocalDefId> { fatal_cycle + arena_cache desc { |tcx| - "computing if `{}` (transitively) calls `{}`", - key.0, - tcx.def_path_str(key.1), + "computing (transitive) callees of `{}` that may recurse", + tcx.def_path_str(key), } + cache_on_disk_if { true } } /// Obtain all the calls into other local functions @@ -1311,7 +1312,7 @@ rustc_queries! { /// /// This query will panic for uninhabited variants and if the passed type is not an enum. query tag_for_variant( - key: (Ty<'tcx>, abi::VariantIdx) + key: PseudoCanonicalInput<'tcx, (Ty<'tcx>, abi::VariantIdx)>, ) -> Option<ty::ScalarInt> { desc { "computing variant tag for enum" } } @@ -1481,6 +1482,10 @@ rustc_queries! { desc { |tcx| "computing should_inherit_track_caller of `{}`", tcx.def_path_str(def_id) } } + query inherited_align(def_id: DefId) -> Option<Align> { + desc { |tcx| "computing inherited_align of `{}`", tcx.def_path_str(def_id) } + } + query lookup_deprecation_entry(def_id: DefId) -> Option<DeprecationEntry> { desc { |tcx| "checking whether `{}` is deprecated", tcx.def_path_str(def_id) } cache_on_disk_if { def_id.is_local() } @@ -2312,13 +2317,32 @@ rustc_queries! { separate_provide_extern } - /// The list of symbols exported from the given crate. + /// The list of non-generic symbols exported from the given crate. + /// + /// This is separate from exported_generic_symbols to avoid having + /// to deserialize all non-generic symbols too for upstream crates + /// in the upstream_monomorphizations query. + /// + /// - All names contained in `exported_non_generic_symbols(cnum)` are + /// guaranteed to correspond to a publicly visible symbol in `cnum` + /// machine code. + /// - The `exported_non_generic_symbols` and `exported_generic_symbols` + /// sets of different crates do not intersect. + query exported_non_generic_symbols(cnum: CrateNum) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] { + desc { "collecting exported non-generic symbols for crate `{}`", cnum} + cache_on_disk_if { *cnum == LOCAL_CRATE } + separate_provide_extern + } + + /// The list of generic symbols exported from the given crate. /// - /// - All names contained in `exported_symbols(cnum)` are guaranteed to - /// correspond to a publicly visible symbol in `cnum` machine code. - /// - The `exported_symbols` sets of different crates do not intersect. - query exported_symbols(cnum: CrateNum) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] { - desc { "collecting exported symbols for crate `{}`", cnum} + /// - All names contained in `exported_generic_symbols(cnum)` are + /// guaranteed to correspond to a publicly visible symbol in `cnum` + /// machine code. + /// - The `exported_non_generic_symbols` and `exported_generic_symbols` + /// sets of different crates do not intersect. + query exported_generic_symbols(cnum: CrateNum) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] { + desc { "collecting exported generic symbols for crate `{}`", cnum} cache_on_disk_if { *cnum == LOCAL_CRATE } separate_provide_extern } diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index e1876f8f0f9..a7ac3442898 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -20,8 +20,8 @@ use rustc_span::hygiene::{ }; use rustc_span::source_map::Spanned; use rustc_span::{ - BytePos, CachingSourceMapView, ExpnData, ExpnHash, Pos, RelativeBytePos, SourceFile, Span, - SpanDecoder, SpanEncoder, StableSourceFileId, Symbol, + BytePos, ByteSymbol, CachingSourceMapView, ExpnData, ExpnHash, Pos, RelativeBytePos, + SourceFile, Span, SpanDecoder, SpanEncoder, StableSourceFileId, Symbol, }; use crate::dep_graph::{DepNodeIndex, SerializedDepNodeIndex}; @@ -42,7 +42,7 @@ const TAG_RELATIVE_SPAN: u8 = 2; const TAG_SYNTAX_CONTEXT: u8 = 0; const TAG_EXPN_DATA: u8 = 1; -// Tags for encoding Symbol's +// Tags for encoding Symbols and ByteSymbols const SYMBOL_STR: u8 = 0; const SYMBOL_OFFSET: u8 = 1; const SYMBOL_PREDEFINED: u8 = 2; @@ -253,7 +253,7 @@ impl OnDiskCache { source_map: CachingSourceMapView::new(tcx.sess.source_map()), file_to_file_index, hygiene_context: &hygiene_encode_context, - symbol_table: Default::default(), + symbol_index_table: Default::default(), }; // Encode query results. @@ -479,6 +479,30 @@ impl<'a, 'tcx> CacheDecoder<'a, 'tcx> { .expect("failed to lookup `SourceFile` in new context") })) } + + // copy&paste impl from rustc_metadata + #[inline] + fn decode_symbol_or_byte_symbol<S>( + &mut self, + new_from_index: impl Fn(u32) -> S, + read_and_intern_str_or_byte_str_this: impl Fn(&mut Self) -> S, + read_and_intern_str_or_byte_str_opaque: impl Fn(&mut MemDecoder<'a>) -> S, + ) -> S { + let tag = self.read_u8(); + + match tag { + SYMBOL_STR => read_and_intern_str_or_byte_str_this(self), + SYMBOL_OFFSET => { + // read str offset + let pos = self.read_usize(); + + // move to str offset and read + self.opaque.with_position(pos, |d| read_and_intern_str_or_byte_str_opaque(d)) + } + SYMBOL_PREDEFINED => new_from_index(self.read_u32()), + _ => unreachable!(), + } + } } // Decodes something that was encoded with `encode_tagged()` and verify that the @@ -653,32 +677,20 @@ impl<'a, 'tcx> SpanDecoder for CacheDecoder<'a, 'tcx> { Span::new(lo, hi, ctxt, parent) } - // copy&paste impl from rustc_metadata - #[inline] fn decode_symbol(&mut self) -> Symbol { - let tag = self.read_u8(); - - match tag { - SYMBOL_STR => { - let s = self.read_str(); - Symbol::intern(s) - } - SYMBOL_OFFSET => { - // read str offset - let pos = self.read_usize(); + self.decode_symbol_or_byte_symbol( + Symbol::new, + |this| Symbol::intern(this.read_str()), + |opaque| Symbol::intern(opaque.read_str()), + ) + } - // move to str offset and read - self.opaque.with_position(pos, |d| { - let s = d.read_str(); - Symbol::intern(s) - }) - } - SYMBOL_PREDEFINED => { - let symbol_index = self.read_u32(); - Symbol::new(symbol_index) - } - _ => unreachable!(), - } + fn decode_byte_symbol(&mut self) -> ByteSymbol { + self.decode_symbol_or_byte_symbol( + ByteSymbol::new, + |this| ByteSymbol::intern(this.read_byte_str()), + |opaque| ByteSymbol::intern(opaque.read_byte_str()), + ) } fn decode_crate_num(&mut self) -> CrateNum { @@ -807,7 +819,8 @@ pub struct CacheEncoder<'a, 'tcx> { source_map: CachingSourceMapView<'tcx>, file_to_file_index: FxHashMap<*const SourceFile, SourceFileIndex>, hygiene_context: &'a HygieneEncodeContext, - symbol_table: FxHashMap<Symbol, usize>, + // Used for both `Symbol`s and `ByteSymbol`s. + symbol_index_table: FxHashMap<u32, usize>, } impl<'a, 'tcx> CacheEncoder<'a, 'tcx> { @@ -831,6 +844,34 @@ impl<'a, 'tcx> CacheEncoder<'a, 'tcx> { ((end_pos - start_pos) as u64).encode(self); } + // copy&paste impl from rustc_metadata + fn encode_symbol_or_byte_symbol( + &mut self, + index: u32, + emit_str_or_byte_str: impl Fn(&mut Self), + ) { + // if symbol/byte symbol is predefined, emit tag and symbol index + if Symbol::is_predefined(index) { + self.encoder.emit_u8(SYMBOL_PREDEFINED); + self.encoder.emit_u32(index); + } else { + // otherwise write it as string or as offset to it + match self.symbol_index_table.entry(index) { + Entry::Vacant(o) => { + self.encoder.emit_u8(SYMBOL_STR); + let pos = self.encoder.position(); + o.insert(pos); + emit_str_or_byte_str(self); + } + Entry::Occupied(o) => { + let x = *o.get(); + self.emit_u8(SYMBOL_OFFSET); + self.emit_usize(x); + } + } + } + } + #[inline] fn finish(mut self) -> FileEncodeResult { self.encoder.finish() @@ -889,28 +930,14 @@ impl<'a, 'tcx> SpanEncoder for CacheEncoder<'a, 'tcx> { len.encode(self); } - // copy&paste impl from rustc_metadata - fn encode_symbol(&mut self, symbol: Symbol) { - // if symbol predefined, emit tag and symbol index - if symbol.is_predefined() { - self.encoder.emit_u8(SYMBOL_PREDEFINED); - self.encoder.emit_u32(symbol.as_u32()); - } else { - // otherwise write it as string or as offset to it - match self.symbol_table.entry(symbol) { - Entry::Vacant(o) => { - self.encoder.emit_u8(SYMBOL_STR); - let pos = self.encoder.position(); - o.insert(pos); - self.emit_str(symbol.as_str()); - } - Entry::Occupied(o) => { - let x = *o.get(); - self.emit_u8(SYMBOL_OFFSET); - self.emit_usize(x); - } - } - } + fn encode_symbol(&mut self, sym: Symbol) { + self.encode_symbol_or_byte_symbol(sym.as_u32(), |this| this.emit_str(sym.as_str())); + } + + fn encode_byte_symbol(&mut self, byte_sym: ByteSymbol) { + self.encode_symbol_or_byte_symbol(byte_sym.as_u32(), |this| { + this.emit_byte_str(byte_sym.as_byte_str()) + }); } fn encode_crate_num(&mut self, crate_num: CrateNum) { diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index b9a014d14c0..bda8dcadbce 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -378,6 +378,14 @@ pub enum ExprKind<'tcx> { Loop { body: ExprId, }, + /// A `#[loop_match] loop { state = 'blk: { match state { ... } } }` expression. + LoopMatch { + /// The state variable that is updated, and also the scrutinee of the match. + state: ExprId, + region_scope: region::Scope, + arms: Box<[ArmId]>, + match_span: Span, + }, /// Special expression representing the `let` part of an `if let` or similar construct /// (including `if let` guards in match arms, and let-chains formed by `&&`). /// @@ -454,6 +462,11 @@ pub enum ExprKind<'tcx> { Continue { label: region::Scope, }, + /// A `#[const_continue] break` expression. + ConstContinue { + label: region::Scope, + value: ExprId, + }, /// A `return` expression. Return { value: Option<ExprId>, @@ -513,7 +526,7 @@ pub enum ExprKind<'tcx> { Closure(Box<ClosureExpr<'tcx>>), /// A literal. Literal { - lit: &'tcx hir::Lit, + lit: hir::Lit, neg: bool, }, /// For literals that don't correspond to anything in the HIR diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index d8743814d79..c9ef723aea4 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -83,7 +83,7 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( visitor.visit_pat(pat); } Loop { body } => visitor.visit_expr(&visitor.thir()[body]), - Match { scrutinee, ref arms, .. } => { + LoopMatch { state: scrutinee, ref arms, .. } | Match { scrutinee, ref arms, .. } => { visitor.visit_expr(&visitor.thir()[scrutinee]); for &arm in &**arms { visitor.visit_arm(&visitor.thir()[arm]); @@ -108,6 +108,7 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( } } Continue { label: _ } => {} + ConstContinue { value, label: _ } => visitor.visit_expr(&visitor.thir()[value]), Return { value } => { if let Some(value) = value { visitor.visit_expr(&visitor.thir()[value]) diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index d877bd5c626..1a5a9765ce7 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -332,7 +332,11 @@ pub enum ObligationCauseCode<'tcx> { }, /// Computing common supertype in an if expression - IfExpression(Box<IfExpressionCause<'tcx>>), + IfExpression { + expr_id: HirId, + // Is the expectation of this match expression an RPIT? + tail_defines_return_position_impl_trait: Option<LocalDefId>, + }, /// Computing common supertype of an if expression with no else counter-part IfExpressionWithNoElse, @@ -550,18 +554,6 @@ pub struct PatternOriginExpr { pub peeled_prefix_suggestion_parentheses: bool, } -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -#[derive(TypeFoldable, TypeVisitable, HashStable, TyEncodable, TyDecodable)] -pub struct IfExpressionCause<'tcx> { - pub then_id: HirId, - pub else_id: HirId, - pub then_ty: Ty<'tcx>, - pub else_ty: Ty<'tcx>, - pub outer_span: Option<Span>, - // Is the expectation of this match expression an RPIT? - pub tail_defines_return_position_impl_trait: Option<LocalDefId>, -} - #[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] #[derive(TypeVisitable, TypeFoldable)] pub struct DerivedCause<'tcx> { diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index 3bacdfe5ac8..74573455f53 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -36,9 +36,6 @@ pub enum PointerCoercion { /// type. Codegen backends and miri figure out what has to be done /// based on the precise source/target type at hand. Unsize, - - /// Go from a pointer-like type to a `dyn*` object. - DynStar, } /// Represents coercing a value to a different type of value. diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 3d7965f6cfe..335b889b14d 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -8,12 +8,12 @@ use std::hash::Hash; use std::intrinsics; -use std::marker::DiscriminantKind; +use std::marker::{DiscriminantKind, PointeeSized}; use rustc_abi::{FieldIdx, VariantIdx}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::LocalDefId; -use rustc_serialize::{Decodable, Encodable, PointeeSized}; +use rustc_serialize::{Decodable, Encodable}; use rustc_span::source_map::Spanned; use rustc_span::{Span, SpanDecoder, SpanEncoder}; diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 2fbaa2221a1..fd1aa4042bc 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -144,6 +144,19 @@ impl<'tcx> Const<'tcx> { let reported = tcx.dcx().span_delayed_bug(span, msg); Const::new_error(tcx, reported) } + + pub fn is_trivially_wf(self) -> bool { + match self.kind() { + ty::ConstKind::Param(_) | ty::ConstKind::Placeholder(_) | ty::ConstKind::Bound(..) => { + true + } + ty::ConstKind::Infer(_) + | ty::ConstKind::Unevaluated(..) + | ty::ConstKind::Value(_) + | ty::ConstKind::Error(_) + | ty::ConstKind::Expr(_) => false, + } + } } impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> { diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index 2f21d19e03c..d95006dcf4a 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -5,7 +5,7 @@ use rustc_data_structures::intern::Interned; use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use super::ScalarInt; -use crate::mir::interpret::Scalar; +use crate::mir::interpret::{ErrorHandled, Scalar}; use crate::ty::{self, Ty, TyCtxt}; /// This datastructure is used to represent the value of constants used in the type system. @@ -124,6 +124,12 @@ impl fmt::Debug for ValTree<'_> { } } +/// `Ok(Err(ty))` indicates the constant was fine, but the valtree couldn't be constructed +/// because the value contains something of type `ty` that is not valtree-compatible. +/// The caller can then show an appropriate error; the query does not have the +/// necessary context to give good user-facing errors for this case. +pub type ConstToValTreeResult<'tcx> = Result<Result<ValTree<'tcx>, Ty<'tcx>>, ErrorHandled>; + /// A type-level constant value. /// /// Represents a typed, fully evaluated constant. diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index c5f4b95cbbe..f5c55f96875 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -10,13 +10,14 @@ use std::cmp::Ordering; use std::env::VarError; use std::ffi::OsStr; use std::hash::{Hash, Hasher}; -use std::marker::PhantomData; +use std::marker::{PhantomData, PointeeSized}; use std::ops::{Bound, Deref}; use std::sync::{Arc, OnceLock}; use std::{fmt, iter, mem}; use rustc_abi::{ExternAbi, FieldIdx, Layout, LayoutData, TargetDataLayout, VariantIdx}; use rustc_ast as ast; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::defer; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; @@ -43,7 +44,6 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_query_system::cache::WithDepNode; use rustc_query_system::dep_graph::DepNodeIndex; use rustc_query_system::ich::StableHashingContext; -use rustc_serialize::PointeeSized; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use rustc_session::config::CrateType; use rustc_session::cstore::{CrateStoreDyn, Untracked}; @@ -432,6 +432,13 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.explicit_implied_predicates_of(def_id).map_bound(|preds| preds.into_iter().copied()) } + fn impl_super_outlives( + self, + impl_def_id: DefId, + ) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Clause<'tcx>>> { + self.impl_super_outlives(impl_def_id) + } + fn impl_is_const(self, def_id: DefId) -> bool { debug_assert_matches!(self.def_kind(def_id), DefKind::Impl { of_trait: true }); self.is_conditionally_const(def_id) @@ -691,14 +698,6 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.unsizing_params_for_adt(adt_def_id) } - fn find_const_ty_from_env( - self, - param_env: ty::ParamEnv<'tcx>, - placeholder: Self::PlaceholderConst, - ) -> Ty<'tcx> { - placeholder.find_const_ty_from_env(param_env) - } - fn anonymize_bound_vars<T: TypeFoldable<TyCtxt<'tcx>>>( self, binder: ty::Binder<'tcx, T>, @@ -774,8 +773,8 @@ bidirectional_lang_item_map! { Future, FutureOutput, Iterator, - Metadata, MetaSized, + Metadata, Option, PointeeSized, PointeeTrait, @@ -1649,32 +1648,9 @@ impl<'tcx> TyCtxt<'tcx> { /// `rustc_layout_scalar_valid_range` attribute. // FIXME(eddyb) this is an awkward spot for this method, maybe move it? pub fn layout_scalar_valid_range(self, def_id: DefId) -> (Bound<u128>, Bound<u128>) { - let get = |name| { - let Some(attr) = self.get_attr(def_id, name) else { - return Bound::Unbounded; - }; - debug!("layout_scalar_valid_range: attr={:?}", attr); - if let Some( - &[ - ast::MetaItemInner::Lit(ast::MetaItemLit { - kind: ast::LitKind::Int(a, _), .. - }), - ], - ) = attr.meta_item_list().as_deref() - { - Bound::Included(a.get()) - } else { - self.dcx().span_delayed_bug( - attr.span(), - "invalid rustc_layout_scalar_valid_range attribute", - ); - Bound::Unbounded - } - }; - ( - get(sym::rustc_layout_scalar_valid_range_start), - get(sym::rustc_layout_scalar_valid_range_end), - ) + let start = find_attr!(self.get_all_attrs(def_id), AttributeKind::RustcLayoutScalarValidRangeStart(n, _) => Bound::Included(**n)).unwrap_or(Bound::Unbounded); + let end = find_attr!(self.get_all_attrs(def_id), AttributeKind::RustcLayoutScalarValidRangeEnd(n, _) => Bound::Included(**n)).unwrap_or(Bound::Unbounded); + (start, end) } pub fn lift<T: Lift<TyCtxt<'tcx>>>(self, value: T) -> Option<T::Lifted> { diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index d4cc562e70c..c7b3b541549 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -419,7 +419,7 @@ impl<'tcx> GenericPredicates<'tcx> { } } -/// `~const` bounds for a given item. This is represented using a struct much like +/// `[const]` bounds for a given item. This is represented using a struct much like /// `GenericPredicates`, where you can either choose to only instantiate the "own" /// bounds or all of the bounds including those from the parent. This distinction /// is necessary for code like `compare_method_predicate_entailment`. diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 13c281a6182..09379d9d805 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -946,21 +946,6 @@ where } } - ty::Dynamic(_, _, ty::DynStar) => { - if i == 0 { - TyMaybeWithLayout::Ty(Ty::new_mut_ptr(tcx, tcx.types.unit)) - } else if i == 1 { - // FIXME(dyn-star) same FIXME as above applies here too - TyMaybeWithLayout::Ty(Ty::new_imm_ref( - tcx, - tcx.lifetimes.re_static, - Ty::new_array(tcx, tcx.types.usize, 3), - )) - } else { - bug!("no field {i} on dyn*") - } - } - ty::Alias(..) | ty::Bound(..) | ty::Placeholder(..) @@ -1248,11 +1233,12 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: ExternAbi) | EfiApi | AvrInterrupt | AvrNonBlockingInterrupt + | CmseNonSecureCall + | CmseNonSecureEntry + | Custom | RiscvInterruptM | RiscvInterruptS - | CCmseNonSecureCall - | CCmseNonSecureEntry - | Custom + | RustInvalid | Unadjusted => false, Rust | RustCall | RustCold => tcx.sess.panic_strategy() == PanicStrategy::Unwind, } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 97408e31854..84b21fee92f 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -75,8 +75,8 @@ pub use self::closure::{ place_to_string_for_capture, }; pub use self::consts::{ - AnonConstKind, AtomicOrdering, Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, - UnevaluatedConst, ValTree, ValTreeKind, Value, + AnonConstKind, AtomicOrdering, Const, ConstInt, ConstKind, ConstToValTreeResult, Expr, + ExprKind, ScalarInt, UnevaluatedConst, ValTree, ValTreeKind, Value, }; pub use self::context::{ CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt, @@ -652,6 +652,13 @@ impl<'tcx> Term<'tcx> { } } + pub fn is_trivially_wf(&self, tcx: TyCtxt<'tcx>) -> bool { + match self.kind() { + TermKind::Ty(ty) => ty.is_trivially_wf(tcx), + TermKind::Const(ct) => ct.is_trivially_wf(), + } + } + /// Iterator that walks `self` and any types reachable from /// `self`, in depth-first order. Note that just walks the types /// that appear in `self`, it does not descend into the fields of @@ -907,30 +914,6 @@ pub struct Placeholder<T> { pub universe: UniverseIndex, pub bound: T, } -impl Placeholder<BoundVar> { - pub fn find_const_ty_from_env<'tcx>(self, env: ParamEnv<'tcx>) -> Ty<'tcx> { - let mut candidates = env.caller_bounds().iter().filter_map(|clause| { - // `ConstArgHasType` are never desugared to be higher ranked. - match clause.kind().skip_binder() { - ty::ClauseKind::ConstArgHasType(placeholder_ct, ty) => { - assert!(!(placeholder_ct, ty).has_escaping_bound_vars()); - - match placeholder_ct.kind() { - ty::ConstKind::Placeholder(placeholder_ct) if placeholder_ct == self => { - Some(ty) - } - _ => None, - } - } - _ => None, - } - }); - - let ty = candidates.next().unwrap(); - assert!(candidates.next().is_none()); - ty - } -} pub type PlaceholderRegion = Placeholder<BoundRegion>; @@ -2156,7 +2139,7 @@ impl<'tcx> TyCtxt<'tcx> { }, DefKind::Closure => { // Closures and RPITs will eventually have const conditions - // for `~const` bounds. + // for `[const]` bounds. false } DefKind::Ctor(_, CtorKind::Const) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index c10277c75a7..b4c4f48a0a6 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -810,7 +810,6 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } match repr { ty::Dyn => p!("dyn "), - ty::DynStar => p!("dyn* "), } p!(print(data)); if print_r { @@ -1755,7 +1754,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ) -> Result<(), PrintError> { define_scoped_cx!(self); - let (prov, offset) = ptr.into_parts(); + let (prov, offset) = ptr.prov_and_relative_offset(); match ty.kind() { // Byte strings (&[u8; N]) ty::Ref(_, inner, _) => { @@ -2077,7 +2076,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { p!("const "); } ty::BoundConstness::Maybe => { - p!("~const "); + p!("[const] "); } } Ok(()) @@ -3250,7 +3249,7 @@ define_print! { ty::HostEffectPredicate<'tcx> { let constness = match self.constness { ty::BoundConstness::Const => { "const" } - ty::BoundConstness::Maybe => { "~const" } + ty::BoundConstness::Maybe => { "[const]" } }; p!(print(self.trait_ref.self_ty()), ": {constness} "); p!(print(self.trait_ref.print_trait_sugared())) diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 000ba7b6fa7..1214731a3b2 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -230,9 +230,9 @@ TrivialLiftImpls! { usize, u64, // tidy-alphabetical-start + crate::mir::Promoted, crate::mir::interpret::AllocId, crate::mir::interpret::Scalar, - crate::mir::Promoted, rustc_abi::ExternAbi, rustc_abi::Size, rustc_hir::Safety, @@ -267,9 +267,6 @@ TrivialTypeTraversalImpls! { crate::mir::SwitchTargets, crate::traits::IsConstable, crate::traits::OverflowError, - crate::ty::abstract_const::NotConstEvaluatable, - crate::ty::adjustment::AutoBorrowMutability, - crate::ty::adjustment::PointerCoercion, crate::ty::AdtKind, crate::ty::AssocItem, crate::ty::AssocKind, @@ -281,15 +278,18 @@ TrivialTypeTraversalImpls! { crate::ty::Placeholder<ty::BoundVar>, crate::ty::UserTypeAnnotationIndex, crate::ty::ValTree<'tcx>, + crate::ty::abstract_const::NotConstEvaluatable, + crate::ty::adjustment::AutoBorrowMutability, + crate::ty::adjustment::PointerCoercion, rustc_abi::FieldIdx, rustc_abi::VariantIdx, rustc_ast::InlineAsmOptions, rustc_ast::InlineAsmTemplatePiece, rustc_hir::CoroutineKind, - rustc_hir::def_id::LocalDefId, rustc_hir::HirId, rustc_hir::MatchSource, rustc_hir::RangeEnd, + rustc_hir::def_id::LocalDefId, rustc_span::Ident, rustc_span::Span, rustc_span::Symbol, @@ -303,9 +303,9 @@ TrivialTypeTraversalImpls! { // interners). TrivialTypeTraversalAndLiftImpls! { // tidy-alphabetical-start - crate::ty::instance::ReifyReason, crate::ty::ParamConst, crate::ty::ParamTy, + crate::ty::instance::ReifyReason, rustc_hir::def_id::DefId, // tidy-alphabetical-end } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 58829f72a72..399a6d6ebc5 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -346,7 +346,7 @@ impl ParamConst { } #[instrument(level = "debug")] - pub fn find_ty_from_env<'tcx>(self, env: ParamEnv<'tcx>) -> Ty<'tcx> { + pub fn find_const_ty_from_env<'tcx>(self, env: ParamEnv<'tcx>) -> Ty<'tcx> { let mut candidates = env.caller_bounds().iter().filter_map(|clause| { // `ConstArgHasType` are never desugared to be higher ranked. match clause.kind().skip_binder() { @@ -362,8 +362,19 @@ impl ParamConst { } }); - let ty = candidates.next().unwrap(); - assert!(candidates.next().is_none()); + // N.B. it may be tempting to fix ICEs by making this function return + // `Option<Ty<'tcx>>` instead of `Ty<'tcx>`; however, this is generally + // considered to be a bandaid solution, since it hides more important + // underlying issues with how we construct generics and predicates of + // items. It's advised to fix the underlying issue rather than trying + // to modify this function. + let ty = candidates.next().unwrap_or_else(|| { + bug!("cannot find `{self:?}` in param-env: {env:#?}"); + }); + assert!( + candidates.next().is_none(), + "did not expect duplicate `ConstParamHasTy` for `{self:?}` in param-env: {env:#?}" + ); ty } } @@ -1311,11 +1322,6 @@ impl<'tcx> Ty<'tcx> { } #[inline] - pub fn is_dyn_star(self) -> bool { - matches!(self.kind(), Dynamic(_, _, ty::DynStar)) - } - - #[inline] pub fn is_enum(self) -> bool { matches!(self.kind(), Adt(adt_def, _) if adt_def.is_enum()) } @@ -1618,8 +1624,6 @@ impl<'tcx> Ty<'tcx> { | ty::Error(_) // Extern types have metadata = (). | ty::Foreign(..) - // `dyn*` has metadata = (). - | ty::Dynamic(_, _, ty::DynStar) // If returned by `struct_tail_raw` this is a unit struct // without any fields, or not a struct, and therefore is Sized. | ty::Adt(..) @@ -1809,8 +1813,7 @@ impl<'tcx> Ty<'tcx> { | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Never - | ty::Error(_) - | ty::Dynamic(_, _, ty::DynStar) => true, + | ty::Error(_) => true, ty::Str | ty::Slice(_) | ty::Dynamic(_, _, ty::Dyn) => match sizedness { SizedTraitKind::Sized => false, @@ -1832,7 +1835,7 @@ impl<'tcx> Ty<'tcx> { ty::Infer(ty::TyVar(_)) => false, ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { - bug!("`is_trivially_sized` applied to unexpected type: {:?}", self) + bug!("`has_trivial_sizedness` applied to unexpected type: {:?}", self) } } } @@ -1896,6 +1899,52 @@ impl<'tcx> Ty<'tcx> { } } + pub fn is_trivially_wf(self, tcx: TyCtxt<'tcx>) -> bool { + match *self.kind() { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Str + | ty::Never + | ty::Param(_) + | ty::Placeholder(_) + | ty::Bound(..) => true, + + ty::Slice(ty) => { + ty.is_trivially_wf(tcx) && ty.has_trivial_sizedness(tcx, SizedTraitKind::Sized) + } + ty::RawPtr(ty, _) => ty.is_trivially_wf(tcx), + + ty::FnPtr(sig_tys, _) => { + sig_tys.skip_binder().inputs_and_output.iter().all(|ty| ty.is_trivially_wf(tcx)) + } + ty::Ref(_, ty, _) => ty.is_global() && ty.is_trivially_wf(tcx), + + ty::Infer(infer) => match infer { + ty::TyVar(_) => false, + ty::IntVar(_) | ty::FloatVar(_) => true, + ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => true, + }, + + ty::Adt(_, _) + | ty::Tuple(_) + | ty::Array(..) + | ty::Foreign(_) + | ty::Pat(_, _) + | ty::FnDef(..) + | ty::UnsafeBinder(..) + | ty::Dynamic(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) + | ty::CoroutineWitness(..) + | ty::Alias(..) + | ty::Error(_) => false, + } + } + /// If `self` is a primitive, return its [`Symbol`]. pub fn primitive_symbol(self) -> Option<Symbol> { match self.kind() { diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 51f57e71ce9..69b8be3d9cb 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -768,6 +768,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn def_kind_descr(self, def_kind: DefKind, def_id: DefId) -> &'static str { match def_kind { DefKind::AssocFn if self.associated_item(def_id).is_method() => "method", + DefKind::AssocTy if self.opt_rpitit_info(def_id).is_some() => "opaque type", DefKind::Closure if let Some(coroutine_kind) = self.coroutine_kind(def_id) => { match coroutine_kind { hir::CoroutineKind::Desugared( diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml index 1534865cdd3..c4c2d8a7ac8 100644 --- a/compiler/rustc_mir_build/Cargo.toml +++ b/compiler/rustc_mir_build/Cargo.toml @@ -11,6 +11,7 @@ rustc_abi = { path = "../rustc_abi" } rustc_apfloat = "0.2.0" rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } +rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index fae159103e7..e339520cd86 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -84,6 +84,15 @@ mir_build_call_to_unsafe_fn_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = mir_build_confused = missing patterns are not covered because `{$variable}` is interpreted as a constant pattern, not a new variable +mir_build_const_continue_bad_const = could not determine the target branch for this `#[const_continue]` + .label = this value is too generic + .note = the value must be a literal or a monomorphic const + +mir_build_const_continue_missing_value = a `#[const_continue]` must break to a label with a value + +mir_build_const_continue_unknown_jump_target = the target of this `#[const_continue]` is not statically known + .label = this value must be a literal or a monomorphic const + mir_build_const_defined_here = constant defined here mir_build_const_param_in_pattern = constant parameters cannot be referenced in patterns @@ -212,6 +221,30 @@ mir_build_literal_in_range_out_of_bounds = literal out of range for `{$ty}` .label = this value does not fit into the type `{$ty}` whose range is `{$min}..={$max}` +mir_build_loop_match_arm_with_guard = + match arms that are part of a `#[loop_match]` cannot have guards + +mir_build_loop_match_bad_rhs = + this expression must be a single `match` wrapped in a labeled block + +mir_build_loop_match_bad_statements = + statements are not allowed in this position within a `#[loop_match]` + +mir_build_loop_match_invalid_match = + invalid match on `#[loop_match]` state + .note = a local variable must be the scrutinee within a `#[loop_match]` + +mir_build_loop_match_invalid_update = + invalid update of the `#[loop_match]` state + .label = the assignment must update this variable + +mir_build_loop_match_missing_assignment = + expected a single assignment expression + +mir_build_loop_match_unsupported_type = + this `#[loop_match]` state value has type `{$ty}`, which is not supported + .note = only integers, floats, bool, char, and enums without fields are supported + mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper = lower range bound must be less than or equal to upper .label = lower bound larger than upper bound diff --git a/compiler/rustc_mir_build/src/builder/cfg.rs b/compiler/rustc_mir_build/src/builder/cfg.rs index 082cdc2e2a4..2faccc43247 100644 --- a/compiler/rustc_mir_build/src/builder/cfg.rs +++ b/compiler/rustc_mir_build/src/builder/cfg.rs @@ -42,7 +42,7 @@ impl<'tcx> CFG<'tcx> { ) { self.push( block, - Statement { source_info, kind: StatementKind::Assign(Box::new((place, rvalue))) }, + Statement::new(source_info, StatementKind::Assign(Box::new((place, rvalue)))), ); } @@ -88,7 +88,7 @@ impl<'tcx> CFG<'tcx> { place: Place<'tcx>, ) { let kind = StatementKind::FakeRead(Box::new((cause, place))); - let stmt = Statement { source_info, kind }; + let stmt = Statement::new(source_info, kind); self.push(block, stmt); } @@ -99,7 +99,7 @@ impl<'tcx> CFG<'tcx> { place: Place<'tcx>, ) { let kind = StatementKind::PlaceMention(Box::new(place)); - let stmt = Statement { source_info, kind }; + let stmt = Statement::new(source_info, kind); self.push(block, stmt); } @@ -110,7 +110,7 @@ impl<'tcx> CFG<'tcx> { /// syntax (e.g. `continue` or `if !`) that would otherwise not appear in MIR. pub(crate) fn push_coverage_span_marker(&mut self, block: BasicBlock, source_info: SourceInfo) { let kind = StatementKind::Coverage(coverage::CoverageKind::SpanMarker); - let stmt = Statement { source_info, kind }; + let stmt = Statement::new(source_info, kind); self.push(block, stmt); } diff --git a/compiler/rustc_mir_build/src/builder/coverageinfo.rs b/compiler/rustc_mir_build/src/builder/coverageinfo.rs index a80bd4f3c80..aa43b273cff 100644 --- a/compiler/rustc_mir_build/src/builder/coverageinfo.rs +++ b/compiler/rustc_mir_build/src/builder/coverageinfo.rs @@ -61,10 +61,10 @@ impl BlockMarkerGen { block: BasicBlock, ) -> BlockMarkerId { let id = self.next_block_marker_id(); - let marker_statement = mir::Statement { + let marker_statement = mir::Statement::new( source_info, - kind: mir::StatementKind::Coverage(CoverageKind::BlockMarker { id }), - }; + mir::StatementKind::Coverage(CoverageKind::BlockMarker { id }), + ); cfg.push(block, marker_statement); id diff --git a/compiler/rustc_mir_build/src/builder/custom/parse.rs b/compiler/rustc_mir_build/src/builder/custom/parse.rs index 91e284604b6..10154461c33 100644 --- a/compiler/rustc_mir_build/src/builder/custom/parse.rs +++ b/compiler/rustc_mir_build/src/builder/custom/parse.rs @@ -315,10 +315,8 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { let stmt = self.statement_as_expr(*stmt_id)?; let span = self.thir[stmt].span; let statement = self.parse_statement(stmt)?; - data.statements.push(Statement { - source_info: SourceInfo { span, scope: self.source_scope }, - kind: statement, - }); + data.statements + .push(Statement::new(SourceInfo { span, scope: self.source_scope }, statement)); } let Some(trailing) = block.expr else { return Err(self.expr_error(expr_id, "terminator")) }; diff --git a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs index eb8e98ec364..d0d0c21463f 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs @@ -49,7 +49,7 @@ pub(crate) fn as_constant_inner<'tcx>( let Expr { ty, temp_lifetime: _, span, ref kind } = *expr; match *kind { ExprKind::Literal { lit, neg } => { - let const_ = lit_to_mir_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg }); + let const_ = lit_to_mir_constant(tcx, LitToConstInput { lit: lit.node, ty, neg }); ConstOperand { span, user_ty: None, const_ } } @@ -128,34 +128,35 @@ fn lit_to_mir_constant<'tcx>(tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx> (ast::LitKind::ByteStr(data, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Slice(_)) => { - let allocation = Allocation::from_bytes_byte_aligned_immutable(data as &[u8], ()); + let allocation = Allocation::from_bytes_byte_aligned_immutable(data.as_byte_str(), ()); let allocation = tcx.mk_const_alloc(allocation); ConstValue::Slice { data: allocation, meta: allocation.inner().size().bytes() } } - (ast::LitKind::ByteStr(data, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => { - let id = tcx.allocate_bytes_dedup(data, CTFE_ALLOC_SALT); + (ast::LitKind::ByteStr(byte_sym, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => { + let id = tcx.allocate_bytes_dedup(byte_sym.as_byte_str(), CTFE_ALLOC_SALT); ConstValue::Scalar(Scalar::from_pointer(id.into(), &tcx)) } - (ast::LitKind::CStr(data, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::CStr)) => + (ast::LitKind::CStr(byte_sym, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::CStr)) => { - let allocation = Allocation::from_bytes_byte_aligned_immutable(data as &[u8], ()); + let allocation = + Allocation::from_bytes_byte_aligned_immutable(byte_sym.as_byte_str(), ()); let allocation = tcx.mk_const_alloc(allocation); ConstValue::Slice { data: allocation, meta: allocation.inner().size().bytes() } } (ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => { - ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1))) + ConstValue::Scalar(Scalar::from_uint(n, Size::from_bytes(1))) } (ast::LitKind::Int(n, _), ty::Uint(_)) if !neg => trunc(n.get()), (ast::LitKind::Int(n, _), ty::Int(_)) => { trunc(if neg { (n.get() as i128).overflowing_neg().0 as u128 } else { n.get() }) } (ast::LitKind::Float(n, _), ty::Float(fty)) => { - parse_float_into_constval(*n, *fty, neg).unwrap() + parse_float_into_constval(n, *fty, neg).unwrap() } - (ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)), - (ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)), + (ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(b)), + (ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(c)), (ast::LitKind::Err(guar), _) => { - return Const::Ty(Ty::new_error(tcx, *guar), ty::Const::new_error(tcx, *guar)); + return Const::Ty(Ty::new_error(tcx, guar), ty::Const::new_error(tcx, guar)); } _ => bug!("invalid lit/ty combination in `lit_to_mir_constant`: {lit:?}: {ty:?}"), }; diff --git a/compiler/rustc_mir_build/src/builder/expr/as_place.rs b/compiler/rustc_mir_build/src/builder/expr/as_place.rs index f8c64d7d13e..7c851ec465b 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_place.rs @@ -489,16 +489,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let place = place_builder.to_place(this); this.cfg.push( block, - Statement { - source_info: ty_source_info, - kind: StatementKind::AscribeUserType( + Statement::new( + ty_source_info, + StatementKind::AscribeUserType( Box::new(( place, UserTypeProjection { base: annotation_index, projs: vec![] }, )), Variance::Invariant, ), - }, + ), ); } block.and(place_builder) @@ -518,16 +518,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }); this.cfg.push( block, - Statement { - source_info: ty_source_info, - kind: StatementKind::AscribeUserType( + Statement::new( + ty_source_info, + StatementKind::AscribeUserType( Box::new(( Place::from(temp), UserTypeProjection { base: annotation_index, projs: vec![] }, )), Variance::Invariant, ), - }, + ), ); } block.and(PlaceBuilder::from(temp)) @@ -565,12 +565,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | ExprKind::Match { .. } | ExprKind::If { .. } | ExprKind::Loop { .. } + | ExprKind::LoopMatch { .. } | ExprKind::Block { .. } | ExprKind::Let { .. } | ExprKind::Assign { .. } | ExprKind::AssignOp { .. } | ExprKind::Break { .. } | ExprKind::Continue { .. } + | ExprKind::ConstContinue { .. } | ExprKind::Return { .. } | ExprKind::Become { .. } | ExprKind::Literal { .. } diff --git a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs index b23bc089cd4..975226bb642 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs @@ -175,10 +175,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // and therefore is not considered during coroutine auto-trait // determination. See the comment about `box` at `yield_in_scope`. let result = this.local_decls.push(LocalDecl::new(expr.ty, expr_span)); - this.cfg.push( - block, - Statement { source_info, kind: StatementKind::StorageLive(result) }, - ); + this.cfg + .push(block, Statement::new(source_info, StatementKind::StorageLive(result))); if let Some(scope) = scope.temp_lifetime { // schedule a shallow free of that memory, lest we unwind: this.schedule_drop_storage_and_value(expr_span, scope, result); @@ -278,12 +276,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; this.cfg.push( block, - Statement { + Statement::new( source_info, - kind: StatementKind::Intrinsic(Box::new( - NonDivergingIntrinsic::Assume(Operand::Move(assert_place)), - )), - }, + StatementKind::Intrinsic(Box::new(NonDivergingIntrinsic::Assume( + Operand::Move(assert_place), + ))), + ), ); } @@ -538,6 +536,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | ExprKind::RawBorrow { .. } | ExprKind::Adt { .. } | ExprKind::Loop { .. } + | ExprKind::LoopMatch { .. } | ExprKind::LogicalOp { .. } | ExprKind::Call { .. } | ExprKind::Field { .. } @@ -548,6 +547,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | ExprKind::UpvarRef { .. } | ExprKind::Break { .. } | ExprKind::Continue { .. } + | ExprKind::ConstContinue { .. } | ExprKind::Return { .. } | ExprKind::Become { .. } | ExprKind::InlineAsm { .. } @@ -787,7 +787,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let source_info = this.source_info(upvar_span); let temp = this.local_decls.push(LocalDecl::new(upvar_ty, upvar_span)); - this.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(temp) }); + this.cfg.push(block, Statement::new(source_info, StatementKind::StorageLive(temp))); let arg_place_builder = unpack!(block = this.as_place_builder(block, arg)); diff --git a/compiler/rustc_mir_build/src/builder/expr/as_temp.rs b/compiler/rustc_mir_build/src/builder/expr/as_temp.rs index 0bd61168fba..b0ce3527d8b 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_temp.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_temp.rs @@ -102,8 +102,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if let Block { expr: None, targeted_by_break: false, .. } = this.thir[block] && expr_ty.is_never() => {} _ => { - this.cfg - .push(block, Statement { source_info, kind: StatementKind::StorageLive(temp) }); + this.cfg.push(block, Statement::new(source_info, StatementKind::StorageLive(temp))); // In constants, `temp_lifetime` is `None` for temporaries that // live for the `'static` lifetime. Thus we do not drop these diff --git a/compiler/rustc_mir_build/src/builder/expr/category.rs b/compiler/rustc_mir_build/src/builder/expr/category.rs index 34524aed406..5e4219dbf5b 100644 --- a/compiler/rustc_mir_build/src/builder/expr/category.rs +++ b/compiler/rustc_mir_build/src/builder/expr/category.rs @@ -83,9 +83,11 @@ impl Category { | ExprKind::NamedConst { .. } => Some(Category::Constant), ExprKind::Loop { .. } + | ExprKind::LoopMatch { .. } | ExprKind::Block { .. } | ExprKind::Break { .. } | ExprKind::Continue { .. } + | ExprKind::ConstContinue { .. } | ExprKind::Return { .. } | ExprKind::Become { .. } => // FIXME(#27840) these probably want their own diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs index 2074fbce0ae..fe3d072fa88 100644 --- a/compiler/rustc_mir_build/src/builder/expr/into.rs +++ b/compiler/rustc_mir_build/src/builder/expr/into.rs @@ -8,15 +8,16 @@ use rustc_hir::lang_items::LangItem; use rustc_middle::mir::*; use rustc_middle::span_bug; use rustc_middle::thir::*; -use rustc_middle::ty::{CanonicalUserTypeAnnotation, Ty}; +use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty}; use rustc_span::DUMMY_SP; use rustc_span::source_map::Spanned; use rustc_trait_selection::infer::InferCtxtExt; use tracing::{debug, instrument}; use crate::builder::expr::category::{Category, RvalueFunc}; -use crate::builder::matches::DeclareLetBindings; +use crate::builder::matches::{DeclareLetBindings, HasMatchGuard}; use crate::builder::{BlockAnd, BlockAndExtension, BlockFrame, Builder, NeedsTemporary}; +use crate::errors::{LoopMatchArmWithGuard, LoopMatchUnsupportedType}; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Compile `expr`, storing the result into `destination`, which @@ -244,6 +245,122 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None }) } + ExprKind::LoopMatch { state, region_scope, match_span, ref arms } => { + // Intuitively, this is a combination of a loop containing a labeled block + // containing a match. + // + // The only new bit here is that the lowering of the match is wrapped in a + // `in_const_continuable_scope`, which makes the match arms and their target basic + // block available to the lowering of `#[const_continue]`. + + fn is_supported_loop_match_type(ty: Ty<'_>) -> bool { + match ty.kind() { + ty::Uint(_) | ty::Int(_) | ty::Float(_) | ty::Bool | ty::Char => true, + ty::Adt(adt_def, _) => match adt_def.adt_kind() { + ty::AdtKind::Struct | ty::AdtKind::Union => false, + ty::AdtKind::Enum => { + adt_def.variants().iter().all(|v| v.fields.is_empty()) + } + }, + _ => false, + } + } + + let state_ty = this.thir.exprs[state].ty; + if !is_supported_loop_match_type(state_ty) { + let span = this.thir.exprs[state].span; + this.tcx.dcx().emit_fatal(LoopMatchUnsupportedType { span, ty: state_ty }) + } + + let loop_block = this.cfg.start_new_block(); + + // Start the loop. + this.cfg.goto(block, source_info, loop_block); + + this.in_breakable_scope(Some(loop_block), destination, expr_span, |this| { + // Logic for `loop`. + let mut body_block = this.cfg.start_new_block(); + this.cfg.terminate( + loop_block, + source_info, + TerminatorKind::FalseUnwind { + real_target: body_block, + unwind: UnwindAction::Continue, + }, + ); + this.diverge_from(loop_block); + + // Logic for `match`. + let scrutinee_place_builder = + unpack!(body_block = this.as_place_builder(body_block, state)); + let scrutinee_span = this.thir.exprs[state].span; + let match_start_span = match_span.shrink_to_lo().to(scrutinee_span); + + let mut patterns = Vec::with_capacity(arms.len()); + for &arm_id in arms.iter() { + let arm = &this.thir[arm_id]; + + if let Some(guard) = arm.guard { + let span = this.thir.exprs[guard].span; + this.tcx.dcx().emit_fatal(LoopMatchArmWithGuard { span }) + } + + patterns.push((&*arm.pattern, HasMatchGuard::No)); + } + + // The `built_tree` maps match arms to their basic block (where control flow + // jumps to when a value matches the arm). This structure is stored so that a + // `#[const_continue]` can figure out what basic block to jump to. + let built_tree = this.lower_match_tree( + body_block, + scrutinee_span, + &scrutinee_place_builder, + match_start_span, + patterns, + false, + ); + + let state_place = scrutinee_place_builder.to_place(this); + + // This is logic for the labeled block: a block is a drop scope, hence + // `in_scope`, and a labeled block can be broken out of with a `break 'label`, + // hence the `in_breakable_scope`. + // + // Then `in_const_continuable_scope` stores information for the lowering of + // `#[const_continue]`, and finally the match is lowered in the standard way. + unpack!( + body_block = this.in_scope( + (region_scope, source_info), + LintLevel::Inherited, + move |this| { + this.in_breakable_scope(None, state_place, expr_span, |this| { + Some(this.in_const_continuable_scope( + arms.clone(), + built_tree.clone(), + state_place, + expr_span, + |this| { + this.lower_match_arms( + destination, + scrutinee_place_builder, + scrutinee_span, + arms, + built_tree, + this.source_info(match_span), + ) + }, + )) + }) + } + ) + ); + + this.cfg.goto(body_block, source_info, loop_block); + + // Loops are only exited by `break` expressions. + None + }) + } ExprKind::Call { ty: _, fun, ref args, from_hir_call, fn_span } => { let fun = unpack!(block = this.as_local_operand(block, fun)); let args: Box<[_]> = args @@ -601,6 +718,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } ExprKind::Continue { .. } + | ExprKind::ConstContinue { .. } | ExprKind::Break { .. } | ExprKind::Return { .. } | ExprKind::Become { .. } => { diff --git a/compiler/rustc_mir_build/src/builder/expr/stmt.rs b/compiler/rustc_mir_build/src/builder/expr/stmt.rs index 2dff26f02f3..675beceea14 100644 --- a/compiler/rustc_mir_build/src/builder/expr/stmt.rs +++ b/compiler/rustc_mir_build/src/builder/expr/stmt.rs @@ -98,6 +98,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ExprKind::Break { label, value } => { this.break_scope(block, value, BreakableTarget::Break(label), source_info) } + ExprKind::ConstContinue { label, value } => { + this.break_const_continuable_scope(block, value, label, source_info) + } ExprKind::Return { value } => { this.break_scope(block, value, BreakableTarget::Return, source_info) } diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 977d4f3e931..9600067a85f 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -18,7 +18,9 @@ use rustc_middle::bug; use rustc_middle::middle::region; use rustc_middle::mir::{self, *}; use rustc_middle::thir::{self, *}; -use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty}; +use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, ValTree, ValTreeKind}; +use rustc_pattern_analysis::constructor::RangeEnd; +use rustc_pattern_analysis::rustc::{DeconstructedPat, RustcPatCtxt}; use rustc_span::{BytePos, Pos, Span, Symbol, sym}; use tracing::{debug, instrument}; @@ -426,7 +428,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// (by [Builder::lower_match_tree]). /// /// `outer_source_info` is the SourceInfo for the whole match. - fn lower_match_arms( + pub(crate) fn lower_match_arms( &mut self, destination: Place<'tcx>, scrutinee_place_builder: PlaceBuilder<'tcx>, @@ -644,9 +646,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let base = self.canonical_user_type_annotations.push(annotation.clone()); self.cfg.push( block, - Statement { - source_info: ty_source_info, - kind: StatementKind::AscribeUserType( + Statement::new( + ty_source_info, + StatementKind::AscribeUserType( Box::new((place, UserTypeProjection { base, projs: Vec::new() })), // We always use invariant as the variance here. This is because the // variance field from the ascription refers to the variance to use @@ -664,7 +666,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // `<expr>`. ty::Invariant, ), - }, + ), ); self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard); @@ -826,7 +828,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) -> Place<'tcx> { let local_id = self.var_local_id(var, for_guard); let source_info = self.source_info(span); - self.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(local_id) }); + self.cfg.push(block, Statement::new(source_info, StatementKind::StorageLive(local_id))); // Although there is almost always scope for given variable in corner cases // like #92893 we might get variable with no scope. if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id) @@ -1395,7 +1397,7 @@ pub(crate) struct ArmHasGuard(pub(crate) bool); /// A sub-branch in the output of match lowering. Match lowering has generated MIR code that will /// branch to `success_block` when the matched value matches the corresponding pattern. If there is /// a guard, its failure must continue to `otherwise_block`, which will resume testing patterns. -#[derive(Debug)] +#[derive(Debug, Clone)] struct MatchTreeSubBranch<'tcx> { span: Span, /// The block that is branched to if the corresponding subpattern matches. @@ -1411,7 +1413,7 @@ struct MatchTreeSubBranch<'tcx> { } /// A branch in the output of match lowering. -#[derive(Debug)] +#[derive(Debug, Clone)] struct MatchTreeBranch<'tcx> { sub_branches: Vec<MatchTreeSubBranch<'tcx>>, } @@ -1430,8 +1432,8 @@ struct MatchTreeBranch<'tcx> { /// Here the first arm gives the first `MatchTreeBranch`, which has two sub-branches, one for each /// alternative of the or-pattern. They are kept separate because each needs to bind `x` to a /// different place. -#[derive(Debug)] -struct BuiltMatchTree<'tcx> { +#[derive(Debug, Clone)] +pub(crate) struct BuiltMatchTree<'tcx> { branches: Vec<MatchTreeBranch<'tcx>>, otherwise_block: BasicBlock, /// If any of the branches had a guard, we collect here the places and locals to fakely borrow @@ -1489,7 +1491,7 @@ impl<'tcx> MatchTreeBranch<'tcx> { } #[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum HasMatchGuard { +pub(crate) enum HasMatchGuard { Yes, No, } @@ -1504,7 +1506,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// `refutable` indicates whether the candidate list is refutable (for `if let` and `let else`) /// or not (for `let` and `match`). In the refutable case we return the block to which we branch /// on failure. - fn lower_match_tree( + pub(crate) fn lower_match_tree( &mut self, block: BasicBlock, scrutinee_span: Span, @@ -1890,7 +1892,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { debug!("expanding or-pattern: candidate={:#?}\npats={:#?}", candidate, pats); candidate.or_span = Some(match_pair.pattern_span); candidate.subcandidates = pats - .into_vec() .into_iter() .map(|flat_pat| Candidate::from_flat_pat(flat_pat, candidate.has_guard)) .collect(); @@ -2577,16 +2578,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let base = self.canonical_user_type_annotations.push(ascription.annotation); self.cfg.push( block, - Statement { + Statement::new( source_info, - kind: StatementKind::AscribeUserType( + StatementKind::AscribeUserType( Box::new(( ascription.source, UserTypeProjection { base, projs: Vec::new() }, )), ascription.variance, ), - }, + ), ); } } @@ -2864,4 +2865,129 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { true } + + /// Attempt to statically pick the `BasicBlock` that a value would resolve to at runtime. + pub(crate) fn static_pattern_match( + &self, + cx: &RustcPatCtxt<'_, 'tcx>, + valtree: ValTree<'tcx>, + arms: &[ArmId], + built_match_tree: &BuiltMatchTree<'tcx>, + ) -> Option<BasicBlock> { + let it = arms.iter().zip(built_match_tree.branches.iter()); + for (&arm_id, branch) in it { + let pat = cx.lower_pat(&*self.thir.arms[arm_id].pattern); + + // Peel off or-patterns if they exist. + if let rustc_pattern_analysis::rustc::Constructor::Or = pat.ctor() { + for pat in pat.iter_fields() { + // For top-level or-patterns (the only ones we accept right now), when the + // bindings are the same (e.g. there are none), the sub_branch is stored just + // once. + let sub_branch = branch + .sub_branches + .get(pat.idx) + .or_else(|| branch.sub_branches.last()) + .unwrap(); + + match self.static_pattern_match_inner(valtree, &pat.pat) { + true => return Some(sub_branch.success_block), + false => continue, + } + } + } else if self.static_pattern_match_inner(valtree, &pat) { + return Some(branch.sub_branches[0].success_block); + } + } + + None + } + + /// Helper for [`Self::static_pattern_match`], checking whether the value represented by the + /// `ValTree` matches the given pattern. This function does not recurse, meaning that it does + /// not handle or-patterns, or patterns for types with fields. + fn static_pattern_match_inner( + &self, + valtree: ty::ValTree<'tcx>, + pat: &DeconstructedPat<'_, 'tcx>, + ) -> bool { + use rustc_pattern_analysis::constructor::{IntRange, MaybeInfiniteInt}; + use rustc_pattern_analysis::rustc::Constructor; + + match pat.ctor() { + Constructor::Variant(variant_index) => { + let ValTreeKind::Branch(box [actual_variant_idx]) = *valtree else { + bug!("malformed valtree for an enum") + }; + + let ValTreeKind::Leaf(actual_variant_idx) = ***actual_variant_idx else { + bug!("malformed valtree for an enum") + }; + + *variant_index == VariantIdx::from_u32(actual_variant_idx.to_u32()) + } + Constructor::IntRange(int_range) => { + let size = pat.ty().primitive_size(self.tcx); + let actual_int = valtree.unwrap_leaf().to_bits(size); + let actual_int = if pat.ty().is_signed() { + MaybeInfiniteInt::new_finite_int(actual_int, size.bits()) + } else { + MaybeInfiniteInt::new_finite_uint(actual_int) + }; + IntRange::from_singleton(actual_int).is_subrange(int_range) + } + Constructor::Bool(pattern_value) => match valtree.unwrap_leaf().try_to_bool() { + Ok(actual_value) => *pattern_value == actual_value, + Err(()) => bug!("bool value with invalid bits"), + }, + Constructor::F16Range(l, h, end) => { + let actual = valtree.unwrap_leaf().to_f16(); + match end { + RangeEnd::Included => (*l..=*h).contains(&actual), + RangeEnd::Excluded => (*l..*h).contains(&actual), + } + } + Constructor::F32Range(l, h, end) => { + let actual = valtree.unwrap_leaf().to_f32(); + match end { + RangeEnd::Included => (*l..=*h).contains(&actual), + RangeEnd::Excluded => (*l..*h).contains(&actual), + } + } + Constructor::F64Range(l, h, end) => { + let actual = valtree.unwrap_leaf().to_f64(); + match end { + RangeEnd::Included => (*l..=*h).contains(&actual), + RangeEnd::Excluded => (*l..*h).contains(&actual), + } + } + Constructor::F128Range(l, h, end) => { + let actual = valtree.unwrap_leaf().to_f128(); + match end { + RangeEnd::Included => (*l..=*h).contains(&actual), + RangeEnd::Excluded => (*l..*h).contains(&actual), + } + } + Constructor::Wildcard => true, + + // These we may eventually support: + Constructor::Struct + | Constructor::Ref + | Constructor::DerefPattern(_) + | Constructor::Slice(_) + | Constructor::UnionField + | Constructor::Or + | Constructor::Str(_) => bug!("unsupported pattern constructor {:?}", pat.ctor()), + + // These should never occur here: + Constructor::Opaque(_) + | Constructor::Never + | Constructor::NonExhaustive + | Constructor::Hidden + | Constructor::Missing + | Constructor::PrivateUninhabited => { + bug!("unsupported pattern constructor {:?}", pat.ctor()) + } + } + } } diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs index 67988f1fcbc..405d47c7c79 100644 --- a/compiler/rustc_mir_build/src/builder/scope.rs +++ b/compiler/rustc_mir_build/src/builder/scope.rs @@ -83,20 +83,24 @@ that contains only loops and breakable blocks. It tracks where a `break`, use std::mem; +use interpret::ErrorHandled; use rustc_data_structures::fx::FxHashMap; use rustc_hir::HirId; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::middle::region; -use rustc_middle::mir::*; -use rustc_middle::thir::{ExprId, LintLevel}; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::mir::{self, *}; +use rustc_middle::thir::{AdtExpr, AdtExprBase, ArmId, ExprId, ExprKind, LintLevel}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, ValTree}; use rustc_middle::{bug, span_bug}; +use rustc_pattern_analysis::rustc::RustcPatCtxt; use rustc_session::lint::Level; use rustc_span::source_map::Spanned; use rustc_span::{DUMMY_SP, Span}; use tracing::{debug, instrument}; +use super::matches::BuiltMatchTree; use crate::builder::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG}; +use crate::errors::{ConstContinueBadConst, ConstContinueUnknownJumpTarget}; #[derive(Debug)] pub(crate) struct Scopes<'tcx> { @@ -105,6 +109,8 @@ pub(crate) struct Scopes<'tcx> { /// The current set of breakable scopes. See module comment for more details. breakable_scopes: Vec<BreakableScope<'tcx>>, + const_continuable_scopes: Vec<ConstContinuableScope<'tcx>>, + /// The scope of the innermost if-then currently being lowered. if_then_scope: Option<IfThenScope>, @@ -175,6 +181,20 @@ struct BreakableScope<'tcx> { } #[derive(Debug)] +struct ConstContinuableScope<'tcx> { + /// The scope for the `#[loop_match]` which its `#[const_continue]`s will jump to. + region_scope: region::Scope, + /// The place of the state of a `#[loop_match]`, which a `#[const_continue]` must update. + state_place: Place<'tcx>, + + arms: Box<[ArmId]>, + built_match_tree: BuiltMatchTree<'tcx>, + + /// Drops that happen on a `#[const_continue]` + const_continue_drops: DropTree, +} + +#[derive(Debug)] struct IfThenScope { /// The if-then scope or arm scope region_scope: region::Scope, @@ -411,13 +431,13 @@ impl DropTree { cfg.terminate(block, drop_node.data.source_info, terminator); } DropKind::ForLint => { - let stmt = Statement { - source_info: drop_node.data.source_info, - kind: StatementKind::BackwardIncompatibleDropHint { + let stmt = Statement::new( + drop_node.data.source_info, + StatementKind::BackwardIncompatibleDropHint { place: Box::new(drop_node.data.local.into()), reason: BackwardIncompatibleDropReason::Edition2024, }, - }; + ); cfg.push(block, stmt); let target = blocks[drop_node.next].unwrap(); if target != block { @@ -434,10 +454,10 @@ impl DropTree { // Root nodes don't correspond to a drop. DropKind::Storage if drop_idx == ROOT_NODE => {} DropKind::Storage => { - let stmt = Statement { - source_info: drop_node.data.source_info, - kind: StatementKind::StorageDead(drop_node.data.local), - }; + let stmt = Statement::new( + drop_node.data.source_info, + StatementKind::StorageDead(drop_node.data.local), + ); cfg.push(block, stmt); let target = blocks[drop_node.next].unwrap(); if target != block { @@ -461,6 +481,7 @@ impl<'tcx> Scopes<'tcx> { Self { scopes: Vec::new(), breakable_scopes: Vec::new(), + const_continuable_scopes: Vec::new(), if_then_scope: None, unwind_drops: DropTree::new(), coroutine_drops: DropTree::new(), @@ -552,6 +573,59 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } + /// Start a const-continuable scope, which tracks where `#[const_continue] break` should + /// branch to. + pub(crate) fn in_const_continuable_scope<F>( + &mut self, + arms: Box<[ArmId]>, + built_match_tree: BuiltMatchTree<'tcx>, + state_place: Place<'tcx>, + span: Span, + f: F, + ) -> BlockAnd<()> + where + F: FnOnce(&mut Builder<'a, 'tcx>) -> BlockAnd<()>, + { + let region_scope = self.scopes.topmost(); + let scope = ConstContinuableScope { + region_scope, + state_place, + const_continue_drops: DropTree::new(), + arms, + built_match_tree, + }; + self.scopes.const_continuable_scopes.push(scope); + let normal_exit_block = f(self); + let const_continue_scope = self.scopes.const_continuable_scopes.pop().unwrap(); + assert!(const_continue_scope.region_scope == region_scope); + + let break_block = self.build_exit_tree( + const_continue_scope.const_continue_drops, + region_scope, + span, + None, + ); + + match (normal_exit_block, break_block) { + (block, None) => block, + (normal_block, Some(exit_block)) => { + let target = self.cfg.start_new_block(); + let source_info = self.source_info(span); + self.cfg.terminate( + normal_block.into_block(), + source_info, + TerminatorKind::Goto { target }, + ); + self.cfg.terminate( + exit_block.into_block(), + source_info, + TerminatorKind::Goto { target }, + ); + target.unit() + } + } + } + /// Start an if-then scope which tracks drop for `if` expressions and `if` /// guards. /// @@ -742,6 +816,190 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.start_new_block().unit() } + /// Based on `FunctionCx::eval_unevaluated_mir_constant_to_valtree`. + fn eval_unevaluated_mir_constant_to_valtree( + &self, + constant: ConstOperand<'tcx>, + ) -> Result<(ty::ValTree<'tcx>, Ty<'tcx>), interpret::ErrorHandled> { + assert!(!constant.const_.ty().has_param()); + let (uv, ty) = match constant.const_ { + mir::Const::Unevaluated(uv, ty) => (uv.shrink(), ty), + mir::Const::Ty(_, c) => match c.kind() { + // A constant that came from a const generic but was then used as an argument to + // old-style simd_shuffle (passing as argument instead of as a generic param). + ty::ConstKind::Value(cv) => return Ok((cv.valtree, cv.ty)), + other => span_bug!(constant.span, "{other:#?}"), + }, + mir::Const::Val(mir::ConstValue::Scalar(mir::interpret::Scalar::Int(val)), ty) => { + return Ok((ValTree::from_scalar_int(self.tcx, val), ty)); + } + // We should never encounter `Const::Val` unless MIR opts (like const prop) evaluate + // a constant and write that value back into `Operand`s. This could happen, but is + // unlikely. Also: all users of `simd_shuffle` are on unstable and already need to take + // a lot of care around intrinsics. For an issue to happen here, it would require a + // macro expanding to a `simd_shuffle` call without wrapping the constant argument in a + // `const {}` block, but the user pass through arbitrary expressions. + + // FIXME(oli-obk): Replace the magic const generic argument of `simd_shuffle` with a + // real const generic, and get rid of this entire function. + other => span_bug!(constant.span, "{other:#?}"), + }; + + match self.tcx.const_eval_resolve_for_typeck(self.typing_env(), uv, constant.span) { + Ok(Ok(valtree)) => Ok((valtree, ty)), + Ok(Err(ty)) => span_bug!(constant.span, "could not convert {ty:?} to a valtree"), + Err(e) => Err(e), + } + } + + /// Sets up the drops for jumping from `block` to `scope`. + pub(crate) fn break_const_continuable_scope( + &mut self, + mut block: BasicBlock, + value: ExprId, + scope: region::Scope, + source_info: SourceInfo, + ) -> BlockAnd<()> { + let span = source_info.span; + + // A break can only break out of a scope, so the value should be a scope. + let rustc_middle::thir::ExprKind::Scope { value, .. } = self.thir[value].kind else { + span_bug!(span, "break value must be a scope") + }; + + let constant = match &self.thir[value].kind { + ExprKind::Adt(box AdtExpr { variant_index, fields, base, .. }) => { + assert!(matches!(base, AdtExprBase::None)); + assert!(fields.is_empty()); + ConstOperand { + span: self.thir[value].span, + user_ty: None, + const_: Const::Ty( + self.thir[value].ty, + ty::Const::new_value( + self.tcx, + ValTree::from_branches( + self.tcx, + [ValTree::from_scalar_int(self.tcx, variant_index.as_u32().into())], + ), + self.thir[value].ty, + ), + ), + } + } + _ => self.as_constant(&self.thir[value]), + }; + + let break_index = self + .scopes + .const_continuable_scopes + .iter() + .rposition(|const_continuable_scope| const_continuable_scope.region_scope == scope) + .unwrap_or_else(|| span_bug!(span, "no enclosing const-continuable scope found")); + + let scope = &self.scopes.const_continuable_scopes[break_index]; + + let state_decl = &self.local_decls[scope.state_place.as_local().unwrap()]; + let state_ty = state_decl.ty; + let (discriminant_ty, rvalue) = match state_ty.kind() { + ty::Adt(adt_def, _) if adt_def.is_enum() => { + (state_ty.discriminant_ty(self.tcx), Rvalue::Discriminant(scope.state_place)) + } + ty::Uint(_) | ty::Int(_) | ty::Float(_) | ty::Bool | ty::Char => { + (state_ty, Rvalue::Use(Operand::Copy(scope.state_place))) + } + _ => span_bug!(state_decl.source_info.span, "unsupported #[loop_match] state"), + }; + + // The `PatCtxt` is normally used in pattern exhaustiveness checking, but reused + // here because it performs normalization and const evaluation. + let dropless_arena = rustc_arena::DroplessArena::default(); + let typeck_results = self.tcx.typeck(self.def_id); + let cx = RustcPatCtxt { + tcx: self.tcx, + typeck_results, + module: self.tcx.parent_module(self.hir_id).to_def_id(), + // FIXME(#132279): We're in a body, should handle opaques. + typing_env: rustc_middle::ty::TypingEnv::non_body_analysis(self.tcx, self.def_id), + dropless_arena: &dropless_arena, + match_lint_level: self.hir_id, + whole_match_span: Some(rustc_span::Span::default()), + scrut_span: rustc_span::Span::default(), + refutable: true, + known_valid_scrutinee: true, + }; + + let valtree = match self.eval_unevaluated_mir_constant_to_valtree(constant) { + Ok((valtree, ty)) => { + // Defensively check that the type is monomorphic. + assert!(!ty.has_param()); + + valtree + } + Err(ErrorHandled::Reported(..)) => return self.cfg.start_new_block().unit(), + Err(ErrorHandled::TooGeneric(_)) => { + self.tcx.dcx().emit_fatal(ConstContinueBadConst { span: constant.span }); + } + }; + + let Some(real_target) = + self.static_pattern_match(&cx, valtree, &*scope.arms, &scope.built_match_tree) + else { + self.tcx.dcx().emit_fatal(ConstContinueUnknownJumpTarget { span }) + }; + + self.block_context.push(BlockFrame::SubExpr); + let state_place = scope.state_place; + block = self.expr_into_dest(state_place, block, value).into_block(); + self.block_context.pop(); + + let discr = self.temp(discriminant_ty, source_info.span); + let scope_index = self + .scopes + .scope_index(self.scopes.const_continuable_scopes[break_index].region_scope, span); + let scope = &mut self.scopes.const_continuable_scopes[break_index]; + self.cfg.push_assign(block, source_info, discr, rvalue); + let drop_and_continue_block = self.cfg.start_new_block(); + let imaginary_target = self.cfg.start_new_block(); + self.cfg.terminate( + block, + source_info, + TerminatorKind::FalseEdge { real_target: drop_and_continue_block, imaginary_target }, + ); + + let drops = &mut scope.const_continue_drops; + + let drop_idx = self.scopes.scopes[scope_index + 1..] + .iter() + .flat_map(|scope| &scope.drops) + .fold(ROOT_NODE, |drop_idx, &drop| drops.add_drop(drop, drop_idx)); + + drops.add_entry_point(imaginary_target, drop_idx); + + self.cfg.terminate(imaginary_target, source_info, TerminatorKind::UnwindResume); + + let region_scope = scope.region_scope; + let scope_index = self.scopes.scope_index(region_scope, span); + let mut drops = DropTree::new(); + + let drop_idx = self.scopes.scopes[scope_index + 1..] + .iter() + .flat_map(|scope| &scope.drops) + .fold(ROOT_NODE, |drop_idx, &drop| drops.add_drop(drop, drop_idx)); + + drops.add_entry_point(drop_and_continue_block, drop_idx); + + // `build_drop_trees` doesn't have access to our source_info, so we + // create a dummy terminator now. `TerminatorKind::UnwindResume` is used + // because MIR type checking will panic if it hasn't been overwritten. + // (See `<ExitScopes as DropTreeBuilder>::link_entry_point`.) + self.cfg.terminate(drop_and_continue_block, source_info, TerminatorKind::UnwindResume); + + self.build_exit_tree(drops, region_scope, span, Some(real_target)); + + return self.cfg.start_new_block().unit(); + } + /// Sets up the drops for breaking from `block` due to an `if` condition /// that turned out to be false. /// @@ -866,13 +1124,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { DropKind::ForLint => { self.cfg.push( block, - Statement { + Statement::new( source_info, - kind: StatementKind::BackwardIncompatibleDropHint { + StatementKind::BackwardIncompatibleDropHint { place: Box::new(local.into()), reason: BackwardIncompatibleDropReason::Edition2024, }, - }, + ), ); } DropKind::Storage => { @@ -880,7 +1138,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { assert!(local.index() > self.arg_count); self.cfg.push( block, - Statement { source_info, kind: StatementKind::StorageDead(local) }, + Statement::new(source_info, StatementKind::StorageDead(local)), ); } } @@ -1622,13 +1880,13 @@ where cfg.push( block, - Statement { + Statement::new( source_info, - kind: StatementKind::BackwardIncompatibleDropHint { + StatementKind::BackwardIncompatibleDropHint { place: Box::new(local.into()), reason: BackwardIncompatibleDropReason::Edition2024, }, - }, + ), ); } DropKind::Storage => { @@ -1652,7 +1910,7 @@ where } // Only temps and vars need their storage dead. assert!(local.index() > arg_count); - cfg.push(block, Statement { source_info, kind: StatementKind::StorageDead(local) }); + cfg.push(block, Statement::new(source_info, StatementKind::StorageDead(local))); } } } diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index d5061b71699..0b6b36640e9 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -465,10 +465,12 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { | ExprKind::Break { .. } | ExprKind::Closure { .. } | ExprKind::Continue { .. } + | ExprKind::ConstContinue { .. } | ExprKind::Return { .. } | ExprKind::Become { .. } | ExprKind::Yield { .. } | ExprKind::Loop { .. } + | ExprKind::LoopMatch { .. } | ExprKind::Let { .. } | ExprKind::Match { .. } | ExprKind::Box { .. } diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index ae09db50235..20e836f6bf2 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -994,14 +994,15 @@ pub(crate) struct PatternNotCovered<'s, 'tcx> { pub(crate) uncovered: Uncovered, #[subdiagnostic] pub(crate) inform: Option<Inform>, - #[label(mir_build_confused)] - pub(crate) interpreted_as_const: Option<Span>, #[subdiagnostic] - pub(crate) interpreted_as_const_sugg: Option<InterpretedAsConst>, + pub(crate) interpreted_as_const: Option<InterpretedAsConst>, + #[subdiagnostic] + pub(crate) interpreted_as_const_sugg: Option<InterpretedAsConstSugg>, #[subdiagnostic] pub(crate) adt_defined_here: Option<AdtDefinedHere<'tcx>>, #[note(mir_build_privately_uninhabited)] pub(crate) witness_1_is_privately_uninhabited: bool, + pub(crate) witness_1: String, #[note(mir_build_pattern_ty)] pub(crate) _p: (), pub(crate) pattern_ty: Ty<'tcx>, @@ -1016,6 +1017,14 @@ pub(crate) struct PatternNotCovered<'s, 'tcx> { #[note(mir_build_more_information)] pub(crate) struct Inform; +#[derive(Subdiagnostic)] +#[label(mir_build_confused)] +pub(crate) struct InterpretedAsConst { + #[primary_span] + pub(crate) span: Span, + pub(crate) variable: String, +} + pub(crate) struct AdtDefinedHere<'tcx> { pub(crate) adt_def_span: Span, pub(crate) ty: Ty<'tcx>, @@ -1046,7 +1055,7 @@ impl<'tcx> Subdiagnostic for AdtDefinedHere<'tcx> { applicability = "maybe-incorrect", style = "verbose" )] -pub(crate) struct InterpretedAsConst { +pub(crate) struct InterpretedAsConstSugg { #[primary_span] pub(crate) span: Span, pub(crate) variable: String, @@ -1149,3 +1158,80 @@ impl Subdiagnostic for Rust2024IncompatiblePatSugg { } } } + +#[derive(Diagnostic)] +#[diag(mir_build_loop_match_invalid_update)] +pub(crate) struct LoopMatchInvalidUpdate { + #[primary_span] + pub lhs: Span, + #[label] + pub scrutinee: Span, +} + +#[derive(Diagnostic)] +#[diag(mir_build_loop_match_invalid_match)] +#[note] +pub(crate) struct LoopMatchInvalidMatch { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(mir_build_loop_match_unsupported_type)] +#[note] +pub(crate) struct LoopMatchUnsupportedType<'tcx> { + #[primary_span] + pub span: Span, + pub ty: Ty<'tcx>, +} + +#[derive(Diagnostic)] +#[diag(mir_build_loop_match_bad_statements)] +pub(crate) struct LoopMatchBadStatements { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(mir_build_loop_match_bad_rhs)] +pub(crate) struct LoopMatchBadRhs { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(mir_build_loop_match_missing_assignment)] +pub(crate) struct LoopMatchMissingAssignment { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(mir_build_loop_match_arm_with_guard)] +pub(crate) struct LoopMatchArmWithGuard { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(mir_build_const_continue_bad_const)] +pub(crate) struct ConstContinueBadConst { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(mir_build_const_continue_missing_value)] +pub(crate) struct ConstContinueMissingValue { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(mir_build_const_continue_unknown_jump_target)] +#[note] +pub(crate) struct ConstContinueUnknownJumpTarget { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index b4fa55e1c1f..8e218a380e9 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -43,27 +43,23 @@ pub(crate) fn lit_to_const<'tcx>( let str_bytes = s.as_str().as_bytes(); ty::ValTree::from_raw_bytes(tcx, str_bytes) } - (ast::LitKind::ByteStr(data, _), ty::Ref(_, inner_ty, _)) + (ast::LitKind::ByteStr(byte_sym, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Slice(_) | ty::Array(..)) => { - let bytes = data as &[u8]; - ty::ValTree::from_raw_bytes(tcx, bytes) + ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()) } - (ast::LitKind::ByteStr(data, _), ty::Slice(_) | ty::Array(..)) + (ast::LitKind::ByteStr(byte_sym, _), ty::Slice(_) | ty::Array(..)) if tcx.features().deref_patterns() => { // Byte string literal patterns may have type `[u8]` or `[u8; N]` if `deref_patterns` is // enabled, in order to allow, e.g., `deref!(b"..."): Vec<u8>`. - let bytes = data as &[u8]; - ty::ValTree::from_raw_bytes(tcx, bytes) + ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()) } (ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => { - ty::ValTree::from_scalar_int(tcx, (*n).into()) + ty::ValTree::from_scalar_int(tcx, n.into()) } - (ast::LitKind::CStr(data, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::CStr)) => - { - let bytes = data as &[u8]; - ty::ValTree::from_raw_bytes(tcx, bytes) + (ast::LitKind::CStr(byte_sym, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::CStr)) => { + ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()) } (ast::LitKind::Int(n, _), ty::Uint(ui)) if !neg => { let scalar_int = trunc(n.get(), *ui); @@ -76,15 +72,15 @@ pub(crate) fn lit_to_const<'tcx>( ); ty::ValTree::from_scalar_int(tcx, scalar_int) } - (ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int(tcx, (*b).into()), + (ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int(tcx, b.into()), (ast::LitKind::Float(n, _), ty::Float(fty)) => { - let bits = parse_float_into_scalar(*n, *fty, neg).unwrap_or_else(|| { + let bits = parse_float_into_scalar(n, *fty, neg).unwrap_or_else(|| { tcx.dcx().bug(format!("couldn't parse float literal: {:?}", lit_input.lit)) }); ty::ValTree::from_scalar_int(tcx, bits) } - (ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int(tcx, (*c).into()), - (ast::LitKind::Err(guar), _) => return ty::Const::new_error(tcx, *guar), + (ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int(tcx, c.into()), + (ast::LitKind::Err(guar), _) => return ty::Const::new_error(tcx, guar), _ => return ty::Const::new_misc_error(tcx), }; diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 3baeccf6409..5197e93fda7 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -1,6 +1,7 @@ use itertools::Itertools; use rustc_abi::{FIRST_VARIANT, FieldIdx}; use rustc_ast::UnsafeBinderCastKind; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; @@ -21,6 +22,7 @@ use rustc_middle::{bug, span_bug}; use rustc_span::{Span, sym}; use tracing::{debug, info, instrument, trace}; +use crate::errors::*; use crate::thir::cx::ThirBuildCx; impl<'tcx> ThirBuildCx<'tcx> { @@ -479,6 +481,55 @@ impl<'tcx> ThirBuildCx<'tcx> { ExprKind::RawBorrow { mutability, arg: self.mirror_expr(arg) } } + // Make `&pin mut $expr` and `&pin const $expr` into + // `Pin { __pointer: &mut { $expr } }` and `Pin { __pointer: &$expr }`. + hir::ExprKind::AddrOf(hir::BorrowKind::Pin, mutbl, arg_expr) => match expr_ty.kind() { + &ty::Adt(adt_def, args) if tcx.is_lang_item(adt_def.did(), hir::LangItem::Pin) => { + let ty = args.type_at(0); + let arg_ty = self.typeck_results.expr_ty(arg_expr); + let mut arg = self.mirror_expr(arg_expr); + // For `&pin mut $place` where `$place` is not `Unpin`, move the place + // `$place` to ensure it will not be used afterwards. + if mutbl.is_mut() && !arg_ty.is_unpin(self.tcx, self.typing_env) { + let block = self.thir.blocks.push(Block { + targeted_by_break: false, + region_scope: region::Scope { + local_id: arg_expr.hir_id.local_id, + data: region::ScopeData::Node, + }, + span: arg_expr.span, + stmts: Box::new([]), + expr: Some(arg), + safety_mode: BlockSafety::Safe, + }); + let (temp_lifetime, backwards_incompatible) = self + .rvalue_scopes + .temporary_scope(self.region_scope_tree, arg_expr.hir_id.local_id); + arg = self.thir.exprs.push(Expr { + temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible }, + ty: arg_ty, + span: arg_expr.span, + kind: ExprKind::Block { block }, + }); + } + let expr = self.thir.exprs.push(Expr { + temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible }, + ty, + span: expr.span, + kind: ExprKind::Borrow { borrow_kind: mutbl.to_borrow_kind(), arg }, + }); + ExprKind::Adt(Box::new(AdtExpr { + adt_def, + variant_index: FIRST_VARIANT, + args, + fields: Box::new([FieldExpr { name: FieldIdx::from(0u32), expr }]), + user_ty: None, + base: AdtExprBase::None, + })) + } + _ => span_bug!(expr.span, "unexpected type for pinned borrow: {:?}", expr_ty), + }, + hir::ExprKind::Block(blk, _) => ExprKind::Block { block: self.mirror_block(blk) }, hir::ExprKind::Assign(lhs, rhs, _) => { @@ -796,16 +847,38 @@ impl<'tcx> ThirBuildCx<'tcx> { } hir::ExprKind::Ret(v) => ExprKind::Return { value: v.map(|v| self.mirror_expr(v)) }, hir::ExprKind::Become(call) => ExprKind::Become { value: self.mirror_expr(call) }, - hir::ExprKind::Break(dest, ref value) => match dest.target_id { - Ok(target_id) => ExprKind::Break { - label: region::Scope { - local_id: target_id.local_id, - data: region::ScopeData::Node, - }, - value: value.map(|value| self.mirror_expr(value)), - }, - Err(err) => bug!("invalid loop id for break: {}", err), - }, + hir::ExprKind::Break(dest, ref value) => { + if find_attr!(self.tcx.hir_attrs(expr.hir_id), AttributeKind::ConstContinue(_)) { + match dest.target_id { + Ok(target_id) => { + let Some(value) = value else { + let span = expr.span; + self.tcx.dcx().emit_fatal(ConstContinueMissingValue { span }) + }; + + ExprKind::ConstContinue { + label: region::Scope { + local_id: target_id.local_id, + data: region::ScopeData::Node, + }, + value: self.mirror_expr(value), + } + } + Err(err) => bug!("invalid loop id for break: {}", err), + } + } else { + match dest.target_id { + Ok(target_id) => ExprKind::Break { + label: region::Scope { + local_id: target_id.local_id, + data: region::ScopeData::Node, + }, + value: value.map(|value| self.mirror_expr(value)), + }, + Err(err) => bug!("invalid loop id for break: {}", err), + } + } + } hir::ExprKind::Continue(dest) => match dest.target_id { Ok(loop_id) => ExprKind::Continue { label: region::Scope { @@ -840,18 +913,93 @@ impl<'tcx> ThirBuildCx<'tcx> { match_source, }, hir::ExprKind::Loop(body, ..) => { - let block_ty = self.typeck_results.node_type(body.hir_id); - let (temp_lifetime, backwards_incompatible) = self - .rvalue_scopes - .temporary_scope(self.region_scope_tree, body.hir_id.local_id); - let block = self.mirror_block(body); - let body = self.thir.exprs.push(Expr { - ty: block_ty, - temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible }, - span: self.thir[block].span, - kind: ExprKind::Block { block }, - }); - ExprKind::Loop { body } + if find_attr!(self.tcx.hir_attrs(expr.hir_id), AttributeKind::LoopMatch(_)) { + let dcx = self.tcx.dcx(); + + // Accept either `state = expr` or `state = expr;`. + let loop_body_expr = match body.stmts { + [] => match body.expr { + Some(expr) => expr, + None => dcx.emit_fatal(LoopMatchMissingAssignment { span: body.span }), + }, + [single] if body.expr.is_none() => match single.kind { + hir::StmtKind::Expr(expr) | hir::StmtKind::Semi(expr) => expr, + _ => dcx.emit_fatal(LoopMatchMissingAssignment { span: body.span }), + }, + [first @ last] | [first, .., last] => dcx + .emit_fatal(LoopMatchBadStatements { span: first.span.to(last.span) }), + }; + + let hir::ExprKind::Assign(state, rhs_expr, _) = loop_body_expr.kind else { + dcx.emit_fatal(LoopMatchMissingAssignment { span: loop_body_expr.span }) + }; + + let hir::ExprKind::Block(block_body, _) = rhs_expr.kind else { + dcx.emit_fatal(LoopMatchBadRhs { span: rhs_expr.span }) + }; + + // The labeled block should contain one match expression, but defining items is + // allowed. + for stmt in block_body.stmts { + if !matches!(stmt.kind, rustc_hir::StmtKind::Item(_)) { + dcx.emit_fatal(LoopMatchBadStatements { span: stmt.span }) + } + } + + let Some(block_body_expr) = block_body.expr else { + dcx.emit_fatal(LoopMatchBadRhs { span: block_body.span }) + }; + + let hir::ExprKind::Match(scrutinee, arms, _match_source) = block_body_expr.kind + else { + dcx.emit_fatal(LoopMatchBadRhs { span: block_body_expr.span }) + }; + + fn local(expr: &rustc_hir::Expr<'_>) -> Option<hir::HirId> { + if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = expr.kind { + if let Res::Local(hir_id) = path.res { + return Some(hir_id); + } + } + + None + } + + let Some(scrutinee_hir_id) = local(scrutinee) else { + dcx.emit_fatal(LoopMatchInvalidMatch { span: scrutinee.span }) + }; + + if local(state) != Some(scrutinee_hir_id) { + dcx.emit_fatal(LoopMatchInvalidUpdate { + scrutinee: scrutinee.span, + lhs: state.span, + }) + } + + ExprKind::LoopMatch { + state: self.mirror_expr(state), + region_scope: region::Scope { + local_id: block_body.hir_id.local_id, + data: region::ScopeData::Node, + }, + + arms: arms.iter().map(|a| self.convert_arm(a)).collect(), + match_span: block_body_expr.span, + } + } else { + let block_ty = self.typeck_results.node_type(body.hir_id); + let (temp_lifetime, backwards_incompatible) = self + .rvalue_scopes + .temporary_scope(self.region_scope_tree, body.hir_id.local_id); + let block = self.mirror_block(body); + let body = self.thir.exprs.push(Expr { + ty: block_ty, + temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible }, + span: self.thir[block].span, + kind: ExprKind::Block { block }, + }); + ExprKind::Loop { body } + } } hir::ExprKind::Field(source, ..) => ExprKind::Field { lhs: self.mirror_expr(source), diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 245bd866030..41fbabc2539 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -331,7 +331,11 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { | WrapUnsafeBinder { source } => self.is_known_valid_scrutinee(&self.thir()[*source]), // These diverge. - Become { .. } | Break { .. } | Continue { .. } | Return { .. } => true, + Become { .. } + | Break { .. } + | Continue { .. } + | ConstContinue { .. } + | Return { .. } => true, // These are statements that evaluate to `()`. Assign { .. } | AssignOp { .. } | InlineAsm { .. } | Let { .. } => true, @@ -353,6 +357,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { | Literal { .. } | LogicalOp { .. } | Loop { .. } + | LoopMatch { .. } | Match { .. } | NamedConst { .. } | NonHirLiteral { .. } @@ -685,8 +690,8 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { let span = self.tcx.def_span(def_id); let variable = self.tcx.item_name(def_id).to_string(); // When we encounter a constant as the binding name, point at the `const` definition. - interpreted_as_const = Some(span); - interpreted_as_const_sugg = Some(InterpretedAsConst { span: pat.span, variable }); + interpreted_as_const = Some(InterpretedAsConst { span, variable: variable.clone() }); + interpreted_as_const_sugg = Some(InterpretedAsConstSugg { span: pat.span, variable }); } else if let PatKind::Constant { .. } = unpeeled_pat.kind && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span) { @@ -738,6 +743,8 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { false }; + let witness_1 = cx.print_witness_pat(witnesses.get(0).unwrap()); + self.error = Err(self.tcx.dcx().emit_err(PatternNotCovered { span: pat.span, origin, @@ -746,6 +753,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { interpreted_as_const, interpreted_as_const_sugg, witness_1_is_privately_uninhabited, + witness_1, _p: (), pattern_ty, let_suggestion, diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index fcd106d78e2..e44a440b5c1 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -680,7 +680,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { Some(pat_ty) => pat_ty, None => self.typeck_results.node_type(expr.hir_id), }; - let lit_input = LitToConstInput { lit: &lit.node, ty: ct_ty, neg: *negated }; + let lit_input = LitToConstInput { lit: lit.node, ty: ct_ty, neg: *negated }; let constant = self.tcx.at(expr.span).lit_to_const(lit_input); self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind } diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index db9547a481f..1507b6b8c06 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -318,6 +318,20 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { self.print_expr(*body, depth_lvl + 2); print_indented!(self, ")", depth_lvl); } + LoopMatch { state, region_scope, match_span, arms } => { + print_indented!(self, "LoopMatch {", depth_lvl); + print_indented!(self, "state:", depth_lvl + 1); + self.print_expr(*state, depth_lvl + 2); + print_indented!(self, format!("region_scope: {:?}", region_scope), depth_lvl + 1); + print_indented!(self, format!("match_span: {:?}", match_span), depth_lvl + 1); + + print_indented!(self, "arms: [", depth_lvl + 1); + for arm_id in arms.iter() { + self.print_arm(*arm_id, depth_lvl + 2); + } + print_indented!(self, "]", depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } Let { expr, pat } => { print_indented!(self, "Let {", depth_lvl); print_indented!(self, "expr:", depth_lvl + 1); @@ -415,6 +429,13 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { print_indented!(self, format!("label: {:?}", label), depth_lvl + 1); print_indented!(self, "}", depth_lvl); } + ConstContinue { label, value } => { + print_indented!(self, "ConstContinue (", depth_lvl); + print_indented!(self, format!("label: {:?}", label), depth_lvl + 1); + print_indented!(self, "value:", depth_lvl + 1); + self.print_expr(*value, depth_lvl + 2); + print_indented!(self, ")", depth_lvl); + } Return { value } => { print_indented!(self, "Return {", depth_lvl); print_indented!(self, "value:", depth_lvl + 1); diff --git a/compiler/rustc_mir_dataflow/src/framework/tests.rs b/compiler/rustc_mir_dataflow/src/framework/tests.rs index 8602bb55765..23e28a11a45 100644 --- a/compiler/rustc_mir_dataflow/src/framework/tests.rs +++ b/compiler/rustc_mir_dataflow/src/framework/tests.rs @@ -17,13 +17,13 @@ fn mock_body<'tcx>() -> mir::Body<'tcx> { let mut blocks = IndexVec::new(); let mut block = |n, kind| { - let nop = mir::Statement { source_info, kind: mir::StatementKind::Nop }; + let nop = mir::Statement::new(source_info, mir::StatementKind::Nop); - blocks.push(mir::BasicBlockData { - statements: std::iter::repeat(&nop).cloned().take(n).collect(), - terminator: Some(mir::Terminator { source_info, kind }), - is_cleanup: false, - }) + blocks.push(mir::BasicBlockData::new_stmts( + std::iter::repeat(&nop).cloned().take(n).collect(), + Some(mir::Terminator { source_info, kind }), + false, + )) }; let dummy_place = mir::Place { local: mir::RETURN_PLACE, projection: ty::List::empty() }; diff --git a/compiler/rustc_mir_transform/src/add_call_guards.rs b/compiler/rustc_mir_transform/src/add_call_guards.rs index bacff287859..26839ebf61e 100644 --- a/compiler/rustc_mir_transform/src/add_call_guards.rs +++ b/compiler/rustc_mir_transform/src/add_call_guards.rs @@ -44,11 +44,10 @@ impl<'tcx> crate::MirPass<'tcx> for AddCallGuards { let cur_len = body.basic_blocks.len(); let mut new_block = |source_info: SourceInfo, is_cleanup: bool, target: BasicBlock| { - let block = BasicBlockData { - statements: vec![], + let block = BasicBlockData::new( + Some(Terminator { source_info, kind: TerminatorKind::Goto { target } }), is_cleanup, - terminator: Some(Terminator { source_info, kind: TerminatorKind::Goto { target } }), - }; + ); let idx = cur_len + new_blocks.len(); new_blocks.push(block); BasicBlock::new(idx) diff --git a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs index a414d120e68..7ae2ebaf4ff 100644 --- a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs +++ b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs @@ -93,11 +93,11 @@ fn add_move_for_packed_drop<'tcx>( let ty = place.ty(body, tcx).ty; let temp = patch.new_temp(ty, source_info.span); - let storage_dead_block = patch.new_block(BasicBlockData { - statements: vec![Statement { source_info, kind: StatementKind::StorageDead(temp) }], - terminator: Some(Terminator { source_info, kind: TerminatorKind::Goto { target } }), + let storage_dead_block = patch.new_block(BasicBlockData::new_stmts( + vec![Statement::new(source_info, StatementKind::StorageDead(temp))], + Some(Terminator { source_info, kind: TerminatorKind::Goto { target } }), is_cleanup, - }); + )); patch.add_statement(loc, StatementKind::StorageLive(temp)); patch.add_assign(loc, Place::from(temp), Rvalue::Use(Operand::Move(*place))); diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs index e5a28d1b66c..3c29d4624b7 100644 --- a/compiler/rustc_mir_transform/src/add_retag.rs +++ b/compiler/rustc_mir_transform/src/add_retag.rs @@ -81,9 +81,11 @@ impl<'tcx> crate::MirPass<'tcx> for AddRetag { // Emit their retags. basic_blocks[START_BLOCK].statements.splice( 0..0, - places.map(|(place, source_info)| Statement { - source_info, - kind: StatementKind::Retag(RetagKind::FnEntry, Box::new(place)), + places.map(|(place, source_info)| { + Statement::new( + source_info, + StatementKind::Retag(RetagKind::FnEntry, Box::new(place)), + ) }), ); } @@ -113,10 +115,10 @@ impl<'tcx> crate::MirPass<'tcx> for AddRetag { for (source_info, dest_place, dest_block) in returns { basic_blocks[dest_block].statements.insert( 0, - Statement { + Statement::new( source_info, - kind: StatementKind::Retag(RetagKind::Default, Box::new(dest_place)), - }, + StatementKind::Retag(RetagKind::Default, Box::new(dest_place)), + ), ); } @@ -174,10 +176,7 @@ impl<'tcx> crate::MirPass<'tcx> for AddRetag { let source_info = block_data.statements[i].source_info; block_data.statements.insert( i + 1, - Statement { - source_info, - kind: StatementKind::Retag(retag_kind, Box::new(place)), - }, + Statement::new(source_info, StatementKind::Retag(retag_kind, Box::new(place))), ); } } diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs index 8f88613b79f..989787504b7 100644 --- a/compiler/rustc_mir_transform/src/check_alignment.rs +++ b/compiler/rustc_mir_transform/src/check_alignment.rs @@ -51,22 +51,18 @@ fn insert_alignment_check<'tcx>( let const_raw_ptr = Ty::new_imm_ptr(tcx, tcx.types.unit); let rvalue = Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(pointer), const_raw_ptr); let thin_ptr = local_decls.push(LocalDecl::with_source_info(const_raw_ptr, source_info)).into(); - stmts - .push(Statement { source_info, kind: StatementKind::Assign(Box::new((thin_ptr, rvalue))) }); + stmts.push(Statement::new(source_info, StatementKind::Assign(Box::new((thin_ptr, rvalue))))); // Transmute the pointer to a usize (equivalent to `ptr.addr()`). let rvalue = Rvalue::Cast(CastKind::Transmute, Operand::Copy(thin_ptr), tcx.types.usize); let addr = local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into(); - stmts.push(Statement { source_info, kind: StatementKind::Assign(Box::new((addr, rvalue))) }); + stmts.push(Statement::new(source_info, StatementKind::Assign(Box::new((addr, rvalue))))); // Get the alignment of the pointee let alignment = local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into(); let rvalue = Rvalue::NullaryOp(NullOp::AlignOf, pointee_ty); - stmts.push(Statement { - source_info, - kind: StatementKind::Assign(Box::new((alignment, rvalue))), - }); + stmts.push(Statement::new(source_info, StatementKind::Assign(Box::new((alignment, rvalue))))); // Subtract 1 from the alignment to get the alignment mask let alignment_mask = @@ -76,13 +72,13 @@ fn insert_alignment_check<'tcx>( user_ty: None, const_: Const::Val(ConstValue::Scalar(Scalar::from_target_usize(1, &tcx)), tcx.types.usize), })); - stmts.push(Statement { + stmts.push(Statement::new( source_info, - kind: StatementKind::Assign(Box::new(( + StatementKind::Assign(Box::new(( alignment_mask, Rvalue::BinaryOp(BinOp::Sub, Box::new((Operand::Copy(alignment), one))), ))), - }); + )); // If this target does not have reliable alignment, further limit the mask by anding it with // the mask for the highest reliable alignment. @@ -99,31 +95,31 @@ fn insert_alignment_check<'tcx>( tcx.types.usize, ), })); - stmts.push(Statement { + stmts.push(Statement::new( source_info, - kind: StatementKind::Assign(Box::new(( + StatementKind::Assign(Box::new(( alignment_mask, Rvalue::BinaryOp( BinOp::BitAnd, Box::new((Operand::Copy(alignment_mask), max_mask)), ), ))), - }); + )); } // BitAnd the alignment mask with the pointer let alignment_bits = local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into(); - stmts.push(Statement { + stmts.push(Statement::new( source_info, - kind: StatementKind::Assign(Box::new(( + StatementKind::Assign(Box::new(( alignment_bits, Rvalue::BinaryOp( BinOp::BitAnd, Box::new((Operand::Copy(addr), Operand::Copy(alignment_mask))), ), ))), - }); + )); // Check if the alignment bits are all zero let is_ok = local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into(); @@ -132,13 +128,13 @@ fn insert_alignment_check<'tcx>( user_ty: None, const_: Const::Val(ConstValue::Scalar(Scalar::from_target_usize(0, &tcx)), tcx.types.usize), })); - stmts.push(Statement { + stmts.push(Statement::new( source_info, - kind: StatementKind::Assign(Box::new(( + StatementKind::Assign(Box::new(( is_ok, Rvalue::BinaryOp(BinOp::Eq, Box::new((Operand::Copy(alignment_bits), zero.clone()))), ))), - }); + )); // Emit a check that asserts on the alignment and otherwise triggers a // AssertKind::MisalignedPointerDereference. diff --git a/compiler/rustc_mir_transform/src/check_enums.rs b/compiler/rustc_mir_transform/src/check_enums.rs new file mode 100644 index 00000000000..240da87ab27 --- /dev/null +++ b/compiler/rustc_mir_transform/src/check_enums.rs @@ -0,0 +1,500 @@ +use rustc_abi::{Scalar, Size, TagEncoding, Variants, WrappingRange}; +use rustc_hir::LangItem; +use rustc_index::IndexVec; +use rustc_middle::bug; +use rustc_middle::mir::visit::Visitor; +use rustc_middle::mir::*; +use rustc_middle::ty::layout::PrimitiveExt; +use rustc_middle::ty::{self, Ty, TyCtxt, TypingEnv}; +use rustc_session::Session; +use tracing::debug; + +/// This pass inserts checks for a valid enum discriminant where they are most +/// likely to find UB, because checking everywhere like Miri would generate too +/// much MIR. +pub(super) struct CheckEnums; + +impl<'tcx> crate::MirPass<'tcx> for CheckEnums { + fn is_enabled(&self, sess: &Session) -> bool { + sess.ub_checks() + } + + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + // This pass emits new panics. If for whatever reason we do not have a panic + // implementation, running this pass may cause otherwise-valid code to not compile. + if tcx.lang_items().get(LangItem::PanicImpl).is_none() { + return; + } + + let typing_env = body.typing_env(tcx); + let basic_blocks = body.basic_blocks.as_mut(); + let local_decls = &mut body.local_decls; + + // This operation inserts new blocks. Each insertion changes the Location for all + // statements/blocks after. Iterating or visiting the MIR in order would require updating + // our current location after every insertion. By iterating backwards, we dodge this issue: + // The only Locations that an insertion changes have already been handled. + for block in basic_blocks.indices().rev() { + for statement_index in (0..basic_blocks[block].statements.len()).rev() { + let location = Location { block, statement_index }; + let statement = &basic_blocks[block].statements[statement_index]; + let source_info = statement.source_info; + + let mut finder = EnumFinder::new(tcx, local_decls, typing_env); + finder.visit_statement(statement, location); + + for check in finder.into_found_enums() { + debug!("Inserting enum check"); + let new_block = split_block(basic_blocks, location); + + match check { + EnumCheckType::Direct { source_op, discr, op_size, valid_discrs } => { + insert_direct_enum_check( + tcx, + local_decls, + basic_blocks, + block, + source_op, + discr, + op_size, + valid_discrs, + source_info, + new_block, + ) + } + EnumCheckType::Uninhabited => insert_uninhabited_enum_check( + tcx, + local_decls, + &mut basic_blocks[block], + source_info, + new_block, + ), + EnumCheckType::WithNiche { + source_op, + discr, + op_size, + offset, + valid_range, + } => insert_niche_check( + tcx, + local_decls, + &mut basic_blocks[block], + source_op, + valid_range, + discr, + op_size, + offset, + source_info, + new_block, + ), + } + } + } + } + } + + fn is_required(&self) -> bool { + true + } +} + +/// Represent the different kind of enum checks we can insert. +enum EnumCheckType<'tcx> { + /// We know we try to create an uninhabited enum from an inhabited variant. + Uninhabited, + /// We know the enum does no niche optimizations and can thus easily compute + /// the valid discriminants. + Direct { + source_op: Operand<'tcx>, + discr: TyAndSize<'tcx>, + op_size: Size, + valid_discrs: Vec<u128>, + }, + /// We try to construct an enum that has a niche. + WithNiche { + source_op: Operand<'tcx>, + discr: TyAndSize<'tcx>, + op_size: Size, + offset: Size, + valid_range: WrappingRange, + }, +} + +struct TyAndSize<'tcx> { + pub ty: Ty<'tcx>, + pub size: Size, +} + +/// A [Visitor] that finds the construction of enums and evaluates which checks +/// we should apply. +struct EnumFinder<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + local_decls: &'a mut LocalDecls<'tcx>, + typing_env: TypingEnv<'tcx>, + enums: Vec<EnumCheckType<'tcx>>, +} + +impl<'a, 'tcx> EnumFinder<'a, 'tcx> { + fn new( + tcx: TyCtxt<'tcx>, + local_decls: &'a mut LocalDecls<'tcx>, + typing_env: TypingEnv<'tcx>, + ) -> Self { + EnumFinder { tcx, local_decls, typing_env, enums: Vec::new() } + } + + /// Returns the found enum creations and which checks should be inserted. + fn into_found_enums(self) -> Vec<EnumCheckType<'tcx>> { + self.enums + } +} + +impl<'a, 'tcx> Visitor<'tcx> for EnumFinder<'a, 'tcx> { + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { + if let Rvalue::Cast(CastKind::Transmute, op, ty) = rvalue { + let ty::Adt(adt_def, _) = ty.kind() else { + return; + }; + if !adt_def.is_enum() { + return; + } + + let Ok(enum_layout) = self.tcx.layout_of(self.typing_env.as_query_input(*ty)) else { + return; + }; + let Ok(op_layout) = self + .tcx + .layout_of(self.typing_env.as_query_input(op.ty(self.local_decls, self.tcx))) + else { + return; + }; + + match enum_layout.variants { + Variants::Empty if op_layout.is_uninhabited() => return, + // An empty enum that tries to be constructed from an inhabited value, this + // is never correct. + Variants::Empty => { + // The enum layout is uninhabited but we construct it from sth inhabited. + // This is always UB. + self.enums.push(EnumCheckType::Uninhabited); + } + // Construction of Single value enums is always fine. + Variants::Single { .. } => {} + // Construction of an enum with multiple variants but no niche optimizations. + Variants::Multiple { + tag_encoding: TagEncoding::Direct, + tag: Scalar::Initialized { value, .. }, + .. + } => { + let valid_discrs = + adt_def.discriminants(self.tcx).map(|(_, discr)| discr.val).collect(); + + let discr = + TyAndSize { ty: value.to_int_ty(self.tcx), size: value.size(&self.tcx) }; + self.enums.push(EnumCheckType::Direct { + source_op: op.to_copy(), + discr, + op_size: op_layout.size, + valid_discrs, + }); + } + // Construction of an enum with multiple variants and niche optimizations. + Variants::Multiple { + tag_encoding: TagEncoding::Niche { .. }, + tag: Scalar::Initialized { value, valid_range, .. }, + tag_field, + .. + } => { + let discr = + TyAndSize { ty: value.to_int_ty(self.tcx), size: value.size(&self.tcx) }; + self.enums.push(EnumCheckType::WithNiche { + source_op: op.to_copy(), + discr, + op_size: op_layout.size, + offset: enum_layout.fields.offset(tag_field.as_usize()), + valid_range, + }); + } + _ => return, + } + + self.super_rvalue(rvalue, location); + } + } +} + +fn split_block( + basic_blocks: &mut IndexVec<BasicBlock, BasicBlockData<'_>>, + location: Location, +) -> BasicBlock { + let block_data = &mut basic_blocks[location.block]; + + // Drain every statement after this one and move the current terminator to a new basic block. + let new_block = BasicBlockData::new_stmts( + block_data.statements.split_off(location.statement_index), + block_data.terminator.take(), + block_data.is_cleanup, + ); + + basic_blocks.push(new_block) +} + +/// Inserts the cast of an operand (any type) to a u128 value that holds the discriminant value. +fn insert_discr_cast_to_u128<'tcx>( + tcx: TyCtxt<'tcx>, + local_decls: &mut IndexVec<Local, LocalDecl<'tcx>>, + block_data: &mut BasicBlockData<'tcx>, + source_op: Operand<'tcx>, + discr: TyAndSize<'tcx>, + op_size: Size, + offset: Option<Size>, + source_info: SourceInfo, +) -> Place<'tcx> { + let get_ty_for_size = |tcx: TyCtxt<'tcx>, size: Size| -> Ty<'tcx> { + match size.bytes() { + 1 => tcx.types.u8, + 2 => tcx.types.u16, + 4 => tcx.types.u32, + 8 => tcx.types.u64, + 16 => tcx.types.u128, + invalid => bug!("Found discriminant with invalid size, has {} bytes", invalid), + } + }; + + let (cast_kind, discr_ty_bits) = if discr.size.bytes() < op_size.bytes() { + // The discriminant is less wide than the operand, cast the operand into + // [MaybeUninit; N] and then index into it. + let mu = Ty::new_maybe_uninit(tcx, tcx.types.u8); + let array_len = op_size.bytes(); + let mu_array_ty = Ty::new_array(tcx, mu, array_len); + let mu_array = + local_decls.push(LocalDecl::with_source_info(mu_array_ty, source_info)).into(); + let rvalue = Rvalue::Cast(CastKind::Transmute, source_op, mu_array_ty); + block_data + .statements + .push(Statement::new(source_info, StatementKind::Assign(Box::new((mu_array, rvalue))))); + + // Index into the array of MaybeUninit to get something that is actually + // as wide as the discriminant. + let offset = offset.unwrap_or(Size::ZERO); + let smaller_mu_array = mu_array.project_deeper( + &[ProjectionElem::Subslice { + from: offset.bytes(), + to: offset.bytes() + discr.size.bytes(), + from_end: false, + }], + tcx, + ); + + (CastKind::Transmute, Operand::Copy(smaller_mu_array)) + } else { + let operand_int_ty = get_ty_for_size(tcx, op_size); + + let op_as_int = + local_decls.push(LocalDecl::with_source_info(operand_int_ty, source_info)).into(); + let rvalue = Rvalue::Cast(CastKind::Transmute, source_op, operand_int_ty); + block_data.statements.push(Statement::new( + source_info, + StatementKind::Assign(Box::new((op_as_int, rvalue))), + )); + + (CastKind::IntToInt, Operand::Copy(op_as_int)) + }; + + // Cast the resulting value to the actual discriminant integer type. + let rvalue = Rvalue::Cast(cast_kind, discr_ty_bits, discr.ty); + let discr_in_discr_ty = + local_decls.push(LocalDecl::with_source_info(discr.ty, source_info)).into(); + block_data.statements.push(Statement::new( + source_info, + StatementKind::Assign(Box::new((discr_in_discr_ty, rvalue))), + )); + + // Cast the discriminant to a u128 (base for comparisions of enum discriminants). + let const_u128 = Ty::new_uint(tcx, ty::UintTy::U128); + let rvalue = Rvalue::Cast(CastKind::IntToInt, Operand::Copy(discr_in_discr_ty), const_u128); + let discr = local_decls.push(LocalDecl::with_source_info(const_u128, source_info)).into(); + block_data + .statements + .push(Statement::new(source_info, StatementKind::Assign(Box::new((discr, rvalue))))); + + discr +} + +fn insert_direct_enum_check<'tcx>( + tcx: TyCtxt<'tcx>, + local_decls: &mut IndexVec<Local, LocalDecl<'tcx>>, + basic_blocks: &mut IndexVec<BasicBlock, BasicBlockData<'tcx>>, + current_block: BasicBlock, + source_op: Operand<'tcx>, + discr: TyAndSize<'tcx>, + op_size: Size, + discriminants: Vec<u128>, + source_info: SourceInfo, + new_block: BasicBlock, +) { + // Insert a new target block that is branched to in case of an invalid discriminant. + let invalid_discr_block_data = BasicBlockData::new(None, false); + let invalid_discr_block = basic_blocks.push(invalid_discr_block_data); + let block_data = &mut basic_blocks[current_block]; + let discr = insert_discr_cast_to_u128( + tcx, + local_decls, + block_data, + source_op, + discr, + op_size, + None, + source_info, + ); + + // Branch based on the discriminant value. + block_data.terminator = Some(Terminator { + source_info, + kind: TerminatorKind::SwitchInt { + discr: Operand::Copy(discr), + targets: SwitchTargets::new( + discriminants.into_iter().map(|discr| (discr, new_block)), + invalid_discr_block, + ), + }, + }); + + // Abort in case of an invalid enum discriminant. + basic_blocks[invalid_discr_block].terminator = Some(Terminator { + source_info, + kind: TerminatorKind::Assert { + cond: Operand::Constant(Box::new(ConstOperand { + span: source_info.span, + user_ty: None, + const_: Const::Val(ConstValue::from_bool(false), tcx.types.bool), + })), + expected: true, + target: new_block, + msg: Box::new(AssertKind::InvalidEnumConstruction(Operand::Copy(discr))), + // This calls panic_invalid_enum_construction, which is #[rustc_nounwind]. + // We never want to insert an unwind into unsafe code, because unwinding could + // make a failing UB check turn into much worse UB when we start unwinding. + unwind: UnwindAction::Unreachable, + }, + }); +} + +fn insert_uninhabited_enum_check<'tcx>( + tcx: TyCtxt<'tcx>, + local_decls: &mut IndexVec<Local, LocalDecl<'tcx>>, + block_data: &mut BasicBlockData<'tcx>, + source_info: SourceInfo, + new_block: BasicBlock, +) { + let is_ok: Place<'_> = + local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into(); + block_data.statements.push(Statement::new( + source_info, + StatementKind::Assign(Box::new(( + is_ok, + Rvalue::Use(Operand::Constant(Box::new(ConstOperand { + span: source_info.span, + user_ty: None, + const_: Const::Val(ConstValue::from_bool(false), tcx.types.bool), + }))), + ))), + )); + + block_data.terminator = Some(Terminator { + source_info, + kind: TerminatorKind::Assert { + cond: Operand::Copy(is_ok), + expected: true, + target: new_block, + msg: Box::new(AssertKind::InvalidEnumConstruction(Operand::Constant(Box::new( + ConstOperand { + span: source_info.span, + user_ty: None, + const_: Const::Val(ConstValue::from_u128(0), tcx.types.u128), + }, + )))), + // This calls panic_invalid_enum_construction, which is #[rustc_nounwind]. + // We never want to insert an unwind into unsafe code, because unwinding could + // make a failing UB check turn into much worse UB when we start unwinding. + unwind: UnwindAction::Unreachable, + }, + }); +} + +fn insert_niche_check<'tcx>( + tcx: TyCtxt<'tcx>, + local_decls: &mut IndexVec<Local, LocalDecl<'tcx>>, + block_data: &mut BasicBlockData<'tcx>, + source_op: Operand<'tcx>, + valid_range: WrappingRange, + discr: TyAndSize<'tcx>, + op_size: Size, + offset: Size, + source_info: SourceInfo, + new_block: BasicBlock, +) { + let discr = insert_discr_cast_to_u128( + tcx, + local_decls, + block_data, + source_op, + discr, + op_size, + Some(offset), + source_info, + ); + + // Compare the discriminant agains the valid_range. + let start_const = Operand::Constant(Box::new(ConstOperand { + span: source_info.span, + user_ty: None, + const_: Const::Val(ConstValue::from_u128(valid_range.start), tcx.types.u128), + })); + let end_start_diff_const = Operand::Constant(Box::new(ConstOperand { + span: source_info.span, + user_ty: None, + const_: Const::Val( + ConstValue::from_u128(u128::wrapping_sub(valid_range.end, valid_range.start)), + tcx.types.u128, + ), + })); + + let discr_diff: Place<'_> = + local_decls.push(LocalDecl::with_source_info(tcx.types.u128, source_info)).into(); + block_data.statements.push(Statement::new( + source_info, + StatementKind::Assign(Box::new(( + discr_diff, + Rvalue::BinaryOp(BinOp::Sub, Box::new((Operand::Copy(discr), start_const))), + ))), + )); + + let is_ok: Place<'_> = + local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into(); + block_data.statements.push(Statement::new( + source_info, + StatementKind::Assign(Box::new(( + is_ok, + Rvalue::BinaryOp( + // This is a `WrappingRange`, so make sure to get the wrapping right. + BinOp::Le, + Box::new((Operand::Copy(discr_diff), end_start_diff_const)), + ), + ))), + )); + + block_data.terminator = Some(Terminator { + source_info, + kind: TerminatorKind::Assert { + cond: Operand::Copy(is_ok), + expected: true, + target: new_block, + msg: Box::new(AssertKind::InvalidEnumConstruction(Operand::Copy(discr))), + // This calls panic_invalid_enum_construction, which is #[rustc_nounwind]. + // We never want to insert an unwind into unsafe code, because unwinding could + // make a failing UB check turn into much worse UB when we start unwinding. + unwind: UnwindAction::Unreachable, + }, + }); +} diff --git a/compiler/rustc_mir_transform/src/check_null.rs b/compiler/rustc_mir_transform/src/check_null.rs index ad74e335bd9..e365d36580a 100644 --- a/compiler/rustc_mir_transform/src/check_null.rs +++ b/compiler/rustc_mir_transform/src/check_null.rs @@ -41,13 +41,12 @@ fn insert_null_check<'tcx>( let const_raw_ptr = Ty::new_imm_ptr(tcx, tcx.types.unit); let rvalue = Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(pointer), const_raw_ptr); let thin_ptr = local_decls.push(LocalDecl::with_source_info(const_raw_ptr, source_info)).into(); - stmts - .push(Statement { source_info, kind: StatementKind::Assign(Box::new((thin_ptr, rvalue))) }); + stmts.push(Statement::new(source_info, StatementKind::Assign(Box::new((thin_ptr, rvalue))))); // Transmute the pointer to a usize (equivalent to `ptr.addr()`). let rvalue = Rvalue::Cast(CastKind::Transmute, Operand::Copy(thin_ptr), tcx.types.usize); let addr = local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into(); - stmts.push(Statement { source_info, kind: StatementKind::Assign(Box::new((addr, rvalue))) }); + stmts.push(Statement::new(source_info, StatementKind::Assign(Box::new((addr, rvalue))))); let zero = Operand::Constant(Box::new(ConstOperand { span: source_info.span, @@ -71,24 +70,24 @@ fn insert_null_check<'tcx>( let rvalue = Rvalue::NullaryOp(NullOp::SizeOf, pointee_ty); let sizeof_pointee = local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into(); - stmts.push(Statement { + stmts.push(Statement::new( source_info, - kind: StatementKind::Assign(Box::new((sizeof_pointee, rvalue))), - }); + StatementKind::Assign(Box::new((sizeof_pointee, rvalue))), + )); // Check that the pointee is not a ZST. let is_pointee_not_zst = local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into(); - stmts.push(Statement { + stmts.push(Statement::new( source_info, - kind: StatementKind::Assign(Box::new(( + StatementKind::Assign(Box::new(( is_pointee_not_zst, Rvalue::BinaryOp( BinOp::Ne, Box::new((Operand::Copy(sizeof_pointee), zero.clone())), ), ))), - }); + )); // Pointer needs to be checked only if pointee is not a ZST. Operand::Copy(is_pointee_not_zst) @@ -97,38 +96,38 @@ fn insert_null_check<'tcx>( // Check whether the pointer is null. let is_null = local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into(); - stmts.push(Statement { + stmts.push(Statement::new( source_info, - kind: StatementKind::Assign(Box::new(( + StatementKind::Assign(Box::new(( is_null, Rvalue::BinaryOp(BinOp::Eq, Box::new((Operand::Copy(addr), zero))), ))), - }); + )); // We want to throw an exception if the pointer is null and the pointee is not unconditionally // allowed (which for all non-borrow place uses, is when the pointee is ZST). let should_throw_exception = local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into(); - stmts.push(Statement { + stmts.push(Statement::new( source_info, - kind: StatementKind::Assign(Box::new(( + StatementKind::Assign(Box::new(( should_throw_exception, Rvalue::BinaryOp( BinOp::BitAnd, Box::new((Operand::Copy(is_null), pointee_should_be_checked)), ), ))), - }); + )); // The final condition whether this pointer usage is ok or not. let is_ok = local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into(); - stmts.push(Statement { + stmts.push(Statement::new( source_info, - kind: StatementKind::Assign(Box::new(( + StatementKind::Assign(Box::new(( is_ok, Rvalue::UnaryOp(UnOp::Not, Operand::Copy(should_throw_exception)), ))), - }); + )); // Emit a PointerCheck that asserts on the condition and otherwise triggers // a AssertKind::NullPointerDereference. diff --git a/compiler/rustc_mir_transform/src/check_pointers.rs b/compiler/rustc_mir_transform/src/check_pointers.rs index bf94f1aad24..4f913c1fca0 100644 --- a/compiler/rustc_mir_transform/src/check_pointers.rs +++ b/compiler/rustc_mir_transform/src/check_pointers.rs @@ -235,11 +235,11 @@ fn split_block( let block_data = &mut basic_blocks[location.block]; // Drain every statement after this one and move the current terminator to a new basic block. - let new_block = BasicBlockData { - statements: block_data.statements.split_off(location.statement_index), - terminator: block_data.terminator.take(), - is_cleanup: block_data.is_cleanup, - }; + let new_block = BasicBlockData::new_stmts( + block_data.statements.split_off(location.statement_index), + block_data.terminator.take(), + block_data.is_cleanup, + ); basic_blocks.push(new_block) } diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs index fe78a104fa0..cddeefca681 100644 --- a/compiler/rustc_mir_transform/src/copy_prop.rs +++ b/compiler/rustc_mir_transform/src/copy_prop.rs @@ -33,24 +33,26 @@ impl<'tcx> crate::MirPass<'tcx> for CopyProp { debug!(borrowed_locals = ?ssa.borrowed_locals()); debug!(copy_classes = ?ssa.copy_classes()); - let fully_moved = fully_moved_locals(&ssa, body); - debug!(?fully_moved); - - let mut storage_to_remove = DenseBitSet::new_empty(fully_moved.domain_size()); + let mut any_replacement = false; + let mut storage_to_remove = DenseBitSet::new_empty(body.local_decls.len()); for (local, &head) in ssa.copy_classes().iter_enumerated() { if local != head { + any_replacement = true; storage_to_remove.insert(head); } } - let any_replacement = ssa.copy_classes().iter_enumerated().any(|(l, &h)| l != h); + if !any_replacement { + return; + } + + let fully_moved = fully_moved_locals(&ssa, body); + debug!(?fully_moved); Replacer { tcx, copy_classes: ssa.copy_classes(), fully_moved, storage_to_remove } .visit_body_preserves_cfg(body); - if any_replacement { - crate::simplify::remove_unused_definitions(body); - } + crate::simplify::remove_unused_definitions(body); } fn is_required(&self) -> bool { diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 06c6b46a9c2..761d5461a99 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -252,16 +252,16 @@ impl<'tcx> TransformVisitor<'tcx> { } }; - let statements = vec![Statement { - kind: StatementKind::Assign(Box::new((Place::return_place(), none_value))), + let statements = vec![Statement::new( source_info, - }]; + StatementKind::Assign(Box::new((Place::return_place(), none_value))), + )]; - body.basic_blocks_mut().push(BasicBlockData { + body.basic_blocks_mut().push(BasicBlockData::new_stmts( statements, - terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }), - is_cleanup: false, - }); + Some(Terminator { source_info, kind: TerminatorKind::Return }), + false, + )); block } @@ -342,10 +342,10 @@ impl<'tcx> TransformVisitor<'tcx> { } }; - statements.push(Statement { - kind: StatementKind::Assign(Box::new((Place::return_place(), rvalue))), + statements.push(Statement::new( source_info, - }); + StatementKind::Assign(Box::new((Place::return_place(), rvalue))), + )); } // Create a Place referencing a coroutine struct field @@ -361,13 +361,13 @@ impl<'tcx> TransformVisitor<'tcx> { // Create a statement which changes the discriminant fn set_discr(&self, state_disc: VariantIdx, source_info: SourceInfo) -> Statement<'tcx> { let self_place = Place::from(SELF_ARG); - Statement { + Statement::new( source_info, - kind: StatementKind::SetDiscriminant { + StatementKind::SetDiscriminant { place: Box::new(self_place), variant_index: state_disc, }, - } + ) } // Create a statement which reads the discriminant into a temporary @@ -377,10 +377,10 @@ impl<'tcx> TransformVisitor<'tcx> { let temp = Place::from(local_decls_len); let self_place = Place::from(SELF_ARG); - let assign = Statement { - source_info: SourceInfo::outermost(body.span), - kind: StatementKind::Assign(Box::new((temp, Rvalue::Discriminant(self_place)))), - }; + let assign = Statement::new( + SourceInfo::outermost(body.span), + StatementKind::Assign(Box::new((temp, Rvalue::Discriminant(self_place)))), + ); (assign, temp) } } @@ -450,7 +450,7 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> { && !self.always_live_locals.contains(l); if needs_storage_dead { data.statements - .push(Statement { source_info, kind: StatementKind::StorageDead(l) }); + .push(Statement::new(source_info, StatementKind::StorageDead(l))); } } @@ -596,10 +596,8 @@ fn eliminate_get_context_call<'tcx>(bb_data: &mut BasicBlockData<'tcx>) -> Local let local = arg.node.place().unwrap().local; let arg = Rvalue::Use(arg.node); - let assign = Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new((destination, arg))), - }; + let assign = + Statement::new(terminator.source_info, StatementKind::Assign(Box::new((destination, arg)))); bb_data.statements.push(assign); bb_data.terminator = Some(Terminator { source_info: terminator.source_info, @@ -1075,11 +1073,11 @@ fn insert_switch<'tcx>( let source_info = SourceInfo::outermost(body.span); body.basic_blocks_mut().raw.insert( 0, - BasicBlockData { - statements: vec![assign], - terminator: Some(Terminator { source_info, kind: switch }), - is_cleanup: false, - }, + BasicBlockData::new_stmts( + vec![assign], + Some(Terminator { source_info, kind: switch }), + false, + ), ); for b in body.basic_blocks_mut().iter_mut() { @@ -1089,11 +1087,7 @@ fn insert_switch<'tcx>( fn insert_term_block<'tcx>(body: &mut Body<'tcx>, kind: TerminatorKind<'tcx>) -> BasicBlock { let source_info = SourceInfo::outermost(body.span); - body.basic_blocks_mut().push(BasicBlockData { - statements: Vec::new(), - terminator: Some(Terminator { source_info, kind }), - is_cleanup: false, - }) + body.basic_blocks_mut().push(BasicBlockData::new(Some(Terminator { source_info, kind }), false)) } fn return_poll_ready_assign<'tcx>(tcx: TyCtxt<'tcx>, source_info: SourceInfo) -> Statement<'tcx> { @@ -1109,19 +1103,16 @@ fn return_poll_ready_assign<'tcx>(tcx: TyCtxt<'tcx>, source_info: SourceInfo) -> Box::new(AggregateKind::Adt(poll_def_id, VariantIdx::from_usize(0), args, None, None)), IndexVec::from_raw(vec![val]), ); - Statement { - kind: StatementKind::Assign(Box::new((Place::return_place(), ready_val))), - source_info, - } + Statement::new(source_info, StatementKind::Assign(Box::new((Place::return_place(), ready_val)))) } fn insert_poll_ready_block<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> BasicBlock { let source_info = SourceInfo::outermost(body.span); - body.basic_blocks_mut().push(BasicBlockData { - statements: [return_poll_ready_assign(tcx, source_info)].to_vec(), - terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }), - is_cleanup: false, - }) + body.basic_blocks_mut().push(BasicBlockData::new_stmts( + [return_poll_ready_assign(tcx, source_info)].to_vec(), + Some(Terminator { source_info, kind: TerminatorKind::Return }), + false, + )) } fn insert_panic_block<'tcx>( @@ -1205,13 +1196,11 @@ fn generate_poison_block_and_redirect_unwinds_there<'tcx>( body: &mut Body<'tcx>, ) { let source_info = SourceInfo::outermost(body.span); - let poison_block = body.basic_blocks_mut().push(BasicBlockData { - statements: vec![ - transform.set_discr(VariantIdx::new(CoroutineArgs::POISONED), source_info), - ], - terminator: Some(Terminator { source_info, kind: TerminatorKind::UnwindResume }), - is_cleanup: true, - }); + let poison_block = body.basic_blocks_mut().push(BasicBlockData::new_stmts( + vec![transform.set_discr(VariantIdx::new(CoroutineArgs::POISONED), source_info)], + Some(Terminator { source_info, kind: TerminatorKind::UnwindResume }), + true, + )); for (idx, block) in body.basic_blocks_mut().iter_enumerated_mut() { let source_info = block.terminator().source_info; @@ -1345,32 +1334,28 @@ fn create_cases<'tcx>( && !transform.remap.contains(l) && !transform.always_live_locals.contains(l); if needs_storage_live { - statements - .push(Statement { source_info, kind: StatementKind::StorageLive(l) }); + statements.push(Statement::new(source_info, StatementKind::StorageLive(l))); } } if operation == Operation::Resume { // Move the resume argument to the destination place of the `Yield` terminator let resume_arg = CTX_ARG; - statements.push(Statement { + statements.push(Statement::new( source_info, - kind: StatementKind::Assign(Box::new(( + StatementKind::Assign(Box::new(( point.resume_arg, Rvalue::Use(Operand::Move(resume_arg.into())), ))), - }); + )); } // Then jump to the real target - let block = body.basic_blocks_mut().push(BasicBlockData { + let block = body.basic_blocks_mut().push(BasicBlockData::new_stmts( statements, - terminator: Some(Terminator { - source_info, - kind: TerminatorKind::Goto { target }, - }), - is_cleanup: false, - }); + Some(Terminator { source_info, kind: TerminatorKind::Goto { target } }), + false, + )); (point.state, block) }) @@ -1540,13 +1525,13 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform { let stmts = &mut body.basic_blocks_mut()[START_BLOCK].statements; stmts.insert( 0, - Statement { + Statement::new( source_info, - kind: StatementKind::Assign(Box::new(( + StatementKind::Assign(Box::new(( old_resume_local.into(), Rvalue::Use(Operand::Move(resume_local.into())), ))), - }, + ), ); let always_live_locals = always_storage_live_locals(body); diff --git a/compiler/rustc_mir_transform/src/coroutine/drop.rs b/compiler/rustc_mir_transform/src/coroutine/drop.rs index dc68629ec0d..406575c4f43 100644 --- a/compiler/rustc_mir_transform/src/coroutine/drop.rs +++ b/compiler/rustc_mir_transform/src/coroutine/drop.rs @@ -87,12 +87,11 @@ fn build_pin_fut<'tcx>( const_: Const::zero_sized(pin_fut_new_unchecked_fn), })); - let storage_live = - Statement { source_info, kind: StatementKind::StorageLive(fut_pin_place.local) }; + let storage_live = Statement::new(source_info, StatementKind::StorageLive(fut_pin_place.local)); - let fut_ref_assign = Statement { + let fut_ref_assign = Statement::new( source_info, - kind: StatementKind::Assign(Box::new(( + StatementKind::Assign(Box::new(( fut_ref_place, Rvalue::Ref( tcx.lifetimes.re_erased, @@ -100,12 +99,12 @@ fn build_pin_fut<'tcx>( fut_place, ), ))), - }; + ); // call Pin<FutTy>::new_unchecked(&mut fut) - let pin_fut_bb = body.basic_blocks_mut().push(BasicBlockData { - statements: [storage_live, fut_ref_assign].to_vec(), - terminator: Some(Terminator { + let pin_fut_bb = body.basic_blocks_mut().push(BasicBlockData::new_stmts( + [storage_live, fut_ref_assign].to_vec(), + Some(Terminator { source_info, kind: TerminatorKind::Call { func: pin_fut_new_unchecked_fn, @@ -117,8 +116,8 @@ fn build_pin_fut<'tcx>( fn_span: span, }, }), - is_cleanup: false, - }); + false, + )); (pin_fut_bb, fut_pin_place) } @@ -156,19 +155,15 @@ fn build_poll_switch<'tcx>( let source_info = SourceInfo::outermost(body.span); let poll_discr_place = Place::from(body.local_decls.push(LocalDecl::new(poll_discr_ty, source_info.span))); - let discr_assign = Statement { + let discr_assign = Statement::new( source_info, - kind: StatementKind::Assign(Box::new(( - poll_discr_place, - Rvalue::Discriminant(*poll_unit_place), - ))), - }; - let storage_dead = - Statement { source_info, kind: StatementKind::StorageDead(fut_pin_place.local) }; + StatementKind::Assign(Box::new((poll_discr_place, Rvalue::Discriminant(*poll_unit_place)))), + ); + let storage_dead = Statement::new(source_info, StatementKind::StorageDead(fut_pin_place.local)); let unreachable_block = insert_term_block(body, TerminatorKind::Unreachable); - body.basic_blocks_mut().push(BasicBlockData { - statements: [storage_dead, discr_assign].to_vec(), - terminator: Some(Terminator { + body.basic_blocks_mut().push(BasicBlockData::new_stmts( + [storage_dead, discr_assign].to_vec(), + Some(Terminator { source_info, kind: TerminatorKind::SwitchInt { discr: Operand::Move(poll_discr_place), @@ -179,8 +174,8 @@ fn build_poll_switch<'tcx>( ), }, }), - is_cleanup: false, - }) + false, + )) } // Gather blocks, reachable through 'drop' targets of Yield and Drop terminators (chained) @@ -330,10 +325,10 @@ pub(super) fn expand_async_drops<'tcx>( let context_ref_place = Place::from(body.local_decls.push(LocalDecl::new(context_mut_ref, source_info.span))); let arg = Rvalue::Use(Operand::Move(Place::from(CTX_ARG))); - body[bb].statements.push(Statement { + body[bb].statements.push(Statement::new( source_info, - kind: StatementKind::Assign(Box::new((context_ref_place, arg))), - }); + StatementKind::Assign(Box::new((context_ref_place, arg))), + )); let yield_block = insert_term_block(body, TerminatorKind::Unreachable); // `kind` replaced later to yield let (pin_bb, fut_pin_place) = build_pin_fut(tcx, body, fut_place.clone(), UnwindAction::Continue); @@ -551,11 +546,8 @@ pub(super) fn insert_clean_drop<'tcx>( }; // Create a block to destroy an unresumed coroutines. This can only destroy upvars. - body.basic_blocks_mut().push(BasicBlockData { - statements: Vec::new(), - terminator: Some(Terminator { source_info, kind: term }), - is_cleanup: false, - }) + body.basic_blocks_mut() + .push(BasicBlockData::new(Some(Terminator { source_info, kind: term }), false)) } pub(super) fn create_coroutine_drop_shim<'tcx>( @@ -734,11 +726,7 @@ pub(super) fn create_coroutine_drop_shim_proxy_async<'tcx>( body.local_decls[RETURN_PLACE] = LocalDecl::with_source_info(poll_enum, source_info); // call coroutine_drop() - let call_bb = body.basic_blocks_mut().push(BasicBlockData { - statements: Vec::new(), - terminator: None, - is_cleanup: false, - }); + let call_bb = body.basic_blocks_mut().push(BasicBlockData::new(None, false)); // return Poll::Ready() let ret_bb = insert_poll_ready_block(tcx, &mut body); diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 702c62eddc7..f253d1662ca 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -259,7 +259,7 @@ fn inject_statement(mir_body: &mut mir::Body<'_>, counter_kind: CoverageKind, bb debug!(" injecting statement {counter_kind:?} for {bb:?}"); let data = &mut mir_body[bb]; let source_info = data.terminator().source_info; - let statement = Statement { source_info, kind: StatementKind::Coverage(counter_kind) }; + let statement = Statement::new(source_info, StatementKind::Coverage(counter_kind)); data.statements.insert(0, statement); } diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs index 3c0053c610d..b0fc5e90f07 100644 --- a/compiler/rustc_mir_transform/src/coverage/tests.rs +++ b/compiler/rustc_mir_transform/src/coverage/tests.rs @@ -68,14 +68,13 @@ impl<'tcx> MockBlocks<'tcx> { BytePos(1) }; let next_hi = next_lo + BytePos(1); - self.blocks.push(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { + self.blocks.push(BasicBlockData::new( + Some(Terminator { source_info: SourceInfo::outermost(Span::with_root_ctxt(next_lo, next_hi)), kind, }), - is_cleanup: false, - }) + false, + )) } fn link(&mut self, from_block: BasicBlock, to_block: BasicBlock) { diff --git a/compiler/rustc_mir_transform/src/ctfe_limit.rs b/compiler/rustc_mir_transform/src/ctfe_limit.rs index d0b313e149a..fb17cca30f4 100644 --- a/compiler/rustc_mir_transform/src/ctfe_limit.rs +++ b/compiler/rustc_mir_transform/src/ctfe_limit.rs @@ -55,8 +55,8 @@ fn has_back_edge( } fn insert_counter(basic_block_data: &mut BasicBlockData<'_>) { - basic_block_data.statements.push(Statement { - source_info: basic_block_data.terminator().source_info, - kind: StatementKind::ConstEvalCounter, - }); + basic_block_data.statements.push(Statement::new( + basic_block_data.terminator().source_info, + StatementKind::ConstEvalCounter, + )); } diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 0cf8142a560..fe53de31f75 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -16,7 +16,6 @@ use rustc_middle::bug; use rustc_middle::mir::interpret::{InterpResult, Scalar}; use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; use rustc_middle::mir::*; -use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_mir_dataflow::fmt::DebugWithContext; use rustc_mir_dataflow::lattice::{FlatSet, HasBottom}; diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs index c9bc52c6c7e..de96b1f255a 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drop.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs @@ -222,15 +222,14 @@ where let span = self.source_info.span; let pin_obj_bb = bb.unwrap_or_else(|| { - self.elaborator.patch().new_block(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { + self.elaborator.patch().new_block(BasicBlockData::new( + Some(Terminator { // Temporary terminator, will be replaced by patch source_info: self.source_info, kind: TerminatorKind::Return, }), - is_cleanup: false, - }) + false, + )) }); let (fut_ty, drop_fn_def_id, trait_args) = if call_destructor_only { @@ -366,10 +365,8 @@ where call_statements.push(self.assign(obj_ptr_place, addr)); obj_ptr_place }; - call_statements.push(Statement { - source_info: self.source_info, - kind: StatementKind::StorageLive(fut.local), - }); + call_statements + .push(Statement::new(self.source_info, StatementKind::StorageLive(fut.local))); let call_drop_bb = self.new_block_with_statements( unwind, @@ -732,17 +729,17 @@ where let do_drop_bb = self.drop_subpath(interior, interior_path, succ, unwind, dropline); - let setup_bbd = BasicBlockData { - statements: vec![self.assign( + let setup_bbd = BasicBlockData::new_stmts( + vec![self.assign( Place::from(ptr_local), Rvalue::Cast(CastKind::Transmute, Operand::Copy(nonnull_place), ptr_ty), )], - terminator: Some(Terminator { + Some(Terminator { kind: TerminatorKind::Goto { target: do_drop_bb }, source_info: self.source_info, }), - is_cleanup: unwind.is_cleanup(), - }; + unwind.is_cleanup(), + ); self.elaborator.patch().new_block(setup_bbd) } @@ -753,14 +750,13 @@ where args: GenericArgsRef<'tcx>, ) -> BasicBlock { if adt.variants().is_empty() { - return self.elaborator.patch().new_block(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { + return self.elaborator.patch().new_block(BasicBlockData::new( + Some(Terminator { source_info: self.source_info, kind: TerminatorKind::Unreachable, }), - is_cleanup: self.unwind.is_cleanup(), - }); + self.unwind.is_cleanup(), + )); } let skip_contents = adt.is_union() || adt.is_manually_drop(); @@ -927,9 +923,9 @@ where let discr_ty = adt.repr().discr_type().to_ty(self.tcx()); let discr = Place::from(self.new_temp(discr_ty)); let discr_rv = Rvalue::Discriminant(self.place); - let switch_block = BasicBlockData { - statements: vec![self.assign(discr, discr_rv)], - terminator: Some(Terminator { + let switch_block = BasicBlockData::new_stmts( + vec![self.assign(discr, discr_rv)], + Some(Terminator { source_info: self.source_info, kind: TerminatorKind::SwitchInt { discr: Operand::Move(discr), @@ -939,8 +935,8 @@ where ), }, }), - is_cleanup: unwind.is_cleanup(), - }; + unwind.is_cleanup(), + ); let switch_block = self.elaborator.patch().new_block(switch_block); self.drop_flag_test_block(switch_block, succ, unwind) } @@ -956,8 +952,8 @@ where let ref_place = self.new_temp(ref_ty); let unit_temp = Place::from(self.new_temp(tcx.types.unit)); - let result = BasicBlockData { - statements: vec![self.assign( + let result = BasicBlockData::new_stmts( + vec![self.assign( Place::from(ref_place), Rvalue::Ref( tcx.lifetimes.re_erased, @@ -965,7 +961,7 @@ where self.place, ), )], - terminator: Some(Terminator { + Some(Terminator { kind: TerminatorKind::Call { func: Operand::function_handle( tcx, @@ -983,8 +979,8 @@ where }, source_info: self.source_info, }), - is_cleanup: unwind.is_cleanup(), - }; + unwind.is_cleanup(), + ); let destructor_block = self.elaborator.patch().new_block(result); @@ -1047,8 +1043,8 @@ where let can_go = Place::from(self.new_temp(tcx.types.bool)); let one = self.constant_usize(1); - let drop_block = BasicBlockData { - statements: vec![ + let drop_block = BasicBlockData::new_stmts( + vec![ self.assign( ptr, Rvalue::RawPtr(RawPtrKind::Mut, tcx.mk_place_index(self.place, cur)), @@ -1058,26 +1054,26 @@ where Rvalue::BinaryOp(BinOp::Add, Box::new((move_(cur.into()), one))), ), ], - is_cleanup: unwind.is_cleanup(), - terminator: Some(Terminator { + Some(Terminator { source_info: self.source_info, // this gets overwritten by drop elaboration. kind: TerminatorKind::Unreachable, }), - }; + unwind.is_cleanup(), + ); let drop_block = self.elaborator.patch().new_block(drop_block); - let loop_block = BasicBlockData { - statements: vec![self.assign( + let loop_block = BasicBlockData::new_stmts( + vec![self.assign( can_go, Rvalue::BinaryOp(BinOp::Eq, Box::new((copy(Place::from(cur)), copy(len.into())))), )], - is_cleanup: unwind.is_cleanup(), - terminator: Some(Terminator { + Some(Terminator { source_info: self.source_info, kind: TerminatorKind::if_(move_(can_go), succ, drop_block), }), - }; + unwind.is_cleanup(), + ); let loop_block = self.elaborator.patch().new_block(loop_block); let place = tcx.mk_place_deref(ptr); @@ -1187,8 +1183,8 @@ where let slice_ptr_ty = Ty::new_mut_ptr(tcx, slice_ty); let slice_ptr = self.new_temp(slice_ptr_ty); - let mut delegate_block = BasicBlockData { - statements: vec![ + let mut delegate_block = BasicBlockData::new_stmts( + vec![ self.assign(Place::from(array_ptr), Rvalue::RawPtr(RawPtrKind::Mut, self.place)), self.assign( Place::from(slice_ptr), @@ -1202,9 +1198,9 @@ where ), ), ], - is_cleanup: self.unwind.is_cleanup(), - terminator: None, - }; + None, + self.unwind.is_cleanup(), + ); let array_place = mem::replace( &mut self.place, @@ -1246,8 +1242,8 @@ where }; let zero = self.constant_usize(0); - let block = BasicBlockData { - statements: vec![ + let block = BasicBlockData::new_stmts( + vec![ self.assign( len.into(), Rvalue::UnaryOp( @@ -1257,12 +1253,12 @@ where ), self.assign(cur.into(), Rvalue::Use(zero)), ], - is_cleanup: unwind.is_cleanup(), - terminator: Some(Terminator { + Some(Terminator { source_info: self.source_info, kind: TerminatorKind::Goto { target: loop_block }, }), - }; + unwind.is_cleanup(), + ); let drop_block = self.elaborator.patch().new_block(block); // FIXME(#34708): handle partially-dropped array/slice elements. @@ -1308,14 +1304,13 @@ where self.source_info.span, "open drop for unsafe binder shouldn't be encountered", ); - self.elaborator.patch().new_block(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { + self.elaborator.patch().new_block(BasicBlockData::new( + Some(Terminator { source_info: self.source_info, kind: TerminatorKind::Unreachable, }), - is_cleanup: self.unwind.is_cleanup(), - }) + self.unwind.is_cleanup(), + )) } _ => span_bug!(self.source_info.span, "open drop from non-ADT `{:?}`", ty), @@ -1434,11 +1429,10 @@ where } fn new_block(&mut self, unwind: Unwind, k: TerminatorKind<'tcx>) -> BasicBlock { - self.elaborator.patch().new_block(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { source_info: self.source_info, kind: k }), - is_cleanup: unwind.is_cleanup(), - }) + self.elaborator.patch().new_block(BasicBlockData::new( + Some(Terminator { source_info: self.source_info, kind: k }), + unwind.is_cleanup(), + )) } fn new_block_with_statements( @@ -1447,11 +1441,11 @@ where statements: Vec<Statement<'tcx>>, k: TerminatorKind<'tcx>, ) -> BasicBlock { - self.elaborator.patch().new_block(BasicBlockData { + self.elaborator.patch().new_block(BasicBlockData::new_stmts( statements, - terminator: Some(Terminator { source_info: self.source_info, kind: k }), - is_cleanup: unwind.is_cleanup(), - }) + Some(Terminator { source_info: self.source_info, kind: k }), + unwind.is_cleanup(), + )) } fn new_temp(&mut self, ty: Ty<'tcx>) -> Local { @@ -1467,9 +1461,6 @@ where } fn assign(&self, lhs: Place<'tcx>, rhs: Rvalue<'tcx>) -> Statement<'tcx> { - Statement { - source_info: self.source_info, - kind: StatementKind::Assign(Box::new((lhs, rhs))), - } + Statement::new(self.source_info, StatementKind::Assign(Box::new((lhs, rhs)))) } } diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index bda71ceaa55..335354c23b6 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -102,7 +102,7 @@ use rustc_middle::bug; use rustc_middle::mir::interpret::GlobalAlloc; use rustc_middle::mir::visit::*; use rustc_middle::mir::*; -use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf}; +use rustc_middle::ty::layout::HasTypingEnv; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::DUMMY_SP; use rustc_span::def_id::DefId; @@ -1625,7 +1625,7 @@ fn op_to_prop_const<'tcx>( // If this constant is already represented as an `Allocation`, // try putting it into global memory to return it. if let Either::Left(mplace) = op.as_mplace_or_imm() { - let (size, _align) = ecx.size_and_align_of_mplace(&mplace).discard_err()??; + let (size, _align) = ecx.size_and_align_of_val(&mplace).discard_err()??; // Do not try interning a value that contains provenance. // Due to https://github.com/rust-lang/rust/issues/79738, doing so could lead to bugs. @@ -1636,7 +1636,7 @@ fn op_to_prop_const<'tcx>( } let pointer = mplace.ptr().into_pointer_or_addr().ok()?; - let (prov, offset) = pointer.into_parts(); + let (prov, offset) = pointer.prov_and_relative_offset(); let alloc_id = prov.alloc_id(); intern_const_alloc_for_constprop(ecx, alloc_id).discard_err()?; diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index f48dba9663a..7852bb7ae2f 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -770,14 +770,15 @@ fn check_mir_is_available<'tcx, I: Inliner<'tcx>>( return Ok(()); } - if callee_def_id.is_local() + if let Some(callee_def_id) = callee_def_id.as_local() && !inliner .tcx() .is_lang_item(inliner.tcx().parent(caller_def_id), rustc_hir::LangItem::FnOnce) { // If we know for sure that the function we're calling will itself try to // call us, then we avoid inlining that function. - if inliner.tcx().mir_callgraph_reachable((callee, caller_def_id.expect_local())) { + if inliner.tcx().mir_callgraph_cyclic(caller_def_id.expect_local()).contains(&callee_def_id) + { debug!("query cycle avoidance"); return Err("caller might be reachable from callee"); } @@ -899,10 +900,10 @@ fn inline_call<'tcx, I: Inliner<'tcx>>( ); let dest_ty = dest.ty(caller_body, tcx); let temp = Place::from(new_call_temp(caller_body, callsite, dest_ty, return_block)); - caller_body[callsite.block].statements.push(Statement { - source_info: callsite.source_info, - kind: StatementKind::Assign(Box::new((temp, dest))), - }); + caller_body[callsite.block].statements.push(Statement::new( + callsite.source_info, + StatementKind::Assign(Box::new((temp, dest))), + )); tcx.mk_place_deref(temp) } else { destination @@ -946,10 +947,9 @@ fn inline_call<'tcx, I: Inliner<'tcx>>( for local in callee_body.vars_and_temps_iter() { if integrator.always_live_locals.contains(local) { let new_local = integrator.map_local(local); - caller_body[callsite.block].statements.push(Statement { - source_info: callsite.source_info, - kind: StatementKind::StorageLive(new_local), - }); + caller_body[callsite.block] + .statements + .push(Statement::new(callsite.source_info, StatementKind::StorageLive(new_local))); } } if let Some(block) = return_block { @@ -957,22 +957,22 @@ fn inline_call<'tcx, I: Inliner<'tcx>>( // the slice once. let mut n = 0; if remap_destination { - caller_body[block].statements.push(Statement { - source_info: callsite.source_info, - kind: StatementKind::Assign(Box::new(( + caller_body[block].statements.push(Statement::new( + callsite.source_info, + StatementKind::Assign(Box::new(( dest, Rvalue::Use(Operand::Move(destination_local.into())), ))), - }); + )); n += 1; } for local in callee_body.vars_and_temps_iter().rev() { if integrator.always_live_locals.contains(local) { let new_local = integrator.map_local(local); - caller_body[block].statements.push(Statement { - source_info: callsite.source_info, - kind: StatementKind::StorageDead(new_local), - }); + caller_body[block].statements.push(Statement::new( + callsite.source_info, + StatementKind::StorageDead(new_local), + )); n += 1; } } @@ -1125,10 +1125,10 @@ fn create_temp_if_necessary<'tcx, I: Inliner<'tcx>>( trace!("creating temp for argument {:?}", arg); let arg_ty = arg.ty(caller_body, inliner.tcx()); let local = new_call_temp(caller_body, callsite, arg_ty, return_block); - caller_body[callsite.block].statements.push(Statement { - source_info: callsite.source_info, - kind: StatementKind::Assign(Box::new((Place::from(local), Rvalue::Use(arg)))), - }); + caller_body[callsite.block].statements.push(Statement::new( + callsite.source_info, + StatementKind::Assign(Box::new((Place::from(local), Rvalue::Use(arg)))), + )); local } @@ -1141,19 +1141,14 @@ fn new_call_temp<'tcx>( ) -> Local { let local = caller_body.local_decls.push(LocalDecl::new(ty, callsite.source_info.span)); - caller_body[callsite.block].statements.push(Statement { - source_info: callsite.source_info, - kind: StatementKind::StorageLive(local), - }); + caller_body[callsite.block] + .statements + .push(Statement::new(callsite.source_info, StatementKind::StorageLive(local))); if let Some(block) = return_block { - caller_body[block].statements.insert( - 0, - Statement { - source_info: callsite.source_info, - kind: StatementKind::StorageDead(local), - }, - ); + caller_body[block] + .statements + .insert(0, Statement::new(callsite.source_info, StatementKind::StorageDead(local))); } local diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index a944960ce4a..08f3ce5fd67 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -1,5 +1,6 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_data_structures::stack::ensure_sufficient_stack; +use rustc_data_structures::unord::UnordSet; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::mir::TerminatorKind; use rustc_middle::ty::{self, GenericArgsRef, InstanceKind, TyCtxt, TypeVisitableExt}; @@ -7,137 +8,143 @@ use rustc_session::Limit; use rustc_span::sym; use tracing::{instrument, trace}; -// FIXME: check whether it is cheaper to precompute the entire call graph instead of invoking -// this query ridiculously often. -#[instrument(level = "debug", skip(tcx, root, target))] -pub(crate) fn mir_callgraph_reachable<'tcx>( +#[instrument(level = "debug", skip(tcx), ret)] +fn should_recurse<'tcx>(tcx: TyCtxt<'tcx>, callee: ty::Instance<'tcx>) -> bool { + match callee.def { + // If there is no MIR available (either because it was not in metadata or + // because it has no MIR because it's an extern function), then the inliner + // won't cause cycles on this. + InstanceKind::Item(_) => { + if !tcx.is_mir_available(callee.def_id()) { + return false; + } + } + + // These have no own callable MIR. + InstanceKind::Intrinsic(_) | InstanceKind::Virtual(..) => return false, + + // These have MIR and if that MIR is inlined, instantiated and then inlining is run + // again, a function item can end up getting inlined. Thus we'll be able to cause + // a cycle that way + InstanceKind::VTableShim(_) + | InstanceKind::ReifyShim(..) + | InstanceKind::FnPtrShim(..) + | InstanceKind::ClosureOnceShim { .. } + | InstanceKind::ConstructCoroutineInClosureShim { .. } + | InstanceKind::ThreadLocalShim { .. } + | InstanceKind::CloneShim(..) => {} + + // This shim does not call any other functions, thus there can be no recursion. + InstanceKind::FnPtrAddrShim(..) => return false, + + // FIXME: A not fully instantiated drop shim can cause ICEs if one attempts to + // have its MIR built. Likely oli-obk just screwed up the `ParamEnv`s, so this + // needs some more analysis. + InstanceKind::DropGlue(..) + | InstanceKind::FutureDropPollShim(..) + | InstanceKind::AsyncDropGlue(..) + | InstanceKind::AsyncDropGlueCtorShim(..) => { + if callee.has_param() { + return false; + } + } + } + + crate::pm::should_run_pass(tcx, &crate::inline::Inline, crate::pm::Optimizations::Allowed) + || crate::inline::ForceInline::should_run_pass_for_callee(tcx, callee.def.def_id()) +} + +#[instrument( + level = "debug", + skip(tcx, typing_env, seen, involved, recursion_limiter, recursion_limit), + ret +)] +fn process<'tcx>( tcx: TyCtxt<'tcx>, - (root, target): (ty::Instance<'tcx>, LocalDefId), + typing_env: ty::TypingEnv<'tcx>, + caller: ty::Instance<'tcx>, + target: LocalDefId, + seen: &mut FxHashSet<ty::Instance<'tcx>>, + involved: &mut FxHashSet<LocalDefId>, + recursion_limiter: &mut FxHashMap<DefId, usize>, + recursion_limit: Limit, ) -> bool { - trace!(%root, target = %tcx.def_path_str(target)); - assert_ne!( - root.def_id().expect_local(), - target, - "you should not call `mir_callgraph_reachable` on immediate self recursion" - ); - assert!( - matches!(root.def, InstanceKind::Item(_)), - "you should not call `mir_callgraph_reachable` on shims" - ); - assert!( - !tcx.is_constructor(root.def_id()), - "you should not call `mir_callgraph_reachable` on enum/struct constructor functions" - ); - #[instrument( - level = "debug", - skip(tcx, typing_env, target, stack, seen, recursion_limiter, caller, recursion_limit) - )] - fn process<'tcx>( - tcx: TyCtxt<'tcx>, - typing_env: ty::TypingEnv<'tcx>, - caller: ty::Instance<'tcx>, - target: LocalDefId, - stack: &mut Vec<ty::Instance<'tcx>>, - seen: &mut FxHashSet<ty::Instance<'tcx>>, - recursion_limiter: &mut FxHashMap<DefId, usize>, - recursion_limit: Limit, - ) -> bool { - trace!(%caller); - for &(callee, args) in tcx.mir_inliner_callees(caller.def) { - let Ok(args) = caller.try_instantiate_mir_and_normalize_erasing_regions( - tcx, - typing_env, - ty::EarlyBinder::bind(args), - ) else { - trace!(?caller, ?typing_env, ?args, "cannot normalize, skipping"); - continue; - }; - let Ok(Some(callee)) = ty::Instance::try_resolve(tcx, typing_env, callee, args) else { - trace!(?callee, "cannot resolve, skipping"); - continue; - }; + trace!(%caller); + let mut cycle_found = false; - // Found a path. - if callee.def_id() == target.to_def_id() { - return true; - } + for &(callee, args) in tcx.mir_inliner_callees(caller.def) { + let Ok(args) = caller.try_instantiate_mir_and_normalize_erasing_regions( + tcx, + typing_env, + ty::EarlyBinder::bind(args), + ) else { + trace!(?caller, ?typing_env, ?args, "cannot normalize, skipping"); + continue; + }; + let Ok(Some(callee)) = ty::Instance::try_resolve(tcx, typing_env, callee, args) else { + trace!(?callee, "cannot resolve, skipping"); + continue; + }; - if tcx.is_constructor(callee.def_id()) { - trace!("constructors always have MIR"); - // Constructor functions cannot cause a query cycle. - continue; - } + // Found a path. + if callee.def_id() == target.to_def_id() { + cycle_found = true; + } - match callee.def { - InstanceKind::Item(_) => { - // If there is no MIR available (either because it was not in metadata or - // because it has no MIR because it's an extern function), then the inliner - // won't cause cycles on this. - if !tcx.is_mir_available(callee.def_id()) { - trace!(?callee, "no mir available, skipping"); - continue; - } - } - // These have no own callable MIR. - InstanceKind::Intrinsic(_) | InstanceKind::Virtual(..) => continue, - // These have MIR and if that MIR is inlined, instantiated and then inlining is run - // again, a function item can end up getting inlined. Thus we'll be able to cause - // a cycle that way - InstanceKind::VTableShim(_) - | InstanceKind::ReifyShim(..) - | InstanceKind::FnPtrShim(..) - | InstanceKind::ClosureOnceShim { .. } - | InstanceKind::ConstructCoroutineInClosureShim { .. } - | InstanceKind::ThreadLocalShim { .. } - | InstanceKind::CloneShim(..) => {} - - // This shim does not call any other functions, thus there can be no recursion. - InstanceKind::FnPtrAddrShim(..) => { - continue; - } - InstanceKind::DropGlue(..) - | InstanceKind::FutureDropPollShim(..) - | InstanceKind::AsyncDropGlue(..) - | InstanceKind::AsyncDropGlueCtorShim(..) => { - // FIXME: A not fully instantiated drop shim can cause ICEs if one attempts to - // have its MIR built. Likely oli-obk just screwed up the `ParamEnv`s, so this - // needs some more analysis. - if callee.has_param() { - continue; - } - } - } + if tcx.is_constructor(callee.def_id()) { + trace!("constructors always have MIR"); + // Constructor functions cannot cause a query cycle. + continue; + } + + if !should_recurse(tcx, callee) { + continue; + } - if seen.insert(callee) { - let recursion = recursion_limiter.entry(callee.def_id()).or_default(); - trace!(?callee, recursion = *recursion); - if recursion_limit.value_within_limit(*recursion) { - *recursion += 1; - stack.push(callee); - let found_recursion = ensure_sufficient_stack(|| { - process( - tcx, - typing_env, - callee, - target, - stack, - seen, - recursion_limiter, - recursion_limit, - ) - }); - if found_recursion { - return true; - } - stack.pop(); - } else { - // Pessimistically assume that there could be recursion. - return true; + if seen.insert(callee) { + let recursion = recursion_limiter.entry(callee.def_id()).or_default(); + trace!(?callee, recursion = *recursion); + let found_recursion = if recursion_limit.value_within_limit(*recursion) { + *recursion += 1; + ensure_sufficient_stack(|| { + process( + tcx, + typing_env, + callee, + target, + seen, + involved, + recursion_limiter, + recursion_limit, + ) + }) + } else { + // Pessimistically assume that there could be recursion. + true + }; + if found_recursion { + if let Some(callee) = callee.def_id().as_local() { + // Calling `optimized_mir` of a non-local definition cannot cycle. + involved.insert(callee); } + cycle_found = true; } } - false } + + cycle_found +} + +#[instrument(level = "debug", skip(tcx), ret)] +pub(crate) fn mir_callgraph_cyclic<'tcx>( + tcx: TyCtxt<'tcx>, + root: LocalDefId, +) -> UnordSet<LocalDefId> { + assert!( + !tcx.is_constructor(root.to_def_id()), + "you should not call `mir_callgraph_reachable` on enum/struct constructor functions" + ); + // FIXME(-Znext-solver=no): Remove this hack when trait solver overflow can return an error. // In code like that pointed out in #128887, the type complexity we ask the solver to deal with // grows as we recurse into the call graph. If we use the same recursion limit here and in the @@ -146,16 +153,32 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( // the default recursion limits are quite generous for us. If we need to recurse 64 times // into the call graph, we're probably not going to find any useful MIR inlining. let recursion_limit = tcx.recursion_limit() / 2; + let mut involved = FxHashSet::default(); + let typing_env = ty::TypingEnv::post_analysis(tcx, root); + let Ok(Some(root_instance)) = ty::Instance::try_resolve( + tcx, + typing_env, + root.to_def_id(), + ty::GenericArgs::identity_for_item(tcx, root.to_def_id()), + ) else { + trace!("cannot resolve, skipping"); + return involved.into(); + }; + if !should_recurse(tcx, root_instance) { + trace!("cannot walk, skipping"); + return involved.into(); + } process( tcx, - ty::TypingEnv::post_analysis(tcx, target), + typing_env, + root_instance, root, - target, - &mut Vec::new(), &mut FxHashSet::default(), + &mut involved, &mut FxHashMap::default(), recursion_limit, - ) + ); + involved.into() } pub(crate) fn mir_inliner_callees<'tcx>( diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index 5f0c55ddc09..dbcaed20953 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -240,15 +240,15 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> { let Some(arg_place) = arg.node.place() else { return }; - statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( + statements.push(Statement::new( + terminator.source_info, + StatementKind::Assign(Box::new(( *destination, Rvalue::Use(Operand::Copy( arg_place.project_deeper(&[ProjectionElem::Deref], self.tcx), )), ))), - }); + )); terminator.kind = TerminatorKind::Goto { target: *destination_block }; } diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index b45bff2af44..f9e642e28eb 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -45,7 +45,6 @@ use rustc_middle::bug; use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; -use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, ScalarInt, TyCtxt}; use rustc_mir_dataflow::lattice::HasBottom; use rustc_mir_dataflow::value_analysis::{Map, PlaceIndex, State, TrackElem}; diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 572ad585c8c..08f25276cec 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -117,6 +117,7 @@ declare_passes! { mod check_inline : CheckForceInline; mod check_call_recursion : CheckCallRecursion, CheckDropRecursion; mod check_alignment : CheckAlignment; + mod check_enums : CheckEnums; mod check_const_item_mutation : CheckConstItemMutation; mod check_null : CheckNull; mod check_packed_ref : CheckPackedRef; @@ -215,7 +216,7 @@ pub fn provide(providers: &mut Providers) { optimized_mir, is_mir_available, is_ctfe_mir_available: is_mir_available, - mir_callgraph_reachable: inline::cycle::mir_callgraph_reachable, + mir_callgraph_cyclic: inline::cycle::mir_callgraph_cyclic, mir_inliner_callees: inline::cycle::mir_inliner_callees, promoted_mir, deduced_param_attrs: deduce_param_attrs::deduced_param_attrs, @@ -258,13 +259,13 @@ fn remap_mir_for_const_eval_select<'tcx>( // (const generic stuff) so we just create a temporary and deconstruct // that. let local = body.local_decls.push(LocalDecl::new(ty, fn_span)); - bb.statements.push(Statement { - source_info: SourceInfo::outermost(fn_span), - kind: StatementKind::Assign(Box::new(( + bb.statements.push(Statement::new( + SourceInfo::outermost(fn_span), + StatementKind::Assign(Box::new(( local.into(), Rvalue::Use(tupled_args.node.clone()), ))), - }); + )); (Operand::Move, local.into()) } Operand::Move(place) => (Operand::Move, place), @@ -666,6 +667,7 @@ pub(crate) fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<' // Add some UB checks before any UB gets optimized away. &check_alignment::CheckAlignment, &check_null::CheckNull, + &check_enums::CheckEnums, // Before inlining: trim down MIR with passes to reduce inlining work. // Has to be done before inlining, otherwise actual call will be almost always inlined. diff --git a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs index 75f351f05c3..1bd770a8526 100644 --- a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs +++ b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs @@ -516,8 +516,12 @@ struct LocalLabel<'a> { /// A custom `Subdiagnostic` implementation so that the notes are delivered in a specific order impl Subdiagnostic for LocalLabel<'_> { fn add_to_diag<G: rustc_errors::EmissionGuarantee>(self, diag: &mut rustc_errors::Diag<'_, G>) { + // Becuase parent uses this field , we need to remove it delay before adding it. + diag.remove_arg("name"); diag.arg("name", self.name); + diag.remove_arg("is_generated_name"); diag.arg("is_generated_name", self.is_generated_name); + diag.remove_arg("is_dropped_first_edition_2024"); diag.arg("is_dropped_first_edition_2024", self.is_dropped_first_edition_2024); let msg = diag.eagerly_translate(crate::fluent_generated::mir_transform_tail_expr_local); diag.span_label(self.span, msg); diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index fa29ab985b7..8dadce0d448 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -25,31 +25,31 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { } sym::ub_checks => { let target = target.unwrap(); - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( + block.statements.push(Statement::new( + terminator.source_info, + StatementKind::Assign(Box::new(( *destination, Rvalue::NullaryOp(NullOp::UbChecks, tcx.types.bool), ))), - }); + )); terminator.kind = TerminatorKind::Goto { target }; } sym::contract_checks => { let target = target.unwrap(); - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( + block.statements.push(Statement::new( + terminator.source_info, + StatementKind::Assign(Box::new(( *destination, Rvalue::NullaryOp(NullOp::ContractChecks, tcx.types.bool), ))), - }); + )); terminator.kind = TerminatorKind::Goto { target }; } sym::forget => { let target = target.unwrap(); - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( + block.statements.push(Statement::new( + terminator.source_info, + StatementKind::Assign(Box::new(( *destination, Rvalue::Use(Operand::Constant(Box::new(ConstOperand { span: terminator.source_info.span, @@ -57,7 +57,7 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { const_: Const::zero_sized(tcx.types.unit), }))), ))), - }); + )); terminator.kind = TerminatorKind::Goto { target }; } sym::copy_nonoverlapping => { @@ -65,9 +65,9 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { let Ok([src, dst, count]) = take_array(args) else { bug!("Wrong arguments for copy_non_overlapping intrinsic"); }; - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Intrinsic(Box::new( + block.statements.push(Statement::new( + terminator.source_info, + StatementKind::Intrinsic(Box::new( NonDivergingIntrinsic::CopyNonOverlapping( rustc_middle::mir::CopyNonOverlapping { src: src.node, @@ -76,7 +76,7 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { }, ), )), - }); + )); terminator.kind = TerminatorKind::Goto { target }; } sym::assume => { @@ -84,12 +84,12 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { let Ok([arg]) = take_array(args) else { bug!("Wrong arguments for assume intrinsic"); }; - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Intrinsic(Box::new( - NonDivergingIntrinsic::Assume(arg.node), - )), - }); + block.statements.push(Statement::new( + terminator.source_info, + StatementKind::Intrinsic(Box::new(NonDivergingIntrinsic::Assume( + arg.node, + ))), + )); terminator.kind = TerminatorKind::Goto { target }; } sym::wrapping_add @@ -121,13 +121,13 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { sym::unchecked_shr => BinOp::ShrUnchecked, _ => bug!("unexpected intrinsic"), }; - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( + block.statements.push(Statement::new( + terminator.source_info, + StatementKind::Assign(Box::new(( *destination, Rvalue::BinaryOp(bin_op, Box::new((lhs.node, rhs.node))), ))), - }); + )); terminator.kind = TerminatorKind::Goto { target }; } sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => { @@ -141,13 +141,13 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { sym::mul_with_overflow => BinOp::MulWithOverflow, _ => bug!("unexpected intrinsic"), }; - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( + block.statements.push(Statement::new( + terminator.source_info, + StatementKind::Assign(Box::new(( *destination, Rvalue::BinaryOp(bin_op, Box::new((lhs.node, rhs.node))), ))), - }); + )); terminator.kind = TerminatorKind::Goto { target }; } sym::size_of | sym::align_of => { @@ -158,13 +158,13 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { sym::align_of => NullOp::AlignOf, _ => bug!("unexpected intrinsic"), }; - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( + block.statements.push(Statement::new( + terminator.source_info, + StatementKind::Assign(Box::new(( *destination, Rvalue::NullaryOp(null_op, tp_ty), ))), - }); + )); terminator.kind = TerminatorKind::Goto { target }; } sym::read_via_copy => { @@ -183,13 +183,13 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { }; // Add new statement at the end of the block that does the read, and patch // up the terminator. - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( + block.statements.push(Statement::new( + terminator.source_info, + StatementKind::Assign(Box::new(( *destination, Rvalue::Use(Operand::Copy(derefed_place)), ))), - }); + )); terminator.kind = match *target { None => { // No target means this read something uninhabited, @@ -217,13 +217,10 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { "Only passing a local is supported" ); }; - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( - derefed_place, - Rvalue::Use(val.node), - ))), - }); + block.statements.push(Statement::new( + terminator.source_info, + StatementKind::Assign(Box::new((derefed_place, Rvalue::Use(val.node)))), + )); terminator.kind = TerminatorKind::Goto { target }; } sym::discriminant_value => { @@ -236,13 +233,13 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { }; let arg = arg.node.place().unwrap(); let arg = tcx.mk_place_deref(arg); - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( + block.statements.push(Statement::new( + terminator.source_info, + StatementKind::Assign(Box::new(( *destination, Rvalue::Discriminant(arg), ))), - }); + )); terminator.kind = TerminatorKind::Goto { target }; } sym::offset => { @@ -253,13 +250,13 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { "Wrong number of arguments for offset intrinsic", ); }; - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( + block.statements.push(Statement::new( + terminator.source_info, + StatementKind::Assign(Box::new(( *destination, Rvalue::BinaryOp(BinOp::Offset, Box::new((ptr.node, delta.node))), ))), - }); + )); terminator.kind = TerminatorKind::Goto { target }; } sym::slice_get_unchecked => { @@ -302,10 +299,10 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { _ => bug!("Unknown return type {ret_ty:?}"), }; - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new((*destination, rvalue))), - }); + block.statements.push(Statement::new( + terminator.source_info, + StatementKind::Assign(Box::new((*destination, rvalue))), + )); terminator.kind = TerminatorKind::Goto { target }; } sym::transmute | sym::transmute_unchecked => { @@ -320,13 +317,13 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { // Always emit the cast, even if we transmute to an uninhabited type, // because that lets CTFE and codegen generate better error messages // when such a transmute actually ends up reachable. - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( + block.statements.push(Statement::new( + terminator.source_info, + StatementKind::Assign(Box::new(( *destination, Rvalue::Cast(CastKind::Transmute, arg.node, dst_ty), ))), - }); + )); if let Some(target) = *target { terminator.kind = TerminatorKind::Goto { target }; } else { @@ -351,13 +348,13 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { ); }; let fields = [data.node, meta.node]; - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( + block.statements.push(Statement::new( + terminator.source_info, + StatementKind::Assign(Box::new(( *destination, Rvalue::Aggregate(Box::new(kind), fields.into()), ))), - }); + )); terminator.kind = TerminatorKind::Goto { target }; } sym::ptr_metadata => { @@ -368,13 +365,13 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { ); }; let target = target.unwrap(); - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( + block.statements.push(Statement::new( + terminator.source_info, + StatementKind::Assign(Box::new(( *destination, Rvalue::UnaryOp(UnOp::PtrMetadata, ptr.node), ))), - }); + )); terminator.kind = TerminatorKind::Goto { target }; } _ => {} diff --git a/compiler/rustc_mir_transform/src/lower_slice_len.rs b/compiler/rustc_mir_transform/src/lower_slice_len.rs index aca80e36e33..79a9017de3e 100644 --- a/compiler/rustc_mir_transform/src/lower_slice_len.rs +++ b/compiler/rustc_mir_transform/src/lower_slice_len.rs @@ -56,8 +56,7 @@ fn lower_slice_len_call<'tcx>(block: &mut BasicBlockData<'tcx>, slice_len_fn_ite // make new RValue for Len let r_value = Rvalue::UnaryOp(UnOp::PtrMetadata, arg.node.clone()); let len_statement_kind = StatementKind::Assign(Box::new((*destination, r_value))); - let add_statement = - Statement { kind: len_statement_kind, source_info: terminator.source_info }; + let add_statement = Statement::new(terminator.source_info, len_statement_kind); // modify terminator into simple Goto let new_terminator_kind = TerminatorKind::Goto { target: *bb }; diff --git a/compiler/rustc_mir_transform/src/mentioned_items.rs b/compiler/rustc_mir_transform/src/mentioned_items.rs index 9fd8d81d64a..f011d394f61 100644 --- a/compiler/rustc_mir_transform/src/mentioned_items.rs +++ b/compiler/rustc_mir_transform/src/mentioned_items.rs @@ -74,8 +74,7 @@ impl<'tcx> Visitor<'tcx> for MentionedItemsVisitor<'_, 'tcx> { match *rvalue { // We need to detect unsizing casts that required vtables. mir::Rvalue::Cast( - mir::CastKind::PointerCoercion(PointerCoercion::Unsize, _) - | mir::CastKind::PointerCoercion(PointerCoercion::DynStar, _), + mir::CastKind::PointerCoercion(PointerCoercion::Unsize, _), ref operand, target_ty, ) => { diff --git a/compiler/rustc_mir_transform/src/patch.rs b/compiler/rustc_mir_transform/src/patch.rs index a872eae15f1..c781d1a5324 100644 --- a/compiler/rustc_mir_transform/src/patch.rs +++ b/compiler/rustc_mir_transform/src/patch.rs @@ -78,14 +78,13 @@ impl<'tcx> MirPatch<'tcx> { return bb; } - let bb = self.new_block(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { + let bb = self.new_block(BasicBlockData::new( + Some(Terminator { source_info: SourceInfo::outermost(self.body_span), kind: TerminatorKind::UnwindResume, }), - is_cleanup: true, - }); + true, + )); self.resume_block = Some(bb); bb } @@ -95,14 +94,13 @@ impl<'tcx> MirPatch<'tcx> { return bb; } - let bb = self.new_block(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { + let bb = self.new_block(BasicBlockData::new( + Some(Terminator { source_info: SourceInfo::outermost(self.body_span), kind: TerminatorKind::Unreachable, }), - is_cleanup: true, - }); + true, + )); self.unreachable_cleanup_block = Some(bb); bb } @@ -112,14 +110,13 @@ impl<'tcx> MirPatch<'tcx> { return bb; } - let bb = self.new_block(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { + let bb = self.new_block(BasicBlockData::new( + Some(Terminator { source_info: SourceInfo::outermost(self.body_span), kind: TerminatorKind::Unreachable, }), - is_cleanup: false, - }); + false, + )); self.unreachable_no_cleanup_block = Some(bb); bb } @@ -131,14 +128,13 @@ impl<'tcx> MirPatch<'tcx> { return cached_bb; } - let bb = self.new_block(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { + let bb = self.new_block(BasicBlockData::new( + Some(Terminator { source_info: SourceInfo::outermost(self.body_span), kind: TerminatorKind::UnwindTerminate(reason), }), - is_cleanup: true, - }); + true, + )); self.terminate_block = Some((bb, reason)); bb } @@ -280,7 +276,7 @@ impl<'tcx> MirPatch<'tcx> { let source_info = Self::source_info_for_index(&body[loc.block], loc); body[loc.block] .statements - .insert(loc.statement_index, Statement { source_info, kind: stmt }); + .insert(loc.statement_index, Statement::new(source_info, stmt)); delta += 1; } } diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index 47d43830970..4e8f30e077b 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -731,23 +731,22 @@ struct Promoter<'a, 'tcx> { impl<'a, 'tcx> Promoter<'a, 'tcx> { fn new_block(&mut self) -> BasicBlock { let span = self.promoted.span; - self.promoted.basic_blocks_mut().push(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { + self.promoted.basic_blocks_mut().push(BasicBlockData::new( + Some(Terminator { source_info: SourceInfo::outermost(span), kind: TerminatorKind::Return, }), - is_cleanup: false, - }) + false, + )) } fn assign(&mut self, dest: Local, rvalue: Rvalue<'tcx>, span: Span) { let last = self.promoted.basic_blocks.last_index().unwrap(); let data = &mut self.promoted[last]; - data.statements.push(Statement { - source_info: SourceInfo::outermost(span), - kind: StatementKind::Assign(Box::new((Place::from(dest), rvalue))), - }); + data.statements.push(Statement::new( + SourceInfo::outermost(span), + StatementKind::Assign(Box::new((Place::from(dest), rvalue))), + )); } fn is_temp_kind(&self, local: Local) -> bool { @@ -914,13 +913,13 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { assert_eq!(self.temps.push(TempState::Unpromotable), promoted_ref); let promoted_operand = promoted_operand(ref_ty, span); - let promoted_ref_statement = Statement { - source_info: statement.source_info, - kind: StatementKind::Assign(Box::new(( + let promoted_ref_statement = Statement::new( + statement.source_info, + StatementKind::Assign(Box::new(( Place::from(promoted_ref), Rvalue::Use(Operand::Constant(Box::new(promoted_operand))), ))), - }; + ); self.extra_statements.push((loc, promoted_ref_statement)); ( diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 6d45bbc6e16..4083038cbb6 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -323,9 +323,7 @@ fn dropee_emit_retag<'tcx>( StatementKind::Retag(RetagKind::FnEntry, Box::new(dropee_ptr)), ]; for s in new_statements { - body.basic_blocks_mut()[START_BLOCK] - .statements - .push(Statement { source_info, kind: s }); + body.basic_blocks_mut()[START_BLOCK].statements.push(Statement::new(source_info, s)); } } dropee_ptr @@ -350,11 +348,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>) let return_block = BasicBlock::new(1); let mut blocks = IndexVec::with_capacity(2); let block = |blocks: &mut IndexVec<_, _>, kind| { - blocks.push(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { source_info, kind }), - is_cleanup: false, - }) + blocks.push(BasicBlockData::new(Some(Terminator { source_info, kind }), false)) }; block(&mut blocks, TerminatorKind::Goto { target: return_block }); block(&mut blocks, TerminatorKind::Return); @@ -515,17 +509,17 @@ fn build_thread_local_shim<'tcx>( let span = tcx.def_span(def_id); let source_info = SourceInfo::outermost(span); - let blocks = IndexVec::from_raw(vec![BasicBlockData { - statements: vec![Statement { + let blocks = IndexVec::from_raw(vec![BasicBlockData::new_stmts( + vec![Statement::new( source_info, - kind: StatementKind::Assign(Box::new(( + StatementKind::Assign(Box::new(( Place::return_place(), Rvalue::ThreadLocalRef(def_id), ))), - }], - terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }), - is_cleanup: false, - }]); + )], + Some(Terminator { source_info, kind: TerminatorKind::Return }), + false, + )]); new_body( MirSource::from_instance(instance), @@ -609,11 +603,11 @@ impl<'tcx> CloneShimBuilder<'tcx> { is_cleanup: bool, ) -> BasicBlock { let source_info = self.source_info(); - self.blocks.push(BasicBlockData { + self.blocks.push(BasicBlockData::new_stmts( statements, - terminator: Some(Terminator { source_info, kind }), + Some(Terminator { source_info, kind }), is_cleanup, - }) + )) } /// Gives the index of an upcoming BasicBlock, with an offset. @@ -625,7 +619,7 @@ impl<'tcx> CloneShimBuilder<'tcx> { } fn make_statement(&self, kind: StatementKind<'tcx>) -> Statement<'tcx> { - Statement { source_info: self.source_info(), kind } + Statement::new(self.source_info(), kind) } fn copy_shim(&mut self) { @@ -901,13 +895,13 @@ fn build_call_shim<'tcx>( .immutable(), ); let borrow_kind = BorrowKind::Mut { kind: MutBorrowKind::Default }; - statements.push(Statement { + statements.push(Statement::new( source_info, - kind: StatementKind::Assign(Box::new(( + StatementKind::Assign(Box::new(( Place::from(ref_rcvr), Rvalue::Ref(tcx.lifetimes.re_erased, borrow_kind, rcvr_place()), ))), - }); + )); Operand::Move(Place::from(ref_rcvr)) } }); @@ -956,11 +950,11 @@ fn build_call_shim<'tcx>( let n_blocks = if let Some(Adjustment::RefMut) = rcvr_adjustment { 5 } else { 2 }; let mut blocks = IndexVec::with_capacity(n_blocks); let block = |blocks: &mut IndexVec<_, _>, statements, kind, is_cleanup| { - blocks.push(BasicBlockData { + blocks.push(BasicBlockData::new_stmts( statements, - terminator: Some(Terminator { source_info, kind }), + Some(Terminator { source_info, kind }), is_cleanup, - }) + )) }; // BB #0 @@ -1071,8 +1065,9 @@ pub(super) fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> { let kind = AggregateKind::Adt(adt_def.did(), variant_index, args, None, None); let variant = adt_def.variant(variant_index); - let statement = Statement { - kind: StatementKind::Assign(Box::new(( + let statement = Statement::new( + source_info, + StatementKind::Assign(Box::new(( Place::return_place(), Rvalue::Aggregate( Box::new(kind), @@ -1081,14 +1076,13 @@ pub(super) fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> { .collect(), ), ))), - source_info, - }; + ); - let start_block = BasicBlockData { - statements: vec![statement], - terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }), - is_cleanup: false, - }; + let start_block = BasicBlockData::new_stmts( + vec![statement], + Some(Terminator { source_info, kind: TerminatorKind::Return }), + false, + ); let source = MirSource::item(ctor_id); let mut body = new_body( @@ -1130,16 +1124,16 @@ fn build_fn_ptr_addr_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'t Operand::Move(Place::from(Local::new(1))), Ty::new_imm_ptr(tcx, tcx.types.unit), ); - let stmt = Statement { + let stmt = Statement::new( source_info, - kind: StatementKind::Assign(Box::new((Place::return_place(), rvalue))), - }; + StatementKind::Assign(Box::new((Place::return_place(), rvalue))), + ); let statements = vec![stmt]; - let start_block = BasicBlockData { + let start_block = BasicBlockData::new_stmts( statements, - terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }), - is_cleanup: false, - }; + Some(Terminator { source_info, kind: TerminatorKind::Return }), + false, + ); let source = MirSource::from_instance(ty::InstanceKind::FnPtrAddrShim(def_id, self_ty)); new_body(source, IndexVec::from_elem_n(start_block, 1), locals, sig.inputs().len(), span) } @@ -1230,16 +1224,16 @@ fn build_construct_coroutine_by_move_shim<'tcx>( Box::new(AggregateKind::Coroutine(coroutine_def_id, coroutine_args)), IndexVec::from_raw(fields), ); - let stmt = Statement { + let stmt = Statement::new( source_info, - kind: StatementKind::Assign(Box::new((Place::return_place(), rvalue))), - }; + StatementKind::Assign(Box::new((Place::return_place(), rvalue))), + ); let statements = vec![stmt]; - let start_block = BasicBlockData { + let start_block = BasicBlockData::new_stmts( statements, - terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }), - is_cleanup: false, - }; + Some(Terminator { source_info, kind: TerminatorKind::Return }), + false, + ); let source = MirSource::from_instance(ty::InstanceKind::ConstructCoroutineInClosureShim { coroutine_closure_def_id, diff --git a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs index fd7b7362cd9..18d09473c19 100644 --- a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs +++ b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs @@ -88,11 +88,7 @@ pub(super) fn build_async_drop_shim<'tcx>( let return_block = BasicBlock::new(1); let mut blocks = IndexVec::with_capacity(2); let block = |blocks: &mut IndexVec<_, _>, kind| { - blocks.push(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { source_info, kind }), - is_cleanup: false, - }) + blocks.push(BasicBlockData::new(Some(Terminator { source_info, kind }), false)) }; block( &mut blocks, @@ -133,7 +129,7 @@ pub(super) fn build_async_drop_shim<'tcx>( dropee_ptr, Rvalue::Use(Operand::Move(coroutine_layout_dropee)), ))); - body.basic_blocks_mut()[START_BLOCK].statements.push(Statement { source_info, kind: st_kind }); + body.basic_blocks_mut()[START_BLOCK].statements.push(Statement::new(source_info, st_kind)); dropee_ptr = dropee_emit_retag(tcx, &mut body, dropee_ptr, span); let dropline = body.basic_blocks.last_index(); @@ -240,13 +236,13 @@ fn build_adrop_for_coroutine_shim<'tcx>( .project_deeper(&[PlaceElem::Field(FieldIdx::ZERO, proxy_ref)], tcx); body.basic_blocks_mut()[START_BLOCK].statements.insert( idx, - Statement { + Statement::new( source_info, - kind: StatementKind::Assign(Box::new(( + StatementKind::Assign(Box::new(( Place::from(proxy_ref_local), Rvalue::CopyForDeref(proxy_ref_place), ))), - }, + ), ); idx += 1; let mut cor_ptr_local = proxy_ref_local; @@ -261,13 +257,13 @@ fn build_adrop_for_coroutine_shim<'tcx>( // _cor_ptr = _proxy.0.0 (... .0) body.basic_blocks_mut()[START_BLOCK].statements.insert( idx, - Statement { + Statement::new( source_info, - kind: StatementKind::Assign(Box::new(( + StatementKind::Assign(Box::new(( Place::from(cor_ptr_local), Rvalue::CopyForDeref(impl_ptr_place), ))), - }, + ), ); idx += 1; } @@ -281,10 +277,10 @@ fn build_adrop_for_coroutine_shim<'tcx>( ); body.basic_blocks_mut()[START_BLOCK].statements.insert( idx, - Statement { + Statement::new( source_info, - kind: StatementKind::Assign(Box::new((Place::from(cor_ref_local), reborrow))), - }, + StatementKind::Assign(Box::new((Place::from(cor_ref_local), reborrow))), + ), ); } body @@ -334,13 +330,13 @@ fn build_adrop_for_adrop_shim<'tcx>( let mut statements = Vec::new(); - statements.push(Statement { + statements.push(Statement::new( source_info, - kind: StatementKind::Assign(Box::new(( + StatementKind::Assign(Box::new(( Place::from(proxy_ref_local), Rvalue::CopyForDeref(proxy_ref_place), ))), - }); + )); let mut cor_ptr_local = proxy_ref_local; proxy_ty.find_async_drop_impl_coroutine(tcx, |ty| { @@ -350,13 +346,13 @@ fn build_adrop_for_adrop_shim<'tcx>( .project_deeper(&[PlaceElem::Deref, PlaceElem::Field(FieldIdx::ZERO, ty_ptr)], tcx); cor_ptr_local = locals.push(LocalDecl::new(ty_ptr, span)); // _cor_ptr = _proxy.0.0 (... .0) - statements.push(Statement { + statements.push(Statement::new( source_info, - kind: StatementKind::Assign(Box::new(( + StatementKind::Assign(Box::new(( Place::from(cor_ptr_local), Rvalue::CopyForDeref(impl_ptr_place), ))), - }); + )); } }); @@ -367,10 +363,10 @@ fn build_adrop_for_adrop_shim<'tcx>( tcx.mk_place_deref(Place::from(cor_ptr_local)), ); let cor_ref_place = Place::from(locals.push(LocalDecl::new(cor_ref, span))); - statements.push(Statement { + statements.push(Statement::new( source_info, - kind: StatementKind::Assign(Box::new((cor_ref_place, reborrow))), - }); + StatementKind::Assign(Box::new((cor_ref_place, reborrow))), + )); // cor_pin_ty = `Pin<&mut cor_ref>` let cor_pin_ty = Ty::new_adt(tcx, pin_adt_ref, tcx.mk_args(&[cor_ref.into()])); @@ -378,9 +374,9 @@ fn build_adrop_for_adrop_shim<'tcx>( let pin_fn = tcx.require_lang_item(LangItem::PinNewUnchecked, span); // call Pin<FutTy>::new_unchecked(&mut impl_cor) - blocks.push(BasicBlockData { + blocks.push(BasicBlockData::new_stmts( statements, - terminator: Some(Terminator { + Some(Terminator { source_info, kind: TerminatorKind::Call { func: Operand::function_handle(tcx, pin_fn, [cor_ref.into()], span), @@ -392,15 +388,14 @@ fn build_adrop_for_adrop_shim<'tcx>( fn_span: span, }, }), - is_cleanup: false, - }); + false, + )); // When dropping async drop coroutine, we continue its execution: // we call impl::poll (impl_layout, ctx) let poll_fn = tcx.require_lang_item(LangItem::FuturePoll, span); let resume_ctx = Place::from(Local::new(2)); - blocks.push(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { + blocks.push(BasicBlockData::new( + Some(Terminator { source_info, kind: TerminatorKind::Call { func: Operand::function_handle(tcx, poll_fn, [impl_ty.into()], span), @@ -416,13 +411,12 @@ fn build_adrop_for_adrop_shim<'tcx>( fn_span: span, }, }), - is_cleanup: false, - }); - blocks.push(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }), - is_cleanup: false, - }); + false, + )); + blocks.push(BasicBlockData::new( + Some(Terminator { source_info, kind: TerminatorKind::Return }), + false, + )); let source = MirSource::from_instance(instance); let mut body = new_body(source, blocks, locals, sig.inputs().len(), span); diff --git a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs index bd008230731..c60eb566521 100644 --- a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs +++ b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs @@ -115,10 +115,10 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyComparisonIntegral { for bb_idx in new_targets.all_targets() { storage_deads_to_insert.push(( *bb_idx, - Statement { - source_info: terminator.source_info, - kind: StatementKind::StorageDead(opt.to_switch_on.local), - }, + Statement::new( + terminator.source_info, + StatementKind::StorageDead(opt.to_switch_on.local), + ), )); } } diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 7dcdd7999f2..cbb9bbfd12f 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -1260,9 +1260,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { self.fail(location, format!("Unsize coercion, but `{op_ty}` isn't coercible to `{target_type}`")); } } - CastKind::PointerCoercion(PointerCoercion::DynStar, _) => { - // FIXME(dyn-star): make sure nothing needs to be done here. - } CastKind::IntToInt | CastKind::IntToFloat => { let input_valid = op_ty.is_integral() || op_ty.is_char() || op_ty.is_bool(); let target_valid = target_type.is_numeric() || target_type.is_char(); diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index e90e32ebebb..91e371d697d 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -694,8 +694,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { // have to instantiate all methods of the trait being cast to, so we // can build the appropriate vtable. mir::Rvalue::Cast( - mir::CastKind::PointerCoercion(PointerCoercion::Unsize, _) - | mir::CastKind::PointerCoercion(PointerCoercion::DynStar, _), + mir::CastKind::PointerCoercion(PointerCoercion::Unsize, _), ref operand, target_ty, ) => { @@ -710,9 +709,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { // This could also be a different Unsize instruction, like // from a fixed sized array to a slice. But we are only // interested in things that produce a vtable. - if (target_ty.is_trait() && !source_ty.is_trait()) - || (target_ty.is_dyn_star() && !source_ty.is_dyn_star()) - { + if target_ty.is_trait() && !source_ty.is_trait() { create_mono_items_for_vtable_methods( self.tcx, target_ty, @@ -834,6 +831,9 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { mir::AssertKind::NullPointerDereference => { push_mono_lang_item(self, LangItem::PanicNullPointerDereference); } + mir::AssertKind::InvalidEnumConstruction(_) => { + push_mono_lang_item(self, LangItem::PanicInvalidEnumConstruction); + } _ => { push_mono_lang_item(self, msg.panic_function()); } @@ -1106,14 +1106,6 @@ fn find_tails_for_unsizing<'tcx>( find_tails_for_unsizing(tcx, source_field, target_field) } - // `T` as `dyn* Trait` unsizes *directly*. - // - // FIXME(dyn_star): This case is a bit awkward, b/c we're not really computing - // a tail here. We probably should handle this separately in the *caller* of - // this function, rather than returning something that is semantically different - // than what we return above. - (_, &ty::Dynamic(_, _, ty::DynStar)) => (source_ty, target_ty), - _ => bug!( "find_vtable_types_for_unsizing: invalid coercion {:?} -> {:?}", source_ty, @@ -1341,9 +1333,7 @@ fn visit_mentioned_item<'tcx>( // This could also be a different Unsize instruction, like // from a fixed sized array to a slice. But we are only // interested in things that produce a vtable. - if (target_ty.is_trait() && !source_ty.is_trait()) - || (target_ty.is_dyn_star() && !source_ty.is_dyn_star()) - { + if target_ty.is_trait() && !source_ty.is_trait() { create_mono_items_for_vtable_methods(tcx, target_ty, source_ty, span, output); } } @@ -1489,12 +1479,14 @@ impl<'v> RootCollector<'_, 'v> { // Const items only generate mono items if they are actually used somewhere. // Just declaring them is insufficient. - // But even just declaring them must collect the items they refer to - // unless their generics require monomorphization. - if !self.tcx.generics_of(id.owner_id).own_requires_monomorphization() - && let Ok(val) = self.tcx.const_eval_poly(id.owner_id.to_def_id()) - { - collect_const_value(self.tcx, val, self.output); + // If we're collecting items eagerly, then recurse into all constants. + // Otherwise the value is only collected when explicitly mentioned in other items. + if self.strategy == MonoItemCollectionStrategy::Eager { + if !self.tcx.generics_of(id.owner_id).own_requires_monomorphization() + && let Ok(val) = self.tcx.const_eval_poly(id.owner_id.to_def_id()) + { + collect_const_value(self.tcx, val, self.output); + } } } DefKind::Impl { .. } => { diff --git a/compiler/rustc_next_trait_solver/src/lib.rs b/compiler/rustc_next_trait_solver/src/lib.rs index e3f42c181fa..d3965e14c68 100644 --- a/compiler/rustc_next_trait_solver/src/lib.rs +++ b/compiler/rustc_next_trait_solver/src/lib.rs @@ -5,9 +5,9 @@ //! So if you got to this crate from the old solver, it's totally normal. // tidy-alphabetical-start +#![allow(rustc::direct_use_of_rustc_type_ir)] #![allow(rustc::usage_of_type_ir_inherent)] #![allow(rustc::usage_of_type_ir_traits)] -#![cfg_attr(not(bootstrap), allow(rustc::direct_use_of_rustc_type_ir))] // tidy-alphabetical-end pub mod canonicalizer; diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index a300558c0c9..c281ef216c7 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -383,10 +383,10 @@ where let mut candidates = vec![]; - if let TypingMode::Coherence = self.typing_mode() { - if let Ok(candidate) = self.consider_coherence_unknowable_candidate(goal) { - return vec![candidate]; - } + if let TypingMode::Coherence = self.typing_mode() + && let Ok(candidate) = self.consider_coherence_unknowable_candidate(goal) + { + return vec![candidate]; } self.assemble_alias_bound_candidates(goal, &mut candidates); diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index f39d3226009..c0bebdf6fb6 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -135,7 +135,6 @@ where | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Never - | ty::Dynamic(_, _, ty::DynStar) | ty::Error(_) => Ok(ty::Binder::dummy(vec![])), // impl {Meta,}Sized for str, [T], dyn Trait @@ -326,11 +325,10 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<I: Intern let kind_ty = args.kind_ty(); let sig = args.coroutine_closure_sig().skip_binder(); - // FIXME: let_chains - let kind = kind_ty.to_opt_closure_kind(); - let coroutine_ty = if kind.is_some() && !args.tupled_upvars_ty().is_ty_var() { - let closure_kind = kind.unwrap(); - if !closure_kind.extends(goal_kind) { + let coroutine_ty = if let Some(kind) = kind_ty.to_opt_closure_kind() + && !args.tupled_upvars_ty().is_ty_var() + { + if !kind.extends(goal_kind) { return Err(NoSolution); } @@ -435,10 +433,10 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<I: let sig = args.coroutine_closure_sig().skip_binder(); let mut nested = vec![]; - // FIXME: let_chains - let kind = kind_ty.to_opt_closure_kind(); - let coroutine_ty = if kind.is_some() && !args.tupled_upvars_ty().is_ty_var() { - if !kind.unwrap().extends(goal_kind) { + let coroutine_ty = if let Some(kind) = kind_ty.to_opt_closure_kind() + && !args.tupled_upvars_ty().is_ty_var() + { + if !kind.extends(goal_kind) { return Err(NoSolution); } @@ -735,11 +733,11 @@ pub(in crate::solve) fn const_conditions_for_destruct<I: Interner>( let destruct_def_id = cx.require_lang_item(TraitSolverLangItem::Destruct); match self_ty.kind() { - // `ManuallyDrop` is trivially `~const Destruct` as we do not run any drop glue on it. + // `ManuallyDrop` is trivially `[const] Destruct` as we do not run any drop glue on it. ty::Adt(adt_def, _) if adt_def.is_manually_drop() => Ok(vec![]), - // An ADT is `~const Destruct` only if all of the fields are, - // *and* if there is a `Drop` impl, that `Drop` impl is also `~const`. + // An ADT is `[const] Destruct` only if all of the fields are, + // *and* if there is a `Drop` impl, that `Drop` impl is also `[const]`. ty::Adt(adt_def, args) => { let mut const_conditions: Vec<_> = adt_def .all_field_tys(cx) @@ -747,9 +745,9 @@ pub(in crate::solve) fn const_conditions_for_destruct<I: Interner>( .map(|field_ty| ty::TraitRef::new(cx, destruct_def_id, [field_ty])) .collect(); match adt_def.destructor(cx) { - // `Drop` impl exists, but it's not const. Type cannot be `~const Destruct`. + // `Drop` impl exists, but it's not const. Type cannot be `[const] Destruct`. Some(AdtDestructorKind::NotConst) => return Err(NoSolution), - // `Drop` impl exists, and it's const. Require `Ty: ~const Drop` to hold. + // `Drop` impl exists, and it's const. Require `Ty: [const] Drop` to hold. Some(AdtDestructorKind::Const) => { let drop_def_id = cx.require_lang_item(TraitSolverLangItem::Drop); let drop_trait_ref = ty::TraitRef::new(cx, drop_def_id, [self_ty]); @@ -770,7 +768,7 @@ pub(in crate::solve) fn const_conditions_for_destruct<I: Interner>( .map(|field_ty| ty::TraitRef::new(cx, destruct_def_id, [field_ty])) .collect()), - // Trivially implement `~const Destruct` + // Trivially implement `[const] Destruct` ty::Bool | ty::Char | ty::Int(..) @@ -785,14 +783,14 @@ pub(in crate::solve) fn const_conditions_for_destruct<I: Interner>( | ty::Infer(ty::InferTy::FloatVar(_) | ty::InferTy::IntVar(_)) | ty::Error(_) => Ok(vec![]), - // Coroutines and closures could implement `~const Drop`, + // Coroutines and closures could implement `[const] Drop`, // but they don't really need to right now. ty::Closure(_, _) | ty::CoroutineClosure(_, _) | ty::Coroutine(_, _) | ty::CoroutineWitness(_, _) => Err(NoSolution), - // FIXME(unsafe_binders): Unsafe binders could implement `~const Drop` + // FIXME(unsafe_binders): Unsafe binders could implement `[const] Drop` // if their inner type implements it. ty::UnsafeBinder(_) => Err(NoSolution), @@ -998,12 +996,12 @@ where } fn try_fold_ty(&mut self, ty: I::Ty) -> Result<I::Ty, Ambiguous> { - if let ty::Alias(ty::Projection, alias_ty) = ty.kind() { - if let Some(term) = self.try_eagerly_replace_alias(alias_ty.into())? { - return Ok(term.expect_ty()); - } + if let ty::Alias(ty::Projection, alias_ty) = ty.kind() + && let Some(term) = self.try_eagerly_replace_alias(alias_ty.into())? + { + Ok(term.expect_ty()) + } else { + ty.try_super_fold_with(self) } - - ty.try_super_fold_with(self) } } diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index 1690c908d12..42264f58bcd 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -1,5 +1,5 @@ //! Dealing with host effect goals, i.e. enforcing the constness in -//! `T: const Trait` or `T: ~const Trait`. +//! `T: const Trait` or `T: [const] Trait`. use rustc_type_ir::fast_reject::DeepRejectCtxt; use rustc_type_ir::inherent::*; @@ -42,20 +42,18 @@ where goal: Goal<I, Self>, assumption: I::Clause, ) -> Result<(), NoSolution> { - if let Some(host_clause) = assumption.as_host_effect_clause() { - if host_clause.def_id() == goal.predicate.def_id() - && host_clause.constness().satisfies(goal.predicate.constness) - { - if DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify( - goal.predicate.trait_ref.args, - host_clause.skip_binder().trait_ref.args, - ) { - return Ok(()); - } - } + if let Some(host_clause) = assumption.as_host_effect_clause() + && host_clause.def_id() == goal.predicate.def_id() + && host_clause.constness().satisfies(goal.predicate.constness) + && DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify( + goal.predicate.trait_ref.args, + host_clause.skip_binder().trait_ref.args, + ) + { + Ok(()) + } else { + Err(NoSolution) } - - Err(NoSolution) } fn match_assumption( @@ -72,7 +70,7 @@ where then(ecx) } - /// Register additional assumptions for aliases corresponding to `~const` item bounds. + /// Register additional assumptions for aliases corresponding to `[const]` item bounds. /// /// Unlike item bounds, they are not simply implied by the well-formedness of the alias. /// Instead, they only hold if the const conditons on the alias also hold. This is why @@ -161,7 +159,7 @@ where .map(|pred| goal.with(cx, pred)); ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds); - // For this impl to be `const`, we need to check its `~const` bounds too. + // For this impl to be `const`, we need to check its `[const]` bounds too. let const_conditions = cx .const_conditions(impl_def_id) .iter_instantiated(cx, impl_args) diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 00fd3ba8046..b42587618b5 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -3,7 +3,7 @@ use std::ops::ControlFlow; #[cfg(feature = "nightly")] use rustc_macros::HashStable_NoContext; -use rustc_type_ir::data_structures::{HashMap, HashSet, ensure_sufficient_stack}; +use rustc_type_ir::data_structures::{HashMap, HashSet}; use rustc_type_ir::fast_reject::DeepRejectCtxt; use rustc_type_ir::inherent::*; use rustc_type_ir::relate::Relate; @@ -147,13 +147,9 @@ pub trait SolverDelegateEvalExt: SolverDelegate { fn evaluate_root_goal( &self, goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>, - generate_proof_tree: GenerateProofTree, span: <Self::Interner as Interner>::Span, stalled_on: Option<GoalStalledOn<Self::Interner>>, - ) -> ( - Result<GoalEvaluation<Self::Interner>, NoSolution>, - Option<inspect::GoalEvaluation<Self::Interner>>, - ); + ) -> Result<GoalEvaluation<Self::Interner>, NoSolution>; /// Check whether evaluating `goal` with a depth of `root_depth` may /// succeed. This only returns `false` if the goal is guaranteed to @@ -170,17 +166,16 @@ pub trait SolverDelegateEvalExt: SolverDelegate { // FIXME: This is only exposed because we need to use it in `analyse.rs` // which is not yet uplifted. Once that's done, we should remove this. - fn evaluate_root_goal_raw( + fn evaluate_root_goal_for_proof_tree( &self, goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>, - generate_proof_tree: GenerateProofTree, - stalled_on: Option<GoalStalledOn<Self::Interner>>, + span: <Self::Interner as Interner>::Span, ) -> ( Result< (NestedNormalizationGoals<Self::Interner>, GoalEvaluation<Self::Interner>), NoSolution, >, - Option<inspect::GoalEvaluation<Self::Interner>>, + inspect::GoalEvaluation<Self::Interner>, ); } @@ -193,13 +188,17 @@ where fn evaluate_root_goal( &self, goal: Goal<I, I::Predicate>, - generate_proof_tree: GenerateProofTree, span: I::Span, stalled_on: Option<GoalStalledOn<I>>, - ) -> (Result<GoalEvaluation<I>, NoSolution>, Option<inspect::GoalEvaluation<I>>) { - EvalCtxt::enter_root(self, self.cx().recursion_limit(), generate_proof_tree, span, |ecx| { - ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal, stalled_on) - }) + ) -> Result<GoalEvaluation<I>, NoSolution> { + EvalCtxt::enter_root( + self, + self.cx().recursion_limit(), + GenerateProofTree::No, + span, + |ecx| ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal, stalled_on), + ) + .0 } fn root_goal_may_hold_with_depth( @@ -217,24 +216,22 @@ where } #[instrument(level = "debug", skip(self))] - fn evaluate_root_goal_raw( + fn evaluate_root_goal_for_proof_tree( &self, goal: Goal<I, I::Predicate>, - generate_proof_tree: GenerateProofTree, - stalled_on: Option<GoalStalledOn<I>>, + span: I::Span, ) -> ( Result<(NestedNormalizationGoals<I>, GoalEvaluation<I>), NoSolution>, - Option<inspect::GoalEvaluation<I>>, + inspect::GoalEvaluation<I>, ) { - EvalCtxt::enter_root( + let (result, proof_tree) = EvalCtxt::enter_root( self, self.cx().recursion_limit(), - generate_proof_tree, - I::Span::dummy(), - |ecx| { - ecx.evaluate_goal_raw(GoalEvaluationKind::Root, GoalSource::Misc, goal, stalled_on) - }, - ) + GenerateProofTree::Yes, + span, + |ecx| ecx.evaluate_goal_raw(GoalEvaluationKind::Root, GoalSource::Misc, goal, None), + ); + (result, proof_tree.unwrap()) } } @@ -339,13 +336,12 @@ where /// Creates a nested evaluation context that shares the same search graph as the /// one passed in. This is suitable for evaluation, granted that the search graph - /// has had the nested goal recorded on its stack ([`SearchGraph::with_new_goal`]), - /// but it's preferable to use other methods that call this one rather than this - /// method directly. + /// has had the nested goal recorded on its stack. This method only be used by + /// `search_graph::Delegate::compute_goal`. /// /// This function takes care of setting up the inference context, setting the anchor, /// and registering opaques from the canonicalized input. - fn enter_canonical<R>( + pub(super) fn enter_canonical<R>( cx: I, search_graph: &'a mut SearchGraph<D>, canonical_input: CanonicalInput<I>, @@ -401,56 +397,6 @@ where result } - /// The entry point of the solver. - /// - /// This function deals with (coinductive) cycles, overflow, and caching - /// and then calls [`EvalCtxt::compute_goal`] which contains the actual - /// logic of the solver. - /// - /// Instead of calling this function directly, use either [EvalCtxt::evaluate_goal] - /// if you're inside of the solver or [SolverDelegateEvalExt::evaluate_root_goal] if you're - /// outside of it. - #[instrument(level = "debug", skip(cx, search_graph, goal_evaluation), ret)] - fn evaluate_canonical_goal( - cx: I, - search_graph: &'a mut SearchGraph<D>, - canonical_input: CanonicalInput<I>, - step_kind_from_parent: PathKind, - goal_evaluation: &mut ProofTreeBuilder<D>, - ) -> QueryResult<I> { - let mut canonical_goal_evaluation = - goal_evaluation.new_canonical_goal_evaluation(canonical_input); - - // Deal with overflow, caching, and coinduction. - // - // The actual solver logic happens in `ecx.compute_goal`. - let result = ensure_sufficient_stack(|| { - search_graph.with_new_goal( - cx, - canonical_input, - step_kind_from_parent, - &mut canonical_goal_evaluation, - |search_graph, cx, canonical_input, canonical_goal_evaluation| { - EvalCtxt::enter_canonical( - cx, - search_graph, - canonical_input, - canonical_goal_evaluation, - |ecx, goal| { - let result = ecx.compute_goal(goal); - ecx.inspect.query_result(result); - result - }, - ) - }, - ) - }); - - canonical_goal_evaluation.query_result(result); - goal_evaluation.canonical_goal_evaluation(canonical_goal_evaluation); - result - } - /// Recursively evaluates `goal`, returning whether any inference vars have /// been constrained and the certainty of the result. fn evaluate_goal( @@ -483,39 +429,36 @@ where // If we have run this goal before, and it was stalled, check that any of the goal's // args have changed. Otherwise, we don't need to re-run the goal because it'll remain // stalled, since it'll canonicalize the same way and evaluation is pure. - if let Some(stalled_on) = stalled_on { - if !stalled_on.stalled_vars.iter().any(|value| self.delegate.is_changed_arg(*value)) - && !self - .delegate - .opaque_types_storage_num_entries() - .needs_reevaluation(stalled_on.num_opaques) - { - return Ok(( - NestedNormalizationGoals::empty(), - GoalEvaluation { - certainty: Certainty::Maybe(stalled_on.stalled_cause), - has_changed: HasChanged::No, - stalled_on: Some(stalled_on), - }, - )); - } + if let Some(stalled_on) = stalled_on + && !stalled_on.stalled_vars.iter().any(|value| self.delegate.is_changed_arg(*value)) + && !self + .delegate + .opaque_types_storage_num_entries() + .needs_reevaluation(stalled_on.num_opaques) + { + return Ok(( + NestedNormalizationGoals::empty(), + GoalEvaluation { + certainty: Certainty::Maybe(stalled_on.stalled_cause), + has_changed: HasChanged::No, + stalled_on: Some(stalled_on), + }, + )); } let (orig_values, canonical_goal) = self.canonicalize_goal(goal); let mut goal_evaluation = self.inspect.new_goal_evaluation(goal, &orig_values, goal_evaluation_kind); - let canonical_response = EvalCtxt::evaluate_canonical_goal( + let canonical_result = self.search_graph.evaluate_goal( self.cx(), - self.search_graph, canonical_goal, self.step_kind_for_source(source), &mut goal_evaluation, ); - let response = match canonical_response { - Err(e) => { - self.inspect.goal_evaluation(goal_evaluation); - return Err(e); - } + goal_evaluation.query_result(canonical_result); + self.inspect.goal_evaluation(goal_evaluation); + let response = match canonical_result { + Err(e) => return Err(e), Ok(response) => response, }; @@ -524,7 +467,6 @@ where let (normalization_nested_goals, certainty) = self.instantiate_and_apply_query_response(goal.param_env, &orig_values, response); - self.inspect.goal_evaluation(goal_evaluation); // FIXME: We previously had an assert here that checked that recomputing // a goal after applying its constraints did not change its response. @@ -585,7 +527,7 @@ where Ok((normalization_nested_goals, GoalEvaluation { certainty, has_changed, stalled_on })) } - fn compute_goal(&mut self, goal: Goal<I, I::Predicate>) -> QueryResult<I> { + pub(super) fn compute_goal(&mut self, goal: Goal<I, I::Predicate>) -> QueryResult<I> { let Goal { param_env, predicate } = goal; let kind = predicate.kind(); if let Some(kind) = kind.no_bound_vars() { @@ -890,14 +832,11 @@ where match t.kind() { ty::Infer(ty::TyVar(vid)) => { - if let ty::TermKind::Ty(term) = self.term.kind() { - if let ty::Infer(ty::TyVar(term_vid)) = term.kind() { - if self.delegate.root_ty_var(vid) - == self.delegate.root_ty_var(term_vid) - { - return ControlFlow::Break(()); - } - } + if let ty::TermKind::Ty(term) = self.term.kind() + && let ty::Infer(ty::TyVar(term_vid)) = term.kind() + && self.delegate.root_ty_var(vid) == self.delegate.root_ty_var(term_vid) + { + return ControlFlow::Break(()); } self.check_nameable(self.delegate.universe_of_ty(vid).unwrap())?; @@ -917,15 +856,12 @@ where fn visit_const(&mut self, c: I::Const) -> Self::Result { match c.kind() { ty::ConstKind::Infer(ty::InferConst::Var(vid)) => { - if let ty::TermKind::Const(term) = self.term.kind() { - if let ty::ConstKind::Infer(ty::InferConst::Var(term_vid)) = term.kind() - { - if self.delegate.root_const_var(vid) - == self.delegate.root_const_var(term_vid) - { - return ControlFlow::Break(()); - } - } + if let ty::TermKind::Const(term) = self.term.kind() + && let ty::ConstKind::Infer(ty::InferConst::Var(term_vid)) = term.kind() + && self.delegate.root_const_var(vid) + == self.delegate.root_const_var(term_vid) + { + return ControlFlow::Break(()); } self.check_nameable(self.delegate.universe_of_ct(vid).unwrap()) diff --git a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs index f22b275bc44..c8521624ebb 100644 --- a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs +++ b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs @@ -13,8 +13,7 @@ use rustc_type_ir::{self as ty, Interner}; use crate::delegate::SolverDelegate; use crate::solve::eval_ctxt::canonical; use crate::solve::{ - CanonicalInput, Certainty, GenerateProofTree, Goal, GoalEvaluationKind, GoalSource, - QueryResult, inspect, + Certainty, GenerateProofTree, Goal, GoalEvaluationKind, GoalSource, QueryResult, inspect, }; /// The core data structure when building proof trees. @@ -54,7 +53,6 @@ where enum DebugSolver<I: Interner> { Root, GoalEvaluation(WipGoalEvaluation<I>), - CanonicalGoalEvaluation(WipCanonicalGoalEvaluation<I>), CanonicalGoalEvaluationStep(WipCanonicalGoalEvaluationStep<I>), } @@ -64,12 +62,6 @@ impl<I: Interner> From<WipGoalEvaluation<I>> for DebugSolver<I> { } } -impl<I: Interner> From<WipCanonicalGoalEvaluation<I>> for DebugSolver<I> { - fn from(g: WipCanonicalGoalEvaluation<I>) -> DebugSolver<I> { - DebugSolver::CanonicalGoalEvaluation(g) - } -} - impl<I: Interner> From<WipCanonicalGoalEvaluationStep<I>> for DebugSolver<I> { fn from(g: WipCanonicalGoalEvaluationStep<I>) -> DebugSolver<I> { DebugSolver::CanonicalGoalEvaluationStep(g) @@ -80,7 +72,10 @@ impl<I: Interner> From<WipCanonicalGoalEvaluationStep<I>> for DebugSolver<I> { struct WipGoalEvaluation<I: Interner> { pub uncanonicalized_goal: Goal<I, I::Predicate>, pub orig_values: Vec<I::GenericArg>, - pub evaluation: Option<WipCanonicalGoalEvaluation<I>>, + pub encountered_overflow: bool, + /// After we finished evaluating this is moved into `kind`. + pub final_revision: Option<WipCanonicalGoalEvaluationStep<I>>, + pub result: Option<QueryResult<I>>, } impl<I: Interner> WipGoalEvaluation<I> { @@ -88,31 +83,12 @@ impl<I: Interner> WipGoalEvaluation<I> { inspect::GoalEvaluation { uncanonicalized_goal: self.uncanonicalized_goal, orig_values: self.orig_values, - evaluation: self.evaluation.unwrap().finalize(), - } - } -} - -#[derive_where(PartialEq, Eq, Debug; I: Interner)] -struct WipCanonicalGoalEvaluation<I: Interner> { - goal: CanonicalInput<I>, - encountered_overflow: bool, - /// Only used for uncached goals. After we finished evaluating - /// the goal, this is interned and moved into `kind`. - final_revision: Option<WipCanonicalGoalEvaluationStep<I>>, - result: Option<QueryResult<I>>, -} - -impl<I: Interner> WipCanonicalGoalEvaluation<I> { - fn finalize(self) -> inspect::CanonicalGoalEvaluation<I> { - inspect::CanonicalGoalEvaluation { - goal: self.goal, kind: if self.encountered_overflow { assert!(self.final_revision.is_none()); - inspect::CanonicalGoalEvaluationKind::Overflow + inspect::GoalEvaluationKind::Overflow } else { let final_revision = self.final_revision.unwrap().finalize(); - inspect::CanonicalGoalEvaluationKind::Evaluation { final_revision } + inspect::GoalEvaluationKind::Evaluation { final_revision } }, result: self.result.unwrap(), } @@ -256,55 +232,27 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<D> { pub(in crate::solve) fn new_goal_evaluation( &mut self, - goal: Goal<I, I::Predicate>, + uncanonicalized_goal: Goal<I, I::Predicate>, orig_values: &[I::GenericArg], kind: GoalEvaluationKind, ) -> ProofTreeBuilder<D> { self.opt_nested(|| match kind { GoalEvaluationKind::Root => Some(WipGoalEvaluation { - uncanonicalized_goal: goal, + uncanonicalized_goal, orig_values: orig_values.to_vec(), - evaluation: None, + encountered_overflow: false, + final_revision: None, + result: None, }), GoalEvaluationKind::Nested => None, }) } - pub(crate) fn new_canonical_goal_evaluation( - &mut self, - goal: CanonicalInput<I>, - ) -> ProofTreeBuilder<D> { - self.nested(|| WipCanonicalGoalEvaluation { - goal, - encountered_overflow: false, - final_revision: None, - result: None, - }) - } - - pub(crate) fn canonical_goal_evaluation( - &mut self, - canonical_goal_evaluation: ProofTreeBuilder<D>, - ) { - if let Some(this) = self.as_mut() { - match (this, *canonical_goal_evaluation.state.unwrap()) { - ( - DebugSolver::GoalEvaluation(goal_evaluation), - DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluation), - ) => { - let prev = goal_evaluation.evaluation.replace(canonical_goal_evaluation); - assert_eq!(prev, None); - } - _ => unreachable!(), - } - } - } - pub(crate) fn canonical_goal_evaluation_overflow(&mut self) { if let Some(this) = self.as_mut() { match this { - DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluation) => { - canonical_goal_evaluation.encountered_overflow = true; + DebugSolver::GoalEvaluation(goal_evaluation) => { + goal_evaluation.encountered_overflow = true; } _ => unreachable!(), }; @@ -343,10 +291,10 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<D> { if let Some(this) = self.as_mut() { match (this, *goal_evaluation_step.state.unwrap()) { ( - DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluations), + DebugSolver::GoalEvaluation(goal_evaluation), DebugSolver::CanonicalGoalEvaluationStep(goal_evaluation_step), ) => { - canonical_goal_evaluations.final_revision = Some(goal_evaluation_step); + goal_evaluation.final_revision = Some(goal_evaluation_step); } _ => unreachable!(), } @@ -489,8 +437,8 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<D> { pub(crate) fn query_result(&mut self, result: QueryResult<I>) { if let Some(this) = self.as_mut() { match this { - DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluation) => { - assert_eq!(canonical_goal_evaluation.result.replace(result), None); + DebugSolver::GoalEvaluation(goal_evaluation) => { + assert_eq!(goal_evaluation.result.replace(result), None); } DebugSolver::CanonicalGoalEvaluationStep(evaluation_step) => { assert_eq!( diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index e4e0aba7b50..e68ea22c7a2 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -191,6 +191,7 @@ where goal: Goal<I, (I::Const, I::Ty)>, ) -> QueryResult<I> { let (ct, ty) = goal.predicate; + let ct = self.structurally_normalize_const(goal.param_env, ct)?; let ct_ty = match ct.kind() { ty::ConstKind::Infer(_) => { @@ -211,7 +212,7 @@ where ty::ConstKind::Bound(_, _) => panic!("escaping bound vars in {:?}", ct), ty::ConstKind::Value(cv) => cv.ty(), ty::ConstKind::Placeholder(placeholder) => { - self.cx().find_const_ty_from_env(goal.param_env, placeholder) + placeholder.find_const_ty_from_env(goal.param_env) } }; diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index d51c87fe68e..1e0a90eb2ee 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -112,18 +112,17 @@ where goal: Goal<I, Self>, assumption: I::Clause, ) -> Result<(), NoSolution> { - if let Some(projection_pred) = assumption.as_projection_clause() { - if projection_pred.item_def_id() == goal.predicate.def_id() { - if DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify( - goal.predicate.alias.args, - projection_pred.skip_binder().projection_term.args, - ) { - return Ok(()); - } - } + if let Some(projection_pred) = assumption.as_projection_clause() + && projection_pred.item_def_id() == goal.predicate.def_id() + && DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify( + goal.predicate.alias.args, + projection_pred.skip_binder().projection_term.args, + ) + { + Ok(()) + } else { + Err(NoSolution) } - - Err(NoSolution) } fn match_assumption( @@ -658,8 +657,7 @@ where | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Never - | ty::Foreign(..) - | ty::Dynamic(_, _, ty::DynStar) => Ty::new_unit(cx), + | ty::Foreign(..) => Ty::new_unit(cx), ty::Error(e) => Ty::new_error(cx, e), diff --git a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs index ecffbbff7a2..12cbc7e8f91 100644 --- a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs +++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs @@ -1,13 +1,14 @@ use std::convert::Infallible; use std::marker::PhantomData; +use rustc_type_ir::data_structures::ensure_sufficient_stack; use rustc_type_ir::search_graph::{self, PathKind}; use rustc_type_ir::solve::{CanonicalInput, Certainty, NoSolution, QueryResult}; use rustc_type_ir::{Interner, TypingMode}; -use super::inspect::ProofTreeBuilder; -use super::{FIXPOINT_STEP_LIMIT, has_no_inference_or_external_constraints}; use crate::delegate::SolverDelegate; +use crate::solve::inspect::ProofTreeBuilder; +use crate::solve::{EvalCtxt, FIXPOINT_STEP_LIMIT, has_no_inference_or_external_constraints}; /// This type is never constructed. We only use it to implement `search_graph::Delegate` /// for all types which impl `SolverDelegate` and doing it directly fails in coherence. @@ -80,8 +81,8 @@ where fn on_stack_overflow( cx: I, - inspect: &mut ProofTreeBuilder<D>, input: CanonicalInput<I>, + inspect: &mut ProofTreeBuilder<D>, ) -> QueryResult<I> { inspect.canonical_goal_evaluation_overflow(); response_no_constraints(cx, input, Certainty::overflow(true)) @@ -106,6 +107,21 @@ where let certainty = from_result.unwrap().value.certainty; response_no_constraints(cx, for_input, certainty) } + + fn compute_goal( + search_graph: &mut SearchGraph<D>, + cx: I, + input: CanonicalInput<I>, + inspect: &mut Self::ProofTreeBuilder, + ) -> QueryResult<I> { + ensure_sufficient_stack(|| { + EvalCtxt::enter_canonical(cx, search_graph, input, inspect, |ecx, goal| { + let result = ecx.compute_goal(goal); + ecx.inspect.query_result(result); + result + }) + }) + } } fn response_no_constraints<I: Interner>( diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 8ee116b090d..6c9fb63b579 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -103,15 +103,12 @@ where // We currently elaborate all supertrait outlives obligations from impls. // This can be removed when we actually do coinduction correctly, and prove // all supertrait obligations unconditionally. - let goal_clause: I::Clause = goal.predicate.upcast(cx); - for clause in elaborate::elaborate(cx, [goal_clause]) { - if matches!( - clause.kind().skip_binder(), - ty::ClauseKind::TypeOutlives(..) | ty::ClauseKind::RegionOutlives(..) - ) { - ecx.add_goal(GoalSource::Misc, goal.with(cx, clause)); - } - } + ecx.add_goals( + GoalSource::Misc, + cx.impl_super_outlives(impl_def_id) + .iter_instantiated(cx, impl_args) + .map(|pred| goal.with(cx, pred)), + ); ecx.evaluate_added_goals_and_make_canonical_response(maximal_certainty) }) @@ -130,33 +127,32 @@ where goal: Goal<I, Self>, assumption: I::Clause, ) -> Result<(), NoSolution> { - if let Some(trait_clause) = assumption.as_trait_clause() { - if trait_clause.polarity() != goal.predicate.polarity { - return Err(NoSolution); - } - - if trait_clause.def_id() == goal.predicate.def_id() { - if DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify( - goal.predicate.trait_ref.args, - trait_clause.skip_binder().trait_ref.args, - ) { - return Ok(()); - } - } - + fn trait_def_id_matches<I: Interner>( + cx: I, + clause_def_id: I::DefId, + goal_def_id: I::DefId, + ) -> bool { + clause_def_id == goal_def_id // PERF(sized-hierarchy): Sizedness supertraits aren't elaborated to improve perf, so - // check for a `Sized` subtrait when looking for `MetaSized`. `PointeeSized` bounds - // are syntactic sugar for a lack of bounds so don't need this. - if ecx.cx().is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::MetaSized) - && ecx.cx().is_lang_item(trait_clause.def_id(), TraitSolverLangItem::Sized) - { - let meta_sized_clause = - trait_predicate_with_def_id(ecx.cx(), trait_clause, goal.predicate.def_id()); - return Self::fast_reject_assumption(ecx, goal, meta_sized_clause); - } + // check for a `MetaSized` supertrait being matched against a `Sized` assumption. + // + // `PointeeSized` bounds are syntactic sugar for a lack of bounds so don't need this. + || (cx.is_lang_item(clause_def_id, TraitSolverLangItem::Sized) + && cx.is_lang_item(goal_def_id, TraitSolverLangItem::MetaSized)) } - Err(NoSolution) + if let Some(trait_clause) = assumption.as_trait_clause() + && trait_clause.polarity() == goal.predicate.polarity + && trait_def_id_matches(ecx.cx(), trait_clause.def_id(), goal.predicate.def_id()) + && DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify( + goal.predicate.trait_ref.args, + trait_clause.skip_binder().trait_ref.args, + ) + { + return Ok(()); + } else { + Err(NoSolution) + } } fn match_assumption( diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml index 6504081f0b9..c4a0ae2ce9d 100644 --- a/compiler/rustc_parse/Cargo.toml +++ b/compiler/rustc_parse/Cargo.toml @@ -6,7 +6,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start bitflags = "2.4.1" -rustc-literal-escaper = "0.0.2" +rustc-literal-escaper = "0.0.4" rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_data_structures = { path = "../rustc_data_structures" } diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 2845bbed1c0..60d275bf2b4 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -1,5 +1,3 @@ -use std::ops::Range; - use diagnostics::make_unclosed_delims_error; use rustc_ast::ast::{self, AttrStyle}; use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Token, TokenKind}; @@ -10,7 +8,7 @@ use rustc_errors::{Applicability, Diag, DiagCtxtHandle, StashKey}; use rustc_lexer::{ Base, Cursor, DocStyle, FrontmatterAllowed, LiteralKind, RawStrError, is_whitespace, }; -use rustc_literal_escaper::{EscapeError, Mode, unescape_mixed, unescape_unicode}; +use rustc_literal_escaper::{EscapeError, Mode, check_for_errors}; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, RUST_2024_GUARDED_STRING_INCOMPATIBLE_SYNTAX, @@ -702,7 +700,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { } err.emit() } - self.cook_unicode(token::Char, Mode::Char, start, end, 1, 1) // ' ' + self.cook_quoted(token::Char, Mode::Char, start, end, 1, 1) // ' ' } rustc_lexer::LiteralKind::Byte { terminated } => { if !terminated { @@ -714,7 +712,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { .with_code(E0763) .emit() } - self.cook_unicode(token::Byte, Mode::Byte, start, end, 2, 1) // b' ' + self.cook_quoted(token::Byte, Mode::Byte, start, end, 2, 1) // b' ' } rustc_lexer::LiteralKind::Str { terminated } => { if !terminated { @@ -726,7 +724,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { .with_code(E0765) .emit() } - self.cook_unicode(token::Str, Mode::Str, start, end, 1, 1) // " " + self.cook_quoted(token::Str, Mode::Str, start, end, 1, 1) // " " } rustc_lexer::LiteralKind::ByteStr { terminated } => { if !terminated { @@ -738,7 +736,8 @@ impl<'psess, 'src> Lexer<'psess, 'src> { .with_code(E0766) .emit() } - self.cook_unicode(token::ByteStr, Mode::ByteStr, start, end, 2, 1) // b" " + self.cook_quoted(token::ByteStr, Mode::ByteStr, start, end, 2, 1) + // b" " } rustc_lexer::LiteralKind::CStr { terminated } => { if !terminated { @@ -750,13 +749,14 @@ impl<'psess, 'src> Lexer<'psess, 'src> { .with_code(E0767) .emit() } - self.cook_mixed(token::CStr, Mode::CStr, start, end, 2, 1) // c" " + self.cook_quoted(token::CStr, Mode::CStr, start, end, 2, 1) // c" " } rustc_lexer::LiteralKind::RawStr { n_hashes } => { if let Some(n_hashes) = n_hashes { let n = u32::from(n_hashes); let kind = token::StrRaw(n_hashes); - self.cook_unicode(kind, Mode::RawStr, start, end, 2 + n, 1 + n) // r##" "## + self.cook_quoted(kind, Mode::RawStr, start, end, 2 + n, 1 + n) + // r##" "## } else { self.report_raw_str_error(start, 1); } @@ -765,7 +765,8 @@ impl<'psess, 'src> Lexer<'psess, 'src> { if let Some(n_hashes) = n_hashes { let n = u32::from(n_hashes); let kind = token::ByteStrRaw(n_hashes); - self.cook_unicode(kind, Mode::RawByteStr, start, end, 3 + n, 1 + n) // br##" "## + self.cook_quoted(kind, Mode::RawByteStr, start, end, 3 + n, 1 + n) + // br##" "## } else { self.report_raw_str_error(start, 2); } @@ -774,7 +775,8 @@ impl<'psess, 'src> Lexer<'psess, 'src> { if let Some(n_hashes) = n_hashes { let n = u32::from(n_hashes); let kind = token::CStrRaw(n_hashes); - self.cook_unicode(kind, Mode::RawCStr, start, end, 3 + n, 1 + n) // cr##" "## + self.cook_quoted(kind, Mode::RawCStr, start, end, 3 + n, 1 + n) + // cr##" "## } else { self.report_raw_str_error(start, 2); } @@ -1091,7 +1093,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { self.dcx().emit_fatal(errors::TooManyHashes { span: self.mk_sp(start, self.pos), num }); } - fn cook_common( + fn cook_quoted( &self, mut kind: token::LitKind, mode: Mode, @@ -1099,32 +1101,28 @@ impl<'psess, 'src> Lexer<'psess, 'src> { end: BytePos, prefix_len: u32, postfix_len: u32, - unescape: fn(&str, Mode, &mut dyn FnMut(Range<usize>, Result<(), EscapeError>)), ) -> (token::LitKind, Symbol) { let content_start = start + BytePos(prefix_len); let content_end = end - BytePos(postfix_len); let lit_content = self.str_from_to(content_start, content_end); - unescape(lit_content, mode, &mut |range, result| { - // Here we only check for errors. The actual unescaping is done later. - if let Err(err) = result { - let span_with_quotes = self.mk_sp(start, end); - let (start, end) = (range.start as u32, range.end as u32); - let lo = content_start + BytePos(start); - let hi = lo + BytePos(end - start); - let span = self.mk_sp(lo, hi); - let is_fatal = err.is_fatal(); - if let Some(guar) = emit_unescape_error( - self.dcx(), - lit_content, - span_with_quotes, - span, - mode, - range, - err, - ) { - assert!(is_fatal); - kind = token::Err(guar); - } + check_for_errors(lit_content, mode, |range, err| { + let span_with_quotes = self.mk_sp(start, end); + let (start, end) = (range.start as u32, range.end as u32); + let lo = content_start + BytePos(start); + let hi = lo + BytePos(end - start); + let span = self.mk_sp(lo, hi); + let is_fatal = err.is_fatal(); + if let Some(guar) = emit_unescape_error( + self.dcx(), + lit_content, + span_with_quotes, + span, + mode, + range, + err, + ) { + assert!(is_fatal); + kind = token::Err(guar); } }); @@ -1137,34 +1135,6 @@ impl<'psess, 'src> Lexer<'psess, 'src> { }; (kind, sym) } - - fn cook_unicode( - &self, - kind: token::LitKind, - mode: Mode, - start: BytePos, - end: BytePos, - prefix_len: u32, - postfix_len: u32, - ) -> (token::LitKind, Symbol) { - self.cook_common(kind, mode, start, end, prefix_len, postfix_len, |src, mode, callback| { - unescape_unicode(src, mode, &mut |span, result| callback(span, result.map(drop))) - }) - } - - fn cook_mixed( - &self, - kind: token::LitKind, - mode: Mode, - start: BytePos, - end: BytePos, - prefix_len: u32, - postfix_len: u32, - ) -> (token::LitKind, Symbol) { - self.cook_common(kind, mode, start, end, prefix_len, postfix_len, |src, mode, callback| { - unescape_mixed(src, mode, &mut |span, result| callback(span, result.map(drop))) - }) - } } pub fn nfc_normalize(string: &str) -> Symbol { diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index a64bb424117..1df0ccbd8af 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -2731,7 +2731,7 @@ impl<'a> Parser<'a> { return first_pat; } if !matches!(first_pat.kind, PatKind::Ident(_, _, None) | PatKind::Path(..)) - || !self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident()) + || !self.look_ahead(1, |token| token.is_non_reserved_ident()) { let mut snapshot_type = self.create_snapshot_for_diagnostic(); snapshot_type.bump(); // `:` diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 93c76c47f06..3cedc86dc0d 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -847,7 +847,7 @@ impl<'a> Parser<'a> { self.dcx().emit_err(errors::LifetimeInBorrowExpression { span, lifetime_span: lt_span }); } - /// Parse `mut?` or `raw [ const | mut ]`. + /// Parse `mut?` or `[ raw | pin ] [ const | mut ]`. fn parse_borrow_modifiers(&mut self) -> (ast::BorrowKind, ast::Mutability) { if self.check_keyword(exp!(Raw)) && self.look_ahead(1, Token::is_mutability) { // `raw [ const | mut ]`. @@ -855,6 +855,11 @@ impl<'a> Parser<'a> { assert!(found_raw); let mutability = self.parse_const_or_mut().unwrap(); (ast::BorrowKind::Raw, mutability) + } else if let Some((ast::Pinnedness::Pinned, mutbl)) = self.parse_pin_and_mut() { + // `pin [ const | mut ]`. + // `pin` has been gated in `self.parse_pin_and_mut()` so we don't + // need to gate it here. + (ast::BorrowKind::Pin, mutbl) } else { // `mut?` (ast::BorrowKind::Ref, self.parse_mutability()) @@ -3870,8 +3875,7 @@ impl<'a> Parser<'a> { // Check if a colon exists one ahead. This means we're parsing a fieldname. let is_shorthand = !this.look_ahead(1, |t| t == &token::Colon || t == &token::Eq); // Proactively check whether parsing the field will be incorrect. - let is_wrong = this.token.is_ident() - && !this.token.is_reserved_ident() + let is_wrong = this.token.is_non_reserved_ident() && !this.look_ahead(1, |t| { t == &token::Colon || t == &token::Eq diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index c05479feb61..af1d1a1ec66 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -353,6 +353,20 @@ impl<'a> Parser<'a> { if !self.eat_keyword(exp!(Where)) { return Ok((where_clause, None)); } + + if self.eat_noexpect(&token::Colon) { + let colon_span = self.prev_token.span; + self.dcx() + .struct_span_err(colon_span, "unexpected colon after `where`") + .with_span_suggestion_short( + colon_span, + "remove the colon", + "", + Applicability::MachineApplicable, + ) + .emit(); + } + where_clause.has_where_token = true; let where_lo = self.prev_token.span; diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 5088caa80f8..9ed7124a11c 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1552,7 +1552,8 @@ impl<'a> Parser<'a> { }) .map_err(|mut err| { err.span_label(ident.span, "while parsing this enum"); - if self.token == token::Colon { + // Try to recover `enum Foo { ident : Ty }`. + if self.prev_token.is_non_reserved_ident() && self.token == token::Colon { let snapshot = self.create_snapshot_for_diagnostic(); self.bump(); match self.parse_ty() { diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index b2e90251367..cfc0399b0ca 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -685,7 +685,7 @@ impl<'a> Parser<'a> { /// Is the given keyword `kw` followed by a non-reserved identifier? fn is_kw_followed_by_ident(&self, kw: Symbol) -> bool { - self.token.is_keyword(kw) && self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident()) + self.token.is_keyword(kw) && self.look_ahead(1, |t| t.is_non_reserved_ident()) } #[inline] diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 9bce2fa74ca..1f4049f197f 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -126,7 +126,7 @@ impl<'a> Parser<'a> { /// ``` fn recover_colon_before_qpath_proj(&mut self) -> bool { if !self.check_noexpect(&TokenKind::Colon) - || self.look_ahead(1, |t| !t.is_ident() || t.is_reserved_ident()) + || self.look_ahead(1, |t| !t.is_non_reserved_ident()) { return false; } @@ -260,7 +260,7 @@ impl<'a> Parser<'a> { if self.may_recover() && style == PathStyle::Expr // (!) && self.token == token::Colon - && self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident()) + && self.look_ahead(1, |token| token.is_non_reserved_ident()) { // Emit a special error message for `a::b:c` to help users // otherwise, `a: c` might have meant to introduce a new binding @@ -334,9 +334,7 @@ impl<'a> Parser<'a> { self.expect_gt().map_err(|mut err| { // Try to recover a `:` into a `::` if self.token == token::Colon - && self.look_ahead(1, |token| { - token.is_ident() && !token.is_reserved_ident() - }) + && self.look_ahead(1, |token| token.is_non_reserved_ident()) { err.cancel(); err = self.dcx().create_err(PathSingleColon { diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index c37cb0881c3..2fa6520f2a4 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -798,7 +798,7 @@ impl<'a> Parser<'a> { } if self.prev_token.is_reserved_ident() && self.prev_token.is_ident_named(kw::Await) { // Likely `foo.await bar` - } else if !self.prev_token.is_reserved_ident() && self.prev_token.is_ident() { + } else if self.prev_token.is_non_reserved_ident() { // Likely `foo bar` } else if self.prev_token.kind == token::Question { // `foo? bar` diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 620a34044d1..8221c709027 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -796,16 +796,10 @@ impl<'a> Parser<'a> { /// /// Note that this does *not* parse bare trait objects. fn parse_dyn_ty(&mut self, impl_dyn_multi: &mut bool) -> PResult<'a, TyKind> { - let lo = self.token.span; self.bump(); // `dyn` - // parse dyn* types - let syntax = if self.eat(exp!(Star)) { - self.psess.gated_spans.gate(sym::dyn_star, lo.to(self.prev_token.span)); - TraitObjectSyntax::DynStar - } else { - TraitObjectSyntax::Dyn - }; + // We used to parse `*` for `dyn*` here. + let syntax = TraitObjectSyntax::Dyn; // Always parse bounds greedily for better error recovery. let bounds = self.parse_generic_bounds()?; @@ -885,6 +879,7 @@ impl<'a> Parser<'a> { || self.check(exp!(Tilde)) || self.check_keyword(exp!(For)) || self.check(exp!(OpenParen)) + || self.check(exp!(OpenBracket)) || self.check_keyword(exp!(Const)) || self.check_keyword(exp!(Async)) || self.check_keyword(exp!(Use)) @@ -982,12 +977,12 @@ impl<'a> Parser<'a> { Ok(()) } - /// Parses the modifiers that may precede a trait in a bound, e.g. `?Trait` or `~const Trait`. + /// Parses the modifiers that may precede a trait in a bound, e.g. `?Trait` or `[const] Trait`. /// /// If no modifiers are present, this does not consume any tokens. /// /// ```ebnf - /// CONSTNESS = [["~"] "const"] + /// CONSTNESS = [["["] "const" ["]"]] /// ASYNCNESS = ["async"] /// POLARITY = ["?" | "!"] /// ``` @@ -995,18 +990,7 @@ impl<'a> Parser<'a> { /// See `parse_generic_ty_bound` for the complete grammar of trait bound modifiers. fn parse_trait_bound_modifiers(&mut self) -> PResult<'a, TraitBoundModifiers> { let modifier_lo = self.token.span; - let constness = if self.eat(exp!(Tilde)) { - let tilde = self.prev_token.span; - self.expect_keyword(exp!(Const))?; - let span = tilde.to(self.prev_token.span); - self.psess.gated_spans.gate(sym::const_trait_impl, span); - BoundConstness::Maybe(span) - } else if self.eat_keyword(exp!(Const)) { - self.psess.gated_spans.gate(sym::const_trait_impl, self.prev_token.span); - BoundConstness::Always(self.prev_token.span) - } else { - BoundConstness::Never - }; + let constness = self.parse_bound_constness()?; let asyncness = if self.token_uninterpolated_span().at_least_rust_2018() && self.eat_keyword(exp!(Async)) @@ -1068,13 +1052,41 @@ impl<'a> Parser<'a> { Ok(TraitBoundModifiers { constness, asyncness, polarity }) } + pub fn parse_bound_constness(&mut self) -> PResult<'a, BoundConstness> { + // FIXME(const_trait_impl): remove `~const` parser support once bootstrap has the new syntax + // in rustfmt + Ok(if self.eat(exp!(Tilde)) { + let tilde = self.prev_token.span; + self.expect_keyword(exp!(Const))?; + let span = tilde.to(self.prev_token.span); + self.psess.gated_spans.gate(sym::const_trait_impl, span); + BoundConstness::Maybe(span) + } else if self.check(exp!(OpenBracket)) + && self.look_ahead(1, |t| t.is_keyword(kw::Const)) + && self.look_ahead(2, |t| *t == token::CloseBracket) + { + let start = self.token.span; + self.bump(); + self.expect_keyword(exp!(Const)).unwrap(); + self.bump(); + let span = start.to(self.prev_token.span); + self.psess.gated_spans.gate(sym::const_trait_impl, span); + BoundConstness::Maybe(span) + } else if self.eat_keyword(exp!(Const)) { + self.psess.gated_spans.gate(sym::const_trait_impl, self.prev_token.span); + BoundConstness::Always(self.prev_token.span) + } else { + BoundConstness::Never + }) + } + /// Parses a type bound according to: /// ```ebnf /// TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN) /// TY_BOUND_NOPAREN = [for<GENERIC_PARAMS> CONSTNESS ASYNCNESS | POLARITY] SIMPLE_PATH /// ``` /// - /// For example, this grammar accepts `for<'a: 'b> ~const ?m::Trait<'a>`. + /// For example, this grammar accepts `for<'a: 'b> [const] ?m::Trait<'a>`. fn parse_generic_ty_bound( &mut self, lo: Span, @@ -1101,7 +1113,7 @@ impl<'a> Parser<'a> { } // Recover erroneous lifetime bound with modifiers or binder. - // e.g. `T: for<'a> 'a` or `T: ~const 'a`. + // e.g. `T: for<'a> 'a` or `T: [const] 'a`. if self.token.is_lifetime() { let _: ErrorGuaranteed = self.error_lt_bound_with_modifiers(modifiers, binder_span); return self.parse_generic_lt_bound(lo, has_parens); diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 8e6442353c3..6c2c571d240 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -286,14 +286,28 @@ fn emit_malformed_attribute( if matches!( name, sym::inline + | sym::may_dangle + | sym::rustc_as_ptr + | sym::rustc_pub_transparent + | sym::rustc_const_stable_indirect | sym::rustc_force_inline | sym::rustc_confusables + | sym::rustc_skip_during_method_dispatch | sym::repr | sym::align | sym::deprecated | sym::optimize | sym::cold + | sym::naked + | sym::no_mangle | sym::must_use + | sym::track_caller + | sym::link_name + | sym::export_name + | sym::rustc_macro_transparency + | sym::link_section + | sym::rustc_layout_scalar_valid_range_start + | sym::rustc_layout_scalar_valid_range_end ) { return; } diff --git a/compiler/rustc_parse_format/Cargo.toml b/compiler/rustc_parse_format/Cargo.toml index 52f23c00d4b..0666ae29409 100644 --- a/compiler/rustc_parse_format/Cargo.toml +++ b/compiler/rustc_parse_format/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -rustc-literal-escaper = "0.0.2" +rustc-literal-escaper = "0.0.4" rustc_lexer = { path = "../rustc_lexer" } # tidy-alphabetical-end diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 42bd0f5d847..8e4da7923fc 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -20,7 +20,6 @@ use std::ops::Range; pub use Alignment::*; pub use Count::*; pub use Position::*; -use rustc_literal_escaper::{Mode, unescape_unicode}; /// The type of format string that we are parsing. #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -320,7 +319,7 @@ impl<'input> Parser<'input> { let without_quotes = &snippet[1..snippet.len() - 1]; let (mut ok, mut vec) = (true, vec![]); let mut chars = input.chars(); - unescape_unicode(without_quotes, Mode::Str, &mut |range, res| match res { + rustc_literal_escaper::unescape_str(without_quotes, |range, res| match res { Ok(ch) if ok && chars.next().is_some_and(|c| ch == c) => { vec.push((range, ch)); } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 29526817257..9a60c151034 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -82,11 +82,14 @@ passes_collapse_debuginfo = passes_confusables = attribute should be applied to an inherent method .label = not an inherent method +passes_const_continue_attr = + `#[const_continue]` should be applied to a break expression + .label = not a break expression + passes_const_stable_not_stable = attribute `#[rustc_const_stable]` can only be applied to functions that are declared `#[stable]` .label = attribute specified here - passes_coroutine_on_non_closure = attribute should be applied to closures .label = not a closure @@ -291,7 +294,7 @@ passes_duplicate_lang_item_crate_depends = .second_definition_path = second definition in `{$crate_name}` loaded from {$path} passes_enum_variant_same_name = - it is impossible to refer to the {$descr} `{$dead_name}` because it is shadowed by this enum variant with the same name + it is impossible to refer to the {$dead_descr} `{$dead_name}` because it is shadowed by this enum variant with the same name passes_export_name = attribute should be applied to a free function, impl method or static @@ -446,6 +449,10 @@ passes_linkage = attribute should be applied to a function or static .label = not a function definition or static +passes_loop_match_attr = + `#[loop_match]` should be applied to a loop + .label = not a loop + passes_macro_export = `#[macro_export]` only has an effect on macro definitions @@ -479,6 +486,11 @@ passes_missing_panic_handler = passes_missing_stability_attr = {$descr} has missing stability attribute +passes_mixed_export_name_and_no_mangle = `{$no_mangle_attr}` attribute may not be used in combination with `{$export_name_attr}` + .label = `{$no_mangle_attr}` is ignored + .note = `{$export_name_attr}` takes precedence + .suggestion = remove the `{$no_mangle_attr}` attribute + passes_multiple_rustc_main = multiple functions with a `#[rustc_main]` attribute .first = first `#[rustc_main]` function @@ -606,9 +618,6 @@ passes_rustc_force_inline_coro = attribute cannot be applied to a `async`, `gen` or `async gen` function .label = `async`, `gen` or `async gen` function -passes_rustc_layout_scalar_valid_range_arg = - expected exactly one integer literal argument - passes_rustc_layout_scalar_valid_range_not_struct = attribute should be applied to a struct .label = not a struct @@ -804,9 +813,6 @@ passes_unused_variable_try_prefix = unused variable: `{$name}` .suggestion = if this is intentional, prefix it with an underscore -passes_used_compiler_linker = - `used(compiler)` and `used(linker)` can't be used together - passes_used_static = attribute must be applied to a `static` variable .label = but this is a {$target} diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index c2a58b4cd7d..1b965b9545c 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -9,7 +9,7 @@ use std::cell::Cell; use std::collections::hash_map::Entry; use rustc_abi::{Align, ExternAbi, Size}; -use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, MetaItemLit, ast}; +use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, ast}; use rustc_attr_data_structures::{AttributeKind, InlineAttr, ReprAttr, find_attr}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey}; @@ -30,11 +30,13 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, TyCtxt, TypingMode}; use rustc_middle::{bug, span_bug}; use rustc_session::config::CrateType; +use rustc_session::lint; use rustc_session::lint::builtin::{ CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS, UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES, }; use rustc_session::parse::feature_err; +use rustc_span::edition::Edition; use rustc_span::{BytePos, DUMMY_SP, Span, Symbol, edition, sym}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs}; @@ -118,6 +120,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> { for attr in attrs { let mut style = None; match attr { + Attribute::Parsed(AttributeKind::SkipDuringMethodDispatch { + span: attr_span, + .. + }) => { + self.check_must_be_applied_to_trait(*attr_span, span, target); + } Attribute::Parsed(AttributeKind::Confusables { first_span, .. }) => { self.check_confusables(*first_span, target); } @@ -132,6 +140,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::Optimize(_, attr_span)) => { self.check_optimize(hir_id, *attr_span, span, target) } + Attribute::Parsed(AttributeKind::LoopMatch(attr_span)) => { + self.check_loop_match(hir_id, *attr_span, target) + } + Attribute::Parsed(AttributeKind::ConstContinue(attr_span)) => { + self.check_const_continue(hir_id, *attr_span, target) + } Attribute::Parsed(AttributeKind::AllowInternalUnstable(syms)) => self .check_allow_internal_unstable( hir_id, @@ -150,19 +164,34 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } Attribute::Parsed(AttributeKind::Repr(_)) => { /* handled below this loop and elsewhere */ } - + Attribute::Parsed(AttributeKind::RustcObjectLifetimeDefault) => { + self.check_object_lifetime_default(hir_id); + } &Attribute::Parsed(AttributeKind::PubTransparent(attr_span)) => { self.check_rustc_pub_transparent(attr_span, span, attrs) } Attribute::Parsed(AttributeKind::Cold(attr_span)) => { self.check_cold(hir_id, *attr_span, span, target) } + Attribute::Parsed(AttributeKind::ExportName { span: attr_span, .. }) => { + self.check_export_name(hir_id, *attr_span, span, target) + } Attribute::Parsed(AttributeKind::Align { align, span: repr_span }) => { self.check_align(span, target, *align, *repr_span) } + Attribute::Parsed(AttributeKind::LinkSection { span: attr_span, .. }) => { + self.check_link_section(hir_id, *attr_span, span, target) + } Attribute::Parsed(AttributeKind::Naked(attr_span)) => { self.check_naked(hir_id, *attr_span, span, target) } + Attribute::Parsed(AttributeKind::TrackCaller(attr_span)) => { + self.check_track_caller(hir_id, *attr_span, attrs, span, target) + } + Attribute::Parsed( + AttributeKind::RustcLayoutScalarValidRangeStart(_num, attr_span) + | AttributeKind::RustcLayoutScalarValidRangeEnd(_num, attr_span), + ) => self.check_rustc_layout_scalar_valid_range(*attr_span, span, target), Attribute::Parsed( AttributeKind::BodyStability { .. } | AttributeKind::ConstStabilityIndirect @@ -171,6 +200,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::AsPtr(attr_span)) => { self.check_applied_to_fn_or_method(hir_id, *attr_span, span, target) } + Attribute::Parsed(AttributeKind::LinkName { span: attr_span, name }) => { + self.check_link_name(hir_id, *attr_span, *name, span, target) + } Attribute::Parsed(AttributeKind::MayDangle(attr_span)) => { self.check_may_dangle(hir_id, *attr_span) } @@ -180,6 +212,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::NoMangle(attr_span)) => { self.check_no_mangle(hir_id, *attr_span, span, target) } + Attribute::Parsed(AttributeKind::Used { span: attr_span, .. }) => { + self.check_used(*attr_span, target, span); + } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); match attr.path().as_slice() { @@ -199,9 +234,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.check_target_feature(hir_id, attr, span, target, attrs) } [sym::thread_local, ..] => self.check_thread_local(attr, span, target), - [sym::track_caller, ..] => { - self.check_track_caller(hir_id, attr.span(), attrs, span, target) - } [sym::doc, ..] => self.check_doc_attrs( attr, attr_item.style, @@ -211,11 +243,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { &mut doc_aliases, ), [sym::no_link, ..] => self.check_no_link(hir_id, attr, span, target), - [sym::export_name, ..] => self.check_export_name(hir_id, attr, span, target), - [sym::rustc_layout_scalar_valid_range_start, ..] - | [sym::rustc_layout_scalar_valid_range_end, ..] => { - self.check_rustc_layout_scalar_valid_range(attr, span, target) - } [sym::debugger_visualizer, ..] => self.check_debugger_visualizer(attr, target), [sym::rustc_std_internal_symbol, ..] => { self.check_rustc_std_internal_symbol(attr, span, target) @@ -250,7 +277,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | [sym::rustc_must_implement_one_of, ..] | [sym::rustc_deny_explicit_impl, ..] | [sym::rustc_do_not_implement_via_object, ..] - | [sym::const_trait, ..] => self.check_must_be_applied_to_trait(attr, span, target), + | [sym::const_trait, ..] => self.check_must_be_applied_to_trait(attr.span(), span, target), [sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target), [sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target), [sym::rustc_pass_by_value, ..] => self.check_pass_by_value(attr, span, target), @@ -264,8 +291,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::ffi_const, ..] => self.check_ffi_const(attr.span(), target), [sym::link_ordinal, ..] => self.check_link_ordinal(attr, span, target), [sym::link, ..] => self.check_link(hir_id, attr, span, target), - [sym::link_name, ..] => self.check_link_name(hir_id, attr, span, target), - [sym::link_section, ..] => self.check_link_section(hir_id, attr, span, target), [sym::macro_use, ..] | [sym::macro_escape, ..] => { self.check_macro_use(hir_id, attr, target) } @@ -280,7 +305,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::no_implicit_prelude, ..] => { self.check_generic_attr(hir_id, attr, target, Target::Mod) } - [sym::rustc_object_lifetime_default, ..] => self.check_object_lifetime_default(hir_id), [sym::proc_macro, ..] => { self.check_proc_macro(hir_id, target, ProcMacroKind::FunctionLike) } @@ -317,7 +341,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::cfi_encoding // FIXME(cfi_encoding) | sym::pointee // FIXME(derive_coerce_pointee) | sym::omit_gdb_pretty_printer_section // FIXME(omit_gdb_pretty_printer_section) - | sym::used // handled elsewhere to restrict to static items | sym::instruction_set // broken on stable!!! | sym::windows_subsystem // broken on stable!!! | sym::patchable_function_entry // FIXME(patchable_function_entry) @@ -387,8 +410,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } self.check_repr(attrs, span, target, item, hir_id); - self.check_used(attrs, target, span); self.check_rustc_force_inline(hir_id, attrs, span, target); + self.check_mix_no_mangle_export(hir_id, attrs); } fn inline_attr_str_error_with_macro_def(&self, hir_id: HirId, attr_span: Span, sym: &str) { @@ -716,9 +739,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { - for attr in attrs { - self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "track_caller"); - } + self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "track_caller"); } _ => { self.dcx().emit_err(errors::TrackedCallerWrongLocation { @@ -1588,7 +1609,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if `#[link_name]` is applied to an item other than a foreign function or static. - fn check_link_name(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) { + fn check_link_name( + &self, + hir_id: HirId, + attr_span: Span, + name: Symbol, + span: Span, + target: Target, + ) { match target { Target::ForeignFn | Target::ForeignStatic => {} // FIXME(#80564): We permit struct fields, match arms and macro defs to have an @@ -1596,27 +1624,18 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "link_name"); + self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "link_name"); } _ => { - // FIXME: #[cold] was previously allowed on non-functions/statics and some crates + // FIXME: #[link_name] was previously allowed on non-functions/statics and some crates // used this, so only emit a warning. - let attr_span = matches!(target, Target::ForeignMod).then_some(attr.span()); - if let Some(s) = attr.value_str() { - self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr.span(), - errors::LinkName { span, attr_span, value: s.as_str() }, - ); - } else { - self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr.span(), - errors::LinkName { span, attr_span, value: "..." }, - ); - }; + let help_span = matches!(target, Target::ForeignMod).then_some(attr_span); + self.tcx.emit_node_span_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr_span, + errors::LinkName { span, help_span, value: name.as_str() }, + ); } } } @@ -1643,7 +1662,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if `#[export_name]` is applied to a function or static. - fn check_export_name(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) { + fn check_export_name(&self, hir_id: HirId, attr_span: Span, span: Span, target: Target) { match target { Target::Static | Target::Fn => {} Target::Method(..) if self.is_impl_item(hir_id) => {} @@ -1652,32 +1671,19 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "export_name"); + self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "export_name"); } _ => { - self.dcx().emit_err(errors::ExportName { attr_span: attr.span(), span }); + self.dcx().emit_err(errors::ExportName { attr_span, span }); } } } - fn check_rustc_layout_scalar_valid_range(&self, attr: &Attribute, span: Span, target: Target) { + fn check_rustc_layout_scalar_valid_range(&self, attr_span: Span, span: Span, target: Target) { if target != Target::Struct { - self.dcx().emit_err(errors::RustcLayoutScalarValidRangeNotStruct { - attr_span: attr.span(), - span, - }); + self.dcx().emit_err(errors::RustcLayoutScalarValidRangeNotStruct { attr_span, span }); return; } - - let Some(list) = attr.meta_item_list() else { - return; - }; - - if !matches!(&list[..], &[MetaItemInner::Lit(MetaItemLit { kind: LitKind::Int(..), .. })]) { - self.tcx - .dcx() - .emit_err(errors::RustcLayoutScalarValidRangeArg { attr_span: attr.span() }); - } } /// Checks if `#[rustc_legacy_const_generics]` is applied to a function and has a valid argument. @@ -1805,20 +1811,17 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if the attribute is applied to a trait. - fn check_must_be_applied_to_trait(&self, attr: &Attribute, span: Span, target: Target) { + fn check_must_be_applied_to_trait(&self, attr_span: Span, defn_span: Span, target: Target) { match target { Target::Trait => {} _ => { - self.dcx().emit_err(errors::AttrShouldBeAppliedToTrait { - attr_span: attr.span(), - defn_span: span, - }); + self.dcx().emit_err(errors::AttrShouldBeAppliedToTrait { attr_span, defn_span }); } } } /// Checks if `#[link_section]` is applied to a function or static. - fn check_link_section(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) { + fn check_link_section(&self, hir_id: HirId, attr_span: Span, span: Span, target: Target) { match target { Target::Static | Target::Fn | Target::Method(..) => {} // FIXME(#80564): We permit struct fields, match arms and macro defs to have an @@ -1826,7 +1829,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "link_section"); + self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "link_section"); } _ => { // FIXME: #[link_section] was previously allowed on non-functions/statics and some @@ -1834,7 +1837,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr_span, errors::LinkSection { span }, ); } @@ -2095,44 +2098,13 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_used(&self, attrs: &[Attribute], target: Target, target_span: Span) { - let mut used_linker_span = None; - let mut used_compiler_span = None; - for attr in attrs.iter().filter(|attr| attr.has_name(sym::used)) { - if target != Target::Static { - self.dcx().emit_err(errors::UsedStatic { - attr_span: attr.span(), - span: target_span, - target: target.name(), - }); - } - let inner = attr.meta_item_list(); - match inner.as_deref() { - Some([item]) if item.has_name(sym::linker) => { - if used_linker_span.is_none() { - used_linker_span = Some(attr.span()); - } - } - Some([item]) if item.has_name(sym::compiler) => { - if used_compiler_span.is_none() { - used_compiler_span = Some(attr.span()); - } - } - Some(_) => { - // This error case is handled in rustc_hir_analysis::collect. - } - None => { - // Default case (compiler) when arg isn't defined. - if used_compiler_span.is_none() { - used_compiler_span = Some(attr.span()); - } - } - } - } - if let (Some(linker_span), Some(compiler_span)) = (used_linker_span, used_compiler_span) { - self.tcx - .dcx() - .emit_err(errors::UsedCompilerLinker { spans: vec![linker_span, compiler_span] }); + fn check_used(&self, attr_span: Span, target: Target, target_span: Span) { + if target != Target::Static { + self.dcx().emit_err(errors::UsedStatic { + attr_span, + span: target_span, + target: target.name(), + }); } } @@ -2619,6 +2591,36 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } + fn check_mix_no_mangle_export(&self, hir_id: HirId, attrs: &[Attribute]) { + if let Some(export_name_span) = find_attr!(attrs, AttributeKind::ExportName { span: export_name_span, .. } => *export_name_span) + && let Some(no_mangle_span) = + find_attr!(attrs, AttributeKind::NoMangle(no_mangle_span) => *no_mangle_span) + { + let no_mangle_attr = if no_mangle_span.edition() >= Edition::Edition2024 { + "#[unsafe(no_mangle)]" + } else { + "#[no_mangle]" + }; + let export_name_attr = if export_name_span.edition() >= Edition::Edition2024 { + "#[unsafe(export_name)]" + } else { + "#[export_name]" + }; + + self.tcx.emit_node_span_lint( + lint::builtin::UNUSED_ATTRIBUTES, + hir_id, + no_mangle_span, + errors::MixedExportNameAndNoMangle { + no_mangle_span, + export_name_span, + no_mangle_attr, + export_name_attr, + }, + ); + } + } + /// Checks if `#[autodiff]` is applied to an item other than a function item. fn check_autodiff(&self, _hir_id: HirId, _attr: &Attribute, span: Span, target: Target) { debug!("check_autodiff"); @@ -2630,6 +2632,32 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } } + + fn check_loop_match(&self, hir_id: HirId, attr_span: Span, target: Target) { + let node_span = self.tcx.hir_span(hir_id); + + if !matches!(target, Target::Expression) { + self.dcx().emit_err(errors::LoopMatchAttr { attr_span, node_span }); + return; + } + + if !matches!(self.tcx.hir_expect_expr(hir_id).kind, hir::ExprKind::Loop(..)) { + self.dcx().emit_err(errors::LoopMatchAttr { attr_span, node_span }); + }; + } + + fn check_const_continue(&self, hir_id: HirId, attr_span: Span, target: Target) { + let node_span = self.tcx.hir_span(hir_id); + + if !matches!(target, Target::Expression) { + self.dcx().emit_err(errors::ConstContinueAttr { attr_span, node_span }); + return; + } + + if !matches!(self.tcx.hir_expect_expr(hir_id).kind, hir::ExprKind::Break(..)) { + self.dcx().emit_err(errors::ConstContinueAttr { attr_span, node_span }); + }; + } } impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { @@ -2804,7 +2832,7 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { .find(|item| !item.span.is_dummy()) // Skip prelude `use`s .map(|item| errors::ItemFollowingInnerAttr { span: if let Some(ident) = item.kind.ident() { ident.span } else { item.span }, - kind: item.kind.descr(), + kind: tcx.def_descr(item.owner_id.to_def_id()), }); let err = tcx.dcx().create_err(errors::InvalidAttrAtCrateLevel { span, diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 4738036318d..ce43b2c281d 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -1056,7 +1056,7 @@ impl<'tcx> DeadVisitor<'tcx> { maybe_enum.variants().iter().find(|i| i.name == dead_item.name) { Some(crate::errors::EnumVariantSameName { - descr: tcx.def_descr(dead_item.def_id.to_def_id()), + dead_descr: tcx.def_descr(dead_item.def_id.to_def_id()), dead_name: dead_item.name, variant_span: tcx.def_span(variant.def_id), }) diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 94c8ae77ed7..d4988277073 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -31,6 +31,36 @@ pub(crate) struct AutoDiffAttr { pub attr_span: Span, } +#[derive(Diagnostic)] +#[diag(passes_loop_match_attr)] +pub(crate) struct LoopMatchAttr { + #[primary_span] + pub attr_span: Span, + #[label] + pub node_span: Span, +} + +#[derive(Diagnostic)] +#[diag(passes_const_continue_attr)] +pub(crate) struct ConstContinueAttr { + #[primary_span] + pub attr_span: Span, + #[label] + pub node_span: Span, +} + +#[derive(LintDiagnostic)] +#[diag(passes_mixed_export_name_and_no_mangle)] +pub(crate) struct MixedExportNameAndNoMangle { + #[label] + #[suggestion(style = "verbose", code = "", applicability = "machine-applicable")] + pub no_mangle_span: Span, + #[note] + pub export_name_span: Span, + pub no_mangle_attr: &'static str, + pub export_name_attr: &'static str, +} + #[derive(LintDiagnostic)] #[diag(passes_outer_crate_level_attr)] pub(crate) struct OuterCrateLevelAttr; @@ -472,7 +502,7 @@ pub(crate) struct Link { #[warning] pub(crate) struct LinkName<'a> { #[help] - pub attr_span: Option<Span>, + pub help_span: Option<Span>, #[label] pub span: Span, pub value: &'a str, @@ -506,13 +536,6 @@ pub(crate) struct RustcLayoutScalarValidRangeNotStruct { } #[derive(Diagnostic)] -#[diag(passes_rustc_layout_scalar_valid_range_arg)] -pub(crate) struct RustcLayoutScalarValidRangeArg { - #[primary_span] - pub attr_span: Span, -} - -#[derive(Diagnostic)] #[diag(passes_rustc_legacy_const_generics_only)] pub(crate) struct RustcLegacyConstGenericsOnly { #[primary_span] @@ -612,13 +635,6 @@ pub(crate) struct UsedStatic { } #[derive(Diagnostic)] -#[diag(passes_used_compiler_linker)] -pub(crate) struct UsedCompilerLinker { - #[primary_span] - pub spans: Vec<Span>, -} - -#[derive(Diagnostic)] #[diag(passes_allow_internal_unstable)] pub(crate) struct AllowInternalUnstable { #[primary_span] @@ -1498,7 +1514,7 @@ pub(crate) struct EnumVariantSameName<'tcx> { #[primary_span] pub variant_span: Span, pub dead_name: Symbol, - pub descr: &'tcx str, + pub dead_descr: &'tcx str, } #[derive(Subdiagnostic)] @@ -1696,6 +1712,7 @@ impl Subdiagnostic for UnusedVariableStringInterp { #[derive(LintDiagnostic)] #[diag(passes_unused_variable_try_ignore)] pub(crate) struct UnusedVarTryIgnore { + pub name: String, #[subdiagnostic] pub sugg: UnusedVarTryIgnoreSugg, } diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs index 46e6c0bf7da..40bc18939d6 100644 --- a/compiler/rustc_passes/src/input_stats.rs +++ b/compiler/rustc_passes/src/input_stats.rs @@ -65,16 +65,16 @@ pub fn print_hir_stats(tcx: TyCtxt<'_>) { StatCollector { tcx: Some(tcx), nodes: FxHashMap::default(), seen: FxHashSet::default() }; tcx.hir_walk_toplevel_module(&mut collector); tcx.hir_walk_attributes(&mut collector); - collector.print("HIR STATS", "hir-stats"); + collector.print(tcx, "HIR STATS", "hir-stats"); } -pub fn print_ast_stats(krate: &ast::Crate, title: &str, prefix: &str) { +pub fn print_ast_stats(tcx: TyCtxt<'_>, krate: &ast::Crate) { use rustc_ast::visit::Visitor; let mut collector = StatCollector { tcx: None, nodes: FxHashMap::default(), seen: FxHashSet::default() }; collector.visit_crate(krate); - collector.print(title, prefix); + collector.print(tcx, "POST EXPANSION AST STATS", "ast-stats"); } impl<'k> StatCollector<'k> { @@ -116,29 +116,48 @@ impl<'k> StatCollector<'k> { } } - fn print(&self, title: &str, prefix: &str) { + fn print(&self, tcx: TyCtxt<'_>, title: &str, prefix: &str) { + use std::fmt::Write; + // We will soon sort, so the initial order does not matter. #[allow(rustc::potential_query_instability)] let mut nodes: Vec<_> = self.nodes.iter().collect(); nodes.sort_by_cached_key(|(label, node)| (node.stats.accum_size(), label.to_owned())); + nodes.reverse(); // bigger items first + + let name_w = 18; + let acc_size1_w = 10; + let acc_size2_w = 8; // " (NN.N%)" + let acc_size_w = acc_size1_w + acc_size2_w; + let count_w = 14; + let item_size_w = 14; + let banner_w = name_w + acc_size_w + count_w + item_size_w; let total_size = nodes.iter().map(|(_, node)| node.stats.accum_size()).sum(); let total_count = nodes.iter().map(|(_, node)| node.stats.count).sum(); - eprintln!("{prefix} {title}"); - eprintln!( - "{} {:<18}{:>18}{:>14}{:>14}", - prefix, "Name", "Accumulated Size", "Count", "Item Size" + // We write all the text into a string and print it with a single + // `eprint!`. This is an attempt to minimize interleaved text if multiple + // rustc processes are printing macro-stats at the same time (e.g. with + // `RUSTFLAGS='-Zinput-stats' cargo build`). It still doesn't guarantee + // non-interleaving, though. + let mut s = String::new(); + _ = writeln!(s, "{prefix} {}", "=".repeat(banner_w)); + _ = writeln!(s, "{prefix} {title}: {}", tcx.crate_name(hir::def_id::LOCAL_CRATE)); + _ = writeln!( + s, + "{prefix} {:<name_w$}{:>acc_size_w$}{:>count_w$}{:>item_size_w$}", + "Name", "Accumulated Size", "Count", "Item Size" ); - eprintln!("{prefix} ----------------------------------------------------------------"); + _ = writeln!(s, "{prefix} {}", "-".repeat(banner_w)); let percent = |m, n| (m * 100) as f64 / n as f64; for (label, node) in nodes { let size = node.stats.accum_size(); - eprintln!( - "{} {:<18}{:>10} ({:4.1}%){:>14}{:>14}", - prefix, + _ = writeln!( + s, + "{prefix} {:<name_w$}{:>acc_size1_w$} ({:4.1}%){:>count_w$}{:>item_size_w$}", label, usize_with_underscores(size), percent(size, total_size), @@ -155,9 +174,9 @@ impl<'k> StatCollector<'k> { for (label, subnode) in subnodes { let size = subnode.accum_size(); - eprintln!( - "{} - {:<18}{:>10} ({:4.1}%){:>14}", - prefix, + _ = writeln!( + s, + "{prefix} - {:<name_w$}{:>acc_size1_w$} ({:4.1}%){:>count_w$}", label, usize_with_underscores(size), percent(size, total_size), @@ -166,15 +185,17 @@ impl<'k> StatCollector<'k> { } } } - eprintln!("{prefix} ----------------------------------------------------------------"); - eprintln!( - "{} {:<18}{:>10} {:>14}", - prefix, + _ = writeln!(s, "{prefix} {}", "-".repeat(banner_w)); + _ = writeln!( + s, + "{prefix} {:<name_w$}{:>acc_size1_w$}{:>acc_size2_w$}{:>count_w$}", "Total", usize_with_underscores(total_size), + "", usize_with_underscores(total_count), ); - eprintln!("{prefix}"); + _ = writeln!(s, "{prefix} {}", "=".repeat(banner_w)); + eprint!("{s}"); } } diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 125730377ef..3088e189c20 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -1744,6 +1744,7 @@ impl<'tcx> Liveness<'_, 'tcx> { .map(|(_, pat_span, _)| *pat_span) .collect::<Vec<_>>(), errors::UnusedVarTryIgnore { + name: name.clone(), sugg: errors::UnusedVarTryIgnoreSugg { shorthands, non_shorthands, diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs index f7a4931c111..09685640e50 100644 --- a/compiler/rustc_pattern_analysis/src/constructor.rs +++ b/compiler/rustc_pattern_analysis/src/constructor.rs @@ -314,7 +314,8 @@ impl IntRange { IntRange { lo, hi } } - fn is_subrange(&self, other: &Self) -> bool { + #[inline] + pub fn is_subrange(&self, other: &Self) -> bool { other.lo <= self.lo && self.hi <= other.hi } diff --git a/compiler/rustc_proc_macro/Cargo.toml b/compiler/rustc_proc_macro/Cargo.toml index 4a7c0d78ede..748fa944e28 100644 --- a/compiler/rustc_proc_macro/Cargo.toml +++ b/compiler/rustc_proc_macro/Cargo.toml @@ -15,7 +15,7 @@ test = false doctest = false [dependencies] -rustc-literal-escaper = "0.0.2" +rustc-literal-escaper = "0.0.4" [features] rustc-dep-of-std = [] diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 16852d1661e..1e345b11c14 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -2,12 +2,12 @@ use std::mem; use rustc_ast::visit::FnKind; use rustc_ast::*; -use rustc_ast_pretty::pprust; use rustc_attr_parsing::{AttributeParser, Early, OmitDoc}; use rustc_expand::expand::AstFragment; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind}; use rustc_hir::def_id::LocalDefId; +use rustc_middle::span_bug; use rustc_span::hygiene::LocalExpnId; use rustc_span::{Span, Symbol, sym}; use tracing::debug; @@ -380,20 +380,20 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } fn visit_ty(&mut self, ty: &'a Ty) { - match &ty.kind { + match ty.kind { TyKind::MacCall(..) => self.visit_macro_invoc(ty.id), - TyKind::ImplTrait(id, _) => { - // HACK: pprust breaks strings with newlines when the type - // gets too long. We don't want these to show up in compiler - // output or built artifacts, so replace them here... - // Perhaps we should instead format APITs more robustly. - let name = Symbol::intern(&pprust::ty_to_string(ty).replace('\n', " ")); + TyKind::ImplTrait(opaque_id, _) => { + let name = *self + .resolver + .impl_trait_names + .get(&ty.id) + .unwrap_or_else(|| span_bug!(ty.span, "expected this opaque to be named")); let kind = match self.invocation_parent.impl_trait_context { ImplTraitContext::Universal => DefKind::TyParam, ImplTraitContext::Existential => DefKind::OpaqueTy, ImplTraitContext::InBinding => return visit::walk_ty(self, ty), }; - let id = self.create_def(*id, Some(name), kind, ty.span); + let id = self.create_def(opaque_id, Some(name), kind, ty.span); match self.invocation_parent.impl_trait_context { // Do not nest APIT, as we desugar them as `impl_trait: bounds`, // so the `impl_trait` node is not a parent to `bounds`. diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 9149974a617..18078b760c3 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -256,22 +256,19 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; let label = match new_binding.is_import_user_facing() { - true => errors::NameDefinedMultipleTimeLabel::Reimported { span, name }, - false => errors::NameDefinedMultipleTimeLabel::Redefined { span, name }, + true => errors::NameDefinedMultipleTimeLabel::Reimported { span }, + false => errors::NameDefinedMultipleTimeLabel::Redefined { span }, }; let old_binding_label = (!old_binding.span.is_dummy() && old_binding.span != span).then(|| { let span = self.tcx.sess.source_map().guess_head_span(old_binding.span); match old_binding.is_import_user_facing() { - true => errors::NameDefinedMultipleTimeOldBindingLabel::Import { - span, - name, - old_kind, - }, + true => { + errors::NameDefinedMultipleTimeOldBindingLabel::Import { span, old_kind } + } false => errors::NameDefinedMultipleTimeOldBindingLabel::Definition { span, - name, old_kind, }, } @@ -281,6 +278,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .dcx() .create_err(errors::NameDefinedMultipleTime { span, + name, descr: ns.descr(), container, label, @@ -2423,6 +2421,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } else { let suggestion = if suggestion.is_some() { suggestion + } else if let Some(m) = self.undeclared_module_exists(ident) { + self.undeclared_module_suggest_declare(ident, m) } else if was_invoked_from_cargo() { Some(( vec![], @@ -2444,6 +2444,55 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } + fn undeclared_module_suggest_declare( + &mut self, + ident: Ident, + path: std::path::PathBuf, + ) -> Option<(Vec<(Span, String)>, String, Applicability)> { + Some(( + vec![(self.current_crate_outer_attr_insert_span, format!("mod {ident};\n"))], + format!( + "to make use of source file {}, use `mod {ident}` \ + in this file to declare the module", + path.display() + ), + Applicability::MaybeIncorrect, + )) + } + + fn undeclared_module_exists(&mut self, ident: Ident) -> Option<std::path::PathBuf> { + let map = self.tcx.sess.source_map(); + + let src = map.span_to_filename(ident.span).into_local_path()?; + let i = ident.as_str(); + // FIXME: add case where non parent using undeclared module (hard?) + let dir = src.parent()?; + let src = src.file_stem()?.to_str()?; + for file in [ + // …/x.rs + dir.join(i).with_extension("rs"), + // …/x/mod.rs + dir.join(i).join("mod.rs"), + ] { + if file.exists() { + return Some(file); + } + } + if !matches!(src, "main" | "lib" | "mod") { + for file in [ + // …/x/y.rs + dir.join(src).join(i).with_extension("rs"), + // …/x/y/mod.rs + dir.join(src).join(i).join("mod.rs"), + ] { + if file.exists() { + return Some(file); + } + } + } + None + } + /// Adds suggestions for a path that cannot be resolved. #[instrument(level = "debug", skip(self, parent_scope))] pub(crate) fn make_path_suggestion( diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 7fe74378b67..6d3752c0c83 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -978,6 +978,7 @@ pub(crate) struct VariableNotInAllPatterns { pub(crate) struct NameDefinedMultipleTime { #[primary_span] pub(crate) span: Span, + pub(crate) name: Symbol, pub(crate) descr: &'static str, pub(crate) container: &'static str, #[subdiagnostic] @@ -992,13 +993,11 @@ pub(crate) enum NameDefinedMultipleTimeLabel { Reimported { #[primary_span] span: Span, - name: Symbol, }, #[label(resolve_name_defined_multiple_time_redefined)] Redefined { #[primary_span] span: Span, - name: Symbol, }, } @@ -1008,14 +1007,12 @@ pub(crate) enum NameDefinedMultipleTimeOldBindingLabel { Import { #[primary_span] span: Span, - name: Symbol, old_kind: &'static str, }, #[label(resolve_name_defined_multiple_time_old_binding_definition)] Definition { #[primary_span] span: Span, - name: Symbol, old_kind: &'static str, }, } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index e989209e177..2e81b54b136 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -174,7 +174,14 @@ pub(crate) struct ImportData<'ra> { pub parent_scope: ParentScope<'ra>, pub module_path: Vec<Segment>, - /// The resolution of `module_path`. + /// The resolution of `module_path`: + /// + /// | `module_path` | `imported_module` | remark | + /// |-|-|-| + /// |`use prefix::foo`| `ModuleOrUniformRoot::Module(prefix)` | - | + /// |`use ::foo` | `ModuleOrUniformRoot::ExternPrelude` | 2018+ editions | + /// |`use ::foo` | `ModuleOrUniformRoot::CrateRootAndExternPrelude` | a special case in 2015 edition | + /// |`use foo` | `ModuleOrUniformRoot::CurrentScope` | - | pub imported_module: Cell<Option<ModuleOrUniformRoot<'ra>>>, pub vis: ty::Visibility, } @@ -608,7 +615,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - self.throw_unresolved_import_error(errors, glob_error); + if !errors.is_empty() { + self.throw_unresolved_import_error(errors, glob_error); + } } pub(crate) fn check_hidden_glob_reexports( @@ -688,14 +697,19 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Some(def_id) if self.mods_with_parse_errors.contains(&def_id) => false, _ => true, }); + errors.retain(|(_import, err)| { + // If we've encountered something like `use _;`, we've already emitted an error stating + // that `_` is not a valid identifier, so we ignore that resolve error. + err.segment != Some(kw::Underscore) + }); + if errors.is_empty() { + self.tcx.dcx().delayed_bug("expected a parse or \"`_` can't be an identifier\" error"); return; } - /// Upper limit on the number of `span_label` messages. - const MAX_LABEL_COUNT: usize = 10; - let span = MultiSpan::from_spans(errors.iter().map(|(_, err)| err.span).collect()); + let paths = errors .iter() .map(|(import, err)| { @@ -715,6 +729,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { diag.note(note.clone()); } + /// Upper limit on the number of `span_label` messages. + const MAX_LABEL_COUNT: usize = 10; + for (import, err) in errors.into_iter().take(MAX_LABEL_COUNT) { if let Some(label) = err.label { diag.span_label(err.span, label); diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index d5dd3bdb6cd..e7b8c988cd4 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -3122,15 +3122,10 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { &mut err, Some(lifetime_ref.ident.name.as_str()), |err, _, span, message, suggestion, span_suggs| { - err.multipart_suggestion_with_style( + err.multipart_suggestion_verbose( message, std::iter::once((span, suggestion)).chain(span_suggs.clone()).collect(), Applicability::MaybeIncorrect, - if span_suggs.is_empty() { - SuggestionStyle::ShowCode - } else { - SuggestionStyle::ShowAlways - }, ); true }, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index f0540725416..05bc3611dd8 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1224,6 +1224,11 @@ pub struct Resolver<'ra, 'tcx> { current_crate_outer_attr_insert_span: Span, mods_with_parse_errors: FxHashSet<DefId>, + + // Stores pre-expansion and pre-placeholder-fragment-insertion names for `impl Trait` types + // that were encountered during resolution. These names are used to generate item names + // for APITs, so we don't want to leak details of resolution into these names. + impl_trait_names: FxHashMap<NodeId, Symbol>, } /// This provides memory for the rest of the crate. The `'ra` lifetime that is @@ -1579,6 +1584,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { impl_binding_keys: Default::default(), current_crate_outer_attr_insert_span, mods_with_parse_errors: Default::default(), + impl_trait_names: Default::default(), }; let root_parent_scope = ParentScope::module(graph_root, &resolver); diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 1b82e9c9799..3d33a02a9c6 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -522,6 +522,10 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { }); Ok(idents) } + + fn insert_impl_trait_name(&mut self, id: NodeId, name: Symbol) { + self.impl_trait_names.insert(id, name); + } } impl<'ra, 'tcx> Resolver<'ra, 'tcx> { diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index 931c6241bf2..3fe5db8ca54 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -49,6 +49,9 @@ pub struct DocFragment { pub doc: Symbol, pub kind: DocFragmentKind, pub indent: usize, + /// Because we tamper with the spans context, this information cannot be correctly retrieved + /// later on. So instead, we compute it and store it here. + pub from_expansion: bool, } #[derive(Clone, Copy, Debug)] @@ -208,17 +211,18 @@ pub fn attrs_to_doc_fragments<'a, A: AttributeExt + Clone + 'a>( for (attr, item_id) in attrs { if let Some((doc_str, comment_kind)) = attr.doc_str_and_comment_kind() { let doc = beautify_doc_string(doc_str, comment_kind); - let (span, kind) = if attr.is_doc_comment() { - (attr.span(), DocFragmentKind::SugaredDoc) + let (span, kind, from_expansion) = if attr.is_doc_comment() { + let span = attr.span(); + (span, DocFragmentKind::SugaredDoc, span.from_expansion()) } else { - ( - attr.value_span() - .map(|i| i.with_ctxt(attr.span().ctxt())) - .unwrap_or(attr.span()), - DocFragmentKind::RawDoc, - ) + let attr_span = attr.span(); + let (span, from_expansion) = match attr.value_span() { + Some(sp) => (sp.with_ctxt(attr_span.ctxt()), sp.from_expansion()), + None => (attr_span, attr_span.from_expansion()), + }; + (span, DocFragmentKind::RawDoc, from_expansion) }; - let fragment = DocFragment { span, doc, kind, item_id, indent: 0 }; + let fragment = DocFragment { span, doc, kind, item_id, indent: 0, from_expansion }; doc_fragments.push(fragment); } else if !doc_only { other_attrs.push(attr.clone()); @@ -505,17 +509,26 @@ fn collect_link_data<'input, F: BrokenLinkCallback<'input>>( display_text.map(String::into_boxed_str) } -/// Returns a span encompassing all the document fragments. -pub fn span_of_fragments(fragments: &[DocFragment]) -> Option<Span> { - if fragments.is_empty() { - return None; - } - let start = fragments[0].span; - if start == DUMMY_SP { +/// Returns a tuple containing a span encompassing all the document fragments and a boolean that is +/// `true` if any of the fragments are from a macro expansion. +pub fn span_of_fragments_with_expansion(fragments: &[DocFragment]) -> Option<(Span, bool)> { + let (first_fragment, last_fragment) = match fragments { + [] => return None, + [first, .., last] => (first, last), + [first] => (first, first), + }; + if first_fragment.span == DUMMY_SP { return None; } - let end = fragments.last().expect("no doc strings provided").span; - Some(start.to(end)) + Some(( + first_fragment.span.to(last_fragment.span), + fragments.iter().any(|frag| frag.from_expansion), + )) +} + +/// Returns a span encompassing all the document fragments. +pub fn span_of_fragments(fragments: &[DocFragment]) -> Option<Span> { + span_of_fragments_with_expansion(fragments).map(|(sp, _)| sp) } /// Attempts to match a range of bytes from parsed markdown to a `Span` in the source code. @@ -529,18 +542,22 @@ pub fn span_of_fragments(fragments: &[DocFragment]) -> Option<Span> { /// This method will return `Some` only if one of the following is true: /// /// - The doc is made entirely from sugared doc comments, which cannot contain escapes -/// - The doc is entirely from a single doc fragment with a string literal exactly equal to `markdown`. +/// - The doc is entirely from a single doc fragment with a string literal exactly equal to +/// `markdown`. /// - The doc comes from `include_str!` -/// - The doc includes exactly one substring matching `markdown[md_range]` which is contained in a single doc fragment. +/// - The doc includes exactly one substring matching `markdown[md_range]` which is contained in a +/// single doc fragment. +/// +/// This function is defined in the compiler so it can be used by both `rustdoc` and `clippy`. /// -/// This function is defined in the compiler so it can be used by -/// both `rustdoc` and `clippy`. +/// It returns a tuple containing a span encompassing all the document fragments and a boolean that +/// is `true` if any of the *matched* fragments are from a macro expansion. pub fn source_span_for_markdown_range( tcx: TyCtxt<'_>, markdown: &str, md_range: &Range<usize>, fragments: &[DocFragment], -) -> Option<Span> { +) -> Option<(Span, bool)> { let map = tcx.sess.source_map(); source_span_for_markdown_range_inner(map, markdown, md_range, fragments) } @@ -551,7 +568,7 @@ pub fn source_span_for_markdown_range_inner( markdown: &str, md_range: &Range<usize>, fragments: &[DocFragment], -) -> Option<Span> { +) -> Option<(Span, bool)> { use rustc_span::BytePos; if let &[fragment] = &fragments @@ -562,11 +579,14 @@ pub fn source_span_for_markdown_range_inner( && let Ok(md_range_hi) = u32::try_from(md_range.end) { // Single fragment with string that contains same bytes as doc. - return Some(Span::new( - fragment.span.lo() + rustc_span::BytePos(md_range_lo), - fragment.span.lo() + rustc_span::BytePos(md_range_hi), - fragment.span.ctxt(), - fragment.span.parent(), + return Some(( + Span::new( + fragment.span.lo() + rustc_span::BytePos(md_range_lo), + fragment.span.lo() + rustc_span::BytePos(md_range_hi), + fragment.span.ctxt(), + fragment.span.parent(), + ), + fragment.from_expansion, )); } @@ -598,19 +618,21 @@ pub fn source_span_for_markdown_range_inner( { match_data = Some((i, match_start)); } else { - // Heirustic produced ambiguity, return nothing. + // Heuristic produced ambiguity, return nothing. return None; } } } if let Some((i, match_start)) = match_data { - let sp = fragments[i].span; + let fragment = &fragments[i]; + let sp = fragment.span; // we need to calculate the span start, // then use that in our calulations for the span end let lo = sp.lo() + BytePos(match_start as u32); - return Some( + return Some(( sp.with_lo(lo).with_hi(lo + BytePos((md_range.end - md_range.start) as u32)), - ); + fragment.from_expansion, + )); } return None; } @@ -664,8 +686,13 @@ pub fn source_span_for_markdown_range_inner( } } - Some(span_of_fragments(fragments)?.from_inner(InnerSpan::new( + let (span, _) = span_of_fragments_with_expansion(fragments)?; + let src_span = span.from_inner(InnerSpan::new( md_range.start + start_bytes, md_range.end + start_bytes + end_bytes, - ))) + )); + Some(( + src_span, + fragments.iter().any(|frag| frag.span.overlaps(src_span) && frag.from_expansion), + )) } diff --git a/compiler/rustc_resolve/src/rustdoc/tests.rs b/compiler/rustc_resolve/src/rustdoc/tests.rs index 221ac907e7c..6a98ae06630 100644 --- a/compiler/rustc_resolve/src/rustdoc/tests.rs +++ b/compiler/rustc_resolve/src/rustdoc/tests.rs @@ -10,7 +10,7 @@ use super::{DocFragment, DocFragmentKind, source_span_for_markdown_range_inner}; fn single_backtick() { let sm = SourceMap::new(FilePathMapping::empty()); sm.new_source_file(PathBuf::from("foo.rs").into(), r#"#[doc = "`"] fn foo() {}"#.to_string()); - let span = source_span_for_markdown_range_inner( + let (span, _) = source_span_for_markdown_range_inner( &sm, "`", &(0..1), @@ -20,6 +20,7 @@ fn single_backtick() { kind: DocFragmentKind::RawDoc, doc: sym::empty, // unused placeholder indent: 0, + from_expansion: false, }], ) .unwrap(); @@ -32,7 +33,7 @@ fn utf8() { // regression test for https://github.com/rust-lang/rust/issues/141665 let sm = SourceMap::new(FilePathMapping::empty()); sm.new_source_file(PathBuf::from("foo.rs").into(), r#"#[doc = "âš "] fn foo() {}"#.to_string()); - let span = source_span_for_markdown_range_inner( + let (span, _) = source_span_for_markdown_range_inner( &sm, "âš ", &(0..3), @@ -42,6 +43,7 @@ fn utf8() { kind: DocFragmentKind::RawDoc, doc: sym::empty, // unused placeholder indent: 0, + from_expansion: false, }], ) .unwrap(); diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs index 9d1d3412f8d..f4a14b36ce5 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs @@ -631,7 +631,6 @@ pub(crate) fn encode_ty<'tcx>( // vendor extended type. let mut s = String::from(match kind { ty::Dyn => "u3dynI", - ty::DynStar => "u7dynstarI", }); s.push_str(&encode_predicates(tcx, predicates, dict, options)); s.push_str(&encode_region(*region, dict)); diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs index 656ecfcab36..806d880b19c 100644 --- a/compiler/rustc_serialize/src/lib.rs +++ b/compiler/rustc_serialize/src/lib.rs @@ -3,7 +3,6 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::internal)] -#![cfg_attr(not(bootstrap), feature(sized_hierarchy))] #![cfg_attr(test, feature(test))] #![doc( html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", @@ -15,6 +14,7 @@ #![feature(min_specialization)] #![feature(never_type)] #![feature(rustdoc_internals)] +#![feature(sized_hierarchy)] // tidy-alphabetical-end // Allows macros to refer to this crate as `::rustc_serialize`. @@ -28,19 +28,3 @@ mod serialize; pub mod int_overflow; pub mod leb128; pub mod opaque; - -// This has nothing to do with `rustc_serialize` but it is convenient to define it in one place -// for the rest of the compiler so that `cfg(bootstrap)` doesn't need to be littered throughout -// the compiler wherever `PointeeSized` would be used. `rustc_serialize` happens to be the deepest -// crate in the crate graph which uses `PointeeSized`. -// -// When bootstrap bumps, remove both the `cfg(not(bootstrap))` and `cfg(bootstrap)` lines below -// and just import `std::marker::PointeeSized` whereever this item was used. - -#[cfg(not(bootstrap))] -pub use std::marker::PointeeSized; - -#[cfg(bootstrap)] -pub trait PointeeSized {} -#[cfg(bootstrap)] -impl<T: ?Sized> PointeeSized for T {} diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs index 8940d10696d..6ea70600626 100644 --- a/compiler/rustc_serialize/src/serialize.rs +++ b/compiler/rustc_serialize/src/serialize.rs @@ -4,7 +4,7 @@ use std::borrow::Cow; use std::cell::{Cell, RefCell}; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet, VecDeque}; use std::hash::{BuildHasher, Hash}; -use std::marker::PhantomData; +use std::marker::{PhantomData, PointeeSized}; use std::num::NonZero; use std::path; use std::rc::Rc; @@ -21,6 +21,11 @@ use thin_vec::ThinVec; /// [utf8]: https://en.wikipedia.org/w/index.php?title=UTF-8&oldid=1058865525#Codepage_layout const STR_SENTINEL: u8 = 0xC1; +/// For byte strings there are no bytes that canot occur. Just use this value +/// as a best-effort sentinel. There is no validation skipped so the potential +/// for badness is lower than in the `STR_SENTINEL` case. +const BYTE_STR_SENTINEL: u8 = 0xC2; + /// A note about error handling. /// /// Encoders may be fallible, but in practice failure is rare and there are so @@ -72,6 +77,13 @@ pub trait Encoder { self.emit_u8(STR_SENTINEL); } + #[inline] + fn emit_byte_str(&mut self, v: &[u8]) { + self.emit_usize(v.len()); + self.emit_raw_bytes(v); + self.emit_u8(BYTE_STR_SENTINEL); + } + fn emit_raw_bytes(&mut self, s: &[u8]); } @@ -122,9 +134,19 @@ pub trait Decoder { let len = self.read_usize(); let bytes = self.read_raw_bytes(len + 1); assert!(bytes[len] == STR_SENTINEL); + // SAFETY: the presence of `STR_SENTINEL` gives us high (but not + // perfect) confidence that the bytes we just read truly are UTF-8. unsafe { std::str::from_utf8_unchecked(&bytes[..len]) } } + #[inline] + fn read_byte_str(&mut self) -> &[u8] { + let len = self.read_usize(); + let bytes = self.read_raw_bytes(len + 1); + assert!(bytes[len] == BYTE_STR_SENTINEL); + &bytes[..len] + } + fn read_raw_bytes(&mut self, len: usize) -> &[u8]; fn peek_byte(&self) -> u8; @@ -142,7 +164,7 @@ pub trait Decoder { /// `rustc_metadata::rmeta::Lazy`. /// * `TyEncodable` should be used for types that are only serialized in crate /// metadata or the incremental cache. This is most types in `rustc_middle`. -pub trait Encodable<S: Encoder>: crate::PointeeSized { +pub trait Encodable<S: Encoder>: PointeeSized { fn encode(&self, s: &mut S); } @@ -198,7 +220,7 @@ direct_serialize_impls! { char emit_char read_char } -impl<S: Encoder, T: ?Sized + crate::PointeeSized> Encodable<S> for &T +impl<S: Encoder, T: ?Sized + PointeeSized> Encodable<S> for &T where T: Encodable<S>, { @@ -239,7 +261,7 @@ impl<S: Encoder> Encodable<S> for str { impl<S: Encoder> Encodable<S> for String { fn encode(&self, s: &mut S) { - s.emit_str(&self[..]); + s.emit_str(&self); } } diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml index f0ee19e3c67..5b88a7017c5 100644 --- a/compiler/rustc_session/Cargo.toml +++ b/compiler/rustc_session/Cargo.toml @@ -22,7 +22,6 @@ rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } -smallvec = "1.8.1" termize = "0.1.1" tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 87e4b0a17aa..73bb0471c22 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -227,13 +227,15 @@ pub enum CoverageLevel { } /// The different settings that the `-Z autodiff` flag can have. -#[derive(Clone, Copy, PartialEq, Hash, Debug)] +#[derive(Clone, PartialEq, Hash, Debug)] pub enum AutoDiff { /// Enable the autodiff opt pipeline Enable, /// Print TypeAnalysis information PrintTA, + /// Print TypeAnalysis information for a specific function + PrintTAFn(String), /// Print ActivityAnalysis Information PrintAA, /// Print Performance Warnings from Enzyme @@ -1296,6 +1298,28 @@ bitflags::bitflags! { } } +#[derive(Clone, Debug)] +pub struct Sysroot { + pub explicit: Option<PathBuf>, + pub default: PathBuf, +} + +impl Sysroot { + pub fn new(explicit: Option<PathBuf>) -> Sysroot { + Sysroot { explicit, default: filesearch::default_sysroot() } + } + + /// Return explicit sysroot if it was passed with `--sysroot`, or default sysroot otherwise. + pub fn path(&self) -> &Path { + self.explicit.as_deref().unwrap_or(&self.default) + } + + /// Returns both explicit sysroot if it was passed with `--sysroot` and the default sysroot. + pub fn all_paths(&self) -> impl Iterator<Item = &Path> { + self.explicit.as_deref().into_iter().chain(iter::once(&*self.default)) + } +} + pub fn host_tuple() -> &'static str { // Get the host triple out of the build environment. This ensures that our // idea of the host triple is the same as for the set of libraries we've @@ -1342,7 +1366,7 @@ impl Default for Options { describe_lints: false, output_types: OutputTypes(BTreeMap::new()), search_paths: vec![], - sysroot: filesearch::materialize_sysroot(None), + sysroot: Sysroot::new(None), target_triple: TargetTuple::from_tuple(host_tuple()), test: false, incremental: None, @@ -2673,7 +2697,6 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M let cg = cg; - let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m)); let target_triple = parse_target_triple(early_dcx, matches); let opt_level = parse_opt_level(early_dcx, matches, &cg); // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able @@ -2712,10 +2735,10 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M let logical_env = parse_logical_env(early_dcx, matches); - let sysroot = filesearch::materialize_sysroot(sysroot_opt); + let sysroot = Sysroot::new(matches.opt_str("sysroot").map(PathBuf::from)); let real_source_base_dir = |suffix: &str, confirm: &str| { - let mut candidate = sysroot.join(suffix); + let mut candidate = sysroot.path().join(suffix); if let Ok(metadata) = candidate.symlink_metadata() { // Replace the symlink bootstrap creates, with its destination. // We could try to use `fs::canonicalize` instead, but that might @@ -2742,7 +2765,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M let mut search_paths = vec![]; for s in &matches.opt_strs("L") { search_paths.push(SearchPath::from_cli_opt( - &sysroot, + sysroot.path(), &target_triple, early_dcx, s, diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs index 4f8c3926207..f64fa86948c 100644 --- a/compiler/rustc_session/src/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -5,7 +5,6 @@ use std::{env, fs}; use rustc_fs_util::try_canonicalize; use rustc_target::spec::Target; -use smallvec::{SmallVec, smallvec}; use crate::search_paths::{PathKind, SearchPath}; @@ -182,24 +181,9 @@ fn current_dll_path() -> Result<PathBuf, String> { Err("current_dll_path is not supported on WASI".to_string()) } -pub fn sysroot_with_fallback(sysroot: &Path) -> SmallVec<[PathBuf; 2]> { - let mut candidates = smallvec![sysroot.to_owned()]; - let default_sysroot = get_or_default_sysroot(); - if default_sysroot != sysroot { - candidates.push(default_sysroot); - } - candidates -} - -/// Returns the provided sysroot or calls [`get_or_default_sysroot`] if it's none. -/// Panics if [`get_or_default_sysroot`] returns an error. -pub fn materialize_sysroot(maybe_sysroot: Option<PathBuf>) -> PathBuf { - maybe_sysroot.unwrap_or_else(|| get_or_default_sysroot()) -} - /// This function checks if sysroot is found using env::args().next(), and if it /// is not found, finds sysroot from current rustc_driver dll. -pub fn get_or_default_sysroot() -> PathBuf { +pub(crate) fn default_sysroot() -> PathBuf { fn default_from_rustc_driver_dll() -> Result<PathBuf, String> { let dll = current_dll_path()?; diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 7fef942525b..ecd82c0cc01 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -337,7 +337,7 @@ top_level_options!( output_types: OutputTypes [TRACKED], search_paths: Vec<SearchPath> [UNTRACKED], libs: Vec<NativeLib> [TRACKED], - sysroot: PathBuf [UNTRACKED], + sysroot: Sysroot [UNTRACKED], target_triple: TargetTuple [TRACKED], @@ -725,7 +725,7 @@ mod desc { pub(crate) const parse_list: &str = "a space-separated list of strings"; pub(crate) const parse_list_with_polarity: &str = "a comma-separated list of strings, with elements beginning with + or -"; - pub(crate) const parse_autodiff: &str = "a comma separated list of settings: `Enable`, `PrintSteps`, `PrintTA`, `PrintAA`, `PrintPerf`, `PrintModBefore`, `PrintModAfter`, `PrintModFinal`, `PrintPasses`, `NoPostopt`, `LooseTypes`, `Inline`"; + pub(crate) const parse_autodiff: &str = "a comma separated list of settings: `Enable`, `PrintSteps`, `PrintTA`, `PrintTAFn`, `PrintAA`, `PrintPerf`, `PrintModBefore`, `PrintModAfter`, `PrintModFinal`, `PrintPasses`, `NoPostopt`, `LooseTypes`, `Inline`"; pub(crate) const parse_comma_list: &str = "a comma-separated list of strings"; pub(crate) const parse_opt_comma_list: &str = parse_comma_list; pub(crate) const parse_number: &str = "a number"; @@ -1365,9 +1365,22 @@ pub mod parse { let mut v: Vec<&str> = v.split(",").collect(); v.sort_unstable(); for &val in v.iter() { - let variant = match val { + // Split each entry on '=' if it has an argument + let (key, arg) = match val.split_once('=') { + Some((k, a)) => (k, Some(a)), + None => (val, None), + }; + + let variant = match key { "Enable" => AutoDiff::Enable, "PrintTA" => AutoDiff::PrintTA, + "PrintTAFn" => { + if let Some(fun) = arg { + AutoDiff::PrintTAFn(fun.to_string()) + } else { + return false; + } + } "PrintAA" => AutoDiff::PrintAA, "PrintPerf" => AutoDiff::PrintPerf, "PrintSteps" => AutoDiff::PrintSteps, diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index ad58c3c8f7d..bad2581ae31 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -149,7 +149,6 @@ pub struct Session { pub opts: config::Options, pub target_tlib_path: Arc<SearchPath>, pub psess: ParseSess, - pub sysroot: PathBuf, /// Input, input file path and output file path to this compilation process. pub io: CompilerIO, @@ -456,8 +455,10 @@ impl Session { /// directories are also returned, for example if `--sysroot` is used but tools are missing /// (#125246): we also add the bin directories to the sysroot where rustc is located. pub fn get_tools_search_paths(&self, self_contained: bool) -> Vec<PathBuf> { - let search_paths = filesearch::sysroot_with_fallback(&self.sysroot) - .into_iter() + let search_paths = self + .opts + .sysroot + .all_paths() .map(|sysroot| filesearch::make_target_bin_path(&sysroot, config::host_tuple())); if self_contained { @@ -1028,7 +1029,6 @@ pub fn build_session( fluent_resources: Vec<&'static str>, driver_lint_caps: FxHashMap<lint::LintId, lint::Level>, target: Target, - sysroot: PathBuf, cfg_version: &'static str, ice_file: Option<PathBuf>, using_internal_features: &'static AtomicBool, @@ -1063,7 +1063,7 @@ pub fn build_session( } let host_triple = TargetTuple::from_tuple(config::host_tuple()); - let (host, target_warnings) = Target::search(&host_triple, &sysroot) + let (host, target_warnings) = Target::search(&host_triple, sopts.sysroot.path()) .unwrap_or_else(|e| dcx.handle().fatal(format!("Error loading host specification: {e}"))); for warning in target_warnings.warning_messages() { dcx.handle().warn(warning) @@ -1096,13 +1096,14 @@ pub fn build_session( let host_triple = config::host_tuple(); let target_triple = sopts.target_triple.tuple(); // FIXME use host sysroot? - let host_tlib_path = Arc::new(SearchPath::from_sysroot_and_triple(&sysroot, host_triple)); + let host_tlib_path = + Arc::new(SearchPath::from_sysroot_and_triple(sopts.sysroot.path(), host_triple)); let target_tlib_path = if host_triple == target_triple { // Use the same `SearchPath` if host and target triple are identical to avoid unnecessary // rescanning of the target lib path and an unnecessary allocation. Arc::clone(&host_tlib_path) } else { - Arc::new(SearchPath::from_sysroot_and_triple(&sysroot, target_triple)) + Arc::new(SearchPath::from_sysroot_and_triple(sopts.sysroot.path(), target_triple)) }; let prof = SelfProfilerRef::new( @@ -1134,7 +1135,6 @@ pub fn build_session( opts: sopts, target_tlib_path, psess, - sysroot, io, incr_comp_session: RwLock::new(IncrCompSession::NotInitialized), prof, diff --git a/compiler/rustc_smir/src/lib.rs b/compiler/rustc_smir/src/lib.rs index 63623cfad72..067adda791d 100644 --- a/compiler/rustc_smir/src/lib.rs +++ b/compiler/rustc_smir/src/lib.rs @@ -9,13 +9,13 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::usage_of_ty_tykind)] -#![cfg_attr(not(bootstrap), feature(sized_hierarchy))] #![doc( html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", test(attr(allow(unused_variables), deny(warnings))) )] #![doc(rust_logo)] #![feature(rustdoc_internals)] +#![feature(sized_hierarchy)] // tidy-alphabetical-end pub mod rustc_internal; diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index a4c6f186222..f878b6e6b71 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -369,7 +369,6 @@ impl RustcInternal for DynKind { fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { match self { DynKind::Dyn => rustc_ty::DynKind::Dyn, - DynKind::DynStar => rustc_ty::DynKind::DynStar, } } } @@ -479,6 +478,8 @@ impl RustcInternal for Abi { Abi::Vectorcall { unwind } => rustc_abi::ExternAbi::Vectorcall { unwind }, Abi::Thiscall { unwind } => rustc_abi::ExternAbi::Thiscall { unwind }, Abi::Aapcs { unwind } => rustc_abi::ExternAbi::Aapcs { unwind }, + Abi::CCmseNonSecureCall => rustc_abi::ExternAbi::CmseNonSecureCall, + Abi::CCmseNonSecureEntry => rustc_abi::ExternAbi::CmseNonSecureEntry, Abi::Win64 { unwind } => rustc_abi::ExternAbi::Win64 { unwind }, Abi::SysV64 { unwind } => rustc_abi::ExternAbi::SysV64 { unwind }, Abi::PtxKernel => rustc_abi::ExternAbi::PtxKernel, @@ -488,12 +489,11 @@ impl RustcInternal for Abi { Abi::EfiApi => rustc_abi::ExternAbi::EfiApi, Abi::AvrInterrupt => rustc_abi::ExternAbi::AvrInterrupt, Abi::AvrNonBlockingInterrupt => rustc_abi::ExternAbi::AvrNonBlockingInterrupt, - Abi::CCmseNonSecureCall => rustc_abi::ExternAbi::CCmseNonSecureCall, - Abi::CCmseNonSecureEntry => rustc_abi::ExternAbi::CCmseNonSecureEntry, Abi::System { unwind } => rustc_abi::ExternAbi::System { unwind }, Abi::RustCall => rustc_abi::ExternAbi::RustCall, Abi::Unadjusted => rustc_abi::ExternAbi::Unadjusted, Abi::RustCold => rustc_abi::ExternAbi::RustCold, + Abi::RustInvalid => rustc_abi::ExternAbi::RustInvalid, Abi::RiscvInterruptM => rustc_abi::ExternAbi::RiscvInterruptM, Abi::RiscvInterruptS => rustc_abi::ExternAbi::RiscvInterruptS, Abi::Custom => rustc_abi::ExternAbi::Custom, diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index 42b3e59b73a..daea4acc36c 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -301,11 +301,9 @@ impl<'tcx> Stable<'tcx> for mir::CastKind { type T = stable_mir::mir::CastKind; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { use rustc_middle::mir::CastKind::*; - use rustc_middle::ty::adjustment::PointerCoercion; match self { PointerExposeProvenance => stable_mir::mir::CastKind::PointerExposeAddress, PointerWithExposedProvenance => stable_mir::mir::CastKind::PointerWithExposedProvenance, - PointerCoercion(PointerCoercion::DynStar, _) => stable_mir::mir::CastKind::DynStar, PointerCoercion(c, _) => stable_mir::mir::CastKind::PointerCoercion(c.stable(tables)), IntToInt => stable_mir::mir::CastKind::IntToInt, FloatToInt => stable_mir::mir::CastKind::FloatToInt, @@ -506,6 +504,9 @@ impl<'tcx> Stable<'tcx> for mir::AssertMessage<'tcx> { AssertKind::NullPointerDereference => { stable_mir::mir::AssertMessage::NullPointerDereference } + AssertKind::InvalidEnumConstruction(source) => { + stable_mir::mir::AssertMessage::InvalidEnumConstruction(source.stable(tables)) + } } } } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index b4239ddd896..ff0b8e833dc 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -43,7 +43,6 @@ impl<'tcx> Stable<'tcx> for ty::DynKind { fn stable(&self, _: &mut Tables<'_>) -> Self::T { match self { ty::Dyn => stable_mir::ty::DynKind::Dyn, - ty::DynStar => stable_mir::ty::DynKind::DynStar, } } } @@ -120,7 +119,6 @@ impl<'tcx> Stable<'tcx> for ty::adjustment::PointerCoercion { } PointerCoercion::ArrayToPointer => stable_mir::mir::PointerCoercion::ArrayToPointer, PointerCoercion::Unsize => stable_mir::mir::PointerCoercion::Unsize, - PointerCoercion::DynStar => unreachable!("represented as `CastKind::DynStar` in smir"), } } } @@ -871,12 +869,13 @@ impl<'tcx> Stable<'tcx> for rustc_abi::ExternAbi { ExternAbi::EfiApi => Abi::EfiApi, ExternAbi::AvrInterrupt => Abi::AvrInterrupt, ExternAbi::AvrNonBlockingInterrupt => Abi::AvrNonBlockingInterrupt, - ExternAbi::CCmseNonSecureCall => Abi::CCmseNonSecureCall, - ExternAbi::CCmseNonSecureEntry => Abi::CCmseNonSecureEntry, + ExternAbi::CmseNonSecureCall => Abi::CCmseNonSecureCall, + ExternAbi::CmseNonSecureEntry => Abi::CCmseNonSecureEntry, ExternAbi::System { unwind } => Abi::System { unwind }, ExternAbi::RustCall => Abi::RustCall, ExternAbi::Unadjusted => Abi::Unadjusted, ExternAbi::RustCold => Abi::RustCold, + ExternAbi::RustInvalid => Abi::RustInvalid, ExternAbi::RiscvInterruptM => Abi::RiscvInterruptM, ExternAbi::RiscvInterruptS => Abi::RiscvInterruptS, ExternAbi::Custom => Abi::Custom, diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 64fe181c26d..26de9b0a496 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -7,9 +7,9 @@ //! //! For now, we are developing everything inside `rustc`, thus, we keep this module private. +use std::marker::PointeeSized; use std::ops::RangeInclusive; -use rustc_data_structures::PointeeSized; use rustc_hir::def::DefKind; use rustc_middle::mir; use rustc_middle::mir::interpret::AllocId; diff --git a/compiler/rustc_smir/src/stable_mir/mir/body.rs b/compiler/rustc_smir/src/stable_mir/mir/body.rs index 660cd7db080..90d4a06b177 100644 --- a/compiler/rustc_smir/src/stable_mir/mir/body.rs +++ b/compiler/rustc_smir/src/stable_mir/mir/body.rs @@ -270,6 +270,7 @@ pub enum AssertMessage { ResumedAfterDrop(CoroutineKind), MisalignedPointerDereference { required: Operand, found: Operand }, NullPointerDereference, + InvalidEnumConstruction(Operand), } impl AssertMessage { @@ -342,6 +343,9 @@ impl AssertMessage { Ok("misaligned pointer dereference") } AssertMessage::NullPointerDereference => Ok("null pointer dereference occurred"), + AssertMessage::InvalidEnumConstruction(_) => { + Ok("trying to construct an enum from an invalid value") + } } } } @@ -1021,8 +1025,6 @@ pub enum CastKind { PointerExposeAddress, PointerWithExposedProvenance, PointerCoercion(PointerCoercion), - // FIXME(smir-rename): change this to PointerCoercion(DynStar) - DynStar, IntToInt, FloatToInt, FloatToFloat, diff --git a/compiler/rustc_smir/src/stable_mir/mir/pretty.rs b/compiler/rustc_smir/src/stable_mir/mir/pretty.rs index ba20651f993..b068a9a1081 100644 --- a/compiler/rustc_smir/src/stable_mir/mir/pretty.rs +++ b/compiler/rustc_smir/src/stable_mir/mir/pretty.rs @@ -313,6 +313,10 @@ fn pretty_assert_message<W: Write>(writer: &mut W, msg: &AssertMessage) -> io::R AssertMessage::NullPointerDereference => { write!(writer, "\"null pointer dereference occurred\"") } + AssertMessage::InvalidEnumConstruction(op) => { + let pretty_op = pretty_operand(op); + write!(writer, "\"trying to construct an enum from an invalid value {{}}\",{pretty_op}") + } AssertMessage::ResumedAfterReturn(_) | AssertMessage::ResumedAfterPanic(_) | AssertMessage::ResumedAfterDrop(_) => { diff --git a/compiler/rustc_smir/src/stable_mir/mir/visit.rs b/compiler/rustc_smir/src/stable_mir/mir/visit.rs index e21dc11eea9..b7dd433eb09 100644 --- a/compiler/rustc_smir/src/stable_mir/mir/visit.rs +++ b/compiler/rustc_smir/src/stable_mir/mir/visit.rs @@ -367,7 +367,8 @@ macro_rules! make_mir_visitor { } AssertMessage::OverflowNeg(op) | AssertMessage::DivisionByZero(op) - | AssertMessage::RemainderByZero(op) => { + | AssertMessage::RemainderByZero(op) + | AssertMessage::InvalidEnumConstruction(op) => { self.visit_operand(op, location); } AssertMessage::ResumedAfterReturn(_) diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs index 4415cd6e2e3..4ea2bb04c5d 100644 --- a/compiler/rustc_smir/src/stable_mir/ty.rs +++ b/compiler/rustc_smir/src/stable_mir/ty.rs @@ -757,6 +757,12 @@ crate_def! { } impl CoroutineDef { + /// Retrieves the body of the coroutine definition. Returns None if the body + /// isn't available. + pub fn body(&self) -> Option<Body> { + with(|cx| cx.has_body(self.0).then(|| cx.mir_body(self.0))) + } + pub fn discriminant_for_variant(&self, args: &GenericArgs, idx: VariantIdx) -> Discr { with(|cx| cx.coroutine_discr_for_variant(*self, args, idx)) } @@ -1126,6 +1132,7 @@ pub enum Abi { RustCold, RiscvInterruptM, RiscvInterruptS, + RustInvalid, Custom, } @@ -1198,7 +1205,6 @@ pub enum BoundRegionKind { #[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum DynKind { Dyn, - DynStar, } #[derive(Clone, Debug, Eq, PartialEq, Serialize)] diff --git a/compiler/rustc_span/src/analyze_source_file.rs b/compiler/rustc_span/src/analyze_source_file.rs index 55d899c9ada..c32593a6d95 100644 --- a/compiler/rustc_span/src/analyze_source_file.rs +++ b/compiler/rustc_span/src/analyze_source_file.rs @@ -29,18 +29,7 @@ pub(crate) fn analyze_source_file(src: &str) -> (Vec<RelativeBytePos>, Vec<Multi (lines, multi_byte_chars) } -// cfg(bootstrap) -macro_rules! cfg_select_dispatch { - ($($tokens:tt)*) => { - #[cfg(bootstrap)] - cfg_match! { $($tokens)* } - - #[cfg(not(bootstrap))] - cfg_select! { $($tokens)* } - }; -} - -cfg_select_dispatch! { +cfg_select! { any(target_arch = "x86", target_arch = "x86_64") => { fn analyze_source_file_dispatch( src: &str, diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index c8a29a2f68f..c18ff285c4e 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -17,11 +17,10 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(bootstrap, feature(cfg_match))] -#![cfg_attr(not(bootstrap), feature(cfg_select))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(array_windows)] +#![feature(cfg_select)] #![feature(core_io_borrowed_buf)] #![feature(if_let_guard)] #![feature(map_try_insert)] @@ -66,7 +65,9 @@ mod span_encoding; pub use span_encoding::{DUMMY_SP, Span}; pub mod symbol; -pub use symbol::{Ident, MacroRulesNormalizedIdent, STDLIB_STABLE_CRATES, Symbol, kw, sym}; +pub use symbol::{ + ByteSymbol, Ident, MacroRulesNormalizedIdent, STDLIB_STABLE_CRATES, Symbol, kw, sym, +}; mod analyze_source_file; pub mod fatal_error; @@ -1184,11 +1185,12 @@ rustc_index::newtype_index! { /// It is similar to rustc_type_ir's TyEncoder. pub trait SpanEncoder: Encoder { fn encode_span(&mut self, span: Span); - fn encode_symbol(&mut self, symbol: Symbol); + fn encode_symbol(&mut self, sym: Symbol); + fn encode_byte_symbol(&mut self, byte_sym: ByteSymbol); fn encode_expn_id(&mut self, expn_id: ExpnId); fn encode_syntax_context(&mut self, syntax_context: SyntaxContext); - /// As a local identifier, a `CrateNum` is only meaningful within its context, e.g. within a tcx. - /// Therefore, make sure to include the context when encode a `CrateNum`. + /// As a local identifier, a `CrateNum` is only meaningful within its context, e.g. within a + /// tcx. Therefore, make sure to include the context when encode a `CrateNum`. fn encode_crate_num(&mut self, crate_num: CrateNum); fn encode_def_index(&mut self, def_index: DefIndex); fn encode_def_id(&mut self, def_id: DefId); @@ -1201,8 +1203,12 @@ impl SpanEncoder for FileEncoder { span.hi.encode(self); } - fn encode_symbol(&mut self, symbol: Symbol) { - self.emit_str(symbol.as_str()); + fn encode_symbol(&mut self, sym: Symbol) { + self.emit_str(sym.as_str()); + } + + fn encode_byte_symbol(&mut self, byte_sym: ByteSymbol) { + self.emit_byte_str(byte_sym.as_byte_str()); } fn encode_expn_id(&mut self, _expn_id: ExpnId) { @@ -1239,6 +1245,12 @@ impl<E: SpanEncoder> Encodable<E> for Symbol { } } +impl<E: SpanEncoder> Encodable<E> for ByteSymbol { + fn encode(&self, s: &mut E) { + s.encode_byte_symbol(*self); + } +} + impl<E: SpanEncoder> Encodable<E> for ExpnId { fn encode(&self, s: &mut E) { s.encode_expn_id(*self) @@ -1280,6 +1292,7 @@ impl<E: SpanEncoder> Encodable<E> for AttrId { pub trait SpanDecoder: Decoder { fn decode_span(&mut self) -> Span; fn decode_symbol(&mut self) -> Symbol; + fn decode_byte_symbol(&mut self) -> ByteSymbol; fn decode_expn_id(&mut self) -> ExpnId; fn decode_syntax_context(&mut self) -> SyntaxContext; fn decode_crate_num(&mut self) -> CrateNum; @@ -1300,6 +1313,10 @@ impl SpanDecoder for MemDecoder<'_> { Symbol::intern(self.read_str()) } + fn decode_byte_symbol(&mut self) -> ByteSymbol { + ByteSymbol::intern(self.read_byte_str()) + } + fn decode_expn_id(&mut self) -> ExpnId { panic!("cannot decode `ExpnId` with `MemDecoder`"); } @@ -1337,6 +1354,12 @@ impl<D: SpanDecoder> Decodable<D> for Symbol { } } +impl<D: SpanDecoder> Decodable<D> for ByteSymbol { + fn decode(s: &mut D) -> ByteSymbol { + s.decode_byte_symbol() + } +} + impl<D: SpanDecoder> Decodable<D> for ExpnId { fn decode(s: &mut D) -> ExpnId { s.decode_expn_id() diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 684b1781b44..34869a38bb4 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -150,14 +150,10 @@ symbols! { // As well as the symbols listed, there are symbols for the strings // "0", "1", ..., "9", which are accessible via `sym::integer`. // - // The proc macro will abort if symbols are not in alphabetical order (as - // defined by `impl Ord for str`) or if any symbols are duplicated. Vim - // users can sort the list by selecting it and executing the command - // `:'<,'>!LC_ALL=C sort`. - // // There is currently no checking that all symbols are used; that would be // nice to have. Symbols { + // tidy-alphabetical-start Abi, AcqRel, Acquire, @@ -175,18 +171,18 @@ symbols! { AsyncGenPending, AsyncGenReady, AtomicBool, - AtomicI128, + AtomicI8, AtomicI16, AtomicI32, AtomicI64, - AtomicI8, + AtomicI128, AtomicIsize, AtomicPtr, - AtomicU128, + AtomicU8, AtomicU16, AtomicU32, AtomicU64, - AtomicU8, + AtomicU128, AtomicUsize, BTreeEntry, BTreeMap, @@ -406,6 +402,7 @@ symbols! { abi_amdgpu_kernel, abi_avr_interrupt, abi_c_cmse_nonsecure_call, + abi_cmse_nonsecure_call, abi_custom, abi_efiapi, abi_gpu_kernel, @@ -577,6 +574,7 @@ symbols! { box_new, box_patterns, box_syntax, + boxed_slice, bpf_target_feature, braced_empty_structs, branch, @@ -605,10 +603,10 @@ symbols! { catch_unwind, cause, cdylib, - ceilf128, ceilf16, ceilf32, ceilf64, + ceilf128, cfg, cfg_accessible, cfg_attr, @@ -692,6 +690,7 @@ symbols! { const_closures, const_compare_raw_pointers, const_constructor, + const_continue, const_deallocate, const_destruct, const_eval_limit, @@ -744,10 +743,10 @@ symbols! { copy, copy_closures, copy_nonoverlapping, - copysignf128, copysignf16, copysignf32, copysignf64, + copysignf128, core, core_panic, core_panic_2015_macro, @@ -760,10 +759,10 @@ symbols! { coroutine_state, coroutine_yield, coroutines, - cosf128, cosf16, cosf32, cosf64, + cosf128, count, coverage, coverage_attribute, @@ -871,8 +870,8 @@ symbols! { dotdot_in_tuple_patterns, dotdoteq_in_patterns, dreg, - dreg_low16, dreg_low8, + dreg_low16, drop, drop_in_place, drop_types_in_const, @@ -925,16 +924,16 @@ symbols! { exhaustive_integer_patterns, exhaustive_patterns, existential_type, - exp2f128, exp2f16, exp2f32, exp2f64, + exp2f128, expect, expected, - expf128, expf16, expf32, expf64, + expf128, explicit_extern_abis, explicit_generic_args_with_impl_trait, explicit_tail_calls, @@ -955,9 +954,6 @@ symbols! { external, external_doc, f, - f128, - f128_epsilon, - f128_nan, f16, f16_epsilon, f16_nan, @@ -996,10 +992,13 @@ symbols! { f64_legacy_const_neg_infinity, f64_legacy_const_radix, f64_nan, - fabsf128, + f128, + f128_epsilon, + f128_nan, fabsf16, fabsf32, fabsf64, + fabsf128, fadd_algebraic, fadd_fast, fake_variadic, @@ -1021,22 +1020,22 @@ symbols! { flags, float, float_to_int_unchecked, - floorf128, floorf16, floorf32, floorf64, - fmaf128, + floorf128, fmaf16, fmaf32, fmaf64, + fmaf128, fmt, fmt_debug, fmul_algebraic, fmul_fast, - fmuladdf128, fmuladdf16, fmuladdf32, fmuladdf64, + fmuladdf128, fn_align, fn_body, fn_delegation, @@ -1137,13 +1136,12 @@ symbols! { html_root_url, hwaddress, i, - i128, - i128_legacy_const_max, - i128_legacy_const_min, - i128_legacy_fn_max_value, - i128_legacy_fn_min_value, - i128_legacy_mod, - i128_type, + i8, + i8_legacy_const_max, + i8_legacy_const_min, + i8_legacy_fn_max_value, + i8_legacy_fn_min_value, + i8_legacy_mod, i16, i16_legacy_const_max, i16_legacy_const_min, @@ -1162,12 +1160,13 @@ symbols! { i64_legacy_fn_max_value, i64_legacy_fn_min_value, i64_legacy_mod, - i8, - i8_legacy_const_max, - i8_legacy_const_min, - i8_legacy_fn_max_value, - i8_legacy_fn_min_value, - i8_legacy_mod, + i128, + i128_legacy_const_max, + i128_legacy_const_min, + i128_legacy_fn_max_value, + i128_legacy_fn_min_value, + i128_legacy_mod, + i128_type, ident, if_let, if_let_guard, @@ -1289,21 +1288,22 @@ symbols! { loaded_from_disk, local, local_inner_macros, - log10f128, - log10f16, - log10f32, - log10f64, - log2f128, log2f16, log2f32, log2f64, + log2f128, + log10f16, + log10f32, + log10f64, + log10f128, log_syntax, - logf128, logf16, logf32, logf64, + logf128, loongarch_target_feature, loop_break_value, + loop_match, lt, m68k_target_feature, macro_at_most_once_rep, @@ -1330,14 +1330,14 @@ symbols! { match_beginning_vert, match_default_bindings, matches_macro, - maximumf128, maximumf16, maximumf32, maximumf64, - maxnumf128, + maximumf128, maxnumf16, maxnumf32, maxnumf64, + maxnumf128, may_dangle, may_unwind, maybe_uninit, @@ -1368,14 +1368,14 @@ symbols! { min_generic_const_args, min_specialization, min_type_alias_impl_trait, - minimumf128, minimumf16, minimumf32, minimumf64, - minnumf128, + minimumf128, minnumf16, minnumf32, minnumf64, + minnumf128, mips_target_feature, mir_assume, mir_basic_block, @@ -1582,6 +1582,7 @@ symbols! { panic_implementation, panic_in_cleanup, panic_info, + panic_invalid_enum_construction, panic_location, panic_misaligned_pointer_dereference, panic_nounwind, @@ -1613,6 +1614,7 @@ symbols! { pie, pin, pin_ergonomics, + pin_macro, platform_intrinsics, plugin, plugin_registrar, @@ -1628,14 +1630,14 @@ symbols! { post_dash_lto: "post-lto", postfix_match, powerpc_target_feature, - powf128, powf16, powf32, powf64, - powif128, + powf128, powif16, powif32, powif64, + powif128, pre_dash_lto: "pre-lto", precise_capturing, precise_capturing_in_traits, @@ -1780,14 +1782,14 @@ symbols! { ropi_rwpi: "ropi-rwpi", rotate_left, rotate_right, - round_ties_even_f128, round_ties_even_f16, round_ties_even_f32, round_ties_even_f64, - roundf128, + round_ties_even_f128, roundf16, roundf32, roundf64, + roundf128, rt, rtm_target_feature, rust, @@ -1871,6 +1873,7 @@ symbols! { rustc_never_returns_null_ptr, rustc_never_type_options, rustc_no_implicit_autorefs, + rustc_no_implicit_bounds, rustc_no_mir_inline, rustc_nonnull_optimization_guaranteed, rustc_nounwind, @@ -1966,14 +1969,16 @@ symbols! { simd_fexp2, simd_ffi, simd_flog, - simd_flog10, simd_flog2, + simd_flog10, simd_floor, simd_fma, simd_fmax, simd_fmin, simd_fsin, simd_fsqrt, + simd_funnel_shl, + simd_funnel_shr, simd_gather, simd_ge, simd_gt, @@ -2001,6 +2006,7 @@ symbols! { simd_relaxed_fma, simd_rem, simd_round, + simd_round_ties_even, simd_saturating_add, simd_saturating_sub, simd_scatter, @@ -2015,10 +2021,10 @@ symbols! { simd_with_exposed_provenance, simd_xor, since, - sinf128, sinf16, sinf32, sinf64, + sinf128, size, size_of, size_of_val, @@ -2040,10 +2046,10 @@ symbols! { specialization, speed, spotlight, - sqrtf128, sqrtf16, sqrtf32, sqrtf64, + sqrtf128, sreg, sreg_low16, sse, @@ -2121,10 +2127,10 @@ symbols! { target_has_atomic, target_has_atomic_equal_alignment, target_has_atomic_load_store, - target_has_reliable_f128, - target_has_reliable_f128_math, target_has_reliable_f16, target_has_reliable_f16_math, + target_has_reliable_f128, + target_has_reliable_f128_math, target_os, target_pointer_width, target_thread_local, @@ -2167,10 +2173,10 @@ symbols! { transparent_enums, transparent_unions, trivial_bounds, - truncf128, truncf16, truncf32, truncf64, + truncf128, try_blocks, try_capture, try_from, @@ -2199,12 +2205,12 @@ symbols! { type_name, type_privacy_lints, typed_swap_nonoverlapping, - u128, - u128_legacy_const_max, - u128_legacy_const_min, - u128_legacy_fn_max_value, - u128_legacy_fn_min_value, - u128_legacy_mod, + u8, + u8_legacy_const_max, + u8_legacy_const_min, + u8_legacy_fn_max_value, + u8_legacy_fn_min_value, + u8_legacy_mod, u16, u16_legacy_const_max, u16_legacy_const_min, @@ -2223,12 +2229,12 @@ symbols! { u64_legacy_fn_max_value, u64_legacy_fn_min_value, u64_legacy_mod, - u8, - u8_legacy_const_max, - u8_legacy_const_min, - u8_legacy_fn_max_value, - u8_legacy_fn_min_value, - u8_legacy_mod, + u128, + u128_legacy_const_max, + u128_legacy_const_min, + u128_legacy_fn_max_value, + u128_legacy_fn_min_value, + u128_legacy_mod, ub_checks, unaligned_volatile_load, unaligned_volatile_store, @@ -2381,6 +2387,7 @@ symbols! { zfh, zfhmin, zmm_reg, + // tidy-alphabetical-end } } @@ -2576,7 +2583,7 @@ impl fmt::Display for MacroRulesNormalizedIdent { } } -/// An interned string. +/// An interned UTF-8 string. /// /// Internally, a `Symbol` is implemented as an index, and all operations /// (including hashing, equality, and ordering) operate on that index. The use @@ -2588,20 +2595,23 @@ impl fmt::Display for MacroRulesNormalizedIdent { #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Symbol(SymbolIndex); +// Used within both `Symbol` and `ByteSymbol`. rustc_index::newtype_index! { #[orderable] struct SymbolIndex {} } impl Symbol { + /// Avoid this except for things like deserialization of previously + /// serialized symbols, and testing. Use `intern` instead. pub const fn new(n: u32) -> Self { Symbol(SymbolIndex::from_u32(n)) } /// Maps a string to its interned representation. #[rustc_diagnostic_item = "SymbolIntern"] - pub fn intern(string: &str) -> Self { - with_session_globals(|session_globals| session_globals.symbol_interner.intern(string)) + pub fn intern(str: &str) -> Self { + with_session_globals(|session_globals| session_globals.symbol_interner.intern_str(str)) } /// Access the underlying string. This is a slowish operation because it @@ -2614,7 +2624,7 @@ impl Symbol { /// it works out ok. pub fn as_str(&self) -> &str { with_session_globals(|session_globals| unsafe { - std::mem::transmute::<&str, &str>(session_globals.symbol_interner.get(*self)) + std::mem::transmute::<&str, &str>(session_globals.symbol_interner.get_str(*self)) }) } @@ -2671,56 +2681,130 @@ impl StableCompare for Symbol { } } +/// Like `Symbol`, but for byte strings. `ByteSymbol` is used less widely, so +/// it has fewer operations defined than `Symbol`. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct ByteSymbol(SymbolIndex); + +impl ByteSymbol { + /// Avoid this except for things like deserialization of previously + /// serialized symbols, and testing. Use `intern` instead. + pub const fn new(n: u32) -> Self { + ByteSymbol(SymbolIndex::from_u32(n)) + } + + /// Maps a string to its interned representation. + pub fn intern(byte_str: &[u8]) -> Self { + with_session_globals(|session_globals| { + session_globals.symbol_interner.intern_byte_str(byte_str) + }) + } + + /// Like `Symbol::as_str`. + pub fn as_byte_str(&self) -> &[u8] { + with_session_globals(|session_globals| unsafe { + std::mem::transmute::<&[u8], &[u8]>(session_globals.symbol_interner.get_byte_str(*self)) + }) + } + + pub fn as_u32(self) -> u32 { + self.0.as_u32() + } +} + +impl fmt::Debug for ByteSymbol { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self.as_byte_str(), f) + } +} + +impl<CTX> HashStable<CTX> for ByteSymbol { + #[inline] + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { + self.as_byte_str().hash_stable(hcx, hasher); + } +} + +// Interner used for both `Symbol`s and `ByteSymbol`s. If a string and a byte +// string with identical contents (e.g. "foo" and b"foo") are both interned, +// only one copy will be stored and the resulting `Symbol` and `ByteSymbol` +// will have the same index. pub(crate) struct Interner(Lock<InternerInner>); -// The `&'static str`s in this type actually point into the arena. +// The `&'static [u8]`s in this type actually point into the arena. // // This type is private to prevent accidentally constructing more than one // `Interner` on the same thread, which makes it easy to mix up `Symbol`s // between `Interner`s. struct InternerInner { arena: DroplessArena, - strings: FxIndexSet<&'static str>, + byte_strs: FxIndexSet<&'static [u8]>, } impl Interner { + // These arguments are `&str`, but because of the sharing, we are + // effectively pre-interning all these strings for both `Symbol` and + // `ByteSymbol`. fn prefill(init: &[&'static str], extra: &[&'static str]) -> Self { - let strings = FxIndexSet::from_iter(init.iter().copied().chain(extra.iter().copied())); + let byte_strs = FxIndexSet::from_iter( + init.iter().copied().chain(extra.iter().copied()).map(|str| str.as_bytes()), + ); assert_eq!( - strings.len(), + byte_strs.len(), init.len() + extra.len(), - "there are duplicate symbols in the rustc symbol list and the extra symbols added by the driver", + "duplicate symbols in the rustc symbol list and the extra symbols added by the driver", ); - Interner(Lock::new(InternerInner { arena: Default::default(), strings })) + Interner(Lock::new(InternerInner { arena: Default::default(), byte_strs })) + } + + fn intern_str(&self, str: &str) -> Symbol { + Symbol::new(self.intern_inner(str.as_bytes())) + } + + fn intern_byte_str(&self, byte_str: &[u8]) -> ByteSymbol { + ByteSymbol::new(self.intern_inner(byte_str)) } #[inline] - fn intern(&self, string: &str) -> Symbol { + fn intern_inner(&self, byte_str: &[u8]) -> u32 { let mut inner = self.0.lock(); - if let Some(idx) = inner.strings.get_index_of(string) { - return Symbol::new(idx as u32); + if let Some(idx) = inner.byte_strs.get_index_of(byte_str) { + return idx as u32; } - let string: &str = inner.arena.alloc_str(string); + let byte_str: &[u8] = inner.arena.alloc_slice(byte_str); // SAFETY: we can extend the arena allocation to `'static` because we // only access these while the arena is still alive. - let string: &'static str = unsafe { &*(string as *const str) }; + let byte_str: &'static [u8] = unsafe { &*(byte_str as *const [u8]) }; // This second hash table lookup can be avoided by using `RawEntryMut`, // but this code path isn't hot enough for it to be worth it. See // #91445 for details. - let (idx, is_new) = inner.strings.insert_full(string); + let (idx, is_new) = inner.byte_strs.insert_full(byte_str); debug_assert!(is_new); // due to the get_index_of check above - Symbol::new(idx as u32) + idx as u32 } /// Get the symbol as a string. /// /// [`Symbol::as_str()`] should be used in preference to this function. - fn get(&self, symbol: Symbol) -> &str { - self.0.lock().strings.get_index(symbol.0.as_usize()).unwrap() + fn get_str(&self, symbol: Symbol) -> &str { + let byte_str = self.get_inner(symbol.0.as_usize()); + // SAFETY: known to be a UTF8 string because it's a `Symbol`. + unsafe { str::from_utf8_unchecked(byte_str) } + } + + /// Get the symbol as a string. + /// + /// [`ByteSymbol::as_byte_str()`] should be used in preference to this function. + fn get_byte_str(&self, symbol: ByteSymbol) -> &[u8] { + self.get_inner(symbol.0.as_usize()) + } + + fn get_inner(&self, index: usize) -> &[u8] { + self.0.lock().byte_strs.get_index(index).unwrap() } } @@ -2815,9 +2899,11 @@ impl Symbol { self != sym::empty && self != kw::Underscore && !self.is_path_segment_keyword() } - /// Was this symbol predefined in the compiler's `symbols!` macro - pub fn is_predefined(self) -> bool { - self.as_u32() < PREDEFINED_SYMBOLS_COUNT + /// Was this symbol index predefined in the compiler's `symbols!` macro? + /// Note: this applies to both `Symbol`s and `ByteSymbol`s, which is why it + /// takes a `u32` argument instead of a `&self` argument. Use with care. + pub fn is_predefined(index: u32) -> bool { + index < PREDEFINED_SYMBOLS_COUNT } } diff --git a/compiler/rustc_span/src/symbol/tests.rs b/compiler/rustc_span/src/symbol/tests.rs index 660d0d7179a..bf0660aa510 100644 --- a/compiler/rustc_span/src/symbol/tests.rs +++ b/compiler/rustc_span/src/symbol/tests.rs @@ -5,14 +5,14 @@ use crate::create_default_session_globals_then; fn interner_tests() { let i = Interner::prefill(&[], &[]); // first one is zero: - assert_eq!(i.intern("dog"), Symbol::new(0)); - // re-use gets the same entry: - assert_eq!(i.intern("dog"), Symbol::new(0)); + assert_eq!(i.intern_str("dog"), Symbol::new(0)); + // re-use gets the same entry, even with a `ByteSymbol` + assert_eq!(i.intern_byte_str(b"dog"), ByteSymbol::new(0)); // different string gets a different #: - assert_eq!(i.intern("cat"), Symbol::new(1)); - assert_eq!(i.intern("cat"), Symbol::new(1)); + assert_eq!(i.intern_byte_str(b"cat"), ByteSymbol::new(1)); + assert_eq!(i.intern_str("cat"), Symbol::new(1)); // dog is still at zero - assert_eq!(i.intern("dog"), Symbol::new(0)); + assert_eq!(i.intern_str("dog"), Symbol::new(0)); } #[test] diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 1db8ad72b32..fe0f8e6113e 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -576,8 +576,6 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { ty::Dynamic(predicates, r, kind) => { self.push(match kind { ty::Dyn => "D", - // FIXME(dyn-star): need to update v0 mangling docs - ty::DynStar => "D*", }); self.print_dyn_existential(predicates)?; r.print(self)?; diff --git a/compiler/rustc_target/src/spec/abi_map.rs b/compiler/rustc_target/src/spec/abi_map.rs index 42ec10a8e15..b13e2112478 100644 --- a/compiler/rustc_target/src/spec/abi_map.rs +++ b/compiler/rustc_target/src/spec/abi_map.rs @@ -85,24 +85,35 @@ impl AbiMap { (ExternAbi::System { .. }, _) => CanonAbi::C, // fallible lowerings + /* multi-platform */ + // always and forever + (ExternAbi::RustInvalid, _) => return AbiMapping::Invalid, + (ExternAbi::EfiApi, Arch::Arm(..)) => CanonAbi::Arm(ArmCall::Aapcs), (ExternAbi::EfiApi, Arch::X86_64) => CanonAbi::X86(X86Call::Win64), (ExternAbi::EfiApi, Arch::Aarch64 | Arch::Riscv | Arch::X86) => CanonAbi::C, (ExternAbi::EfiApi, _) => return AbiMapping::Invalid, + /* arm */ (ExternAbi::Aapcs { .. }, Arch::Arm(..)) => CanonAbi::Arm(ArmCall::Aapcs), (ExternAbi::Aapcs { .. }, _) => return AbiMapping::Invalid, - (ExternAbi::CCmseNonSecureCall, Arch::Arm(ArmVer::ThumbV8M)) => { + (ExternAbi::CmseNonSecureCall, Arch::Arm(ArmVer::ThumbV8M)) => { CanonAbi::Arm(ArmCall::CCmseNonSecureCall) } - (ExternAbi::CCmseNonSecureEntry, Arch::Arm(ArmVer::ThumbV8M)) => { + (ExternAbi::CmseNonSecureEntry, Arch::Arm(ArmVer::ThumbV8M)) => { CanonAbi::Arm(ArmCall::CCmseNonSecureEntry) } - (ExternAbi::CCmseNonSecureCall | ExternAbi::CCmseNonSecureEntry, ..) => { + (ExternAbi::CmseNonSecureCall | ExternAbi::CmseNonSecureEntry, ..) => { return AbiMapping::Invalid; } + /* gpu */ + (ExternAbi::PtxKernel, Arch::Nvptx) => CanonAbi::GpuKernel, + (ExternAbi::GpuKernel, Arch::Amdgpu | Arch::Nvptx) => CanonAbi::GpuKernel, + (ExternAbi::PtxKernel | ExternAbi::GpuKernel, _) => return AbiMapping::Invalid, + + /* x86 */ (ExternAbi::Cdecl { .. }, Arch::X86) => CanonAbi::C, (ExternAbi::Cdecl { .. }, _) => return AbiMapping::Deprecated(CanonAbi::C), @@ -130,10 +141,7 @@ impl AbiMap { (ExternAbi::Win64 { .. }, Arch::X86_64) => CanonAbi::X86(X86Call::Win64), (ExternAbi::SysV64 { .. } | ExternAbi::Win64 { .. }, _) => return AbiMapping::Invalid, - (ExternAbi::PtxKernel, Arch::Nvptx) => CanonAbi::GpuKernel, - (ExternAbi::GpuKernel, Arch::Amdgpu | Arch::Nvptx) => CanonAbi::GpuKernel, - (ExternAbi::PtxKernel | ExternAbi::GpuKernel, _) => return AbiMapping::Invalid, - + /* interrupts */ (ExternAbi::AvrInterrupt, Arch::Avr) => CanonAbi::Interrupt(InterruptKind::Avr), (ExternAbi::AvrNonBlockingInterrupt, Arch::Avr) => { CanonAbi::Interrupt(InterruptKind::AvrNonBlocking) diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 3eea1e070a6..b2af99228fe 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -212,9 +212,6 @@ static AARCH64_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("flagm2", Unstable(sym::aarch64_unstable_target_feature), &[]), // We forbid directly toggling just `fp-armv8`; it must be toggled with `neon`. ("fp-armv8", Stability::Forbidden { reason: "Rust ties `fp-armv8` to `neon`" }, &[]), - // FEAT_FP16 - // Rust ties FP and Neon: https://github.com/rust-lang/rust/pull/91608 - ("fp16", Stable, &["neon"]), // FEAT_FP8 ("fp8", Unstable(sym::aarch64_unstable_target_feature), &["faminmax", "lut", "bf16"]), // FEAT_FP8DOT2 @@ -223,6 +220,9 @@ static AARCH64_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("fp8dot4", Unstable(sym::aarch64_unstable_target_feature), &["fp8fma"]), // FEAT_FP8FMA ("fp8fma", Unstable(sym::aarch64_unstable_target_feature), &["fp8"]), + // FEAT_FP16 + // Rust ties FP and Neon: https://github.com/rust-lang/rust/pull/91608 + ("fp16", Stable, &["neon"]), // FEAT_FRINTTS ("frintts", Stable, &[]), // FEAT_HBC @@ -236,10 +236,10 @@ static AARCH64_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("lor", Stable, &[]), // FEAT_LSE ("lse", Stable, &[]), - // FEAT_LSE128 - ("lse128", Unstable(sym::aarch64_unstable_target_feature), &["lse"]), // FEAT_LSE2 ("lse2", Unstable(sym::aarch64_unstable_target_feature), &[]), + // FEAT_LSE128 + ("lse128", Unstable(sym::aarch64_unstable_target_feature), &["lse"]), // FEAT_LUT ("lut", Unstable(sym::aarch64_unstable_target_feature), &[]), // FEAT_MOPS @@ -283,14 +283,14 @@ static AARCH64_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("sme", Unstable(sym::aarch64_unstable_target_feature), &["bf16"]), // FEAT_SME_B16B16 ("sme-b16b16", Unstable(sym::aarch64_unstable_target_feature), &["bf16", "sme2", "sve-b16b16"]), - // FEAT_SME_F16F16 - ("sme-f16f16", Unstable(sym::aarch64_unstable_target_feature), &["sme2"]), - // FEAT_SME_F64F64 - ("sme-f64f64", Unstable(sym::aarch64_unstable_target_feature), &["sme"]), // FEAT_SME_F8F16 ("sme-f8f16", Unstable(sym::aarch64_unstable_target_feature), &["sme-f8f32"]), // FEAT_SME_F8F32 ("sme-f8f32", Unstable(sym::aarch64_unstable_target_feature), &["sme2", "fp8"]), + // FEAT_SME_F16F16 + ("sme-f16f16", Unstable(sym::aarch64_unstable_target_feature), &["sme2"]), + // FEAT_SME_F64F64 + ("sme-f64f64", Unstable(sym::aarch64_unstable_target_feature), &["sme"]), // FEAT_SME_FA64 ("sme-fa64", Unstable(sym::aarch64_unstable_target_feature), &["sme", "sve2"]), // FEAT_SME_I16I64 @@ -376,8 +376,8 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("amx-avx512", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), ("amx-bf16", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), ("amx-complex", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), - ("amx-fp16", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), ("amx-fp8", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), + ("amx-fp16", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), ("amx-int8", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), ("amx-movrs", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), ("amx-tf32", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), @@ -385,6 +385,7 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("amx-transpose", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), ("apxf", Unstable(sym::apx_target_feature), &[]), ("avx", Stable, &["sse4.2"]), + ("avx2", Stable, &["avx"]), ( "avx10.1", Unstable(sym::avx10_target_feature), @@ -405,7 +406,6 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ], ), ("avx10.2", Unstable(sym::avx10_target_feature), &["avx10.1"]), - ("avx2", Stable, &["avx"]), ("avx512bf16", Stable, &["avx512bw"]), ("avx512bitalg", Stable, &["avx512bw"]), ("avx512bw", Stable, &["avx512f"]), @@ -423,8 +423,8 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("avxifma", Stable, &["avx2"]), ("avxneconvert", Stable, &["avx2"]), ("avxvnni", Stable, &["avx2"]), - ("avxvnniint16", Stable, &["avx2"]), ("avxvnniint8", Stable, &["avx2"]), + ("avxvnniint16", Stable, &["avx2"]), ("bmi1", Stable, &[]), ("bmi2", Stable, &[]), ("cmpxchg16b", Stable, &[]), @@ -498,12 +498,12 @@ static POWERPC_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("altivec", Unstable(sym::powerpc_target_feature), &[]), ("msync", Unstable(sym::powerpc_target_feature), &[]), ("partword-atomics", Unstable(sym::powerpc_target_feature), &[]), - ("power10-vector", Unstable(sym::powerpc_target_feature), &["power9-vector"]), ("power8-altivec", Unstable(sym::powerpc_target_feature), &["altivec"]), ("power8-crypto", Unstable(sym::powerpc_target_feature), &["power8-altivec"]), ("power8-vector", Unstable(sym::powerpc_target_feature), &["vsx", "power8-altivec"]), ("power9-altivec", Unstable(sym::powerpc_target_feature), &["power8-altivec"]), ("power9-vector", Unstable(sym::powerpc_target_feature), &["power8-vector", "power9-altivec"]), + ("power10-vector", Unstable(sym::powerpc_target_feature), &["power9-vector"]), ("quadword-atomics", Unstable(sym::powerpc_target_feature), &[]), ("vsx", Unstable(sym::powerpc_target_feature), &["altivec"]), // tidy-alphabetical-end @@ -535,8 +535,8 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("unaligned-scalar-mem", Unstable(sym::riscv_target_feature), &[]), ("unaligned-vector-mem", Unstable(sym::riscv_target_feature), &[]), ("v", Unstable(sym::riscv_target_feature), &["zvl128b", "zve64d"]), - ("za128rs", Unstable(sym::riscv_target_feature), &[]), ("za64rs", Unstable(sym::riscv_target_feature), &["za128rs"]), // Za64rs ⊃ Za128rs + ("za128rs", Unstable(sym::riscv_target_feature), &[]), ("zaamo", Unstable(sym::riscv_target_feature), &[]), ("zabha", Unstable(sym::riscv_target_feature), &["zaamo"]), ("zacas", Unstable(sym::riscv_target_feature), &["zaamo"]), @@ -613,18 +613,18 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("zvksg", Unstable(sym::riscv_target_feature), &["zvks", "zvkg"]), ("zvksh", Unstable(sym::riscv_target_feature), &["zve32x"]), ("zvkt", Unstable(sym::riscv_target_feature), &[]), - ("zvl1024b", Unstable(sym::riscv_target_feature), &["zvl512b"]), + ("zvl32b", Unstable(sym::riscv_target_feature), &[]), + ("zvl64b", Unstable(sym::riscv_target_feature), &["zvl32b"]), ("zvl128b", Unstable(sym::riscv_target_feature), &["zvl64b"]), - ("zvl16384b", Unstable(sym::riscv_target_feature), &["zvl8192b"]), - ("zvl2048b", Unstable(sym::riscv_target_feature), &["zvl1024b"]), ("zvl256b", Unstable(sym::riscv_target_feature), &["zvl128b"]), - ("zvl32768b", Unstable(sym::riscv_target_feature), &["zvl16384b"]), - ("zvl32b", Unstable(sym::riscv_target_feature), &[]), - ("zvl4096b", Unstable(sym::riscv_target_feature), &["zvl2048b"]), ("zvl512b", Unstable(sym::riscv_target_feature), &["zvl256b"]), - ("zvl64b", Unstable(sym::riscv_target_feature), &["zvl32b"]), - ("zvl65536b", Unstable(sym::riscv_target_feature), &["zvl32768b"]), + ("zvl1024b", Unstable(sym::riscv_target_feature), &["zvl512b"]), + ("zvl2048b", Unstable(sym::riscv_target_feature), &["zvl1024b"]), + ("zvl4096b", Unstable(sym::riscv_target_feature), &["zvl2048b"]), ("zvl8192b", Unstable(sym::riscv_target_feature), &["zvl4096b"]), + ("zvl16384b", Unstable(sym::riscv_target_feature), &["zvl8192b"]), + ("zvl32768b", Unstable(sym::riscv_target_feature), &["zvl16384b"]), + ("zvl65536b", Unstable(sym::riscv_target_feature), &["zvl32768b"]), // tidy-alphabetical-end ]; @@ -651,13 +651,13 @@ const BPF_FEATURES: &[(&str, Stability, ImpliedFeatures)] = static CSKY_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-start - ("10e60", Unstable(sym::csky_target_feature), &["7e10"]), ("2e3", Unstable(sym::csky_target_feature), &["e2"]), ("3e3r1", Unstable(sym::csky_target_feature), &[]), ("3e3r2", Unstable(sym::csky_target_feature), &["3e3r1", "doloop"]), ("3e3r3", Unstable(sym::csky_target_feature), &["doloop"]), ("3e7", Unstable(sym::csky_target_feature), &["2e3"]), ("7e10", Unstable(sym::csky_target_feature), &["3e7"]), + ("10e60", Unstable(sym::csky_target_feature), &["7e10"]), ("cache", Unstable(sym::csky_target_feature), &[]), ("doloop", Unstable(sym::csky_target_feature), &[]), ("dsp1e2", Unstable(sym::csky_target_feature), &[]), @@ -726,12 +726,12 @@ const IBMZ_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("guarded-storage", Unstable(sym::s390x_target_feature), &[]), ("high-word", Unstable(sym::s390x_target_feature), &[]), // LLVM does not define message-security-assist-extension versions 1, 2, 6, 10 and 11. - ("message-security-assist-extension12", Unstable(sym::s390x_target_feature), &[]), ("message-security-assist-extension3", Unstable(sym::s390x_target_feature), &[]), ("message-security-assist-extension4", Unstable(sym::s390x_target_feature), &[]), ("message-security-assist-extension5", Unstable(sym::s390x_target_feature), &[]), ("message-security-assist-extension8", Unstable(sym::s390x_target_feature), &["message-security-assist-extension3"]), ("message-security-assist-extension9", Unstable(sym::s390x_target_feature), &["message-security-assist-extension3", "message-security-assist-extension4"]), + ("message-security-assist-extension12", Unstable(sym::s390x_target_feature), &[]), ("miscellaneous-extensions-2", Unstable(sym::s390x_target_feature), &[]), ("miscellaneous-extensions-3", Unstable(sym::s390x_target_feature), &[]), ("miscellaneous-extensions-4", Unstable(sym::s390x_target_feature), &[]), diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index 2c16672d786..bc464b099e2 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -82,9 +82,7 @@ use crate::infer; use crate::infer::relate::{self, RelateResult, TypeRelation}; use crate::infer::{InferCtxt, InferCtxtExt as _, TypeTrace, ValuePairs}; use crate::solve::deeply_normalize_for_diagnostics; -use crate::traits::{ - IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, -}; +use crate::traits::{MatchExpressionArmCause, ObligationCause, ObligationCauseCode}; mod note_and_explain; mod suggest; @@ -613,18 +611,28 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } }, - ObligationCauseCode::IfExpression(box IfExpressionCause { - then_id, - else_id, - then_ty, - else_ty, - outer_span, - .. - }) => { - let then_span = self.find_block_span_from_hir_id(then_id); - let else_span = self.find_block_span_from_hir_id(else_id); - if let hir::Node::Expr(e) = self.tcx.hir_node(else_id) - && let hir::ExprKind::If(_cond, _then, None) = e.kind + ObligationCauseCode::IfExpression { expr_id, .. } => { + let hir::Node::Expr(&hir::Expr { + kind: hir::ExprKind::If(cond_expr, then_expr, Some(else_expr)), + span: expr_span, + .. + }) = self.tcx.hir_node(expr_id) + else { + return; + }; + let then_span = self.find_block_span_from_hir_id(then_expr.hir_id); + let then_ty = self + .typeck_results + .as_ref() + .expect("if expression only expected inside FnCtxt") + .expr_ty(then_expr); + let else_span = self.find_block_span_from_hir_id(else_expr.hir_id); + let else_ty = self + .typeck_results + .as_ref() + .expect("if expression only expected inside FnCtxt") + .expr_ty(else_expr); + if let hir::ExprKind::If(_cond, _then, None) = else_expr.kind && else_ty.is_unit() { // Account for `let x = if a { 1 } else if b { 2 };` @@ -632,9 +640,32 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { err.note("consider adding an `else` block that evaluates to the expected type"); } err.span_label(then_span, "expected because of this"); + + let outer_span = if self.tcx.sess.source_map().is_multiline(expr_span) { + if then_span.hi() == expr_span.hi() || else_span.hi() == expr_span.hi() { + // Point at condition only if either block has the same end point as + // the whole expression, since that'll cause awkward overlapping spans. + Some(expr_span.shrink_to_lo().to(cond_expr.peel_drop_temps().span)) + } else { + Some(expr_span) + } + } else { + None + }; if let Some(sp) = outer_span { err.span_label(sp, "`if` and `else` have incompatible types"); } + + let then_id = if let hir::ExprKind::Block(then_blk, _) = then_expr.kind { + then_blk.hir_id + } else { + then_expr.hir_id + }; + let else_id = if let hir::ExprKind::Block(else_blk, _) = else_expr.kind { + else_blk.hir_id + } else { + else_expr.hir_id + }; if let Some(subdiag) = self.suggest_remove_semi_or_return_binding( Some(then_id), then_ty, diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs index bfef3340b32..1db05ced8d2 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs @@ -909,11 +909,11 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { } } (GenericArgKind::Const(inner_ct), TermKind::Const(target_ct)) => { - use ty::InferConst::*; match (inner_ct.kind(), target_ct.kind()) { - (ty::ConstKind::Infer(Var(a_vid)), ty::ConstKind::Infer(Var(b_vid))) => { - self.tecx.root_const_var(a_vid) == self.tecx.root_const_var(b_vid) - } + ( + ty::ConstKind::Infer(ty::InferConst::Var(a_vid)), + ty::ConstKind::Infer(ty::InferConst::Var(b_vid)), + ) => self.tecx.root_const_var(a_vid) == self.tecx.root_const_var(b_vid), _ => false, } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mod.rs index e456ba0eda5..c0b4bdab849 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mod.rs @@ -5,7 +5,6 @@ use rustc_span::Span; use crate::error_reporting::TypeErrCtxt; use crate::infer::RegionResolutionError; -use crate::infer::RegionResolutionError::*; mod different_lifetimes; pub mod find_anon_type; @@ -83,8 +82,10 @@ impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> { pub(super) fn regions(&self) -> Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)> { match (&self.error, self.regions) { - (Some(ConcreteFailure(origin, sub, sup)), None) => Some((origin.span(), *sub, *sup)), - (Some(SubSupConflict(_, _, origin, sub, _, sup, _)), None) => { + (Some(RegionResolutionError::ConcreteFailure(origin, sub, sup)), None) => { + Some((origin.span(), *sub, *sup)) + } + (Some(RegionResolutionError::SubSupConflict(_, _, origin, sub, _, sup, _)), None) => { Some((origin.span(), *sub, *sup)) } (None, Some((span, sub, sup))) => Some((span, sub, sup)), diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs index b66bd2c6ab7..f1237130c15 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs @@ -5,6 +5,7 @@ use rustc_hir::def::{Namespace, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{Visitor, walk_ty}; use rustc_hir::{self as hir, AmbigArg}; +use rustc_infer::infer::SubregionOrigin; use rustc_middle::hir::nested_filter; use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::error::ExpectedFound; @@ -16,7 +17,7 @@ use tracing::debug; use crate::error_reporting::infer::nice_region_error::NiceRegionError; use crate::error_reporting::infer::nice_region_error::placeholder_error::Highlighted; use crate::errors::{ConsiderBorrowingParamHelp, RelationshipHelp, TraitImplDiff}; -use crate::infer::{RegionResolutionError, Subtype, ValuePairs}; +use crate::infer::{RegionResolutionError, ValuePairs}; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// Print the error message for lifetime errors when the `impl` doesn't conform to the `trait`. @@ -32,7 +33,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { _sup, _, ) = error.clone() - && let (Subtype(sup_trace), Subtype(sub_trace)) = (&sup_origin, &sub_origin) + && let (SubregionOrigin::Subtype(sup_trace), SubregionOrigin::Subtype(sub_trace)) = + (&sup_origin, &sub_origin) && let &ObligationCauseCode::CompareImplItem { trait_item_def_id, .. } = sub_trace.cause.code() && sub_trace.values == sup_trace.values diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs index be508c8cee1..aea42df4dfd 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs @@ -353,26 +353,6 @@ impl<T> Trait<T> for X { )); } } - (ty::Dynamic(t, _, ty::DynKind::DynStar), _) - if let Some(def_id) = t.principal_def_id() => - { - let mut has_matching_impl = false; - tcx.for_each_relevant_impl(def_id, values.found, |did| { - if DeepRejectCtxt::relate_rigid_infer(tcx) - .types_may_unify(values.found, tcx.type_of(did).skip_binder()) - { - has_matching_impl = true; - } - }); - if has_matching_impl { - let trait_name = tcx.item_name(def_id); - diag.help(format!( - "`{}` implements `{trait_name}`, `#[feature(dyn_star)]` is likely \ - not enabled; that feature it is currently incomplete", - values.found, - )); - } - } (_, ty::Alias(ty::Opaque, opaque_ty)) | (ty::Alias(ty::Opaque, opaque_ty), _) => { if opaque_ty.def_id.is_local() @@ -420,19 +400,33 @@ impl<T> Trait<T> for X { } // If two if arms can be coerced to a trait object, provide a structured // suggestion. - let ObligationCauseCode::IfExpression(cause) = cause.code() else { - return; - }; - let hir::Node::Block(blk) = self.tcx.hir_node(cause.then_id) else { - return; - }; - let Some(then) = blk.expr else { - return; - }; - let hir::Node::Block(blk) = self.tcx.hir_node(cause.else_id) else { + let ObligationCauseCode::IfExpression { expr_id, .. } = cause.code() else { return; }; - let Some(else_) = blk.expr else { + let hir::Node::Expr(&hir::Expr { + kind: + hir::ExprKind::If( + _, + &hir::Expr { + kind: + hir::ExprKind::Block( + &hir::Block { expr: Some(then), .. }, + _, + ), + .. + }, + Some(&hir::Expr { + kind: + hir::ExprKind::Block( + &hir::Block { expr: Some(else_), .. }, + _, + ), + .. + }), + ), + .. + }) = self.tcx.hir_node(*expr_id) + else { return; }; let expected = match values.found.kind() { @@ -486,8 +480,10 @@ impl<T> Trait<T> for X { } } (ty::Adt(_, _), ty::Adt(def, args)) - if let ObligationCauseCode::IfExpression(cause) = cause.code() - && let hir::Node::Block(blk) = self.tcx.hir_node(cause.then_id) + if let ObligationCauseCode::IfExpression { expr_id, .. } = cause.code() + && let hir::Node::Expr(if_expr) = self.tcx.hir_node(*expr_id) + && let hir::ExprKind::If(_, then_expr, _) = if_expr.kind + && let hir::ExprKind::Block(blk, _) = then_expr.kind && let Some(then) = blk.expr && def.is_box() && let boxed_ty = args.type_at(0) diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index 5c669678ccc..4fab67b01cb 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -27,7 +27,10 @@ use crate::errors::{ }; use crate::fluent_generated as fluent; use crate::infer::region_constraints::GenericKind; -use crate::infer::{self, InferCtxt, RegionResolutionError, RegionVariableOrigin, SubregionOrigin}; +use crate::infer::{ + BoundRegionConversionTime, InferCtxt, RegionResolutionError, RegionVariableOrigin, + SubregionOrigin, +}; impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { pub fn report_region_errors( @@ -219,21 +222,21 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { pub(super) fn note_region_origin(&self, err: &mut Diag<'_>, origin: &SubregionOrigin<'tcx>) { match *origin { - infer::Subtype(ref trace) => RegionOriginNote::WithRequirement { + SubregionOrigin::Subtype(ref trace) => RegionOriginNote::WithRequirement { span: trace.cause.span, requirement: ObligationCauseAsDiagArg(trace.cause.clone()), expected_found: self.values_str(trace.values, &trace.cause, err.long_ty_path()), } .add_to_diag(err), - infer::Reborrow(span) => { + SubregionOrigin::Reborrow(span) => { RegionOriginNote::Plain { span, msg: fluent::trait_selection_reborrow } .add_to_diag(err) } - infer::RelateObjectBound(span) => { + SubregionOrigin::RelateObjectBound(span) => { RegionOriginNote::Plain { span, msg: fluent::trait_selection_relate_object_bound } .add_to_diag(err); } - infer::ReferenceOutlivesReferent(ty, span) => { + SubregionOrigin::ReferenceOutlivesReferent(ty, span) => { RegionOriginNote::WithName { span, msg: fluent::trait_selection_reference_outlives_referent, @@ -242,7 +245,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } .add_to_diag(err); } - infer::RelateParamBound(span, ty, opt_span) => { + SubregionOrigin::RelateParamBound(span, ty, opt_span) => { RegionOriginNote::WithName { span, msg: fluent::trait_selection_relate_param_bound, @@ -258,24 +261,24 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .add_to_diag(err); } } - infer::RelateRegionParamBound(span, _) => { + SubregionOrigin::RelateRegionParamBound(span, _) => { RegionOriginNote::Plain { span, msg: fluent::trait_selection_relate_region_param_bound, } .add_to_diag(err); } - infer::CompareImplItemObligation { span, .. } => { + SubregionOrigin::CompareImplItemObligation { span, .. } => { RegionOriginNote::Plain { span, msg: fluent::trait_selection_compare_impl_item_obligation, } .add_to_diag(err); } - infer::CheckAssociatedTypeBounds { ref parent, .. } => { + SubregionOrigin::CheckAssociatedTypeBounds { ref parent, .. } => { self.note_region_origin(err, parent); } - infer::AscribeUserTypeProvePredicate(span) => { + SubregionOrigin::AscribeUserTypeProvePredicate(span) => { RegionOriginNote::Plain { span, msg: fluent::trait_selection_ascribe_user_type_prove_predicate, @@ -293,7 +296,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { sup: Region<'tcx>, ) -> Diag<'a> { let mut err = match origin { - infer::Subtype(box trace) => { + SubregionOrigin::Subtype(box trace) => { let terr = TypeError::RegionsDoesNotOutlive(sup, sub); let mut err = self.report_and_explain_type_error( trace, @@ -347,7 +350,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } err } - infer::Reborrow(span) => { + SubregionOrigin::Reborrow(span) => { let reference_valid = note_and_explain::RegionExplanation::new( self.tcx, generic_param_scope, @@ -369,7 +372,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { notes: reference_valid.into_iter().chain(content_valid).collect(), }) } - infer::RelateObjectBound(span) => { + SubregionOrigin::RelateObjectBound(span) => { let object_valid = note_and_explain::RegionExplanation::new( self.tcx, generic_param_scope, @@ -391,7 +394,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { notes: object_valid.into_iter().chain(pointer_valid).collect(), }) } - infer::RelateParamBound(span, ty, opt_span) => { + SubregionOrigin::RelateParamBound(span, ty, opt_span) => { let prefix = match sub.kind() { ty::ReStatic => note_and_explain::PrefixKind::TypeSatisfy, _ => note_and_explain::PrefixKind::TypeOutlive, @@ -415,7 +418,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { note, }) } - infer::RelateRegionParamBound(span, ty) => { + SubregionOrigin::RelateRegionParamBound(span, ty) => { let param_instantiated = note_and_explain::RegionExplanation::new( self.tcx, generic_param_scope, @@ -457,7 +460,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { notes: param_instantiated.into_iter().chain(param_must_outlive).collect(), }) } - infer::ReferenceOutlivesReferent(ty, span) => { + SubregionOrigin::ReferenceOutlivesReferent(ty, span) => { let pointer_valid = note_and_explain::RegionExplanation::new( self.tcx, generic_param_scope, @@ -480,7 +483,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { notes: pointer_valid.into_iter().chain(data_valid).collect(), }) } - infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => { + SubregionOrigin::CompareImplItemObligation { + span, + impl_item_def_id, + trait_item_def_id, + } => { let mut err = self.report_extra_impl_obligation( span, impl_item_def_id, @@ -499,7 +506,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } err } - infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => { + SubregionOrigin::CheckAssociatedTypeBounds { + impl_item_def_id, + trait_item_def_id, + parent, + } => { let mut err = self.report_concrete_failure(generic_param_scope, *parent, sub, sup); // Don't mention the item name if it's an RPITIT, since that'll just confuse @@ -520,7 +531,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); err } - infer::AscribeUserTypeProvePredicate(span) => { + SubregionOrigin::AscribeUserTypeProvePredicate(span) => { let instantiated = note_and_explain::RegionExplanation::new( self.tcx, generic_param_scope, @@ -618,7 +629,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // I can't think how to do better than this right now. -nikomatsakis debug!(?placeholder_origin, ?sub, ?sup, "report_placeholder_failure"); match placeholder_origin { - infer::Subtype(box ref trace) + SubregionOrigin::Subtype(box ref trace) if matches!( &trace.cause.code().peel_derives(), ObligationCauseCode::WhereClause(..) @@ -648,7 +659,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) } } - infer::Subtype(box trace) => { + SubregionOrigin::Subtype(box trace) => { let terr = TypeError::RegionsPlaceholderMismatch; return self.report_and_explain_type_error( trace, @@ -945,8 +956,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { debug!("report_sub_sup_conflict: sup_region={:?}", sup_region); debug!("report_sub_sup_conflict: sup_origin={:?}", sup_origin); - if let infer::Subtype(ref sup_trace) = sup_origin - && let infer::Subtype(ref sub_trace) = sub_origin + if let SubregionOrigin::Subtype(ref sup_trace) = sup_origin + && let SubregionOrigin::Subtype(ref sub_trace) = sub_origin && let Some((sup_expected, sup_found)) = self.values_str(sup_trace.values, &sup_trace.cause, err.long_ty_path()) && let Some((sub_expected, sub_found)) = @@ -1004,30 +1015,38 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { s }; let var_description = match var_origin { - infer::MiscVariable(_) => String::new(), - infer::PatternRegion(_) => " for pattern".to_string(), - infer::BorrowRegion(_) => " for borrow expression".to_string(), - infer::Autoref(_) => " for autoref".to_string(), - infer::Coercion(_) => " for automatic coercion".to_string(), - infer::BoundRegion(_, br, infer::FnCall) => { + RegionVariableOrigin::Misc(_) => String::new(), + RegionVariableOrigin::PatternRegion(_) => " for pattern".to_string(), + RegionVariableOrigin::BorrowRegion(_) => " for borrow expression".to_string(), + RegionVariableOrigin::Autoref(_) => " for autoref".to_string(), + RegionVariableOrigin::Coercion(_) => " for automatic coercion".to_string(), + RegionVariableOrigin::BoundRegion(_, br, BoundRegionConversionTime::FnCall) => { format!(" for lifetime parameter {}in function call", br_string(br)) } - infer::BoundRegion(_, br, infer::HigherRankedType) => { + RegionVariableOrigin::BoundRegion( + _, + br, + BoundRegionConversionTime::HigherRankedType, + ) => { format!(" for lifetime parameter {}in generic type", br_string(br)) } - infer::BoundRegion(_, br, infer::AssocTypeProjection(def_id)) => format!( + RegionVariableOrigin::BoundRegion( + _, + br, + BoundRegionConversionTime::AssocTypeProjection(def_id), + ) => format!( " for lifetime parameter {}in trait containing associated type `{}`", br_string(br), self.tcx.associated_item(def_id).name() ), - infer::RegionParameterDefinition(_, name) => { + RegionVariableOrigin::RegionParameterDefinition(_, name) => { format!(" for lifetime parameter `{name}`") } - infer::UpvarRegion(ref upvar_id, _) => { + RegionVariableOrigin::UpvarRegion(ref upvar_id, _) => { let var_name = self.tcx.hir_name(upvar_id.var_path.hir_id); format!(" for capture of `{var_name}` by closure") } - infer::Nll(..) => bug!("NLL variable found in lexical phase"), + RegionVariableOrigin::Nll(..) => bug!("NLL variable found in lexical phase"), }; struct_span_code_err!( diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs index 3804c13acce..c0daf08ce07 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs @@ -8,9 +8,7 @@ use rustc_errors::{Applicability, Diag}; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::{MatchSource, Node}; -use rustc_middle::traits::{ - IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, -}; +use rustc_middle::traits::{MatchExpressionArmCause, ObligationCause, ObligationCauseCode}; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self as ty, GenericArgKind, IsSuggestable, Ty, TypeVisitableExt}; @@ -196,8 +194,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { (Some(exp), Some(found)) if self.same_type_modulo_infer(exp, found) => match cause .code() { - ObligationCauseCode::IfExpression(box IfExpressionCause { then_id, .. }) => { - let then_span = self.find_block_span_from_hir_id(*then_id); + ObligationCauseCode::IfExpression { expr_id, .. } => { + let hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::If(_, then_expr, _), .. + }) = self.tcx.hir_node(*expr_id) + else { + return; + }; + let then_span = self.find_block_span_from_hir_id(then_expr.hir_id); Some(ConsiderAddingAwait::BothFuturesSugg { first: then_span.shrink_to_hi(), second: exp_span.shrink_to_hi(), @@ -232,8 +236,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { span: then_span.shrink_to_hi(), }) } - ObligationCauseCode::IfExpression(box IfExpressionCause { then_id, .. }) => { - let then_span = self.find_block_span_from_hir_id(*then_id); + ObligationCauseCode::IfExpression { expr_id, .. } => { + let hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::If(_, then_expr, _), .. + }) = self.tcx.hir_node(*expr_id) + else { + return; + }; + let then_span = self.find_block_span_from_hir_id(then_expr.hir_id); Some(ConsiderAddingAwait::FutureSugg { span: then_span.shrink_to_hi() }) } ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 0c88bd3dcbc..c72eff1d231 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -47,8 +47,8 @@ use crate::infer::{self, InferCtxt, InferCtxtExt as _}; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use crate::traits::{ MismatchedProjectionTypes, NormalizeExt, Obligation, ObligationCause, ObligationCauseCode, - ObligationCtxt, Overflow, PredicateObligation, SelectionContext, SelectionError, - SignatureMismatch, TraitDynIncompatible, elaborate, specialization_graph, + ObligationCtxt, PredicateObligation, SelectionContext, SelectionError, elaborate, + specialization_graph, }; impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { @@ -659,7 +659,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - SignatureMismatch(box SignatureMismatchData { + SelectionError::SignatureMismatch(box SignatureMismatchData { found_trait_ref, expected_trait_ref, terr: terr @ TypeError::CyclicTy(_), @@ -669,7 +669,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { expected_trait_ref, terr, ), - SignatureMismatch(box SignatureMismatchData { + SelectionError::SignatureMismatch(box SignatureMismatchData { found_trait_ref, expected_trait_ref, terr: _, @@ -690,7 +690,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { def_id, ), - TraitDynIncompatible(did) => { + SelectionError::TraitDynIncompatible(did) => { let violations = self.tcx.dyn_compatibility_violations(did); report_dyn_incompatibility(self.tcx, span, None, did, violations) } @@ -710,12 +710,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // Already reported in the query. SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(guar)) | // Already reported. - Overflow(OverflowError::Error(guar)) => { + SelectionError::Overflow(OverflowError::Error(guar)) => { self.set_tainted_by_errors(guar); return guar }, - Overflow(_) => { + SelectionError::Overflow(_) => { bug!("overflow should be handled before the `report_selection_error` path"); } @@ -775,7 +775,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { param_env: ty::ParamEnv<'tcx>, span: Span, ) -> Diag<'a> { - // FIXME(const_trait_impl): We should recompute the predicate with `~const` + // FIXME(const_trait_impl): We should recompute the predicate with `[const]` // if it's `const`, and if it holds, explain that this bound only // *conditionally* holds. If that fails, we should also do selection // to drill this down to an impl or built-in source, so we can @@ -1186,7 +1186,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ty: Ty<'tcx>, obligation: &PredicateObligation<'tcx>, ) -> Diag<'a> { - let span = obligation.cause.span; + let param = obligation.cause.body_id; + let hir::GenericParamKind::Const { ty: &hir::Ty { span, .. }, .. } = + self.tcx.hir_node_by_def_id(param).expect_generic_param().kind + else { + bug!() + }; let mut diag = match ty.kind() { ty::Float(_) => { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index 89dab90dc68..a52dbedfe1e 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -334,7 +334,7 @@ pub struct OnUnimplementedNote { pub append_const_msg: Option<AppendConstMessage>, } -/// Append a message for `~const Trait` errors. +/// Append a message for `[const] Trait` errors. #[derive(Clone, Copy, PartialEq, Eq, Debug, Default)] pub enum AppendConstMessage { #[default] diff --git a/compiler/rustc_trait_selection/src/errors/note_and_explain.rs b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs index 84e7686fdd3..ec3c1ba4a45 100644 --- a/compiler/rustc_trait_selection/src/errors/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs @@ -163,12 +163,14 @@ impl RegionExplanation<'_> { impl Subdiagnostic for RegionExplanation<'_> { fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) { + diag.store_args(); diag.arg("pref_kind", self.prefix); diag.arg("suff_kind", self.suffix); diag.arg("desc_kind", self.desc.kind); diag.arg("desc_arg", self.desc.arg); let msg = diag.eagerly_translate(fluent::trait_selection_region_explanation); + diag.restore_args(); if let Some(span) = self.desc.span { diag.span_note(span, msg); } else { diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index b247c2c2968..d22529d56a4 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -143,6 +143,16 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< None } } + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { + let arg = self.shallow_resolve_term(arg); + if arg.is_trivially_wf(self.tcx) { + Some(Certainty::Yes) + } else if arg.is_infer() { + Some(Certainty::AMBIGUOUS) + } else { + None + } + } _ => None, } } @@ -154,7 +164,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< ) -> ty::GenericArg<'tcx> { match arg.kind() { ty::GenericArgKind::Lifetime(_) => { - self.next_region_var(RegionVariableOrigin::MiscVariable(span)).into() + self.next_region_var(RegionVariableOrigin::Misc(span)).into() } ty::GenericArgKind::Type(_) => self.next_ty_var(span).into(), ty::GenericArgKind::Const(_) => self.next_const_var(span).into(), diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index ed99c678a4d..d56042a5ca2 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -14,7 +14,7 @@ use rustc_middle::ty::{ }; use rustc_next_trait_solver::delegate::SolverDelegate as _; use rustc_next_trait_solver::solve::{ - GenerateProofTree, GoalEvaluation, GoalStalledOn, HasChanged, SolverDelegateEvalExt as _, + GoalEvaluation, GoalStalledOn, HasChanged, SolverDelegateEvalExt as _, }; use rustc_span::Span; use thin_vec::ThinVec; @@ -106,14 +106,11 @@ impl<'tcx> ObligationStorage<'tcx> { self.overflowed.extend( ExtractIf::new(&mut self.pending, |(o, stalled_on)| { let goal = o.as_goal(); - let result = <&SolverDelegate<'tcx>>::from(infcx) - .evaluate_root_goal( - goal, - GenerateProofTree::No, - o.cause.span, - stalled_on.take(), - ) - .0; + let result = <&SolverDelegate<'tcx>>::from(infcx).evaluate_root_goal( + goal, + o.cause.span, + stalled_on.take(), + ); matches!(result, Ok(GoalEvaluation { has_changed: HasChanged::Yes, .. })) }) .map(|(o, _)| o), @@ -207,14 +204,7 @@ where continue; } - let result = delegate - .evaluate_root_goal( - goal, - GenerateProofTree::No, - obligation.cause.span, - stalled_on, - ) - .0; + let result = delegate.evaluate_root_goal(goal, obligation.cause.span, stalled_on); self.inspect_evaluated_obligation(infcx, &obligation, &result); let GoalEvaluation { certainty, has_changed, stalled_on } = match result { Ok(result) => result, diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs index 36a8ae675c0..e31d1052d16 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs @@ -11,9 +11,7 @@ use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; -use rustc_next_trait_solver::solve::{ - GenerateProofTree, GoalEvaluation, SolverDelegateEvalExt as _, -}; +use rustc_next_trait_solver::solve::{GoalEvaluation, SolverDelegateEvalExt as _}; use tracing::{instrument, trace}; use crate::solve::delegate::SolverDelegate; @@ -39,7 +37,9 @@ pub(super) fn fulfillment_error_for_no_solution<'tcx>( ty::ConstKind::Unevaluated(uv) => { infcx.tcx.type_of(uv.def).instantiate(infcx.tcx, uv.args) } - ty::ConstKind::Param(param_ct) => param_ct.find_ty_from_env(obligation.param_env), + ty::ConstKind::Param(param_ct) => { + param_ct.find_const_ty_from_env(obligation.param_env) + } ty::ConstKind::Value(cv) => cv.ty, kind => span_bug!( obligation.cause.span, @@ -90,15 +90,11 @@ pub(super) fn fulfillment_error_for_stalled<'tcx>( root_obligation: PredicateObligation<'tcx>, ) -> FulfillmentError<'tcx> { let (code, refine_obligation) = infcx.probe(|_| { - match <&SolverDelegate<'tcx>>::from(infcx) - .evaluate_root_goal( - root_obligation.as_goal(), - GenerateProofTree::No, - root_obligation.cause.span, - None, - ) - .0 - { + match <&SolverDelegate<'tcx>>::from(infcx).evaluate_root_goal( + root_obligation.as_goal(), + root_obligation.cause.span, + None, + ) { Ok(GoalEvaluation { certainty: Certainty::Maybe(MaybeCause::Ambiguity), .. }) => { (FulfillmentErrorCode::Ambiguity { overflow: None }, true) } diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index b0c8fa1f217..308486811e6 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -20,7 +20,7 @@ use rustc_middle::ty::{TyCtxt, VisitorResult, try_visit}; use rustc_middle::{bug, ty}; use rustc_next_trait_solver::resolve::eager_resolve_vars; use rustc_next_trait_solver::solve::inspect::{self, instantiate_canonical_state}; -use rustc_next_trait_solver::solve::{GenerateProofTree, MaybeCause, SolverDelegateEvalExt as _}; +use rustc_next_trait_solver::solve::{MaybeCause, SolverDelegateEvalExt as _}; use rustc_span::Span; use tracing::instrument; @@ -37,7 +37,7 @@ pub struct InspectGoal<'a, 'tcx> { orig_values: Vec<ty::GenericArg<'tcx>>, goal: Goal<'tcx, ty::Predicate<'tcx>>, result: Result<Certainty, NoSolution>, - evaluation_kind: inspect::CanonicalGoalEvaluationKind<TyCtxt<'tcx>>, + evaluation_kind: inspect::GoalEvaluationKind<TyCtxt<'tcx>>, normalizes_to_term_hack: Option<NormalizesToTermHack<'tcx>>, source: GoalSource, } @@ -248,9 +248,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { // considering the constrained RHS, and pass the resulting certainty to // `InspectGoal::new` so that the goal has the right result (and maintains // the impression that we don't do this normalizes-to infer hack at all). - let (nested, proof_tree) = - infcx.evaluate_root_goal_raw(goal, GenerateProofTree::Yes, None); - let proof_tree = proof_tree.unwrap(); + let (nested, proof_tree) = infcx.evaluate_root_goal_for_proof_tree(goal, span); let nested_goals_result = nested.and_then(|(nested, _)| { normalizes_to_term_hack.constrain_and( infcx, @@ -284,9 +282,8 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { // into another candidate who ends up with different inference // constraints, we get an ICE if we already applied the constraints // from the chosen candidate. - let proof_tree = infcx - .probe(|_| infcx.evaluate_root_goal(goal, GenerateProofTree::Yes, span, None).1) - .unwrap(); + let proof_tree = + infcx.probe(|_| infcx.evaluate_root_goal_for_proof_tree(goal, span).1); InspectGoal::new(infcx, self.goal.depth + 1, proof_tree, None, source) } } @@ -396,8 +393,8 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { let mut candidates = vec![]; let last_eval_step = match &self.evaluation_kind { // An annoying edge case in case the recursion limit is 0. - inspect::CanonicalGoalEvaluationKind::Overflow => return vec![], - inspect::CanonicalGoalEvaluationKind::Evaluation { final_revision } => final_revision, + inspect::GoalEvaluationKind::Overflow => return vec![], + inspect::GoalEvaluationKind::Evaluation { final_revision } => final_revision, }; let mut nested_goals = vec![]; @@ -429,10 +426,10 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { ) -> Self { let infcx = <&SolverDelegate<'tcx>>::from(infcx); - let inspect::GoalEvaluation { uncanonicalized_goal, orig_values, evaluation } = root; + let inspect::GoalEvaluation { uncanonicalized_goal, orig_values, kind, result } = root; // If there's a normalizes-to goal, AND the evaluation result with the result of // constraining the normalizes-to RHS and computing the nested goals. - let result = evaluation.result.and_then(|ok| { + let result = result.and_then(|ok| { let nested_goals_certainty = term_hack_and_nested_certainty.map_or(Ok(Certainty::Yes), |(_, c)| c)?; Ok(ok.value.certainty.and(nested_goals_certainty)) @@ -444,7 +441,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { orig_values, goal: eager_resolve_vars(infcx, uncanonicalized_goal), result, - evaluation_kind: evaluation.kind, + evaluation_kind: kind, normalizes_to_term_hack: term_hack_and_nested_certainty.map(|(n, _)| n), source, } @@ -488,13 +485,8 @@ impl<'tcx> InferCtxt<'tcx> { depth: usize, visitor: &mut V, ) -> V::Result { - let (_, proof_tree) = <&SolverDelegate<'tcx>>::from(self).evaluate_root_goal( - goal, - GenerateProofTree::Yes, - visitor.span(), - None, - ); - let proof_tree = proof_tree.unwrap(); + let (_, proof_tree) = <&SolverDelegate<'tcx>>::from(self) + .evaluate_root_goal_for_proof_tree(goal, visitor.span()); visitor.visit_goal(&InspectGoal::new(self, depth, proof_tree, None, GoalSource::Misc)) } } diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 81893cdcc7e..ce5a4edeaaa 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -356,29 +356,38 @@ fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>( return IntersectionHasImpossibleObligations::Yes; } - let ocx = ObligationCtxt::new_with_diagnostics(infcx); + let ocx = ObligationCtxt::new(infcx); ocx.register_obligations(obligations.iter().cloned()); + let hard_errors = ocx.select_where_possible(); + if !hard_errors.is_empty() { + assert!( + hard_errors.iter().all(|e| e.is_true_error()), + "should not have detected ambiguity during first pass" + ); + return IntersectionHasImpossibleObligations::Yes; + } + + // Make a new `ObligationCtxt` and re-prove the ambiguities with a richer + // `FulfillmentError`. This is so that we can detect overflowing obligations + // without needing to run the `BestObligation` visitor on true errors. + let ambiguities = ocx.into_pending_obligations(); + let ocx = ObligationCtxt::new_with_diagnostics(infcx); + ocx.register_obligations(ambiguities); let errors_and_ambiguities = ocx.select_all_or_error(); // We only care about the obligations that are *definitely* true errors. // Ambiguities do not prove the disjointness of two impls. let (errors, ambiguities): (Vec<_>, Vec<_>) = errors_and_ambiguities.into_iter().partition(|error| error.is_true_error()); - - if errors.is_empty() { - IntersectionHasImpossibleObligations::No { - overflowing_predicates: ambiguities - .into_iter() - .filter(|error| { - matches!( - error.code, - FulfillmentErrorCode::Ambiguity { overflow: Some(true) } - ) - }) - .map(|e| infcx.resolve_vars_if_possible(e.obligation.predicate)) - .collect(), - } - } else { - IntersectionHasImpossibleObligations::Yes + assert!(errors.is_empty(), "should not have ambiguities during second pass"); + + IntersectionHasImpossibleObligations::No { + overflowing_predicates: ambiguities + .into_iter() + .filter(|error| { + matches!(error.code, FulfillmentErrorCode::Ambiguity { overflow: Some(true) }) + }) + .map(|e| infcx.resolve_vars_if_possible(e.obligation.predicate)) + .collect(), } } else { for obligation in obligations { diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index bdfe48a3928..8d049fedf23 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -593,7 +593,7 @@ fn receiver_is_dispatchable<'tcx>( // will cause ambiguity that the user can't really avoid. // // We leave out certain complexities of the param-env query here. Specifically, we: - // 1. Do not add `~const` bounds since there are no `dyn const Trait`s. + // 1. Do not add `[const]` bounds since there are no `dyn const Trait`s. // 2. Do not add RPITIT self projection bounds for defaulted methods, since we // are not constructing a param-env for "inside" of the body of the defaulted // method, so we don't really care about projecting to a specific RPIT type, diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs index e77d9e32cb9..fc95e42d67f 100644 --- a/compiler/rustc_trait_selection/src/traits/effects.rs +++ b/compiler/rustc_trait_selection/src/traits/effects.rs @@ -252,20 +252,20 @@ fn evaluate_host_effect_for_destruct_goal<'tcx>( let self_ty = obligation.predicate.self_ty(); let const_conditions = match *self_ty.kind() { - // `ManuallyDrop` is trivially `~const Destruct` as we do not run any drop glue on it. + // `ManuallyDrop` is trivially `[const] Destruct` as we do not run any drop glue on it. ty::Adt(adt_def, _) if adt_def.is_manually_drop() => thin_vec![], - // An ADT is `~const Destruct` only if all of the fields are, - // *and* if there is a `Drop` impl, that `Drop` impl is also `~const`. + // An ADT is `[const] Destruct` only if all of the fields are, + // *and* if there is a `Drop` impl, that `Drop` impl is also `[const]`. ty::Adt(adt_def, args) => { let mut const_conditions: ThinVec<_> = adt_def .all_fields() .map(|field| ty::TraitRef::new(tcx, destruct_def_id, [field.ty(tcx, args)])) .collect(); match adt_def.destructor(tcx).map(|dtor| tcx.constness(dtor.did)) { - // `Drop` impl exists, but it's not const. Type cannot be `~const Destruct`. + // `Drop` impl exists, but it's not const. Type cannot be `[const] Destruct`. Some(hir::Constness::NotConst) => return Err(EvaluationFailure::NoSolution), - // `Drop` impl exists, and it's const. Require `Ty: ~const Drop` to hold. + // `Drop` impl exists, and it's const. Require `Ty: [const] Drop` to hold. Some(hir::Constness::Const) => { let drop_def_id = tcx.require_lang_item(LangItem::Drop, obligation.cause.span); let drop_trait_ref = ty::TraitRef::new(tcx, drop_def_id, [self_ty]); @@ -285,7 +285,7 @@ fn evaluate_host_effect_for_destruct_goal<'tcx>( tys.iter().map(|field_ty| ty::TraitRef::new(tcx, destruct_def_id, [field_ty])).collect() } - // Trivially implement `~const Destruct` + // Trivially implement `[const] Destruct` ty::Bool | ty::Char | ty::Int(..) @@ -300,14 +300,14 @@ fn evaluate_host_effect_for_destruct_goal<'tcx>( | ty::Infer(ty::InferTy::FloatVar(_) | ty::InferTy::IntVar(_)) | ty::Error(_) => thin_vec![], - // Coroutines and closures could implement `~const Drop`, + // Coroutines and closures could implement `[const] Drop`, // but they don't really need to right now. ty::Closure(_, _) | ty::CoroutineClosure(_, _) | ty::Coroutine(_, _) | ty::CoroutineWitness(_, _) => return Err(EvaluationFailure::NoSolution), - // FIXME(unsafe_binders): Unsafe binders could implement `~const Drop` + // FIXME(unsafe_binders): Unsafe binders could implement `[const] Drop` // if their inner type implements it. ty::UnsafeBinder(_) => return Err(EvaluationFailure::NoSolution), diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 951dfb879ae..64a51e0550b 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -12,7 +12,7 @@ use rustc_middle::bug; use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt, TypingMode}; -use thin_vec::ThinVec; +use thin_vec::{ThinVec, thin_vec}; use tracing::{debug, debug_span, instrument}; use super::effects::{self, HostEffectObligation}; @@ -20,7 +20,7 @@ use super::project::{self, ProjectAndUnifyResult}; use super::select::SelectionContext; use super::{ EvaluationResult, FulfillmentError, FulfillmentErrorCode, PredicateObligation, - ScrubbedTraitError, Unimplemented, const_evaluatable, wf, + ScrubbedTraitError, const_evaluatable, wf, }; use crate::error_reporting::InferCtxtErrorExt; use crate::infer::{InferCtxt, TyOrConstInferVar}; @@ -336,7 +336,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { let infcx = self.selcx.infcx; if sizedness_fast_path(infcx.tcx, obligation.predicate) { - return ProcessResult::Changed(thin_vec::thin_vec![]); + return ProcessResult::Changed(thin_vec![]); } if obligation.predicate.has_aliases() { @@ -456,7 +456,9 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ty::PredicateKind::DynCompatible(trait_def_id) => { if !self.selcx.tcx().is_dyn_compatible(trait_def_id) { - ProcessResult::Error(FulfillmentErrorCode::Select(Unimplemented)) + ProcessResult::Error(FulfillmentErrorCode::Select( + SelectionError::Unimplemented, + )) } else { ProcessResult::Changed(Default::default()) } @@ -507,7 +509,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { } ty::ConstKind::Bound(_, _) => bug!("escaping bound vars in {:?}", ct), ty::ConstKind::Param(param_ct) => { - param_ct.find_ty_from_env(obligation.param_env) + param_ct.find_const_ty_from_env(obligation.param_env) } }; @@ -541,6 +543,10 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { } ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => { + if term.is_trivially_wf(self.selcx.tcx()) { + return ProcessResult::Changed(thin_vec![]); + } + match wf::obligations( self.selcx.infcx, obligation.param_env, diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 999ef97683c..43806d3977b 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -36,8 +36,8 @@ use rustc_middle::ty::{ self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypingMode, Upcast, }; +use rustc_span::Span; use rustc_span::def_id::DefId; -use rustc_span::{DUMMY_SP, Span}; use tracing::{debug, instrument}; pub use self::coherence::{ @@ -644,7 +644,9 @@ pub fn try_evaluate_const<'tcx>( let erased_uv = tcx.erase_regions(uv); use rustc_middle::mir::interpret::ErrorHandled; - match tcx.const_eval_resolve_for_typeck(typing_env, erased_uv, DUMMY_SP) { + // FIXME: `def_span` will point at the definition of this const; ideally, we'd point at + // where it gets used as a const generic. + match tcx.const_eval_resolve_for_typeck(typing_env, erased_uv, tcx.def_span(uv.def)) { Ok(Ok(val)) => Ok(ty::Const::new_value( tcx, val, diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 6dd80551980..28b5b7cf391 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -84,9 +84,6 @@ impl<'tcx> ProjectionCandidateSet<'tcx> { // was discarded -- this could be because of ambiguity, or because // a higher-priority candidate is already there. fn push_candidate(&mut self, candidate: ProjectionCandidate<'tcx>) -> bool { - use self::ProjectionCandidate::*; - use self::ProjectionCandidateSet::*; - // This wacky variable is just used to try and // make code readable and avoid confusing paths. // It is assigned a "value" of `()` only on those @@ -98,12 +95,12 @@ impl<'tcx> ProjectionCandidateSet<'tcx> { let convert_to_ambiguous; match self { - None => { - *self = Single(candidate); + ProjectionCandidateSet::None => { + *self = ProjectionCandidateSet::Single(candidate); return true; } - Single(current) => { + ProjectionCandidateSet::Single(current) => { // Duplicates can happen inside ParamEnv. In the case, we // perform a lazy deduplication. if current == &candidate { @@ -118,16 +115,18 @@ impl<'tcx> ProjectionCandidateSet<'tcx> { // clauses are the safer choice. See the comment on // `select::SelectionCandidate` and #21974 for more details. match (current, candidate) { - (ParamEnv(..), ParamEnv(..)) => convert_to_ambiguous = (), - (ParamEnv(..), _) => return false, - (_, ParamEnv(..)) => bug!( + (ProjectionCandidate::ParamEnv(..), ProjectionCandidate::ParamEnv(..)) => { + convert_to_ambiguous = () + } + (ProjectionCandidate::ParamEnv(..), _) => return false, + (_, ProjectionCandidate::ParamEnv(..)) => bug!( "should never prefer non-param-env candidates over param-env candidates" ), (_, _) => convert_to_ambiguous = (), } } - Ambiguous | Error(..) => { + ProjectionCandidateSet::Ambiguous | ProjectionCandidateSet::Error(..) => { return false; } } @@ -135,7 +134,7 @@ impl<'tcx> ProjectionCandidateSet<'tcx> { // We only ever get here when we moved from a single candidate // to ambiguous. let () = convert_to_ambiguous; - *self = Ambiguous; + *self = ProjectionCandidateSet::Ambiguous; false } } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 80f71c78993..3eca77b43a8 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -11,7 +11,7 @@ use std::ops::ControlFlow; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::lang_items::LangItem; -use rustc_infer::infer::{DefineOpaqueTypes, HigherRankedType, InferOk}; +use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk}; use rustc_infer::traits::ObligationCauseCode; use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData}; use rustc_middle::ty::{ @@ -28,8 +28,7 @@ use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to}; use crate::traits::util::{self, closure_trait_ref_and_return_type}; use crate::traits::{ ImplSource, ImplSourceUserDefinedData, Normalized, Obligation, ObligationCause, - PolyTraitObligation, PredicateObligation, Selection, SelectionError, SignatureMismatch, - TraitDynIncompatible, TraitObligation, Unimplemented, + PolyTraitObligation, PredicateObligation, Selection, SelectionError, TraitObligation, }; impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { @@ -176,7 +175,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let candidate = self.infcx.instantiate_binder_with_fresh_vars( obligation.cause.span, - HigherRankedType, + BoundRegionConversionTime::HigherRankedType, candidate, ); let mut obligations = PredicateObligations::new(); @@ -194,7 +193,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .at(&obligation.cause, obligation.param_env) .eq(DefineOpaqueTypes::No, placeholder_trait_predicate, candidate) .map(|InferOk { obligations, .. }| obligations) - .map_err(|_| Unimplemented)?, + .map_err(|_| SelectionError::Unimplemented)?, ); // FIXME(compiler-errors): I don't think this is needed. @@ -374,7 +373,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { assume = crate::traits::evaluate_const(self.infcx, assume, obligation.param_env) } let Some(assume) = rustc_transmute::Assume::from_const(self.infcx.tcx, assume) else { - return Err(Unimplemented); + return Err(SelectionError::Unimplemented); }; let dst = predicate.trait_ref.args.type_at(0); @@ -386,7 +385,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { transmute_env.is_transmutable(rustc_transmute::Types { dst, src }, assume); let fully_flattened = match maybe_transmutable { - Answer::No(_) => Err(Unimplemented)?, + Answer::No(_) => Err(SelectionError::Unimplemented)?, Answer::If(cond) => flatten_answer_tree(self.tcx(), obligation, cond, assume), Answer::Yes => PredicateObligations::new(), }; @@ -500,7 +499,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }); let object_trait_ref = self.infcx.instantiate_binder_with_fresh_vars( obligation.cause.span, - HigherRankedType, + BoundRegionConversionTime::HigherRankedType, object_trait_ref, ); let object_trait_ref = object_trait_ref.with_self_ty(self.tcx(), self_ty); @@ -513,7 +512,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let upcast_trait_ref = self.infcx.instantiate_binder_with_fresh_vars( obligation.cause.span, - HigherRankedType, + BoundRegionConversionTime::HigherRankedType, unnormalized_upcast_trait_ref, ); let upcast_trait_ref = normalize_with_depth_to( @@ -530,7 +529,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .at(&obligation.cause, obligation.param_env) .eq(DefineOpaqueTypes::No, trait_predicate.trait_ref, upcast_trait_ref) .map(|InferOk { obligations, .. }| obligations) - .map_err(|_| Unimplemented)?, + .map_err(|_| SelectionError::Unimplemented)?, ); // Check supertraits hold. This is so that their associated type bounds @@ -962,7 +961,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> { let found_trait_ref = self.infcx.instantiate_binder_with_fresh_vars( obligation.cause.span, - HigherRankedType, + BoundRegionConversionTime::HigherRankedType, found_trait_ref, ); // Normalize the obligation and expected trait refs together, because why not @@ -986,7 +985,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligations }) .map_err(|terr| { - SignatureMismatch(Box::new(SignatureMismatchData { + SelectionError::SignatureMismatch(Box::new(SignatureMismatchData { expected_trait_ref: obligation_trait_ref, found_trait_ref, terr, @@ -1090,7 +1089,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .infcx .at(&obligation.cause, obligation.param_env) .sup(DefineOpaqueTypes::Yes, target, source_trait) - .map_err(|_| Unimplemented)?; + .map_err(|_| SelectionError::Unimplemented)?; // Register one obligation for 'a: 'b. let outlives = ty::OutlivesPredicate(r_a, r_b); @@ -1109,7 +1108,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { (_, &ty::Dynamic(data, r, ty::Dyn)) => { let mut object_dids = data.auto_traits().chain(data.principal_def_id()); if let Some(did) = object_dids.find(|did| !tcx.is_dyn_compatible(*did)) { - return Err(TraitDynIncompatible(did)); + return Err(SelectionError::TraitDynIncompatible(did)); } let predicate_to_obligation = |predicate| { @@ -1189,7 +1188,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .infcx .at(&obligation.cause, obligation.param_env) .eq(DefineOpaqueTypes::Yes, b, a) - .map_err(|_| Unimplemented)?; + .map_err(|_| SelectionError::Unimplemented)?; ImplSource::Builtin(BuiltinImplSource::Misc, obligations) } @@ -1198,7 +1197,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { (&ty::Adt(def, args_a), &ty::Adt(_, args_b)) => { let unsizing_params = tcx.unsizing_params_for_adt(def.did()); if unsizing_params.is_empty() { - return Err(Unimplemented); + return Err(SelectionError::Unimplemented); } let tail_field = def.non_enum_variant().tail(); @@ -1237,7 +1236,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .infcx .at(&obligation.cause, obligation.param_env) .eq(DefineOpaqueTypes::Yes, target, new_struct) - .map_err(|_| Unimplemented)?; + .map_err(|_| SelectionError::Unimplemented)?; nested.extend(obligations); // Construct the nested `TailField<T>: Unsize<TailField<U>>` predicate. diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 9c0ccb26e53..af3641c22ed 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -39,7 +39,7 @@ use super::coherence::{self, Conflict}; use super::project::ProjectionTermObligation; use super::util::closure_trait_ref_and_return_type; use super::{ - ImplDerivedCause, Normalized, Obligation, ObligationCause, ObligationCauseCode, Overflow, + ImplDerivedCause, Normalized, Obligation, ObligationCause, ObligationCauseCode, PolyTraitObligation, PredicateObligation, Selection, SelectionError, SelectionResult, TraitQueryMode, const_evaluatable, project, util, wf, }; @@ -48,9 +48,7 @@ use crate::infer::{InferCtxt, InferOk, TypeFreshener}; use crate::solve::InferCtxtSelectExt as _; use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to}; use crate::traits::project::{ProjectAndUnifyResult, ProjectionCacheKeyExt}; -use crate::traits::{ - EvaluateConstErr, ProjectionCacheKey, Unimplemented, effects, sizedness_fast_path, -}; +use crate::traits::{EvaluateConstErr, ProjectionCacheKey, effects, sizedness_fast_path}; mod _match; mod candidate_assembly; @@ -454,8 +452,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval })) } Ok(_) => Ok(None), - Err(OverflowError::Canonical) => Err(Overflow(OverflowError::Canonical)), - Err(OverflowError::Error(e)) => Err(Overflow(OverflowError::Error(e))), + Err(OverflowError::Canonical) => { + Err(SelectionError::Overflow(OverflowError::Canonical)) + } + Err(OverflowError::Error(e)) => { + Err(SelectionError::Overflow(OverflowError::Error(e))) + } }) .flat_map(Result::transpose) .collect::<Result<Vec<_>, _>>()?; @@ -479,7 +481,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?stack.obligation.predicate, "found error type in predicate, treating as ambiguous"); Ok(None) } else { - Err(Unimplemented) + Err(SelectionError::Unimplemented) } } else { let has_non_region_infer = stack.obligation.predicate.has_non_region_infer(); @@ -660,6 +662,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => { + if term.is_trivially_wf(self.tcx()) { + return Ok(EvaluatedToOk); + } + // So, there is a bit going on here. First, `WellFormed` predicates // are coinductive, like trait predicates with auto traits. // This means that we need to detect if we have recursively @@ -979,7 +985,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::ConstKind::Bound(_, _) => bug!("escaping bound vars in {:?}", ct), ty::ConstKind::Param(param_ct) => { - param_ct.find_ty_from_env(obligation.param_env) + param_ct.find_const_ty_from_env(obligation.param_env) } }; @@ -1222,7 +1228,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match self.candidate_from_obligation(stack) { Ok(Some(c)) => self.evaluate_candidate(stack, &c), Ok(None) => Ok(EvaluatedToAmbig), - Err(Overflow(OverflowError::Canonical)) => Err(OverflowError::Canonical), + Err(SelectionError::Overflow(OverflowError::Canonical)) => { + Err(OverflowError::Canonical) + } Err(..) => Ok(EvaluatedToErr), } } @@ -1536,7 +1544,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Some(res); } else if cfg!(debug_assertions) { match infcx.selection_cache.get(&(param_env, pred), tcx) { - None | Some(Err(Overflow(OverflowError::Canonical))) => {} + None | Some(Err(SelectionError::Overflow(OverflowError::Canonical))) => {} res => bug!("unexpected local cache result: {res:?}"), } } @@ -1592,7 +1600,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } if self.can_use_global_caches(param_env, cache_fresh_trait_pred) { - if let Err(Overflow(OverflowError::Canonical)) = candidate { + if let Err(SelectionError::Overflow(OverflowError::Canonical)) = candidate { // Don't cache overflow globally; we only produce this in certain modes. } else { debug!(?pred, ?candidate, "insert_candidate_cache global"); @@ -2121,7 +2129,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Never - | ty::Dynamic(_, _, ty::DynStar) | ty::Error(_) => { // safe for everything Where(ty::Binder::dummy(Vec::new())) diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index b30fadd3e5b..4bb12694c47 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -233,7 +233,7 @@ pub(super) fn specialization_enabled_in(tcx: TyCtxt<'_>, _: LocalCrate) -> bool /// /// For the purposes of const traits, we also check that the specializing /// impl is not more restrictive than the parent impl. That is, if the -/// `parent_impl_def_id` is a const impl (conditionally based off of some `~const` +/// `parent_impl_def_id` is a const impl (conditionally based off of some `[const]` /// bounds), then `specializing_impl_def_id` must also be const for the same /// set of types. #[instrument(skip(tcx), level = "debug")] diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs index 9452dca9a4f..19eb85506b6 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs @@ -273,8 +273,6 @@ impl<'tcx> Graph { // Descend the specialization tree, where `parent` is the current parent node. loop { - use self::Inserted::*; - let insert_result = self.children.entry(parent).or_default().insert( tcx, impl_def_id, @@ -283,11 +281,11 @@ impl<'tcx> Graph { )?; match insert_result { - BecameNewSibling(opt_lint) => { + Inserted::BecameNewSibling(opt_lint) => { last_lint = opt_lint; break; } - ReplaceChildren(grand_children_to_be) => { + Inserted::ReplaceChildren(grand_children_to_be) => { // We currently have // // P @@ -326,7 +324,7 @@ impl<'tcx> Graph { } break; } - ShouldRecurseOn(new_parent) => { + Inserted::ShouldRecurseOn(new_parent) => { parent = new_parent; } } diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs index a0a1d454556..9d144010561 100644 --- a/compiler/rustc_traits/src/codegen.rs +++ b/compiler/rustc_traits/src/codegen.rs @@ -10,7 +10,7 @@ use rustc_middle::ty::{self, PseudoCanonicalInput, TyCtxt, TypeVisitableExt, Upc use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::{ ImplSource, Obligation, ObligationCause, ObligationCtxt, ScrubbedTraitError, SelectionContext, - Unimplemented, sizedness_fast_path, + SelectionError, sizedness_fast_path, }; use tracing::debug; @@ -47,7 +47,7 @@ pub(crate) fn codegen_select_candidate<'tcx>( let selection = match selcx.select(&obligation) { Ok(Some(selection)) => selection, Ok(None) => return Err(CodegenObligationError::Ambiguity), - Err(Unimplemented) => return Err(CodegenObligationError::Unimplemented), + Err(SelectionError::Unimplemented) => return Err(CodegenObligationError::Unimplemented), Err(e) => { bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref) } diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index 372b4f5353a..150f5d118e0 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -432,7 +432,9 @@ pub(crate) mod rustc { if variant_layout.is_uninhabited() { return Ok(Self::uninhabited()); } - let tag = cx.tcx().tag_for_variant((cx.tcx().erase_regions(ty), index)); + let tag = cx.tcx().tag_for_variant( + cx.typing_env.as_query_input((cx.tcx().erase_regions(ty), index)), + ); let variant_def = Def::Variant(def.variant(index)); Self::from_variant( variant_def, diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index b275cd382ab..eb751da7c73 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -120,7 +120,7 @@ fn recurse_build<'tcx>( } &ExprKind::Literal { lit, neg } => { let sp = node.span; - tcx.at(sp).lit_to_const(LitToConstInput { lit: &lit.node, ty: node.ty, neg }) + tcx.at(sp).lit_to_const(LitToConstInput { lit: lit.node, ty: node.ty, neg }) } &ExprKind::NonHirLiteral { lit, user_ty: _ } => { let val = ty::ValTree::from_scalar_int(tcx, lit); @@ -226,7 +226,11 @@ fn recurse_build<'tcx>( ExprKind::Yield { .. } => { error(GenericConstantTooComplexSub::YieldNotSupported(node.span))? } - ExprKind::Continue { .. } | ExprKind::Break { .. } | ExprKind::Loop { .. } => { + ExprKind::Continue { .. } + | ExprKind::ConstContinue { .. } + | ExprKind::Break { .. } + | ExprKind::Loop { .. } + | ExprKind::LoopMatch { .. } => { error(GenericConstantTooComplexSub::LoopNotSupported(node.span))? } ExprKind::Box { .. } => error(GenericConstantTooComplexSub::BoxNotSupported(node.span))?, @@ -329,6 +333,7 @@ impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> { | thir::ExprKind::NeverToAny { .. } | thir::ExprKind::PointerCoercion { .. } | thir::ExprKind::Loop { .. } + | thir::ExprKind::LoopMatch { .. } | thir::ExprKind::Let { .. } | thir::ExprKind::Match { .. } | thir::ExprKind::Block { .. } @@ -342,6 +347,7 @@ impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> { | thir::ExprKind::RawBorrow { .. } | thir::ExprKind::Break { .. } | thir::ExprKind::Continue { .. } + | thir::ExprKind::ConstContinue { .. } | thir::ExprKind::Return { .. } | thir::ExprKind::Become { .. } | thir::ExprKind::Array { .. } diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index d5222822461..a225b712d4b 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -449,14 +449,6 @@ fn layout_of_uncached<'tcx>( tcx.mk_layout(LayoutData::scalar_pair(cx, data_ptr, metadata)) } - ty::Dynamic(_, _, ty::DynStar) => { - let mut data = scalar_unit(Pointer(AddressSpace::DATA)); - data.valid_range_mut().start = 0; - let mut vtable = scalar_unit(Pointer(AddressSpace::DATA)); - vtable.valid_range_mut().start = 1; - tcx.mk_layout(LayoutData::scalar_pair(cx, data, vtable)) - } - // Arrays and slices. ty::Array(element, count) => { let count = extract_const_value(cx, ty, count)? diff --git a/compiler/rustc_ty_utils/src/layout/invariant.rs b/compiler/rustc_ty_utils/src/layout/invariant.rs index c929de11624..4b65c05d0e9 100644 --- a/compiler/rustc_ty_utils/src/layout/invariant.rs +++ b/compiler/rustc_ty_utils/src/layout/invariant.rs @@ -277,6 +277,12 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou if !variant.is_uninhabited() { assert!(idx == *untagged_variant || niche_variants.contains(&idx)); } + + // Ensure that for niche encoded tags the discriminant coincides with the variant index. + assert_eq!( + layout.ty.discriminant_for_variant(tcx, idx).unwrap().val, + u128::from(idx.as_u32()), + ); } } for variant in variants.iter() { diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index d996ee2b60a..f8d793464a9 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -38,8 +38,7 @@ fn sizedness_constraint_for_ty<'tcx>( | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) - | ty::Never - | ty::Dynamic(_, _, ty::DynStar) => None, + | ty::Never => None, ty::Str | ty::Slice(..) | ty::Dynamic(_, _, ty::Dyn) => match sizedness { // Never `Sized` @@ -175,7 +174,7 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { } // We extend the param-env of our item with the const conditions of the item, - // since we're allowed to assume `~const` bounds hold within the item itself. + // since we're allowed to assume `[const]` bounds hold within the item itself. if tcx.is_conditionally_const(def_id) { predicates.extend( tcx.const_conditions(def_id).instantiate_identity(tcx).into_iter().map( @@ -383,8 +382,7 @@ fn impl_self_is_guaranteed_unsized<'tcx>(tcx: TyCtxt<'tcx>, impl_def_id: DefId) | ty::Bound(_, _) | ty::Placeholder(_) | ty::Infer(_) - | ty::Error(_) - | ty::Dynamic(_, _, ty::DynStar) => false, + | ty::Error(_) => false, } } diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index 927a2ce84ea..a7b915c4845 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -622,6 +622,17 @@ impl<I: Interner, T: TypeFoldable<I>> ty::EarlyBinder<I, T> { where A: SliceLike<Item = I::GenericArg>, { + // Nothing to fold, so let's avoid visiting things and possibly re-hashing/equating + // them when interning. Perf testing found this to be a modest improvement. + // See: <https://github.com/rust-lang/rust/pull/142317> + if args.is_empty() { + assert!( + !self.value.has_param(), + "{:?} has parameters, but no args were provided in instantiate", + self.value, + ); + return self.value; + } let mut folder = ArgFolder { cx, args: args.as_slice(), binders_passed: 0 }; self.value.fold_with(&mut folder) } diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs index 852949d707b..7ffcf7b5d96 100644 --- a/compiler/rustc_type_ir/src/elaborate.rs +++ b/compiler/rustc_type_ir/src/elaborate.rs @@ -179,7 +179,7 @@ impl<I: Interner, O: Elaboratable<I>> Elaborator<I, O> { ), }; } - // `T: ~const Trait` implies `T: ~const Supertrait`. + // `T: [const] Trait` implies `T: [const] Supertrait`. ty::ClauseKind::HostEffect(data) => self.extend_deduped( cx.explicit_implied_const_bounds(data.def_id()).iter_identity().map(|trait_ref| { elaboratable.child( @@ -320,10 +320,10 @@ pub fn supertrait_def_ids<I: Interner>( let trait_def_id = stack.pop()?; for (predicate, _) in cx.explicit_super_predicates_of(trait_def_id).iter_identity() { - if let ty::ClauseKind::Trait(data) = predicate.kind().skip_binder() { - if set.insert(data.def_id()) { - stack.push(data.def_id()); - } + if let ty::ClauseKind::Trait(data) = predicate.kind().skip_binder() + && set.insert(data.def_id()) + { + stack.push(data.def_id()); } } diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 2bc12d0a23b..8ba9e7105d6 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -117,12 +117,20 @@ impl<I: Interner> TypingMode<I> { } pub fn borrowck(cx: I, body_def_id: I::LocalDefId) -> TypingMode<I> { - TypingMode::Borrowck { defining_opaque_types: cx.opaque_types_defined_by(body_def_id) } + let defining_opaque_types = cx.opaque_types_defined_by(body_def_id); + if defining_opaque_types.is_empty() { + TypingMode::non_body_analysis() + } else { + TypingMode::Borrowck { defining_opaque_types } + } } pub fn post_borrowck_analysis(cx: I, body_def_id: I::LocalDefId) -> TypingMode<I> { - TypingMode::PostBorrowckAnalysis { - defined_opaque_types: cx.opaque_types_defined_by(body_def_id), + let defined_opaque_types = cx.opaque_types_defined_by(body_def_id); + if defined_opaque_types.is_empty() { + TypingMode::non_body_analysis() + } else { + TypingMode::PostBorrowckAnalysis { defined_opaque_types } } } } diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 608efc7515c..2754d40fd36 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -12,7 +12,7 @@ use crate::elaborate::Elaboratable; use crate::fold::{TypeFoldable, TypeSuperFoldable}; use crate::relate::Relate; use crate::solve::{AdtDestructorKind, SizedTraitKind}; -use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; +use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable, TypeVisitableExt}; use crate::{self as ty, CollectAndApply, Interner, UpcastFrom}; pub trait Ty<I: Interner<Ty = Self>>: @@ -183,8 +183,7 @@ pub trait Ty<I: Interner<Ty = Self>>: | ty::Bound(_, _) | ty::Placeholder(_) | ty::Infer(_) - | ty::Error(_) - | ty::Dynamic(_, _, ty::DynStar) => false, + | ty::Error(_) => false, } } } @@ -538,6 +537,45 @@ pub trait PlaceholderLike<I: Interner>: Copy + Debug + Hash + Eq { fn with_updated_universe(self, ui: ty::UniverseIndex) -> Self; } +pub trait PlaceholderConst<I: Interner>: PlaceholderLike<I, Bound = I::BoundConst> { + fn find_const_ty_from_env(self, env: I::ParamEnv) -> I::Ty; +} +impl<I: Interner> PlaceholderConst<I> for I::PlaceholderConst { + fn find_const_ty_from_env(self, env: I::ParamEnv) -> I::Ty { + let mut candidates = env.caller_bounds().iter().filter_map(|clause| { + // `ConstArgHasType` are never desugared to be higher ranked. + match clause.kind().skip_binder() { + ty::ClauseKind::ConstArgHasType(placeholder_ct, ty) => { + assert!(!(placeholder_ct, ty).has_escaping_bound_vars()); + + match placeholder_ct.kind() { + ty::ConstKind::Placeholder(placeholder_ct) if placeholder_ct == self => { + Some(ty) + } + _ => None, + } + } + _ => None, + } + }); + + // N.B. it may be tempting to fix ICEs by making this function return + // `Option<Ty<'tcx>>` instead of `Ty<'tcx>`; however, this is generally + // considered to be a bandaid solution, since it hides more important + // underlying issues with how we construct generics and predicates of + // items. It's advised to fix the underlying issue rather than trying + // to modify this function. + let ty = candidates.next().unwrap_or_else(|| { + panic!("cannot find `{self:?}` in param-env: {env:#?}"); + }); + assert!( + candidates.next().is_none(), + "did not expect duplicate `ConstParamHasTy` for `{self:?}` in param-env: {env:#?}" + ); + ty + } +} + pub trait IntoKind { type Kind; diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 033d2579678..dd3cf1fc181 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -133,7 +133,7 @@ pub trait Interner: type Const: Const<Self>; type ParamConst: Copy + Debug + Hash + Eq + ParamLike; type BoundConst: BoundVarLike<Self>; - type PlaceholderConst: PlaceholderLike<Self, Bound = Self::BoundConst>; + type PlaceholderConst: PlaceholderConst<Self>; type ValueConst: ValueConst<Self>; type ExprConst: ExprConst<Self>; type ValTree: Copy + Debug + Hash + Eq; @@ -271,6 +271,13 @@ pub trait Interner: def_id: Self::DefId, ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = (Self::Clause, Self::Span)>>; + /// This is equivalent to computing the super-predicates of the trait for this impl + /// and filtering them to the outlives predicates. This is purely for performance. + fn impl_super_outlives( + self, + impl_def_id: Self::DefId, + ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>>; + fn impl_is_const(self, def_id: Self::DefId) -> bool; fn fn_is_const(self, def_id: Self::DefId) -> bool; fn alias_has_const_conditions(self, def_id: Self::DefId) -> bool; @@ -341,12 +348,6 @@ pub trait Interner: type UnsizingParams: Deref<Target = DenseBitSet<u32>>; fn unsizing_params_for_adt(self, adt_def_id: Self::DefId) -> Self::UnsizingParams; - fn find_const_ty_from_env( - self, - param_env: Self::ParamEnv, - placeholder: Self::PlaceholderConst, - ) -> Self::Ty; - fn anonymize_bound_vars<T: TypeFoldable<Self>>( self, binder: ty::Binder<Self, T>, diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs index 3ee6e07b7a5..f9994448e28 100644 --- a/compiler/rustc_type_ir/src/lang_items.rs +++ b/compiler/rustc_type_ir/src/lang_items.rs @@ -29,8 +29,8 @@ pub enum TraitSolverLangItem { Future, FutureOutput, Iterator, - Metadata, MetaSized, + Metadata, Option, PointeeSized, PointeeTrait, diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 3863a6d7c5a..a483c18813b 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -1,5 +1,6 @@ #![cfg_attr(feature = "nightly", rustc_diagnostic_item = "type_ir")] // tidy-alphabetical-start +#![allow(rustc::direct_use_of_rustc_type_ir)] #![allow(rustc::usage_of_ty_tykind)] #![allow(rustc::usage_of_type_ir_inherent)] #![allow(rustc::usage_of_type_ir_traits)] @@ -8,7 +9,6 @@ feature(associated_type_defaults, never_type, rustc_attrs, negative_impls) )] #![cfg_attr(feature = "nightly", allow(internal_features))] -#![cfg_attr(not(bootstrap), allow(rustc::direct_use_of_rustc_type_ir))] // tidy-alphabetical-end extern crate self as rustc_type_ir; diff --git a/compiler/rustc_type_ir/src/macros.rs b/compiler/rustc_type_ir/src/macros.rs index c8c293121ca..9064f13eb45 100644 --- a/compiler/rustc_type_ir/src/macros.rs +++ b/compiler/rustc_type_ir/src/macros.rs @@ -53,11 +53,11 @@ TrivialTypeTraversalImpls! { crate::BoundConstness, crate::DebruijnIndex, crate::PredicatePolarity, + crate::UniverseIndex, + crate::Variance, crate::solve::BuiltinImplSource, crate::solve::Certainty, crate::solve::GoalSource, - crate::UniverseIndex, - crate::Variance, rustc_ast_ir::Mutability, // tidy-alphabetical-end } diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index f02d9c988c8..4643cd0ab85 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -911,7 +911,7 @@ pub enum BoundConstness { /// /// A bound is required to be unconditionally const, even in a runtime function. Const, - /// `Type: ~const Trait` + /// `Type: [const] Trait` /// /// Requires resolving to const only when we are in a const context. Maybe, @@ -929,7 +929,7 @@ impl BoundConstness { pub fn as_str(self) -> &'static str { match self { Self::Const => "const", - Self::Maybe => "~const", + Self::Maybe => "[const]", } } } @@ -938,7 +938,7 @@ impl fmt::Display for BoundConstness { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Const => f.write_str("const"), - Self::Maybe => f.write_str("~const"), + Self::Maybe => f.write_str("[const]"), } } } diff --git a/compiler/rustc_type_ir/src/relate/solver_relating.rs b/compiler/rustc_type_ir/src/relate/solver_relating.rs index e42639c6807..79f6bc5dabb 100644 --- a/compiler/rustc_type_ir/src/relate/solver_relating.rs +++ b/compiler/rustc_type_ir/src/relate/solver_relating.rs @@ -284,12 +284,12 @@ where } // If they have no bound vars, relate normally. - if let Some(a_inner) = a.no_bound_vars() { - if let Some(b_inner) = b.no_bound_vars() { - self.relate(a_inner, b_inner)?; - return Ok(a); - } - }; + if let Some(a_inner) = a.no_bound_vars() + && let Some(b_inner) = b.no_bound_vars() + { + self.relate(a_inner, b_inner)?; + return Ok(a); + } match self.ambient_variance { // Checks whether `for<..> sub <: for<..> sup` holds. diff --git a/compiler/rustc_type_ir/src/search_graph/global_cache.rs b/compiler/rustc_type_ir/src/search_graph/global_cache.rs index 1b99cc820f1..eb56c1af408 100644 --- a/compiler/rustc_type_ir/src/search_graph/global_cache.rs +++ b/compiler/rustc_type_ir/src/search_graph/global_cache.rs @@ -80,31 +80,29 @@ impl<X: Cx> GlobalCache<X> { mut candidate_is_applicable: impl FnMut(&NestedGoals<X>) -> bool, ) -> Option<CacheData<'a, X>> { let entry = self.map.get(&input)?; - if let Some(Success { required_depth, ref nested_goals, ref result }) = entry.success { - if available_depth.cache_entry_is_applicable(required_depth) - && candidate_is_applicable(nested_goals) - { - return Some(CacheData { - result: cx.get_tracked(&result), - required_depth, - encountered_overflow: false, - nested_goals, - }); - } + if let Some(Success { required_depth, ref nested_goals, ref result }) = entry.success + && available_depth.cache_entry_is_applicable(required_depth) + && candidate_is_applicable(nested_goals) + { + return Some(CacheData { + result: cx.get_tracked(&result), + required_depth, + encountered_overflow: false, + nested_goals, + }); } let additional_depth = available_depth.0; if let Some(WithOverflow { nested_goals, result }) = entry.with_overflow.get(&additional_depth) + && candidate_is_applicable(nested_goals) { - if candidate_is_applicable(nested_goals) { - return Some(CacheData { - result: cx.get_tracked(result), - required_depth: additional_depth, - encountered_overflow: true, - nested_goals, - }); - } + return Some(CacheData { + result: cx.get_tracked(result), + required_depth: additional_depth, + encountered_overflow: true, + nested_goals, + }); } None diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index a857da2fcd5..8941360d2d0 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -21,7 +21,7 @@ use std::marker::PhantomData; use derive_where::derive_where; #[cfg(feature = "nightly")] use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; -use tracing::debug; +use tracing::{debug, instrument}; use crate::data_structures::HashMap; @@ -56,7 +56,7 @@ pub trait Cx: Copy { fn evaluation_is_concurrent(&self) -> bool; } -pub trait Delegate { +pub trait Delegate: Sized { type Cx: Cx; /// Whether to use the provisional cache. Set to `false` by a fuzzer when /// validating the search graph. @@ -94,8 +94,8 @@ pub trait Delegate { ) -> bool; fn on_stack_overflow( cx: Self::Cx, - inspect: &mut Self::ProofTreeBuilder, input: <Self::Cx as Cx>::Input, + inspect: &mut Self::ProofTreeBuilder, ) -> <Self::Cx as Cx>::Result; fn on_fixpoint_overflow( cx: Self::Cx, @@ -108,6 +108,13 @@ pub trait Delegate { for_input: <Self::Cx as Cx>::Input, from_result: <Self::Cx as Cx>::Result, ) -> <Self::Cx as Cx>::Result; + + fn compute_goal( + search_graph: &mut SearchGraph<Self>, + cx: Self::Cx, + input: <Self::Cx as Cx>::Input, + inspect: &mut Self::ProofTreeBuilder, + ) -> <Self::Cx as Cx>::Result; } /// In the initial iteration of a cycle, we do not yet have a provisional @@ -589,15 +596,15 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> { /// Probably the most involved method of the whole solver. /// - /// Given some goal which is proven via the `prove_goal` closure, this - /// handles caching, overflow, and coinductive cycles. - pub fn with_new_goal( + /// While goals get computed via `D::compute_goal`, this function handles + /// caching, overflow, and cycles. + #[instrument(level = "debug", skip(self, cx, inspect), ret)] + pub fn evaluate_goal( &mut self, cx: X, input: X::Input, step_kind_from_parent: PathKind, inspect: &mut D::ProofTreeBuilder, - evaluate_goal: impl Fn(&mut Self, X, X::Input, &mut D::ProofTreeBuilder) -> X::Result + Copy, ) -> X::Result { let Some(available_depth) = AvailableDepth::allowed_depth_for_nested::<D>(self.root_depth, &self.stack) @@ -666,7 +673,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> { // must not be added to the global cache. Notably, this is the case for // trait solver cycles participants. let (evaluation_result, dep_node) = - cx.with_cached_task(|| self.evaluate_goal_in_task(cx, input, inspect, evaluate_goal)); + cx.with_cached_task(|| self.evaluate_goal_in_task(cx, input, inspect)); // We've finished computing the goal and have popped it from the stack, // lazily update its parent goal. @@ -736,7 +743,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> { } debug!("encountered stack overflow"); - D::on_stack_overflow(cx, inspect, input) + D::on_stack_overflow(cx, input, inspect) } /// When reevaluating a goal with a changed provisional result, all provisional cache entry @@ -1064,7 +1071,6 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> { cx: X, input: X::Input, inspect: &mut D::ProofTreeBuilder, - evaluate_goal: impl Fn(&mut Self, X, X::Input, &mut D::ProofTreeBuilder) -> X::Result + Copy, ) -> EvaluationResult<X> { // We reset `encountered_overflow` each time we rerun this goal // but need to make sure we currently propagate it to the global @@ -1073,7 +1079,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> { let mut encountered_overflow = false; let mut i = 0; loop { - let result = evaluate_goal(self, cx, input, inspect); + let result = D::compute_goal(self, cx, input, inspect); let stack_entry = self.stack.pop(); encountered_overflow |= stack_entry.encountered_overflow; debug_assert_eq!(stack_entry.input, input); diff --git a/compiler/rustc_type_ir/src/solve/inspect.rs b/compiler/rustc_type_ir/src/solve/inspect.rs index b10641b287d..089695d0475 100644 --- a/compiler/rustc_type_ir/src/solve/inspect.rs +++ b/compiler/rustc_type_ir/src/solve/inspect.rs @@ -23,7 +23,7 @@ use std::hash::Hash; use derive_where::derive_where; use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; -use crate::solve::{CandidateSource, CanonicalInput, Certainty, Goal, GoalSource, QueryResult}; +use crate::solve::{CandidateSource, Certainty, Goal, GoalSource, QueryResult}; use crate::{Canonical, CanonicalVarValues, Interner}; /// Some `data` together with information about how they relate to the input @@ -54,18 +54,12 @@ pub type CanonicalState<I, T> = Canonical<I, State<I, T>>; pub struct GoalEvaluation<I: Interner> { pub uncanonicalized_goal: Goal<I, I::Predicate>, pub orig_values: Vec<I::GenericArg>, - pub evaluation: CanonicalGoalEvaluation<I>, -} - -#[derive_where(PartialEq, Eq, Hash, Debug; I: Interner)] -pub struct CanonicalGoalEvaluation<I: Interner> { - pub goal: CanonicalInput<I>, - pub kind: CanonicalGoalEvaluationKind<I>, + pub kind: GoalEvaluationKind<I>, pub result: QueryResult<I>, } #[derive_where(PartialEq, Eq, Hash, Debug; I: Interner)] -pub enum CanonicalGoalEvaluationKind<I: Interner> { +pub enum GoalEvaluationKind<I: Interner> { Overflow, Evaluation { /// This is always `ProbeKind::Root`. diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index bbbeaa29f84..a6571ef261a 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -79,7 +79,7 @@ pub enum GoalSource { TypeRelating, /// We're proving a where-bound of an impl. ImplWhereBound, - /// Const conditions that need to hold for `~const` alias bounds to hold. + /// Const conditions that need to hold for `[const]` alias bounds to hold. AliasBoundConstCondition, /// Instantiating a higher-ranked goal and re-proving it. InstantiateHigherRanked, diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 9669772d1a6..db6fbefcf05 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -20,6 +20,9 @@ use crate::{self as ty, DebruijnIndex, Interner}; mod closure; /// Specifies how a trait object is represented. +/// +/// This used to have a variant `DynStar`, but that variant has been removed, +/// and it's likely this whole enum will be removed soon. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[cfg_attr( feature = "nightly", @@ -28,13 +31,6 @@ mod closure; pub enum DynKind { /// An unsized `dyn Trait` object Dyn, - /// A sized `dyn* Trait` object - /// - /// These objects are represented as a `(data, vtable)` pair where `data` is a value of some - /// ptr-sized and ptr-aligned dynamically determined type `T` and `vtable` is a pointer to the - /// vtable of `impl T for Trait`. This allows a `dyn*` object to be treated agnostically with - /// respect to whether it points to a `Box<T>`, `Rc<T>`, etc. - DynStar, } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] @@ -371,7 +367,6 @@ impl<I: Interner> fmt::Debug for TyKind<I> { UnsafeBinder(binder) => write!(f, "{:?}", binder), Dynamic(p, r, repr) => match repr { DynKind::Dyn => write!(f, "dyn {p:?} + {r:?}"), - DynKind::DynStar => write!(f, "dyn* {p:?} + {r:?}"), }, Closure(d, s) => f.debug_tuple("Closure").field(d).field(&s).finish(), CoroutineClosure(d, s) => f.debug_tuple("CoroutineClosure").field(d).field(&s).finish(), |
