diff options
Diffstat (limited to 'compiler')
340 files changed, 4525 insertions, 3975 deletions
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/src/ast.rs b/compiler/rustc_ast/src/ast.rs index b2d8881e3f6..ac6daba3901 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::*; @@ -1345,7 +1344,7 @@ impl Expr { } } - /// Returns an expression with (when possible) *one* outter brace removed + /// Returns an expression with (when possible) *one* outer brace removed pub fn maybe_unwrap_block(&self) -> &Expr { if let ExprKind::Block(block, None) = &self.kind && let [stmt] = block.stmts.as_slice() @@ -1391,6 +1390,7 @@ impl Expr { path.clone(), TraitBoundModifiers::NONE, self.span, + Parens::No, ))), _ => None, } @@ -1805,10 +1805,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>), @@ -2066,7 +2073,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, @@ -2129,16 +2136,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'`). @@ -2577,8 +2586,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 @@ -2594,8 +2602,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!(), } } @@ -3360,6 +3367,13 @@ pub struct TraitRef { pub ref_id: NodeId, } +/// Whether enclosing parentheses are present or not. +#[derive(Clone, Encodable, Decodable, Debug)] +pub enum Parens { + Yes, + No, +} + #[derive(Clone, Encodable, Decodable, Debug)] pub struct PolyTraitRef { /// The `'a` in `for<'a> Foo<&'a T>`. @@ -3372,6 +3386,10 @@ pub struct PolyTraitRef { pub trait_ref: TraitRef, pub span: Span, + + /// When `Yes`, the first and last character of `span` are an opening + /// and a closing paren respectively. + pub parens: Parens, } impl PolyTraitRef { @@ -3380,12 +3398,14 @@ impl PolyTraitRef { path: Path, modifiers: TraitBoundModifiers, span: Span, + parens: Parens, ) -> Self { PolyTraitRef { bound_generic_params: generic_params, modifiers, trait_ref: TraitRef { path, ref_id: DUMMY_NODE_ID }, span, + parens, } } } 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/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index ad9e5d1468b..fa7878873e5 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -5,7 +5,7 @@ use std::{ascii, fmt, str}; use rustc_literal_escaper::{ 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}; @@ -116,13 +116,12 @@ impl LitKind { 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(); @@ -137,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 @@ -145,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), }) @@ -167,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}", @@ -181,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/src/visit.rs b/compiler/rustc_ast/src/visit.rs index d0c2b2bf68b..42de5b727c5 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -142,7 +142,7 @@ macro_rules! common_visitor_and_walkers { )? // Methods in this trait have one of three forms, with the last two forms - // only occuring on `MutVisitor`: + // only occurring on `MutVisitor`: // // fn visit_t(&mut self, t: &mut T); // common // fn flat_map_t(&mut self, t: T) -> SmallVec<[T; 1]>; // rare @@ -1142,7 +1142,7 @@ macro_rules! common_visitor_and_walkers { vis: &mut V, p: &$($lt)? $($mut)? PolyTraitRef, ) -> V::Result { - let PolyTraitRef { bound_generic_params, modifiers, trait_ref, span } = p; + let PolyTraitRef { bound_generic_params, modifiers, trait_ref, span, parens: _ } = p; try_visit!(visit_modifiers(vis, modifiers)); try_visit!(visit_generic_params(vis, bound_generic_params)); try_visit!(vis.visit_trait_ref(trait_ref)); diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index c2140514e31..8747e624a4a 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -144,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) => { @@ -421,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) => { @@ -433,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 { @@ -2141,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)) } @@ -2161,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/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 8acb5105773..bdcb750ba26 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -2,6 +2,7 @@ use rustc_abi::ExternAbi; use rustc_ast::ptr::P; use rustc_ast::visit::AssocCtxt; use rustc_ast::*; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err}; use rustc_hir::def::{DefKind, PerNS, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; @@ -1621,7 +1622,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let safety = self.lower_safety(h.safety, default_safety); // Treat safe `#[target_feature]` functions as unsafe, but also remember that we did so. - let safety = if attrs.iter().any(|attr| attr.has_name(sym::target_feature)) + let safety = if find_attr!(attrs, AttributeKind::TargetFeature { .. }) && safety.is_safe() && !self.tcx.sess.target.is_like_wasm { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 26d7c0cd6d3..d14e27982ef 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1209,6 +1209,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { modifiers: TraitBoundModifiers::NONE, trait_ref: TraitRef { path: path.clone(), ref_id: t.id }, span: t.span, + parens: ast::Parens::No, }, itctx, ); 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_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 4290f7b7ede..d58c140c696 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -1,6 +1,6 @@ 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 + .suggestion = remove the `{$coroutine_kind_str}` keyword from this definition ast_passes_abi_custom_safe_foreign_function = foreign functions with the "custom" ABI cannot be safe diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 1ec56868f37..5d8ee07178d 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -469,7 +469,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { "`if let` guards are experimental", "you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`" ); - gate_all!(let_chains, "`let` expressions in this position are unstable"); gate_all!( async_trait_bounds, "`async` trait bounds are unstable", @@ -505,7 +504,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 7651e8365a2..8a2cb64b2a0 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -469,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 60a4f289306..61ef31b8f9f 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -198,10 +198,10 @@ pub enum AttributeKind { Align { align: Align, span: Span }, /// Represents `#[rustc_allow_const_fn_unstable]`. - AllowConstFnUnstable(ThinVec<Symbol>), + AllowConstFnUnstable(ThinVec<Symbol>, Span), /// Represents `#[allow_internal_unstable]`. - AllowInternalUnstable(ThinVec<(Symbol, Span)>), + AllowInternalUnstable(ThinVec<(Symbol, Span)>, Span), /// Represents `#[rustc_as_ptr]` (used by the `dangling_pointers_from_temporaries` lint). AsPtr(Span), @@ -253,6 +253,12 @@ pub enum AttributeKind { /// 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), @@ -284,6 +290,15 @@ 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 }, @@ -294,6 +309,9 @@ pub enum AttributeKind { span: Span, }, + /// Represents `#[target_feature(enable = "...")]` + TargetFeature(ThinVec<(Symbol, Span)>, Span), + /// Represents `#[track_caller]` TrackCaller(Span), diff --git a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs index 64bcf1fe6cc..a1b1d670cfe 100644 --- a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs +++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs @@ -24,11 +24,13 @@ impl AttributeKind { 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, @@ -36,7 +38,11 @@ impl AttributeKind { NoMangle(..) => No, Optimize(..) => No, PubTransparent(..) => Yes, + RustcLayoutScalarValidRangeEnd(..) => Yes, + RustcLayoutScalarValidRangeStart(..) => Yes, + RustcObjectLifetimeDefault => No, SkipDuringMethodDispatch { .. } => No, + TargetFeature(..) => 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 86c73f0d9a0..8f8ce575a18 100644 --- a/compiler/rustc_attr_data_structures/src/lib.rs +++ b/compiler/rustc_attr_data_structures/src/lib.rs @@ -49,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 39652335f55..9ad46a83f50 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -99,6 +99,8 @@ attr_parsing_non_ident_feature = 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/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index 21b01a8d071..1c51c3eee4e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -13,7 +13,8 @@ pub(crate) struct AllowInternalUnstableParser; impl<S: Stage> CombineAttributeParser<S> for AllowInternalUnstableParser { const PATH: &[Symbol] = &[sym::allow_internal_unstable]; type Item = (Symbol, Span); - const CONVERT: ConvertFn<Self::Item> = AttributeKind::AllowInternalUnstable; + const CONVERT: ConvertFn<Self::Item> = + |items, span| AttributeKind::AllowInternalUnstable(items, span); const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ..."); fn extend<'c>( @@ -30,7 +31,8 @@ pub(crate) struct AllowConstFnUnstableParser; impl<S: Stage> CombineAttributeParser<S> for AllowConstFnUnstableParser { const PATH: &[Symbol] = &[sym::rustc_allow_const_fn_unstable]; type Item = Symbol; - const CONVERT: ConvertFn<Self::Item> = AttributeKind::AllowConstFnUnstable; + const CONVERT: ConvertFn<Self::Item> = + |items, first_span| AttributeKind::AllowConstFnUnstable(items, first_span); const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ..."); fn extend<'c>( diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index f4d23012af7..a8d9229cbc3 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -14,7 +14,7 @@ use crate::{fluent_generated, parse_version}; /// Emitter of a builtin lint from `cfg_matches`. /// -/// Used to support emiting a lint (currently on check-cfg), either: +/// Used to support emitting a lint (currently on check-cfg), either: /// - as an early buffered lint (in `rustc`) /// - or has a "normal" lint from HIR (in `rustdoc`) pub trait CfgMatchesLintEmitter { diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 7c412d4fa89..13f560dff38 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -3,7 +3,10 @@ use rustc_feature::{AttributeTemplate, template}; use rustc_session::parse::feature_err; use rustc_span::{Span, Symbol, sym}; -use super::{AcceptMapping, AttributeOrder, AttributeParser, OnDuplicate, SingleAttributeParser}; +use super::{ + AcceptMapping, AttributeOrder, AttributeParser, CombineAttributeParser, ConvertFn, + NoArgsAttributeParser, OnDuplicate, SingleAttributeParser, +}; use crate::context::{AcceptContext, FinalizeContext, Stage}; use crate::parser::ArgParser; use crate::session_diagnostics::{NakedFunctionIncompatibleAttribute, NullOnExport}; @@ -43,20 +46,10 @@ impl<S: Stage> SingleAttributeParser<S> for OptimizeParser { pub(crate) struct ColdParser; -impl<S: Stage> SingleAttributeParser<S> for ColdParser { +impl<S: Stage> NoArgsAttributeParser<S> for ColdParser { 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 let Err(span) = args.no_args() { - cx.expected_no_args(span); - return None; - } - - Some(AttributeKind::Cold(cx.attr_span)) - } + const CREATE: fn(Span) -> AttributeKind = AttributeKind::Cold; } pub(crate) struct ExportNameParser; @@ -194,39 +187,17 @@ impl<S: Stage> AttributeParser<S> for NakedParser { } pub(crate) struct TrackCallerParser; - -impl<S: Stage> SingleAttributeParser<S> for TrackCallerParser { +impl<S: Stage> NoArgsAttributeParser<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)) - } + const CREATE: fn(Span) -> AttributeKind = AttributeKind::TrackCaller; } pub(crate) struct NoMangleParser; - -impl<S: Stage> SingleAttributeParser<S> for NoMangleParser { - const PATH: &[rustc_span::Symbol] = &[sym::no_mangle]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast; +impl<S: Stage> NoArgsAttributeParser<S> for NoMangleParser { + const PATH: &[Symbol] = &[sym::no_mangle]; 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::NoMangle(cx.attr_span)) - } + const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoMangle; } #[derive(Default)] @@ -309,3 +280,53 @@ impl<S: Stage> AttributeParser<S> for UsedParser { }) } } + +pub(crate) struct TargetFeatureParser; + +impl<S: Stage> CombineAttributeParser<S> for TargetFeatureParser { + type Item = (Symbol, Span); + const PATH: &[Symbol] = &[sym::target_feature]; + const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature(items, span); + const TEMPLATE: AttributeTemplate = template!(List: "enable = \"feat1, feat2\""); + + fn extend<'c>( + cx: &'c mut AcceptContext<'_, '_, S>, + args: &'c ArgParser<'_>, + ) -> impl IntoIterator<Item = Self::Item> + 'c { + let mut features = Vec::new(); + let ArgParser::List(list) = args else { + cx.expected_list(cx.attr_span); + return features; + }; + for item in list.mixed() { + let Some(name_value) = item.meta_item() else { + cx.expected_name_value(item.span(), Some(sym::enable)); + return features; + }; + + // Validate name + let Some(name) = name_value.path().word_sym() else { + cx.expected_name_value(name_value.path().span(), Some(sym::enable)); + return features; + }; + if name != sym::enable { + cx.expected_name_value(name_value.path().span(), Some(sym::enable)); + return features; + } + + // Use value + let Some(name_value) = name_value.args().name_value() else { + cx.expected_name_value(item.span(), Some(sym::enable)); + return features; + }; + 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 features; + }; + for feature in value_str.as_str().split(",") { + features.push((Symbol::intern(feature), item.span())); + } + } + features + } +} 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 1c8fc5079da..5437803d781 100644 --- a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs +++ b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs @@ -1,38 +1,19 @@ use rustc_attr_data_structures::AttributeKind; -use rustc_feature::{AttributeTemplate, template}; -use rustc_span::{Symbol, sym}; +use rustc_span::{Span, Symbol, sym}; -use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; -use crate::context::{AcceptContext, Stage}; -use crate::parser::ArgParser; +use crate::attributes::{NoArgsAttributeParser, OnDuplicate}; +use crate::context::Stage; pub(crate) struct AsPtrParser; - -impl<S: Stage> SingleAttributeParser<S> for AsPtrParser { +impl<S: Stage> NoArgsAttributeParser<S> for AsPtrParser { const PATH: &[Symbol] = &[sym::rustc_as_ptr]; - 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); - } - Some(AttributeKind::AsPtr(cx.attr_span)) - } + const CREATE: fn(Span) -> AttributeKind = AttributeKind::AsPtr; } pub(crate) struct PubTransparentParser; -impl<S: Stage> SingleAttributeParser<S> for PubTransparentParser { +impl<S: Stage> NoArgsAttributeParser<S> for PubTransparentParser { const PATH: &[Symbol] = &[sym::rustc_pub_transparent]; - 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); - } - Some(AttributeKind::PubTransparent(cx.attr_span)) - } + const CREATE: fn(Span) -> AttributeKind = AttributeKind::PubTransparent; } diff --git a/compiler/rustc_attr_parsing/src/attributes/loop_match.rs b/compiler/rustc_attr_parsing/src/attributes/loop_match.rs index f6c7ac5e3a3..80808b90dc6 100644 --- a/compiler/rustc_attr_parsing/src/attributes/loop_match.rs +++ b/compiler/rustc_attr_parsing/src/attributes/loop_match.rs @@ -1,31 +1,19 @@ use rustc_attr_data_structures::AttributeKind; -use rustc_feature::{AttributeTemplate, template}; -use rustc_span::{Symbol, sym}; +use rustc_span::{Span, Symbol, sym}; -use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; -use crate::context::{AcceptContext, Stage}; -use crate::parser::ArgParser; +use crate::attributes::{NoArgsAttributeParser, OnDuplicate}; +use crate::context::Stage; pub(crate) struct LoopMatchParser; -impl<S: Stage> SingleAttributeParser<S> for LoopMatchParser { +impl<S: Stage> NoArgsAttributeParser<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)) - } + const CREATE: fn(Span) -> AttributeKind = AttributeKind::LoopMatch; } pub(crate) struct ConstContinueParser; -impl<S: Stage> SingleAttributeParser<S> for ConstContinueParser { +impl<S: Stage> NoArgsAttributeParser<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)) - } + const CREATE: fn(Span) -> AttributeKind = AttributeKind::ConstContinue; } diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index d407669cb41..0215504b52b 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -17,7 +17,7 @@ use std::marker::PhantomData; use rustc_attr_data_structures::AttributeKind; -use rustc_feature::AttributeTemplate; +use rustc_feature::{AttributeTemplate, template}; use rustc_span::{Span, Symbol}; use thin_vec::ThinVec; @@ -31,10 +31,12 @@ 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; @@ -227,7 +229,42 @@ pub(crate) enum AttributeOrder { KeepLast, } -type ConvertFn<E> = fn(ThinVec<E>) -> AttributeKind; +/// An even simpler version of [`SingleAttributeParser`]: +/// now automatically check that there are no arguments provided to the attribute. +/// +/// [`WithoutArgs<T> where T: NoArgsAttributeParser`](WithoutArgs) implements [`SingleAttributeParser`]. +// +pub(crate) trait NoArgsAttributeParser<S: Stage>: 'static { + const PATH: &[Symbol]; + const ON_DUPLICATE: OnDuplicate<S>; + + /// Create the [`AttributeKind`] given attribute's [`Span`]. + const CREATE: fn(Span) -> AttributeKind; +} + +pub(crate) struct WithoutArgs<T: NoArgsAttributeParser<S>, S: Stage>(PhantomData<(S, T)>); + +impl<T: NoArgsAttributeParser<S>, S: Stage> Default for WithoutArgs<T, S> { + fn default() -> Self { + Self(Default::default()) + } +} + +impl<T: NoArgsAttributeParser<S>, S: Stage> SingleAttributeParser<S> for WithoutArgs<T, S> { + const PATH: &[Symbol] = T::PATH; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast; + const ON_DUPLICATE: OnDuplicate<S> = T::ON_DUPLICATE; + 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); + } + Some(T::CREATE(cx.attr_span)) + } +} + +type ConvertFn<E> = fn(ThinVec<E>, Span) -> AttributeKind; /// Alternative to [`AttributeParser`] that automatically handles state management. /// If multiple attributes appear on an element, combines the values of each into a @@ -258,14 +295,21 @@ pub(crate) trait CombineAttributeParser<S: Stage>: 'static { /// Use in combination with [`CombineAttributeParser`]. /// `Combine<T: CombineAttributeParser>` implements [`AttributeParser`]. -pub(crate) struct Combine<T: CombineAttributeParser<S>, S: Stage>( - PhantomData<(S, T)>, - ThinVec<<T as CombineAttributeParser<S>>::Item>, -); +pub(crate) struct Combine<T: CombineAttributeParser<S>, S: Stage> { + phantom: PhantomData<(S, T)>, + /// A list of all items produced by parsing attributes so far. One attribute can produce any amount of items. + items: ThinVec<<T as CombineAttributeParser<S>>::Item>, + /// The full span of the first attribute that was encountered. + first_span: Option<Span>, +} impl<T: CombineAttributeParser<S>, S: Stage> Default for Combine<T, S> { fn default() -> Self { - Self(Default::default(), Default::default()) + Self { + phantom: Default::default(), + items: Default::default(), + first_span: Default::default(), + } } } @@ -273,10 +317,18 @@ impl<T: CombineAttributeParser<S>, S: Stage> AttributeParser<S> for Combine<T, S const ATTRIBUTES: AcceptMapping<Self, S> = &[( T::PATH, <T as CombineAttributeParser<S>>::TEMPLATE, - |group: &mut Combine<T, S>, cx, args| group.1.extend(T::extend(cx, args)), + |group: &mut Combine<T, S>, cx, args| { + // Keep track of the span of the first attribute, for diagnostics + group.first_span.get_or_insert(cx.attr_span); + group.items.extend(T::extend(cx, args)) + }, )]; fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { - if self.1.is_empty() { None } else { Some(T::CONVERT(self.1)) } + if let Some(first_span) = self.first_span { + Some(T::CONVERT(self.items, first_span)) + } else { + None + } } } 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/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 4aa27043e98..1c070dc2685 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -23,7 +23,7 @@ pub(crate) struct ReprParser; impl<S: Stage> CombineAttributeParser<S> for ReprParser { type Item = (ReprAttr, Span); const PATH: &[Symbol] = &[sym::repr]; - const CONVERT: ConvertFn<Self::Item> = AttributeKind::Repr; + const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::Repr(items); // FIXME(jdonszelmann): never used const TEMPLATE: AttributeTemplate = template!(List: "C | Rust | align(...) | packed(...) | <integer type> | transparent"); 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 54f50445fbd..74fdff5d2e1 100644 --- a/compiler/rustc_attr_parsing/src/attributes/semantics.rs +++ b/compiler/rustc_attr_parsing/src/attributes/semantics.rs @@ -1,22 +1,12 @@ use rustc_attr_data_structures::AttributeKind; -use rustc_feature::{AttributeTemplate, template}; -use rustc_span::{Symbol, sym}; +use rustc_span::{Span, Symbol, sym}; -use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; -use crate::context::{AcceptContext, Stage}; -use crate::parser::ArgParser; +use crate::attributes::{NoArgsAttributeParser, OnDuplicate}; +use crate::context::Stage; pub(crate) struct MayDangleParser; -impl<S: Stage> SingleAttributeParser<S> for MayDangleParser { +impl<S: Stage> NoArgsAttributeParser<S> for MayDangleParser { const PATH: &[Symbol] = &[sym::may_dangle]; - 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> { - if let Err(span) = args.no_args() { - cx.expected_no_args(span); - } - Some(AttributeKind::MayDangle(cx.attr_span)) - } + const CREATE: fn(span: Span) -> AttributeKind = AttributeKind::MayDangle; } diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index 37104855623..6bccd0042a8 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -5,11 +5,12 @@ use rustc_attr_data_structures::{ StableSince, UnstableReason, VERSION_PLACEHOLDER, }; use rustc_errors::ErrorGuaranteed; -use rustc_feature::{AttributeTemplate, template}; +use rustc_feature::template; use rustc_span::{Ident, Span, Symbol, sym}; use super::util::parse_version; -use super::{AcceptMapping, AttributeOrder, AttributeParser, OnDuplicate, SingleAttributeParser}; +use super::{AcceptMapping, AttributeParser, OnDuplicate}; +use crate::attributes::NoArgsAttributeParser; use crate::context::{AcceptContext, FinalizeContext, Stage}; use crate::parser::{ArgParser, MetaItemParser}; use crate::session_diagnostics::{self, UnsupportedLiteralReason}; @@ -132,19 +133,10 @@ impl<S: Stage> AttributeParser<S> for BodyStabilityParser { } pub(crate) struct ConstStabilityIndirectParser; -// FIXME(jdonszelmann): single word attribute group when we have these -impl<S: Stage> SingleAttributeParser<S> for ConstStabilityIndirectParser { +impl<S: Stage> NoArgsAttributeParser<S> for ConstStabilityIndirectParser { const PATH: &[Symbol] = &[sym::rustc_const_stable_indirect]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Ignore; - 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); - } - Some(AttributeKind::ConstStabilityIndirect) - } + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ConstStabilityIndirect; } #[derive(Default)] diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 71bb86ca3d3..bf8b1438df7 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -16,23 +16,28 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser}; use crate::attributes::codegen_attrs::{ - ColdParser, ExportNameParser, NakedParser, NoMangleParser, OptimizeParser, TrackCallerParser, - UsedParser, + ColdParser, ExportNameParser, NakedParser, NoMangleParser, OptimizeParser, TargetFeatureParser, + 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::attributes::{AttributeParser as _, Combine, Single, WithoutArgs}; use crate::parser::{ArgParser, MetaItemParser, PathParser}; use crate::session_diagnostics::{AttributeParseError, AttributeParseErrorReason, UnknownMetaItem}; @@ -53,6 +58,7 @@ macro_rules! attribute_parsers { use super::*; type Combine<T> = super::Combine<T, Early>; type Single<T> = super::Single<T, Early>; + type WithoutArgs<T> = super::WithoutArgs<T, Early>; attribute_parsers!(@[Early] pub(crate) static $name = [$($names),*];); } @@ -60,6 +66,7 @@ macro_rules! attribute_parsers { use super::*; type Combine<T> = super::Combine<T, Late>; type Single<T> = super::Single<T, Late>; + type WithoutArgs<T> = super::WithoutArgs<T, Late>; attribute_parsers!(@[Late] pub(crate) static $name = [$($names),*];); } @@ -111,26 +118,32 @@ attribute_parsers!( Combine<AllowConstFnUnstableParser>, Combine<AllowInternalUnstableParser>, Combine<ReprParser>, + Combine<TargetFeatureParser>, // tidy-alphabetical-end // tidy-alphabetical-start - Single<AsPtrParser>, - Single<ColdParser>, - Single<ConstContinueParser>, - Single<ConstStabilityIndirectParser>, Single<DeprecationParser>, Single<ExportNameParser>, Single<InlineParser>, - Single<LoopMatchParser>, - Single<MayDangleParser>, + Single<LinkNameParser>, + Single<LinkSectionParser>, Single<MustUseParser>, - Single<NoMangleParser>, Single<OptimizeParser>, - Single<PubTransparentParser>, Single<RustcForceInlineParser>, + Single<RustcLayoutScalarValidRangeEnd>, + Single<RustcLayoutScalarValidRangeStart>, + Single<RustcObjectLifetimeDefaultParser>, Single<SkipDuringMethodDispatchParser>, - Single<TrackCallerParser>, Single<TransparencyParser>, + Single<WithoutArgs<AsPtrParser>>, + Single<WithoutArgs<ColdParser>>, + Single<WithoutArgs<ConstContinueParser>>, + Single<WithoutArgs<ConstStabilityIndirectParser>>, + Single<WithoutArgs<LoopMatchParser>>, + Single<WithoutArgs<MayDangleParser>>, + Single<WithoutArgs<NoMangleParser>>, + Single<WithoutArgs<PubTransparentParser>>, + Single<WithoutArgs<TrackCallerParser>>, // tidy-alphabetical-end ]; ); @@ -177,7 +190,7 @@ impl Stage for Late { } } -/// used when parsing attributes for miscelaneous things *before* ast lowering +/// used when parsing attributes for miscellaneous things *before* ast lowering pub struct Early; /// used when parsing attributes during ast lowering pub struct Late; @@ -271,6 +284,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, diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 7cfce579979..6145f1e1d3e 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -453,6 +453,13 @@ pub(crate) struct NullOnExport { } #[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] @@ -503,6 +510,7 @@ pub(crate) struct NakedFunctionIncompatibleAttribute { pub(crate) enum AttributeParseErrorReason { ExpectedNoArgs, ExpectedStringLiteral { byte_string: Option<Span> }, + ExpectedIntegerLiteral, ExpectedAtLeastOneArgument, ExpectedSingleArgument, ExpectedList, @@ -543,6 +551,9 @@ 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); @@ -566,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/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index fd8a2a6bc35..7c69baba62e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -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/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index e37b5a33af8..05bcd9f862e 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -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; @@ -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/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index df1b1eb60e1..c7844778332 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -562,7 +562,7 @@ mod llvm_enzyme { /// so instead we manually build something that should pass the type checker. /// We also add a inline_asm line, as one more barrier for rustc to prevent inlining /// or const propagation. inline_asm will also triggers an Enzyme crash if due to another - /// bug would ever try to accidentially differentiate this placeholder function body. + /// bug would ever try to accidentally differentiate this placeholder function body. /// Finally, we also add back_box usages of all input arguments, to prevent rustc /// from optimizing any arguments away. fn gen_enzyme_body( @@ -606,7 +606,7 @@ mod llvm_enzyme { return body; } - // Everything from here onwards just tries to fullfil the return type. Fun! + // Everything from here onwards just tries to fulfil the return type. Fun! // having an active-only return means we'll drop the original return type. // So that can be treated identical to not having one in the first place. 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/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 9b6dea21438..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)] 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/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/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 3a62cd52a9d..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) => { 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 68ff0b622c8..6281089ee24 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -496,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() { @@ -527,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 7852aebe0c2..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,7 +1584,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { (value1, value2) } - fn filter_landing_pad(&mut self, pers_fn: 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); } 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 ac8b7f4ea48..2e508813fc3 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs @@ -780,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 }), }; @@ -827,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/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..776658b9cca 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -107,7 +107,7 @@ fn call_simple_intrinsic<'ll, 'tcx>( sym::minimumf32 => ("llvm.minimum", &[bx.type_f32()]), sym::minimumf64 => ("llvm.minimum", &[bx.type_f64()]), // There are issues on x86_64 and aarch64 with the f128 variant, - // let's instead use the instrinsic fallback body. + // let's instead use the intrinsic fallback body. // sym::minimumf128 => ("llvm.minimum", &[cx.type_f128()]), sym::maxnumf16 => ("llvm.maxnum", &[bx.type_f16()]), sym::maxnumf32 => ("llvm.maxnum", &[bx.type_f32()]), @@ -118,7 +118,7 @@ fn call_simple_intrinsic<'ll, 'tcx>( sym::maximumf32 => ("llvm.maximum", &[bx.type_f32()]), sym::maximumf64 => ("llvm.maximum", &[bx.type_f64()]), // There are issues on x86_64 and aarch64 with the f128 variant, - // let's instead use the instrinsic fallback body. + // let's instead use the intrinsic fallback body. // sym::maximumf128 => ("llvm.maximum", &[cx.type_f128()]), sym::copysignf16 => ("llvm.copysign", &[bx.type_f16()]), sym::copysignf32 => ("llvm.copysign", &[bx.type_f32()]), @@ -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 b94716b89d6..7b00b2da6ba 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs @@ -40,7 +40,7 @@ unsafe extern "C" { pub(crate) fn LLVMDumpValue(V: &Value); pub(crate) fn LLVMGetFunctionCallConv(F: &Value) -> c_uint; pub(crate) fn LLVMGetReturnType(T: &Type) -> &Type; - pub(crate) fn LLVMGetParams(Fnc: &Value, parms: *mut &Value); + pub(crate) fn LLVMGetParams(Fnc: &Value, params: *mut &Value); pub(crate) fn LLVMGetNamedFunction(M: &Module, Name: *const c_char) -> Option<&Value>; } 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_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index 236568590be..4fe4c9bcbf2 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -861,7 +861,7 @@ fn emit_xtensa_va_arg<'ll, 'tcx>( // On big-endian, for values smaller than the slot size we'd have to align the read to the end // of the slot rather than the start. While the ISA and GCC support big-endian, all the Xtensa - // targets supported by rustc are litte-endian so don't worry about it. + // targets supported by rustc are little-endian so don't worry about it. // if from_regsave { // unsafe { *regsave_value_ptr } diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 84d63819343..63e9005da45 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -62,6 +62,10 @@ codegen_ssa_failed_to_get_layout = failed to get layout for {$ty}: {$err} codegen_ssa_failed_to_write = failed to write {$path}: {$error} +codegen_ssa_feature_not_valid = the feature named `{$feature}` is not valid for this target + .label = `{$feature}` is not valid for this target + .help = consider removing the leading `+` in the feature name + codegen_ssa_field_associated_value_expected = associated value expected for `{$name}` codegen_ssa_forbidden_ctarget_feature = @@ -289,7 +293,7 @@ codegen_ssa_thorin_missing_referenced_unit = unit {$unit} referenced by executab codegen_ssa_thorin_missing_required_section = input object missing required section `{$section}` -codegen_ssa_thorin_mixed_input_encodings = input objects haved mixed encodings +codegen_ssa_thorin_mixed_input_encodings = input objects have mixed encodings codegen_ssa_thorin_multiple_debug_info_section = multiple `.debug_info.dwo` sections diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 4a2425967e4..343cb0eeca9 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -2767,7 +2767,7 @@ fn add_upstream_rust_crates( if sess.target.is_like_aix { // Unlike ELF linkers, AIX doesn't feature `DT_SONAME` to override - // the dependency name when outputing a shared library. Thus, `ld` will + // the dependency name when outputting a shared library. Thus, `ld` will // use the full path to shared libraries as the dependency if passed it // by default unless `noipath` is passed. // https://www.ibm.com/docs/en/aix/7.3?topic=l-ld-command. @@ -3051,7 +3051,7 @@ fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavo // Supported architecture names can be found in the source: // https://github.com/apple-oss-distributions/ld64/blob/ld64-951.9/src/abstraction/MachOFileAbstraction.hpp#L578-L648 // - // Intentially verbose to ensure that the list always matches correctly + // Intentionally verbose to ensure that the list always matches correctly // with the list in the source above. let ld64_arch = match llvm_arch { "armv7k" => "armv7k", @@ -3118,7 +3118,7 @@ fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavo // We do not currently know the actual SDK version though, so we have a few options: // 1. Use the minimum version supported by rustc. // 2. Use the same as the deployment target. - // 3. Use an arbitary recent version. + // 3. Use an arbitrary recent version. // 4. Omit the version. // // The first option is too low / too conservative, and means that users will not get the diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index fba84dec097..1896f63bd2d 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -1794,7 +1794,10 @@ 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); } } @@ -1870,8 +1873,13 @@ 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(); } } diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index d091c46d9c1..bf38c02e908 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -301,7 +301,7 @@ pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 { "n32" if !is_32bit => e_flags |= elf::EF_MIPS_ABI2, "n64" if !is_32bit => {} "" if is_32bit => e_flags |= elf::EF_MIPS_ABI_O32, - "" => sess.dcx().fatal("LLVM ABI must be specifed for 64-bit MIPS targets"), + "" => sess.dcx().fatal("LLVM ABI must be specified for 64-bit MIPS targets"), s if is_32bit => { sess.dcx().fatal(format!("invalid LLVM ABI `{}` for 32-bit MIPS target", s)) } diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 75f7a463556..2f5eca2d6b2 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -168,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)] { @@ -306,6 +306,22 @@ fn exported_symbols_provider_local<'tcx>( )); } + // 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; @@ -474,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) => { @@ -496,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(); @@ -554,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; 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 b06cfd1e473..102d4ea2fa6 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -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>>( diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index acdda32d58a..2713ec07f97 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -1,6 +1,6 @@ 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::{ @@ -123,6 +123,10 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } 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; @@ -137,6 +141,49 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { }); } } + AttributeKind::TargetFeature(features, attr_span) => { + 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"); + continue; + }; + let safe_target_features = + matches!(sig.header.safety, hir::HeaderSafety::SafeTargetFeatures); + codegen_fn_attrs.safe_target_features = safe_target_features; + if safe_target_features { + if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc { + // The `#[target_feature]` attribute is allowed on + // WebAssembly targets on all functions. Prior to stabilizing + // the `target_feature_11` feature, `#[target_feature]` was + // only permitted on unsafe functions because on most targets + // execution of instructions that are not supported is + // considered undefined behavior. For WebAssembly which is a + // 100% safe target at execution time it's not possible to + // execute undefined instructions, and even if a future + // feature was added in some form for this it would be a + // deterministic trap. There is no undefined behavior when + // executing WebAssembly so `#[target_feature]` is allowed + // on safe functions (but again, only for WebAssembly) + // + // Note that this is also allowed if `actually_rustdoc` so + // if a target is documenting some wasm-specific code then + // it's not spuriously denied. + // + // Now that `#[target_feature]` is permitted on safe functions, + // this exception must still exist for allowing the attribute on + // `main`, `start`, and other functions that are not usually + // allowed. + } else { + check_target_feature_trait_unsafe(tcx, did, *attr_span); + } + } + from_target_feature_attr( + tcx, + did, + features, + rust_target_features, + &mut codegen_fn_attrs.target_features, + ); + } AttributeKind::TrackCaller(attr_span) => { let is_closure = tcx.is_closure_like(did.to_def_id()); @@ -186,49 +233,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL } sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL, - 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"); - continue; - }; - let safe_target_features = - matches!(sig.header.safety, hir::HeaderSafety::SafeTargetFeatures); - codegen_fn_attrs.safe_target_features = safe_target_features; - if safe_target_features { - if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc { - // The `#[target_feature]` attribute is allowed on - // WebAssembly targets on all functions. Prior to stabilizing - // the `target_feature_11` feature, `#[target_feature]` was - // only permitted on unsafe functions because on most targets - // execution of instructions that are not supported is - // considered undefined behavior. For WebAssembly which is a - // 100% safe target at execution time it's not possible to - // execute undefined instructions, and even if a future - // feature was added in some form for this it would be a - // deterministic trap. There is no undefined behavior when - // executing WebAssembly so `#[target_feature]` is allowed - // on safe functions (but again, only for WebAssembly) - // - // Note that this is also allowed if `actually_rustdoc` so - // if a target is documenting some wasm-specific code then - // it's not spuriously denied. - // - // Now that `#[target_feature]` is permitted on safe functions, - // this exception must still exist for allowing the attribute on - // `main`, `start`, and other functions that are not usually - // allowed. - } else { - check_target_feature_trait_unsafe(tcx, did, attr.span()); - } - } - from_target_feature_attr( - tcx, - did, - attr, - rust_target_features, - &mut codegen_fn_attrs.target_features, - ); - } sym::linkage => { if let Some(val) = attr.value_str() { let linkage = Some(linkage_by_name(tcx, did, val.as_str())); @@ -252,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) { @@ -402,6 +395,9 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { 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)) @@ -540,10 +536,10 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { .map(|features| (features.name.as_str(), true)) .collect(), ) { - let span = tcx - .get_attrs(did, sym::target_feature) - .next() - .map_or_else(|| tcx.def_span(did), |a| a.span()); + let span = + find_attr!(tcx.get_all_attrs(did), AttributeKind::TargetFeature(_, span) => *span) + .unwrap_or_else(|| tcx.def_span(did)); + tcx.dcx() .create_err(errors::TargetFeatureDisableOrEnable { features, @@ -556,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> { @@ -734,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 1950a35b364..086c069745c 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -1292,3 +1292,14 @@ pub(crate) struct NoMangleNameless { pub span: Span, pub definition: String, } + +#[derive(Diagnostic)] +#[diag(codegen_ssa_feature_not_valid)] +pub(crate) struct FeatureNotValid<'a> { + pub feature: &'a str, + #[primary_span] + #[label] + pub span: Span, + #[help] + pub plus_hint: bool, +} 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 db5ac6a514f..60cf4e28b5a 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 { + if from_scalar == to_scalar && from_backend_ty == to_backend_ty { return imm; } @@ -1142,13 +1136,7 @@ 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(_)) => { - if from_backend_ty == to_backend_ty { - imm - } else { - bx.bitcast(imm, to_backend_ty) - } - } + (Int(..) | Float(_), Int(..) | Float(_)) => 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/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 67ac619091b..53df99993f0 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -1,8 +1,6 @@ use rustc_attr_data_structures::InstructionSetAttr; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_data_structures::unord::{UnordMap, UnordSet}; -use rustc_errors::Applicability; -use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_middle::middle::codegen_fn_attrs::TargetFeature; @@ -12,110 +10,85 @@ use rustc_session::Session; use rustc_session::lint::builtin::AARCH64_SOFTFLOAT_NEON; use rustc_session::parse::feature_err; use rustc_span::{Span, Symbol, sym}; -use rustc_target::target_features::{self, RUSTC_SPECIFIC_FEATURES, Stability}; +use rustc_target::target_features::{RUSTC_SPECIFIC_FEATURES, Stability}; use smallvec::SmallVec; -use crate::errors; +use crate::errors::FeatureNotValid; +use crate::{errors, target_features}; /// Compute the enabled target features from the `#[target_feature]` function attribute. /// Enabled target features are added to `target_features`. pub(crate) fn from_target_feature_attr( tcx: TyCtxt<'_>, did: LocalDefId, - attr: &hir::Attribute, + features: &[(Symbol, Span)], rust_target_features: &UnordMap<String, target_features::Stability>, target_features: &mut Vec<TargetFeature>, ) { - let Some(list) = attr.meta_item_list() else { return }; - let bad_item = |span| { - let msg = "malformed `target_feature` attribute input"; - let code = "enable = \"..\""; - tcx.dcx() - .struct_span_err(span, msg) - .with_span_suggestion(span, "must be of the form", code, Applicability::HasPlaceholders) - .emit(); - }; let rust_features = tcx.features(); let abi_feature_constraints = tcx.sess.target.abi_required_features(); - for item in list { - // Only `enable = ...` is accepted in the meta-item list. - if !item.has_name(sym::enable) { - bad_item(item.span()); - continue; - } - - // Must be of the form `enable = "..."` (a string). - let Some(value) = item.value_str() else { - bad_item(item.span()); + for &(feature, feature_span) in features { + let feature_str = feature.as_str(); + let Some(stability) = rust_target_features.get(feature_str) else { + let plus_hint = feature_str + .strip_prefix('+') + .is_some_and(|stripped| rust_target_features.contains_key(stripped)); + tcx.dcx().emit_err(FeatureNotValid { + feature: feature_str, + span: feature_span, + plus_hint, + }); continue; }; - // We allow comma separation to enable multiple features. - for feature in value.as_str().split(',') { - let Some(stability) = rust_target_features.get(feature) else { - let msg = format!("the feature named `{feature}` is not valid for this target"); - let mut err = tcx.dcx().struct_span_err(item.span(), msg); - err.span_label(item.span(), format!("`{feature}` is not valid for this target")); - if let Some(stripped) = feature.strip_prefix('+') { - let valid = rust_target_features.contains_key(stripped); - if valid { - err.help("consider removing the leading `+` in the feature name"); - } - } - err.emit(); - continue; - }; - - // Only allow target features whose feature gates have been enabled - // and which are permitted to be toggled. - if let Err(reason) = stability.toggle_allowed() { - tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr { - span: item.span(), - feature, - reason, - }); - } else if let Some(nightly_feature) = stability.requires_nightly() - && !rust_features.enabled(nightly_feature) - { - feature_err( - &tcx.sess, - nightly_feature, - item.span(), - format!("the target feature `{feature}` is currently unstable"), - ) - .emit(); - } else { - // Add this and the implied features. - let feature_sym = Symbol::intern(feature); - for &name in tcx.implied_target_features(feature_sym) { - // But ensure the ABI does not forbid enabling this. - // Here we do assume that the backend doesn't add even more implied features - // we don't know about, at least no features that would have ABI effects! - // We skip this logic in rustdoc, where we want to allow all target features of - // all targets, so we can't check their ABI compatibility and anyway we are not - // generating code so "it's fine". - if !tcx.sess.opts.actually_rustdoc { - if abi_feature_constraints.incompatible.contains(&name.as_str()) { - // For "neon" specifically, we emit an FCW instead of a hard error. - // See <https://github.com/rust-lang/rust/issues/134375>. - if tcx.sess.target.arch == "aarch64" && name.as_str() == "neon" { - tcx.emit_node_span_lint( - AARCH64_SOFTFLOAT_NEON, - tcx.local_def_id_to_hir_id(did), - item.span(), - errors::Aarch64SoftfloatNeon, - ); - } else { - tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr { - span: item.span(), - feature: name.as_str(), - reason: "this feature is incompatible with the target ABI", - }); - } + // Only allow target features whose feature gates have been enabled + // and which are permitted to be toggled. + if let Err(reason) = stability.toggle_allowed() { + tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr { + span: feature_span, + feature: feature_str, + reason, + }); + } else if let Some(nightly_feature) = stability.requires_nightly() + && !rust_features.enabled(nightly_feature) + { + feature_err( + &tcx.sess, + nightly_feature, + feature_span, + format!("the target feature `{feature}` is currently unstable"), + ) + .emit(); + } else { + // Add this and the implied features. + for &name in tcx.implied_target_features(feature) { + // But ensure the ABI does not forbid enabling this. + // Here we do assume that the backend doesn't add even more implied features + // we don't know about, at least no features that would have ABI effects! + // We skip this logic in rustdoc, where we want to allow all target features of + // all targets, so we can't check their ABI compatibility and anyway we are not + // generating code so "it's fine". + if !tcx.sess.opts.actually_rustdoc { + if abi_feature_constraints.incompatible.contains(&name.as_str()) { + // For "neon" specifically, we emit an FCW instead of a hard error. + // See <https://github.com/rust-lang/rust/issues/134375>. + if tcx.sess.target.arch == "aarch64" && name.as_str() == "neon" { + tcx.emit_node_span_lint( + AARCH64_SOFTFLOAT_NEON, + tcx.local_def_id_to_hir_id(did), + feature_span, + errors::Aarch64SoftfloatNeon, + ); + } else { + tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr { + span: feature_span, + feature: name.as_str(), + reason: "this feature is incompatible with the target ABI", + }); } } - target_features.push(TargetFeature { name, implied: name != feature_sym }) } + target_features.push(TargetFeature { name, implied: name != feature }) } } } @@ -457,7 +430,7 @@ pub(crate) fn provide(providers: &mut Providers) { // one, just keep it. } _ => { - // Overwrite stabilite. + // Overwrite stability. occupied_entry.insert(stability); } } diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index d19de6f5d26..9d367748c2a 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -87,7 +87,7 @@ pub trait BuilderMethods<'a, 'tcx>: // // This function is opt-in for back ends. // - // The default implementation calls `self.expect()` before emiting the branch + // The default implementation calls `self.expect()` before emitting the branch // by calling `self.cond_br()` fn cond_br_with_expect( &mut self, diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 2a2c3e6aee2..22a1894ee72 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -263,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 = diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index c1d91f98957..0eb6f28bdb3 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -638,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/mod.rs b/compiler/rustc_const_eval/src/check_consts/mod.rs index d8421415225..9ab8e0692e1 100644 --- a/compiler/rustc_const_eval/src/check_consts/mod.rs +++ b/compiler/rustc_const_eval/src/check_consts/mod.rs @@ -82,7 +82,7 @@ pub fn rustc_allow_const_fn_unstable( ) -> bool { let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id)); - attrs::find_attr!(attrs, attrs::AttributeKind::AllowConstFnUnstable(syms) if syms.contains(&feature_gate)) + attrs::find_attr!(attrs, attrs::AttributeKind::AllowConstFnUnstable(syms, _) if syms.contains(&feature_gate)) } /// Returns `true` if the given `def_id` (trait or function) is "safe to expose on stable". 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 569a07c3a01..08e1877f0eb 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -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 2ec3f8432c7..76fa744361a 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -10,7 +10,7 @@ use rustc_hir::{self as hir, CRATE_HIR_ID, LangItem}; use rustc_middle::mir::AssertMessage; use rustc_middle::mir::interpret::ReportedErrorInfo; use rustc_middle::query::TyCtxtAt; -use rustc_middle::ty::layout::{HasTypingEnv, TyAndLayout}; +use rustc_middle::ty::layout::{HasTypingEnv, TyAndLayout, ValidityRequirement}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, mir}; use rustc_span::{Span, Symbol, sym}; @@ -23,8 +23,8 @@ use crate::fluent_generated as fluent; use crate::interpret::{ self, AllocId, AllocInit, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame, GlobalAlloc, ImmTy, InterpCx, InterpResult, OpTy, PlaceTy, Pointer, RangeSet, Scalar, - compile_time_machine, interp_ok, throw_exhaust, throw_inval, throw_ub, throw_ub_custom, - throw_unsup, throw_unsup_format, + compile_time_machine, err_inval, interp_ok, throw_exhaust, throw_inval, throw_ub, + throw_ub_custom, throw_unsup, throw_unsup_format, }; /// When hitting this many interpreted terminators we emit a deny by default lint @@ -462,6 +462,44 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { // (We know the value here in the machine of course, but this is the runtime of that code, // not the optimization stage.) sym::is_val_statically_known => ecx.write_scalar(Scalar::from_bool(false), dest)?, + + // We handle these here since Miri does not want to have them. + sym::assert_inhabited + | sym::assert_zero_valid + | sym::assert_mem_uninitialized_valid => { + let ty = instance.args.type_at(0); + let requirement = ValidityRequirement::from_intrinsic(intrinsic_name).unwrap(); + + let should_panic = !ecx + .tcx + .check_validity_requirement((requirement, ecx.typing_env().as_query_input(ty))) + .map_err(|_| err_inval!(TooGeneric))?; + + if should_panic { + let layout = ecx.layout_of(ty)?; + + let msg = match requirement { + // For *all* intrinsics we first check `is_uninhabited` to give a more specific + // error message. + _ if layout.is_uninhabited() => format!( + "aborted execution: attempted to instantiate uninhabited type `{ty}`" + ), + ValidityRequirement::Inhabited => bug!("handled earlier"), + ValidityRequirement::Zero => format!( + "aborted execution: attempted to zero-initialize type `{ty}`, which is invalid" + ), + ValidityRequirement::UninitMitigated0x01Fill => format!( + "aborted execution: attempted to leave type `{ty}` uninitialized, which is invalid" + ), + ValidityRequirement::Uninit => bug!("assert_uninit_valid doesn't exist"), + }; + + Self::panic_nounwind(ecx, &msg)?; + // Skip the `return_to_block` at the end (we panicked, we do not return). + return interp_ok(None); + } + } + _ => { // We haven't handled the intrinsic, let's see if we can use a fallback body. if ecx.tcx.intrinsic(instance.def_id()).unwrap().must_be_overridden { @@ -508,6 +546,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() } diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 14abdd8c98c..9133a5fc8ef 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -574,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(), ); } diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index 79c14b204e3..ebaa5a97a4a 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -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 1036935bb10..7a73d70fc85 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -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/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index b29c5c7c7d7..378ed6d0e10 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::{TyAndLayout, ValidityRequirement}; -use rustc_middle::ty::{GenericArgsRef, Ty, TyCtxt}; +use rustc_middle::ty::layout::TyAndLayout; +use rustc_middle::ty::{Ty, TyCtxt}; use rustc_middle::{bug, ty}; use rustc_span::{Symbol, sym}; use tracing::trace; @@ -17,9 +16,9 @@ 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, - err_unsup_format, interp_ok, throw_inval, throw_ub_custom, throw_ub_format, + Allocation, CheckInAllocMsg, ConstAllocation, ImmTy, InterpCx, InterpResult, Machine, OpTy, + PlaceTy, Pointer, PointerArithmetic, Provenance, Scalar, 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); @@ -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 @@ -386,41 +372,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.exact_div(&val, &size, dest)?; } - sym::assert_inhabited - | sym::assert_zero_valid - | sym::assert_mem_uninitialized_valid => { - let ty = instance.args.type_at(0); - let requirement = ValidityRequirement::from_intrinsic(intrinsic_name).unwrap(); - - let should_panic = !self - .tcx - .check_validity_requirement((requirement, self.typing_env.as_query_input(ty))) - .map_err(|_| err_inval!(TooGeneric))?; - - if should_panic { - let layout = self.layout_of(ty)?; - - let msg = match requirement { - // For *all* intrinsics we first check `is_uninhabited` to give a more specific - // error message. - _ if layout.is_uninhabited() => format!( - "aborted execution: attempted to instantiate uninhabited type `{ty}`" - ), - ValidityRequirement::Inhabited => bug!("handled earlier"), - ValidityRequirement::Zero => format!( - "aborted execution: attempted to zero-initialize type `{ty}`, which is invalid" - ), - ValidityRequirement::UninitMitigated0x01Fill => format!( - "aborted execution: attempted to leave type `{ty}` uninitialized, which is invalid" - ), - ValidityRequirement::Uninit => bug!("assert_uninit_valid doesn't exist"), - }; - - M::panic_nounwind(self, &msg)?; - // Skip the `return_to_block` at the end (we panicked, we do not return). - return interp_ok(true); - } - } sym::simd_insert => { let index = u64::from(self.read_scalar(&args[1])?.to_u32()?); let elem = &args[2]; diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index d6d230fbd17..35ec303f961 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -747,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)] @@ -756,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 69fceb02ff9..ff822b52a8d 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -655,7 +655,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// The caller is responsible for calling the access hooks! /// /// You almost certainly want to use `get_ptr_alloc`/`get_ptr_alloc_mut` instead. - fn get_alloc_raw( + pub fn get_alloc_raw( &self, id: AllocId, ) -> InterpResult<'tcx, &Allocation<M::Provenance, M::AllocExtra, M::Bytes>> { @@ -757,7 +757,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// /// Also returns a ptr to `self.extra` so that the caller can use it in parallel with the /// allocation. - fn get_alloc_raw_mut( + /// + /// You almost certainly want to use `get_ptr_alloc`/`get_ptr_alloc_mut` instead. + pub fn get_alloc_raw_mut( &mut self, id: AllocId, ) -> InterpResult<'tcx, (&mut Allocation<M::Provenance, M::AllocExtra, M::Bytes>, &mut M)> { @@ -976,15 +978,15 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { interp_ok(()) } - /// Handle the effect an FFI call might have on the state of allocations. - /// This overapproximates the modifications which external code might make to memory: - /// We set all reachable allocations as initialized, mark all reachable provenances as exposed - /// and overwrite them with `Provenance::WILDCARD`. - /// - /// The allocations in `ids` are assumed to be already exposed. - pub fn prepare_for_native_call(&mut self, ids: Vec<AllocId>) -> InterpResult<'tcx> { + /// Visit all allocations reachable from the given start set, by recursively traversing the + /// provenance information of those allocations. + pub fn visit_reachable_allocs( + &mut self, + start: Vec<AllocId>, + mut visit: impl FnMut(&mut Self, AllocId, &AllocInfo) -> InterpResult<'tcx>, + ) -> InterpResult<'tcx> { let mut done = FxHashSet::default(); - let mut todo = ids; + let mut todo = start; while let Some(id) = todo.pop() { if !done.insert(id) { // We already saw this allocation before, don't process it again. @@ -992,31 +994,20 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } let info = self.get_alloc_info(id); - // If there is no data behind this pointer, skip this. - if !matches!(info.kind, AllocKind::LiveData) { - continue; - } - - // Expose all provenances in this allocation, and add them to `todo`. - let alloc = self.get_alloc_raw(id)?; - for prov in alloc.provenance().provenances() { - M::expose_provenance(self, prov)?; - if let Some(id) = prov.get_alloc_id() { - todo.push(id); + // Recurse, if there is data here. + // Do this *before* invoking the callback, as the callback might mutate the + // allocation and e.g. replace all provenance by wildcards! + if matches!(info.kind, AllocKind::LiveData) { + let alloc = self.get_alloc_raw(id)?; + for prov in alloc.provenance().provenances() { + if let Some(id) = prov.get_alloc_id() { + todo.push(id); + } } } - // Also expose the provenance of the interpreter-level allocation, so it can - // be read by FFI. The `black_box` is defensive programming as LLVM likes - // to (incorrectly) optimize away ptr2int casts whose result is unused. - std::hint::black_box(alloc.get_bytes_unchecked_raw().expose_provenance()); - - // Prepare for possible write from native code if mutable. - if info.mutbl.is_mut() { - self.get_alloc_raw_mut(id)? - .0 - .prepare_for_native_write() - .map_err(|e| e.to_interp_error(id))?; - } + + // Call the callback. + visit(self, id, &info)?; } interp_ok(()) } @@ -1073,7 +1064,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { todo.extend(static_roots(self)); while let Some(id) = todo.pop() { if reachable.insert(id) { - // This is a new allocation, add the allocation it points to `todo`. + // This is a new allocation, add the allocations it points to `todo`. + // We only need to care about `alloc_map` memory here, as entirely unchanged + // global memory cannot point to memory relevant for the leak check. if let Some((_, alloc)) = self.memory.alloc_map.get(id) { todo.extend( alloc.provenance().provenances().filter_map(|prov| prov.get_alloc_id()), @@ -1596,7 +1589,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/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 3028568dd8f..e2284729efd 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -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 } } @@ -572,7 +572,7 @@ where Right((local, offset, locals_addr, layout)) => { if offset.is_some() { // This has been projected to a part of this local, or had the type changed. - // FIMXE: there are cases where we could still avoid allocating an mplace. + // FIXME: there are cases where we could still avoid allocating an mplace. Left(place.force_mplace(self)?) } else { debug_assert_eq!(locals_addr, self.frame().locals_addr()); diff --git a/compiler/rustc_const_eval/src/interpret/stack.rs b/compiler/rustc_const_eval/src/interpret/stack.rs index 3361a586b8e..543d68d7f45 100644 --- a/compiler/rustc_const_eval/src/interpret/stack.rs +++ b/compiler/rustc_const_eval/src/interpret/stack.rs @@ -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 8b634955bb7..e4b5c82853a 100644 --- a/compiler/rustc_const_eval/src/interpret/traits.rs +++ b/compiler/rustc_const_eval/src/interpret/traits.rs @@ -1,4 +1,4 @@ -use rustc_abi::{Align, FieldIdx, Size}; +use rustc_abi::{Align, Size}; use rustc_middle::mir::interpret::{InterpResult, Pointer}; use rustc_middle::ty::{self, ExistentialPredicateStableCmpExt, Ty, TyCtxt, VtblEntry}; use tracing::trace; @@ -125,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 998ef3729ea..fc4d13af8c4 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -358,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); @@ -518,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 @@ -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 whether 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,7 +902,7 @@ 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_val(&mplace)? diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs index d5970b69baf..a27b6646131 100644 --- a/compiler/rustc_const_eval/src/interpret/visitor.rs +++ b/compiler/rustc_const_eval/src/interpret/visitor.rs @@ -101,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 ab2de279ed8..f489b05fbbd 100644 --- a/compiler/rustc_const_eval/src/util/caller_location.rs +++ b/compiler/rustc_const_eval/src/util/caller_location.rs @@ -21,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) }; @@ -41,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_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index d7e97f32bae..4ca39bbc68e 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -69,7 +69,7 @@ fn check_validity_requirement_strict<'tcx>( // require dereferenceability also require non-null, we don't actually get any false negatives // due to this. // The value we are validating is temporary and discarded at the end of this function, so - // there is no point in reseting provenance and padding. + // there is no point in resetting provenance and padding. cx.validate_operand( &allocated.into(), /*recursive*/ false, 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 e3a01e4035c..1b4db7adc27 100644 --- a/compiler/rustc_data_structures/src/profiling.rs +++ b/compiler/rustc_data_structures/src/profiling.rs @@ -88,6 +88,7 @@ use std::fmt::Display; use std::intrinsics::unlikely; use std::path::Path; use std::sync::Arc; +use std::sync::atomic::Ordering; use std::time::{Duration, Instant}; use std::{fs, process}; @@ -99,12 +100,15 @@ use tracing::warn; use crate::fx::FxHashMap; use crate::outline; +use crate::sync::AtomicU64; bitflags::bitflags! { #[derive(Clone, Copy)] struct EventFilter: u16 { const GENERIC_ACTIVITIES = 1 << 0; const QUERY_PROVIDERS = 1 << 1; + /// Store detailed instant events, including timestamp and thread ID, + /// per each query cache hit. Note that this is quite expensive. const QUERY_CACHE_HITS = 1 << 2; const QUERY_BLOCKED = 1 << 3; const INCR_CACHE_LOADS = 1 << 4; @@ -113,16 +117,20 @@ bitflags::bitflags! { const FUNCTION_ARGS = 1 << 6; const LLVM = 1 << 7; const INCR_RESULT_HASHING = 1 << 8; - const ARTIFACT_SIZES = 1 << 9; + const ARTIFACT_SIZES = 1 << 9; + /// Store aggregated counts of cache hits per query invocation. + const QUERY_CACHE_HIT_COUNTS = 1 << 10; const DEFAULT = Self::GENERIC_ACTIVITIES.bits() | Self::QUERY_PROVIDERS.bits() | Self::QUERY_BLOCKED.bits() | Self::INCR_CACHE_LOADS.bits() | Self::INCR_RESULT_HASHING.bits() | - Self::ARTIFACT_SIZES.bits(); + Self::ARTIFACT_SIZES.bits() | + Self::QUERY_CACHE_HIT_COUNTS.bits(); const ARGS = Self::QUERY_KEYS.bits() | Self::FUNCTION_ARGS.bits(); + const QUERY_CACHE_HIT_COMBINED = Self::QUERY_CACHE_HITS.bits() | Self::QUERY_CACHE_HIT_COUNTS.bits(); } } @@ -134,6 +142,7 @@ const EVENT_FILTERS_BY_NAME: &[(&str, EventFilter)] = &[ ("generic-activity", EventFilter::GENERIC_ACTIVITIES), ("query-provider", EventFilter::QUERY_PROVIDERS), ("query-cache-hit", EventFilter::QUERY_CACHE_HITS), + ("query-cache-hit-count", EventFilter::QUERY_CACHE_HITS), ("query-blocked", EventFilter::QUERY_BLOCKED), ("incr-cache-load", EventFilter::INCR_CACHE_LOADS), ("query-keys", EventFilter::QUERY_KEYS), @@ -411,13 +420,24 @@ impl SelfProfilerRef { #[inline(never)] #[cold] fn cold_call(profiler_ref: &SelfProfilerRef, query_invocation_id: QueryInvocationId) { - profiler_ref.instant_query_event( - |profiler| profiler.query_cache_hit_event_kind, - query_invocation_id, - ); + if profiler_ref.event_filter_mask.contains(EventFilter::QUERY_CACHE_HIT_COUNTS) { + profiler_ref + .profiler + .as_ref() + .unwrap() + .increment_query_cache_hit_counters(QueryInvocationId(query_invocation_id.0)); + } + if unlikely(profiler_ref.event_filter_mask.contains(EventFilter::QUERY_CACHE_HITS)) { + profiler_ref.instant_query_event( + |profiler| profiler.query_cache_hit_event_kind, + query_invocation_id, + ); + } } - if unlikely(self.event_filter_mask.contains(EventFilter::QUERY_CACHE_HITS)) { + // We check both kinds of query cache hit events at once, to reduce overhead in the + // common case (with self-profile disabled). + if unlikely(self.event_filter_mask.intersects(EventFilter::QUERY_CACHE_HIT_COMBINED)) { cold_call(self, query_invocation_id); } } @@ -489,6 +509,35 @@ impl SelfProfilerRef { self.profiler.as_ref().map(|p| p.get_or_alloc_cached_string(s)) } + /// Store query cache hits to the self-profile log. + /// Should be called once at the end of the compilation session. + /// + /// The cache hits are stored per **query invocation**, not **per query kind/type**. + /// `analyzeme` can later deduplicate individual query labels from the QueryInvocationId event + /// IDs. + pub fn store_query_cache_hits(&self) { + if self.event_filter_mask.contains(EventFilter::QUERY_CACHE_HIT_COUNTS) { + let profiler = self.profiler.as_ref().unwrap(); + let query_hits = profiler.query_hits.read(); + let builder = EventIdBuilder::new(&profiler.profiler); + let thread_id = get_thread_id(); + for (query_invocation, hit_count) in query_hits.iter().enumerate() { + let hit_count = hit_count.load(Ordering::Relaxed); + // No need to record empty cache hit counts + if hit_count > 0 { + let event_id = + builder.from_label(StringId::new_virtual(query_invocation as u64)); + profiler.profiler.record_integer_event( + profiler.query_cache_hit_count_event_kind, + event_id, + thread_id, + hit_count, + ); + } + } + } + } + #[inline] pub fn enabled(&self) -> bool { self.profiler.is_some() @@ -537,6 +586,19 @@ pub struct SelfProfiler { string_cache: RwLock<FxHashMap<String, StringId>>, + /// Recording individual query cache hits as "instant" measureme events + /// is incredibly expensive. Instead of doing that, we simply aggregate + /// cache hit *counts* per query invocation, and then store the final count + /// of cache hits per invocation at the end of the compilation session. + /// + /// With this approach, we don't know the individual thread IDs and timestamps + /// of cache hits, but it has very little overhead on top of `-Zself-profile`. + /// Recording the cache hits as individual events made compilation 3-5x slower. + /// + /// Query invocation IDs should be monotonic integers, so we can store them in a vec, + /// rather than using a hashmap. + query_hits: RwLock<Vec<AtomicU64>>, + query_event_kind: StringId, generic_activity_event_kind: StringId, incremental_load_result_event_kind: StringId, @@ -544,6 +606,8 @@ pub struct SelfProfiler { query_blocked_event_kind: StringId, query_cache_hit_event_kind: StringId, artifact_size_event_kind: StringId, + /// Total cache hits per query invocation + query_cache_hit_count_event_kind: StringId, } impl SelfProfiler { @@ -573,6 +637,7 @@ impl SelfProfiler { let query_blocked_event_kind = profiler.alloc_string("QueryBlocked"); let query_cache_hit_event_kind = profiler.alloc_string("QueryCacheHit"); let artifact_size_event_kind = profiler.alloc_string("ArtifactSize"); + let query_cache_hit_count_event_kind = profiler.alloc_string("QueryCacheHitCount"); let mut event_filter_mask = EventFilter::empty(); @@ -618,6 +683,8 @@ impl SelfProfiler { query_blocked_event_kind, query_cache_hit_event_kind, artifact_size_event_kind, + query_cache_hit_count_event_kind, + query_hits: Default::default(), }) } @@ -627,6 +694,25 @@ impl SelfProfiler { self.profiler.alloc_string(s) } + /// Store a cache hit of a query invocation + pub fn increment_query_cache_hit_counters(&self, id: QueryInvocationId) { + // Fast path: assume that the query was already encountered before, and just record + // a cache hit. + let mut guard = self.query_hits.upgradable_read(); + let query_hits = &guard; + let index = id.0 as usize; + if index < query_hits.len() { + // We only want to increment the count, no other synchronization is required + query_hits[index].fetch_add(1, Ordering::Relaxed); + } else { + // If not, we need to extend the query hit map to the highest observed ID + guard.with_upgraded(|vec| { + vec.resize_with(index + 1, || AtomicU64::new(0)); + vec[index] = AtomicU64::from(1); + }); + } + } + /// Gets a `StringId` for the given string. This method makes sure that /// any strings going through it will only be allocated once in the /// profiling data. @@ -859,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_data_structures/src/vec_cache.rs b/compiler/rustc_data_structures/src/vec_cache.rs index 3b448c056b7..0ffa6b3205f 100644 --- a/compiler/rustc_data_structures/src/vec_cache.rs +++ b/compiler/rustc_data_structures/src/vec_cache.rs @@ -257,7 +257,7 @@ unsafe impl<K: Idx, #[may_dangle] V, I> Drop for VecCache<K, V, I> { // we are also guaranteed to just need to deallocate any large arrays (not iterate over // contents). // - // Confirm no need to deallocate invidual entries. Note that `V: Copy` is asserted on + // Confirm no need to deallocate individual entries. Note that `V: Copy` is asserted on // insert/lookup but not necessarily construction, primarily to avoid annoyingly propagating // the bounds into struct definitions everywhere. assert!(!std::mem::needs_drop::<K>()); diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 4855fc58d03..18490385455 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -1112,7 +1112,9 @@ 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 = Sysroot::new(matches.opt_str("sysroot").map(PathBuf::from)); let target = config::build_target_config(early_dcx, &target, sysroot.path()); diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 4e4345cfe0f..4b3ecad307f 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -3,7 +3,6 @@ #![doc(rust_logo)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] -#![feature(type_alias_impl_trait)] // tidy-alphabetical-end use std::borrow::Cow; diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 8da7cdd9358..fe9797026de 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -1005,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, @@ -1166,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, 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_errors/src/markdown/parse.rs b/compiler/rustc_errors/src/markdown/parse.rs index f02387d8335..e1b1b32cd3e 100644 --- a/compiler/rustc_errors/src/markdown/parse.rs +++ b/compiler/rustc_errors/src/markdown/parse.rs @@ -352,7 +352,7 @@ fn normalize<'a>(MdStream(stream): MdStream<'a>, linkdefs: &mut Vec<MdTree<'a>>) let new_defs = stream.iter().filter(|tt| matches!(tt, MdTree::LinkDef { .. })); linkdefs.extend(new_defs.cloned()); - // Run plaintest expansions on types that need it, call this function on nested types + // Run plaintext expansions on types that need it, call this function on nested types for item in stream { match item { MdTree::PlainText(txt) => expand_plaintext(txt, &mut new_stream, MdTree::PlainText), diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl index b7555bba28e..3fc0fa06191 100644 --- a/compiler/rustc_expand/messages.ftl +++ b/compiler/rustc_expand/messages.ftl @@ -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 fe76d9e0b64..80f6e9d9fc4 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -880,7 +880,7 @@ impl SyntaxExtension { is_local: bool, ) -> SyntaxExtension { let allow_internal_unstable = - find_attr!(attrs, AttributeKind::AllowInternalUnstable(i) => i) + find_attr!(attrs, AttributeKind::AllowInternalUnstable(i, _) => i) .map(|i| i.as_slice()) .unwrap_or_default(); // FIXME(jdonszelman): allow_internal_unsafe isn't yet new-style diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 14b8cc90d97..a333f2c7cb7 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -195,6 +195,7 @@ impl<'a> ExtCtxt<'a> { }, trait_ref: self.trait_ref(path), span, + parens: ast::Parens::No, } } diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index fe4d2af97a0..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] @@ -499,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/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index 99aa376626d..c607a3a3652 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -195,38 +195,6 @@ impl<'dcx> CollectTrackerAndEmitter<'dcx, '_> { } } -/// Currently used by macro_rules! compilation to extract a little information from the `Failure` -/// case. -pub(crate) struct FailureForwarder<'matcher> { - expected_token: Option<&'matcher Token>, -} - -impl<'matcher> FailureForwarder<'matcher> { - pub(crate) fn new() -> Self { - Self { expected_token: None } - } -} - -impl<'matcher> Tracker<'matcher> for FailureForwarder<'matcher> { - type Failure = (Token, u32, &'static str); - - fn build_failure(tok: Token, position: u32, msg: &'static str) -> Self::Failure { - (tok, position, msg) - } - - fn description() -> &'static str { - "failure-forwarder" - } - - fn set_expected_token(&mut self, tok: &'matcher Token) { - self.expected_token = Some(tok); - } - - fn get_expected_token(&self) -> Option<&'matcher Token> { - self.expected_token - } -} - pub(super) fn emit_frag_parse_err( mut e: Diag<'_>, parser: &Parser<'_>, @@ -321,7 +289,7 @@ enum ExplainDocComment { }, } -pub(super) fn annotate_doc_comment(err: &mut Diag<'_>, sm: &SourceMap, span: Span) { +fn annotate_doc_comment(err: &mut Diag<'_>, sm: &SourceMap, span: Span) { if let Ok(src) = sm.span_to_snippet(span) { if src.starts_with("///") || src.starts_with("/**") { err.subdiagnostic(ExplainDocComment::Outer { span }); @@ -333,7 +301,7 @@ pub(super) fn annotate_doc_comment(err: &mut Diag<'_>, sm: &SourceMap, span: Spa /// Generates an appropriate parsing failure message. For EOF, this is "unexpected end...". For /// other tokens, this is "unexpected token...". -pub(super) fn parse_failure_msg(tok: &Token, expected_token: Option<&Token>) -> Cow<'static, str> { +fn parse_failure_msg(tok: &Token, expected_token: Option<&Token>) -> Cow<'static, str> { if let Some(expected_token) = expected_token { Cow::from(format!("expected {}, found {}", token_descr(expected_token), token_descr(tok))) } else { diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs index dc2d46c4a14..bbdff866feb 100644 --- a/compiler/rustc_expand/src/mbe/macro_check.rs +++ b/compiler/rustc_expand/src/mbe/macro_check.rs @@ -105,8 +105,6 @@ //! stored when entering a macro definition starting from the state in which the meta-variable is //! bound. -use std::iter; - use rustc_ast::token::{Delimiter, IdentIsRaw, Token, TokenKind}; use rustc_ast::{DUMMY_NODE_ID, NodeId}; use rustc_data_structures::fx::FxHashMap; @@ -190,29 +188,22 @@ struct MacroState<'a> { ops: SmallVec<[KleeneToken; 1]>, } -/// Checks that meta-variables are used correctly in a macro definition. +/// Checks that meta-variables are used correctly in one rule of a macro definition. /// /// Arguments: /// - `psess` is used to emit diagnostics and lints /// - `node_id` is used to emit lints -/// - `span` is used when no spans are available -/// - `lhses` and `rhses` should have the same length and represent the macro definition +/// - `lhs` and `rhs` represent the rule pub(super) fn check_meta_variables( psess: &ParseSess, node_id: NodeId, - span: Span, - lhses: &[TokenTree], - rhses: &[TokenTree], + lhs: &TokenTree, + rhs: &TokenTree, ) -> Result<(), ErrorGuaranteed> { - if lhses.len() != rhses.len() { - psess.dcx().span_bug(span, "length mismatch between LHSes and RHSes") - } let mut guar = None; - for (lhs, rhs) in iter::zip(lhses, rhses) { - let mut binders = Binders::default(); - check_binders(psess, node_id, lhs, &Stack::Empty, &mut binders, &Stack::Empty, &mut guar); - check_occurrences(psess, node_id, rhs, &Stack::Empty, &binders, &Stack::Empty, &mut guar); - } + let mut binders = Binders::default(); + check_binders(psess, node_id, lhs, &Stack::Empty, &mut binders, &Stack::Empty, &mut guar); + check_occurrences(psess, node_id, rhs, &Stack::Empty, &binders, &Stack::Empty, &mut guar); guar.map_or(Ok(()), Err) } diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 802e43209a5..3f1fc841ea3 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -536,8 +536,6 @@ impl TtParser { // The separator matches the current token. Advance past it. mp.idx += 1; self.next_mps.push(mp); - } else { - track.set_expected_token(separator); } } &MatcherLoc::SequenceKleeneOpAfterSep { idx_first } => { diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 432ab324740..dad2fd99ef2 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -19,12 +19,13 @@ use rustc_lint_defs::BuiltinLintDiag; use rustc_lint_defs::builtin::{ RUST_2021_INCOMPATIBLE_OR_PATTERNS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS, }; -use rustc_parse::parser::{ParseNtResult, Parser, Recovery}; +use rustc_parse::exp; +use rustc_parse::parser::{Parser, Recovery}; use rustc_session::Session; use rustc_session::parse::ParseSess; use rustc_span::edition::Edition; use rustc_span::hygiene::Transparency; -use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, kw, sym}; +use rustc_span::{Ident, Span, kw, sym}; use tracing::{debug, instrument, trace, trace_span}; use super::macro_parser::{NamedMatches, NamedParseResult}; @@ -34,8 +35,6 @@ use crate::base::{ SyntaxExtensionKind, TTMacroExpander, }; use crate::expand::{AstFragment, AstFragmentKind, ensure_complete_parse, parse_ast_fragment}; -use crate::mbe::diagnostics::{annotate_doc_comment, parse_failure_msg}; -use crate::mbe::macro_parser::NamedMatch::*; use crate::mbe::macro_parser::{Error, ErrorReported, Failure, MatcherLoc, Success, TtParser}; use crate::mbe::transcribe::transcribe; use crate::mbe::{self, KleeneOp, macro_check}; @@ -168,11 +167,6 @@ pub(super) trait Tracker<'matcher> { fn recovery() -> Recovery { Recovery::Forbidden } - - fn set_expected_token(&mut self, _tok: &'matcher Token) {} - fn get_expected_token(&self) -> Option<&'matcher Token> { - None - } } /// A noop tracker that is used in the hot path of the expansion, has zero overhead thanks to @@ -360,11 +354,6 @@ pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>( Err(CanRetry::Yes) } -// Note that macro-by-example's input is also matched against a token tree: -// $( $lhs:tt => $rhs:tt );+ -// -// Holy self-referential! - /// Converts a macro item into a syntax extension. pub fn compile_declarative_macro( sess: &Session, @@ -390,157 +379,66 @@ pub fn compile_declarative_macro( }; let dummy_syn_ext = |guar| (mk_syn_ext(Arc::new(DummyExpander(guar))), Vec::new()); - let lhs_nm = Ident::new(sym::lhs, span); - let rhs_nm = Ident::new(sym::rhs, span); - let tt_spec = NonterminalKind::TT; let macro_rules = macro_def.macro_rules; + let exp_sep = if macro_rules { exp!(Semi) } else { exp!(Comma) }; - // Parse the macro_rules! invocation - - // The pattern that macro_rules matches. - // The grammar for macro_rules! is: - // $( $lhs:tt => $rhs:tt );+ - // ...quasiquoting this would be nice. - // These spans won't matter, anyways - let argument_gram = vec![ - mbe::TokenTree::Sequence( - DelimSpan::dummy(), - mbe::SequenceRepetition { - tts: vec![ - mbe::TokenTree::MetaVarDecl { span, name: lhs_nm, kind: tt_spec }, - mbe::TokenTree::token(token::FatArrow, span), - mbe::TokenTree::MetaVarDecl { span, name: rhs_nm, kind: tt_spec }, - ], - separator: Some(Token::new( - if macro_rules { token::Semi } else { token::Comma }, - span, - )), - kleene: mbe::KleeneToken::new(mbe::KleeneOp::OneOrMore, span), - num_captures: 2, - }, - ), - // to phase into semicolon-termination instead of semicolon-separation - mbe::TokenTree::Sequence( - DelimSpan::dummy(), - mbe::SequenceRepetition { - tts: vec![mbe::TokenTree::token( - if macro_rules { token::Semi } else { token::Comma }, - span, - )], - separator: None, - kleene: mbe::KleeneToken::new(mbe::KleeneOp::ZeroOrMore, span), - num_captures: 0, - }, - ), - ]; - // Convert it into `MatcherLoc` form. - let argument_gram = mbe::macro_parser::compute_locs(&argument_gram); - - let create_parser = || { - let body = macro_def.body.tokens.clone(); - Parser::new(&sess.psess, body, rustc_parse::MACRO_ARGUMENTS) - }; - - let parser = create_parser(); - let mut tt_parser = - TtParser::new(Ident::with_dummy_span(if macro_rules { kw::MacroRules } else { kw::Macro })); - let argument_map = - 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. - let retry_parser = create_parser(); - - let mut track = diagnostics::FailureForwarder::new(); - let parse_result = - tt_parser.parse_tt(&mut Cow::Owned(retry_parser), &argument_gram, &mut track); - let Failure((token, _, msg)) = parse_result else { - unreachable!("matcher returned something other than Failure after retry"); - }; - - let s = parse_failure_msg(&token, track.get_expected_token()); - let sp = token.span.substitute_dummy(span); - let mut err = sess.dcx().struct_span_err(sp, s); - err.span_label(sp, msg); - annotate_doc_comment(&mut err, sess.source_map(), sp); - let guar = err.emit(); - return dummy_syn_ext(guar); - } - Error(sp, msg) => { - let guar = sess.dcx().span_err(sp.substitute_dummy(span), msg); - return dummy_syn_ext(guar); - } - ErrorReported(guar) => { - return dummy_syn_ext(guar); - } - }; + let body = macro_def.body.tokens.clone(); + let mut p = Parser::new(&sess.psess, body, rustc_parse::MACRO_ARGUMENTS); + // Don't abort iteration early, so that multiple errors can be reported. let mut guar = None; let mut check_emission = |ret: Result<(), ErrorGuaranteed>| guar = guar.or(ret.err()); - // Extract the arguments: - let lhses = match &argument_map[&MacroRulesNormalizedIdent::new(lhs_nm)] { - MatchedSeq(s) => s - .iter() - .map(|m| { - if let MatchedSingle(ParseNtResult::Tt(tt)) = m { - let tt = mbe::quoted::parse( - &TokenStream::new(vec![tt.clone()]), - true, - sess, - node_id, - features, - edition, - ) - .pop() - .unwrap(); - // We don't handle errors here, the driver will abort - // after parsing/expansion. We can report every error in every macro this way. - check_emission(check_lhs_nt_follows(sess, node_id, &tt)); - return tt; - } - sess.dcx().span_bug(span, "wrong-structured lhs") - }) - .collect::<Vec<mbe::TokenTree>>(), - _ => sess.dcx().span_bug(span, "wrong-structured lhs"), - }; + let mut lhses = Vec::new(); + let mut rhses = Vec::new(); - let rhses = match &argument_map[&MacroRulesNormalizedIdent::new(rhs_nm)] { - MatchedSeq(s) => s - .iter() - .map(|m| { - if let MatchedSingle(ParseNtResult::Tt(tt)) = m { - return mbe::quoted::parse( - &TokenStream::new(vec![tt.clone()]), - false, - sess, - node_id, - features, - edition, - ) - .pop() - .unwrap(); - } - sess.dcx().span_bug(span, "wrong-structured rhs") - }) - .collect::<Vec<mbe::TokenTree>>(), - _ => sess.dcx().span_bug(span, "wrong-structured rhs"), - }; - - for rhs in &rhses { - check_emission(check_rhs(sess, rhs)); + while p.token != token::Eof { + let lhs_tt = p.parse_token_tree(); + let lhs_tt = mbe::quoted::parse( + &TokenStream::new(vec![lhs_tt]), + true, // LHS + sess, + node_id, + features, + edition, + ) + .pop() + .unwrap(); + // We don't handle errors here, the driver will abort after parsing/expansion. We can + // report every error in every macro this way. + check_emission(check_lhs_nt_follows(sess, node_id, &lhs_tt)); + check_emission(check_lhs_no_empty_seq(sess, slice::from_ref(&lhs_tt))); + if let Err(e) = p.expect(exp!(FatArrow)) { + return dummy_syn_ext(e.emit()); + } + let rhs_tt = p.parse_token_tree(); + let rhs_tt = mbe::quoted::parse( + &TokenStream::new(vec![rhs_tt]), + false, // RHS + sess, + node_id, + features, + edition, + ) + .pop() + .unwrap(); + check_emission(check_rhs(sess, &rhs_tt)); + check_emission(macro_check::check_meta_variables(&sess.psess, node_id, &lhs_tt, &rhs_tt)); + lhses.push(lhs_tt); + rhses.push(rhs_tt); + if p.token == token::Eof { + break; + } + if let Err(e) = p.expect(exp_sep) { + return dummy_syn_ext(e.emit()); + } } - // Don't abort iteration early, so that errors for multiple lhses can be reported. - for lhs in &lhses { - check_emission(check_lhs_no_empty_seq(sess, slice::from_ref(lhs))); + if lhses.is_empty() { + let guar = sess.dcx().span_err(span, "macros must contain at least one rule"); + return dummy_syn_ext(guar); } - check_emission(macro_check::check_meta_variables(&sess.psess, node_id, span, &lhses, &rhses)); - let transparency = find_attr!(attrs, AttributeKind::MacroTransparency(x) => *x) .unwrap_or(Transparency::fallback(macro_rules)); 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/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index a8c4a9e4b1b..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; @@ -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..fd71f2ce948 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 { @@ -677,7 +681,7 @@ impl server::Span for Rustc<'_, '_> { .lookup_char_pos(span.lo()) .file .name - .prefer_remapped_unconditionaly() + .prefer_remapped_unconditionally() .to_string() } diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index cfe0f4e5d6c..83be3241b12 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,9 +262,11 @@ 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 `if/while p && let q = r && ...` chains. + (accepted, let_chains, "1.88.0", Some(53667)), /// Allows `let...else` statements. (accepted, let_else, "1.65.0", Some(87335)), /// Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check. @@ -341,7 +343,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 +367,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 +389,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/removed.rs b/compiler/rustc_feature/src/removed.rs index a855e4c1b0e..7e174c465d5 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -123,6 +123,9 @@ 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), + /// 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), @@ -222,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), @@ -265,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. diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 719ba597da1..efd8bde71d7 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. @@ -356,7 +356,7 @@ declare_features! ( /// 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. @@ -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. @@ -552,8 +550,6 @@ declare_features! ( (unstable, large_assignments, "1.52.0", Some(83518)), /// Allow to have type alias types for inter-crate use. (incomplete, lazy_type_alias, "1.72.0", Some(112792)), - /// Allows `if/while p && let q = r && ...` chains. - (unstable, let_chains, "1.37.0", Some(53667)), /// Allows using `#[link(kind = "link-arg", name = "...")]` /// to pass custom arguments to the linker. (unstable, link_arg_attribute, "1.76.0", Some(99427)), 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 75dff588669..ca6405ea209 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -439,7 +439,7 @@ impl<'hir> ConstArg<'hir, AmbigArg> { } impl<'hir> ConstArg<'hir> { - /// Converts a `ConstArg` in an unambigous position to one in an ambiguous position. This is + /// Converts a `ConstArg` in an unambiguous position to one in an ambiguous position. This is /// fallible as the [`ConstArgKind::Infer`] variant is not present in ambiguous positions. /// /// Functions accepting ambiguous consts will not handle the [`ConstArgKind::Infer`] variant, if @@ -508,7 +508,7 @@ pub enum GenericArg<'hir> { Lifetime(&'hir Lifetime), Type(&'hir Ty<'hir, AmbigArg>), Const(&'hir ConstArg<'hir, AmbigArg>), - /// Inference variables in [`GenericArg`] are always represnted by + /// Inference variables in [`GenericArg`] are always represented by /// `GenericArg::Infer` instead of the `Infer` variants on [`TyKind`] and /// [`ConstArgKind`] as it is not clear until hir ty lowering whether a /// `_` argument is a type or const argument. @@ -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. @@ -3141,15 +3141,6 @@ pub enum TraitItemKind<'hir> { /// type. Type(GenericBounds<'hir>, Option<&'hir Ty<'hir>>), } -impl TraitItemKind<'_> { - pub fn descr(&self) -> &'static str { - match self { - TraitItemKind::Const(..) => "associated constant", - TraitItemKind::Fn(..) => "function", - TraitItemKind::Type(..) => "associated type", - } - } -} // The bodies for items are stored "out of line", in a separate // hashmap in the `Crate`. Here we just record the hir-id of the item @@ -3211,15 +3202,6 @@ pub enum ImplItemKind<'hir> { /// An associated type. Type(&'hir Ty<'hir>), } -impl ImplItemKind<'_> { - pub fn descr(&self) -> &'static str { - match self { - ImplItemKind::Const(..) => "associated constant", - ImplItemKind::Fn(..) => "function", - ImplItemKind::Type(..) => "associated type", - } - } -} /// A constraint on an associated item. /// @@ -3341,7 +3323,7 @@ impl<'hir> Ty<'hir, AmbigArg> { } impl<'hir> Ty<'hir> { - /// Converts a `Ty` in an unambigous position to one in an ambiguous position. This is + /// Converts a `Ty` in an unambiguous position to one in an ambiguous position. This is /// fallible as the [`TyKind::Infer`] variant is not present in ambiguous positions. /// /// Functions accepting ambiguous types will not handle the [`TyKind::Infer`] variant, if @@ -4242,7 +4224,7 @@ impl fmt::Display for Constness { } } -/// The actualy safety specified in syntax. We may treat +/// The actual safety specified in syntax. We may treat /// its safety different within the type system to create a /// "sound by default" system that needs checking this enum /// explicitly to allow unsafe operations. @@ -4418,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 @@ -4545,16 +4506,6 @@ pub enum ForeignItemKind<'hir> { Type, } -impl ForeignItemKind<'_> { - pub fn descr(&self) -> &'static str { - match self { - ForeignItemKind::Fn(..) => "function", - ForeignItemKind::Static(..) => "static variable", - ForeignItemKind::Type => "type", - } - } -} - /// A variable captured by a closure. #[derive(Debug, Copy, Clone, HashStable_Generic)] pub struct Upvar { @@ -4862,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, } } 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/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index a361679e8ad..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 { @@ -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/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 b9124ea0e5e..ed8d25e9915 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -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,16 +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()); - 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: // @@ -295,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> { @@ -357,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 @@ -872,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", ), _ => { @@ -940,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", ), @@ -950,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( @@ -1010,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 @@ -1033,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(); @@ -1049,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 { .. } => { @@ -1083,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(); @@ -1185,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(()) }) } @@ -1215,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(()) }); @@ -1252,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(()) @@ -1328,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); @@ -1346,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(()) }) @@ -1359,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 @@ -1443,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(); @@ -1605,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, @@ -1657,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); @@ -1746,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). @@ -2004,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() @@ -2037,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 { @@ -2053,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); @@ -2062,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 @@ -2082,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() }) { @@ -2301,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/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index d7568554669..b10d5b55789 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -277,17 +277,7 @@ impl<'tcx> ItemCtxt<'tcx> { } _ => self.item_def_id, }; - // FIXME: just invoke `tcx.def_descr` instead of going through the HIR - // Can also remove most `descr` methods then. - let kind = match self.tcx.hir_node_by_def_id(kind_id) { - Node::Item(it) => it.kind.descr(), - Node::ImplItem(it) => it.kind.descr(), - Node::TraitItem(it) => it.kind.descr(), - Node::ForeignItem(it) => it.kind.descr(), - Node::OpaqueTy(_) => "opaque type", - Node::Synthetic => self.tcx.def_descr(kind_id.into()), - node => todo!("{node:#?}"), - }; + let kind = self.tcx.def_descr(kind_id.into()); let mut diag = placeholder_type_error_diag( self, generics, @@ -615,159 +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; - - 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); - } - _ => (), - } - } - } - 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(..) | hir::ItemKind::Const(..) => { - tcx.ensure_ok().generics_of(def_id); - tcx.ensure_ok().type_of(def_id); - tcx.ensure_ok().predicates_of(def_id); - } - - 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); - - 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(..) => { - tcx.ensure_ok().type_of(def_id); - } - - 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); - } - - hir::TraitItemKind::Type(_, None) => { - tcx.ensure_ok().item_bounds(def_id); - tcx.ensure_ok().item_self_bounds(def_id); - } - }; - - 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); - 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(_) => {} - hir::ImplItemKind::Const(..) => {} - } -} - -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); diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 7eb896f0bf1..573af01a62d 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -1,12 +1,11 @@ use std::assert_matches::assert_matches; use std::ops::ControlFlow; -use hir::intravisit::{self, Visitor}; -use hir::{GenericParamKind, HirId, Node}; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; -use rustc_hir::intravisit::VisitorExt; -use rustc_hir::{self as hir, AmbigArg}; +use rustc_hir::intravisit::{self, Visitor, VisitorExt}; +use rustc_hir::{self as hir, AmbigArg, GenericParamKind, HirId, Node}; +use rustc_middle::span_bug; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint; use rustc_span::{Span, Symbol, kw}; @@ -212,7 +211,19 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { // inherit the generics of the item. Some(parent.to_def_id()) } - _ => None, + + // All of these nodes have no parent from which to inherit generics. + Node::Item(_) | Node::ForeignItem(_) => None, + + // Params don't really have generics, but we use it when instantiating their value paths. + Node::GenericParam(_) => None, + + Node::Synthetic => span_bug!( + tcx.def_span(def_id), + "synthetic HIR should have its `generics_of` explicitly fed" + ), + + _ => span_bug!(tcx.def_span(def_id), "unhandled node {node:?}"), }; enum Defaults { 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 74739355e1f..e13daabeb50 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -1088,7 +1088,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // FIXME(#97583): Print associated item bindings properly (i.e., not as equality // predicates!). - // FIXME: Turn this into a structured, translateable & more actionable suggestion. + // FIXME: Turn this into a structured, translatable & more actionable suggestion. let mut where_bounds = vec![]; for bound in [bound, bound2].into_iter().chain(matching_candidates) { let bound_id = bound.def_id(); @@ -1588,7 +1588,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &infcx_ }; - tcx.all_traits() + tcx.all_traits_including_private() .filter(|trait_def_id| { // Consider only traits with the associated type tcx.associated_items(*trait_def_id) @@ -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) } @@ -2460,13 +2459,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // type a projection. let in_trait = match opaque_ty.origin { hir::OpaqueTyOrigin::FnReturn { + parent, in_trait_or_impl: Some(hir::RpitContext::Trait), .. } | hir::OpaqueTyOrigin::AsyncFn { + parent, in_trait_or_impl: Some(hir::RpitContext::Trait), .. - } => true, + } => Some(parent), hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl), .. @@ -2475,7 +2476,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl), .. } - | hir::OpaqueTyOrigin::TyAlias { .. } => false, + | hir::OpaqueTyOrigin::TyAlias { .. } => None, }; self.lower_opaque_ty(opaque_ty.def_id, in_trait) @@ -2595,17 +2596,25 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// Lower an opaque type (i.e., an existential impl-Trait type) from the HIR. #[instrument(level = "debug", skip(self), ret)] - fn lower_opaque_ty(&self, def_id: LocalDefId, in_trait: bool) -> Ty<'tcx> { + fn lower_opaque_ty(&self, def_id: LocalDefId, in_trait: Option<LocalDefId>) -> Ty<'tcx> { let tcx = self.tcx(); let lifetimes = tcx.opaque_captured_lifetimes(def_id); debug!(?lifetimes); - // If this is an RPITIT and we are using the new RPITIT lowering scheme, we - // generate the def_id of an associated type for the trait and return as - // type a projection. - let def_id = if in_trait { - tcx.associated_type_for_impl_trait_in_trait(def_id).to_def_id() + // If this is an RPITIT and we are using the new RPITIT lowering scheme, + // do a linear search to map this to the synthetic associated type that + // it will be lowered to. + let def_id = if let Some(parent_def_id) = in_trait { + *tcx.associated_types_for_impl_traits_in_associated_fn(parent_def_id) + .iter() + .find(|rpitit| match tcx.opt_rpitit_info(**rpitit) { + Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => { + opaque_def_id.expect_local() == def_id + } + _ => unreachable!(), + }) + .unwrap() } else { def_id.to_def_id() }; @@ -2628,7 +2637,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }); debug!(?args); - if in_trait { + if in_trait.is_some() { Ty::new_projection_from_args(tcx, def_id, args) } else { Ty::new_opaque(tcx, def_id, args) 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 087167dfd90..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; @@ -1480,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/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/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 6fa473d177d..b2a229ad651 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -231,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) => @@ -278,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. @@ -323,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, @@ -514,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 @@ -531,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 { @@ -679,7 +726,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { Err(SelectionError::TraitDynIncompatible(_)) => { // Dyn compatibility errors in coercion will *always* be due to the // fact that the RHS of the coercion is a non-dyn compatible `dyn Trait` - // writen in source somewhere (otherwise we will never have lowered + // written in source somewhere (otherwise we will never have lowered // the dyn trait from HIR to middle). // // There's no reason to emit yet another dyn compatibility error, @@ -723,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 @@ -800,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. @@ -848,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(); @@ -888,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) => { @@ -955,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>, @@ -962,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 @@ -1010,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 }), diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index c7b9cb47091..eeb8d33ef65 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -121,7 +121,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => {} } - // We want to emit an error if the const is not structurally resolveable + // We want to emit an error if the const is not structurally resolvable // as otherwise we can wind up conservatively proving `Copy` which may // infer the repeat expr count to something that never required `Copy` in // the first place. @@ -1637,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, @@ -2461,7 +2461,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { spans.push_span_label(param.param.span(), ""); } } - // Highligh each parameter being depended on for a generic type. + // Highlight each parameter being depended on for a generic type. for ((&(_, param), deps), &(_, expected_ty)) in params_with_generics.iter().zip(&dependants).zip(formal_and_expected_inputs) { 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/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 9563cf734f6..4c343bb7c22 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -588,7 +588,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { let def_id = pick.item.def_id; let method_predicates = self.tcx.predicates_of(def_id).instantiate(self.tcx, all_args); - debug!("method_predicates after instantitation = {:?}", method_predicates); + debug!("method_predicates after instantiation = {:?}", method_predicates); let sig = self.tcx.fn_sig(def_id).instantiate(self.tcx, all_args); debug!("type scheme instantiated, sig={:?}", sig); diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 085e7a2f5df..8380c3710e6 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -375,7 +375,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // type parameters or early-bound regions. let tcx = self.tcx; // We use `Ident::with_dummy_span` since no built-in operator methods have - // any macro-specific hygeine, so the span's context doesn't really matter. + // any macro-specific hygiene, so the span's context doesn't really matter. let Some(method_item) = self.associated_value(trait_def_id, Ident::with_dummy_span(method_name)) else { diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index d0a48872f75..2815621ffde 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1725,7 +1725,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if unsatisfied_predicates.is_empty() // ...or if we already suggested that name because of `rustc_confusable` annotation && Some(similar_candidate.name()) != confusable_suggested - // and if the we aren't in an expansion. + // and if we aren't in an expansion. && !span.from_expansion() { self.find_likely_intended_associated_item( @@ -3055,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 @@ -3481,9 +3481,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, err: &mut Diag<'_>, item_name: Ident, - valid_out_of_scope_traits: Vec<DefId>, + mut valid_out_of_scope_traits: Vec<DefId>, explain: bool, ) -> bool { + valid_out_of_scope_traits.retain(|id| self.tcx.is_user_visible_dep(id.krate)); if !valid_out_of_scope_traits.is_empty() { let mut candidates = valid_out_of_scope_traits; candidates.sort_by_key(|id| self.tcx.def_path_str(id)); @@ -4388,7 +4389,7 @@ pub(crate) struct TraitInfo { /// Retrieves all traits in this crate and any dependent crates, /// and wraps them into `TraitInfo` for custom sorting. pub(crate) fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> { - tcx.all_traits().map(|def_id| TraitInfo { def_id }).collect() + tcx.all_traits_including_private().map(|def_id| TraitInfo { def_id }).collect() } fn print_disambiguation_help<'tcx>( 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 349e72090d3..43475521a0f 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -723,7 +723,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // This is maximally flexible, allowing e.g., `Some(mut x) | &Some(mut x)`. // In that example, `Some(mut x)` results in `Peel` whereas `&Some(mut x)` in `Reset`. | PatKind::Or(_) - // Like or-patterns, guard patterns just propogate to their subpatterns. + // Like or-patterns, guard patterns just propagate to their subpatterns. | PatKind::Guard(..) => AdjustMode::Pass, } } 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/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_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index edfb05e2ccd..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,20 +351,30 @@ 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), + uses_with_underscores, thousands::usize_with_underscores(lines), thousands::f64p1_with_underscores(avg_lines), thousands::usize_with_underscores(bytes), diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index b2bd5e188ef..e30dbe80248 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -566,7 +566,7 @@ impl Cursor<'_> { } if !found { - // recovery strategy: a closing statement might have precending whitespace/newline + // recovery strategy: a closing statement might have preceding whitespace/newline // but not have enough dashes to properly close. In this case, we eat until there, // and report a mismatch in the parser. let mut rest = self.as_str(); diff --git a/compiler/rustc_lint/src/autorefs.rs b/compiler/rustc_lint/src/autorefs.rs index 845a1f1b81f..5490a3aac9b 100644 --- a/compiler/rustc_lint/src/autorefs.rs +++ b/compiler/rustc_lint/src/autorefs.rs @@ -41,7 +41,7 @@ declare_lint! { /// } /// ``` /// - /// Otherwise try to find an alternative way to achive your goals using only raw pointers: + /// Otherwise try to find an alternative way to achieve your goals using only raw pointers: /// /// ```rust /// use std::ptr; diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 95663204ec3..b694d3dd49b 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -504,6 +504,7 @@ pub trait LintContext { /// /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature #[rustc_lint_diagnostics] + #[track_caller] fn opt_span_lint<S: Into<MultiSpan>>( &self, lint: &'static Lint, @@ -542,6 +543,7 @@ pub trait LintContext { /// /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature #[rustc_lint_diagnostics] + #[track_caller] fn span_lint<S: Into<MultiSpan>>( &self, lint: &'static Lint, diff --git a/compiler/rustc_lint/src/default_could_be_derived.rs b/compiler/rustc_lint/src/default_could_be_derived.rs index 7734f441df2..0bc772d081f 100644 --- a/compiler/rustc_lint/src/default_could_be_derived.rs +++ b/compiler/rustc_lint/src/default_could_be_derived.rs @@ -133,7 +133,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived { // } // } // where `something()` would have to be a call or path. - // We have nothing meaninful to do with this. + // We have nothing meaningful to do with this. return; } 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/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs index a9b04511c6b..263ea6fa070 100644 --- a/compiler/rustc_lint/src/if_let_rescope.rs +++ b/compiler/rustc_lint/src/if_let_rescope.rs @@ -230,7 +230,7 @@ impl IfLetRescope { } } } - // At this point, any `if let` fragment in the cascade is definitely preceeded by `else`, + // At this point, any `if let` fragment in the cascade is definitely preceded by `else`, // so a opening bracket is mandatory before each `match`. add_bracket_to_match_head = true; if let Some(alt) = alt { 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/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/reference_casting.rs b/compiler/rustc_lint/src/reference_casting.rs index 1d4d380cb68..6ef9d4e9769 100644 --- a/compiler/rustc_lint/src/reference_casting.rs +++ b/compiler/rustc_lint/src/reference_casting.rs @@ -45,7 +45,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidReferenceCasting { let init = cx.expr_or_init(e); let orig_cast = if init.span != e.span { Some(init.span) } else { None }; - // small cache to avoid recomputing needlesly computing peel_casts of init + // small cache to avoid recomputing needlessly computing peel_casts of init let mut peel_casts = { let mut peel_casts_cache = None; move || *peel_casts_cache.get_or_insert_with(|| peel_casts(cx, init)) 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..0627f70507c 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -3,6 +3,7 @@ use std::iter; use rustc_ast::util::{classify, parser}; use rustc_ast::{self as ast, ExprKind, HasAttrs as _, StmtKind}; use rustc_attr_data_structures::{AttributeKind, find_attr}; +use rustc_data_structures::fx::FxHashMap; use rustc_errors::{MultiSpan, pluralize}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; @@ -10,6 +11,7 @@ use rustc_hir::{self as hir, LangItem}; use rustc_infer::traits::util::elaborate; use rustc_middle::ty::{self, Ty, adjustment}; use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass}; +use rustc_span::edition::Edition::Edition2015; use rustc_span::{BytePos, Span, Symbol, kw, sym}; use tracing::instrument; @@ -183,6 +185,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 +194,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 +511,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, @@ -1032,6 +1036,31 @@ pub(crate) struct UnusedParens { /// `1 as (i32) < 2` parses to ExprKind::Lt /// `1 as i32 < 2` parses to i32::<2[missing angle bracket] parens_in_cast_in_lt: Vec<ast::NodeId>, + /// Ty nodes in this map are in TypeNoBounds position. Any bounds they + /// contain may be ambiguous w/r/t trailing `+` operators. + in_no_bounds_pos: FxHashMap<ast::NodeId, NoBoundsException>, +} + +/// Whether parentheses may be omitted from a type without resulting in ambiguity. +/// +/// ``` +/// type Example = Box<dyn Fn() -> &'static (dyn Send) + Sync>; +/// ``` +/// +/// Here, `&'static (dyn Send) + Sync` is a `TypeNoBounds`. As such, it may not directly +/// contain `ImplTraitType` or `TraitObjectType` which is why `(dyn Send)` is parenthesized. +/// However, an exception is made for `ImplTraitTypeOneBound` and `TraitObjectTypeOneBound`. +/// The following is accepted because there is no `+`. +/// +/// ``` +/// type Example = Box<dyn Fn() -> &'static dyn Send>; +/// ``` +enum NoBoundsException { + /// The type must be parenthesized. + None, + /// The type is the last bound of the containing type expression. If it has exactly one bound, + /// parentheses around the type are unnecessary. + OneBound, } impl_lint_pass!(UnusedParens => [UNUSED_PARENS]); @@ -1275,23 +1304,100 @@ impl EarlyLintPass for UnusedParens { ); } ast::TyKind::Paren(r) => { - match &r.kind { - ast::TyKind::TraitObject(..) => {} - ast::TyKind::BareFn(b) - if self.with_self_ty_parens && b.generic_params.len() > 0 => {} - ast::TyKind::ImplTrait(_, bounds) if bounds.len() > 1 => {} - _ => { - let spans = if !ty.span.from_expansion() { + let unused_parens = match &r.kind { + ast::TyKind::ImplTrait(_, bounds) | ast::TyKind::TraitObject(bounds, _) => { + match self.in_no_bounds_pos.get(&ty.id) { + Some(NoBoundsException::None) => false, + Some(NoBoundsException::OneBound) => bounds.len() <= 1, + None => true, + } + } + ast::TyKind::BareFn(b) => { + !self.with_self_ty_parens || b.generic_params.is_empty() + } + _ => true, + }; + + if unused_parens { + let spans = (!ty.span.from_expansion()) + .then(|| { r.span .find_ancestor_inside(ty.span) .map(|r| (ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi()))) + }) + .flatten(); + + self.emit_unused_delims(cx, ty.span, spans, "type", (false, false), false); + } + + self.with_self_ty_parens = false; + } + ast::TyKind::Ref(_, mut_ty) | ast::TyKind::Ptr(mut_ty) => { + self.in_no_bounds_pos.insert(mut_ty.ty.id, NoBoundsException::OneBound); + } + ast::TyKind::TraitObject(bounds, _) | ast::TyKind::ImplTrait(_, bounds) => { + for i in 0..bounds.len() { + let is_last = i == bounds.len() - 1; + + if let ast::GenericBound::Trait(poly_trait_ref) = &bounds[i] { + let fn_with_explicit_ret_ty = if let [.., segment] = + &*poly_trait_ref.trait_ref.path.segments + && let Some(args) = segment.args.as_ref() + && let ast::GenericArgs::Parenthesized(paren_args) = &**args + && let ast::FnRetTy::Ty(ret_ty) = &paren_args.output + { + self.in_no_bounds_pos.insert( + ret_ty.id, + if is_last { + NoBoundsException::OneBound + } else { + NoBoundsException::None + }, + ); + + true } else { - None + false }; - self.emit_unused_delims(cx, ty.span, spans, "type", (false, false), false); + + // In edition 2015, dyn is a contextual keyword and `dyn::foo::Bar` is + // parsed as a path, so parens are necessary to disambiguate. See + // - tests/ui/lint/unused/unused-parens-trait-obj-e2015.rs and + // - https://doc.rust-lang.org/reference/types/trait-object.html#r-type.trait-object.syntax-edition2018 + let dyn2015_exception = cx.sess().psess.edition == Edition2015 + && matches!(ty.kind, ast::TyKind::TraitObject(..)) + && i == 0 + && poly_trait_ref + .trait_ref + .path + .segments + .first() + .map(|s| s.ident.name == kw::PathRoot) + .unwrap_or(false); + + if let ast::Parens::Yes = poly_trait_ref.parens + && (is_last || !fn_with_explicit_ret_ty) + && !dyn2015_exception + { + let s = poly_trait_ref.span; + let spans = (!s.from_expansion()).then(|| { + ( + s.with_hi(s.lo() + rustc_span::BytePos(1)), + s.with_lo(s.hi() - rustc_span::BytePos(1)), + ) + }); + + self.emit_unused_delims( + cx, + poly_trait_ref.span, + spans, + "type", + (false, false), + false, + ); + } } } - self.with_self_ty_parens = false; } _ => {} } @@ -1301,6 +1407,10 @@ impl EarlyLintPass for UnusedParens { <Self as UnusedDelimLint>::check_item(self, cx, item) } + fn check_item_post(&mut self, _: &EarlyContext<'_>, _: &rustc_ast::Item) { + self.in_no_bounds_pos.clear(); + } + fn enter_where_predicate(&mut self, _: &EarlyContext<'_>, pred: &ast::WherePredicate) { use rustc_ast::{WhereBoundPredicate, WherePredicateKind}; if let WherePredicateKind::BoundPredicate(WhereBoundPredicate { diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 10ac14a2fbf..b37548b281c 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1224,7 +1224,7 @@ declare_lint! { /// /// ### Explanation /// - /// A public `use` declaration should not be used to publicly re-export a + /// A public `use` declaration should not be used to publically re-export a /// private `extern crate`. `pub extern crate` should be used instead. /// /// This was historically allowed, but is not the intended behavior diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index 42d006ef301..1006ea3ba10 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -177,7 +177,7 @@ decl_derive! { [PrintAttribute] => /// Derives `PrintAttribute` for `AttributeKind`. /// This macro is pretty specific to `rustc_attr_data_structures` and likely not that useful in - /// other places. It's deriving something close to `Debug` without printing some extraenous + /// other places. It's deriving something close to `Debug` without printing some extraneous /// things like spans. print_attribute::print_attribute } diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 2196f71299a..5821ffa3a30 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -273,8 +273,8 @@ fn add_query_desc_cached_impl( // macro producing a higher order macro that has all its token in the macro declaration we lose // any meaningful spans, resulting in rust-analyzer being unable to make the connection between // the query name and the corresponding providers field. The trick to fix this is to have - // `rustc_queries` emit a field access with the given name's span which allows it to succesfully - // show references / go to definition to the correspondig provider assignment which is usually + // `rustc_queries` emit a field access with the given name's span which allows it to successfully + // show references / go to definition to the corresponding provider assignment which is usually // the more interesting place. let ra_hint = quote! { let crate::query::Providers { #name: _, .. }; @@ -413,7 +413,6 @@ pub(super) fn rustc_queries(input: TokenStream) -> TokenStream { "Query {name} cannot be both `feedable` and `eval_always`." ); feedable_queries.extend(quote! { - #(#doc_comments)* [#attribute_stream] fn #name(#arg) #result, }); } 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 2c882b84c58..e65c7a68426 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -24,8 +24,7 @@ use rustc_middle::ty::data_structures::IndexSet; use rustc_middle::ty::{TyCtxt, TyCtxtFeed}; use rustc_proc_macro::bridge::client::ProcMacro; use rustc_session::config::{ - self, CrateType, ExtendedTargetModifierInfo, ExternLocation, OptionsTargetModifiers, - TargetModifier, + CrateType, ExtendedTargetModifierInfo, ExternLocation, OptionsTargetModifiers, TargetModifier, }; use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate, ExternCrateSource}; use rustc_session::lint::{self, BuiltinLintDiag}; @@ -33,11 +32,11 @@ use rustc_session::output::validate_crate_name; use rustc_session::search_paths::PathKind; use rustc_span::edition::Edition; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym}; -use rustc_target::spec::{PanicStrategy, Target, TargetTuple}; +use rustc_target::spec::{PanicStrategy, Target}; use tracing::{debug, info, trace}; use crate::errors; -use crate::locator::{CrateError, CrateLocator, CratePaths}; +use crate::locator::{CrateError, CrateLocator, CratePaths, CrateRejections}; use crate::rmeta::{ CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob, TargetModifiers, }; @@ -684,61 +683,67 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { fn load_proc_macro<'b>( &self, locator: &mut CrateLocator<'b>, + crate_rejections: &mut CrateRejections, path_kind: PathKind, host_hash: Option<Svh>, ) -> Result<Option<(LoadResult, Option<Library>)>, CrateError> where 'a: 'b, { - // Use a new crate locator so trying to load a proc macro doesn't affect the error - // message we emit - let mut proc_macro_locator = locator.clone(); - - // Try to load a proc macro - proc_macro_locator.is_proc_macro = true; - - // Load the proc macro crate for the target - let (locator, target_result) = if self.sess.opts.unstable_opts.dual_proc_macros { - proc_macro_locator.reset(); - let result = match self.load(&mut proc_macro_locator)? { - Some(LoadResult::Previous(cnum)) => { - return Ok(Some((LoadResult::Previous(cnum), None))); - } - Some(LoadResult::Loaded(library)) => Some(LoadResult::Loaded(library)), - None => return Ok(None), - }; - locator.hash = host_hash; - // Use the locator when looking for the host proc macro crate, as that is required - // so we want it to affect the error message - (locator, result) - } else { - (&mut proc_macro_locator, None) - }; + if self.sess.opts.unstable_opts.dual_proc_macros { + // Use a new crate locator and crate rejections so trying to load a proc macro doesn't + // affect the error message we emit + let mut proc_macro_locator = locator.clone(); + + // Try to load a proc macro + proc_macro_locator.for_target_proc_macro(self.sess, path_kind); + + // Load the proc macro crate for the target + let target_result = + match self.load(&mut proc_macro_locator, &mut CrateRejections::default())? { + Some(LoadResult::Previous(cnum)) => { + return Ok(Some((LoadResult::Previous(cnum), None))); + } + Some(LoadResult::Loaded(library)) => Some(LoadResult::Loaded(library)), + None => return Ok(None), + }; - // Load the proc macro crate for the host + // Use the existing crate_rejections as we want the error message to be affected by + // loading the host proc macro. + *crate_rejections = CrateRejections::default(); - locator.reset(); - locator.is_proc_macro = true; - locator.target = &self.sess.host; - locator.tuple = TargetTuple::from_tuple(config::host_tuple()); - locator.filesearch = self.sess.host_filesearch(); - locator.path_kind = path_kind; + // Load the proc macro crate for the host + locator.for_proc_macro(self.sess, path_kind); - let Some(host_result) = self.load(locator)? else { - return Ok(None); - }; + locator.hash = host_hash; + + let Some(host_result) = self.load(locator, crate_rejections)? else { + return Ok(None); + }; - Ok(Some(if self.sess.opts.unstable_opts.dual_proc_macros { let host_result = match host_result { LoadResult::Previous(..) => { panic!("host and target proc macros must be loaded in lock-step") } LoadResult::Loaded(library) => library, }; - (target_result.unwrap(), Some(host_result)) + Ok(Some((target_result.unwrap(), Some(host_result)))) } else { - (host_result, None) - })) + // Use a new crate locator and crate rejections so trying to load a proc macro doesn't + // affect the error message we emit + let mut proc_macro_locator = locator.clone(); + + // Load the proc macro crate for the host + proc_macro_locator.for_proc_macro(self.sess, path_kind); + + let Some(host_result) = + self.load(&mut proc_macro_locator, &mut CrateRejections::default())? + else { + return Ok(None); + }; + + Ok(Some((host_result, None))) + } } fn resolve_crate( @@ -799,15 +804,21 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { extra_filename, path_kind, ); + let mut crate_rejections = CrateRejections::default(); - match self.load(&mut locator)? { + match self.load(&mut locator, &mut crate_rejections)? { Some(res) => (res, None), None => { info!("falling back to loading proc_macro"); dep_kind = CrateDepKind::MacrosOnly; - match self.load_proc_macro(&mut locator, path_kind, host_hash)? { + match self.load_proc_macro( + &mut locator, + &mut crate_rejections, + path_kind, + host_hash, + )? { Some(res) => res, - None => return Err(locator.into_error(dep_root.cloned())), + None => return Err(locator.into_error(crate_rejections, dep_root.cloned())), } } } @@ -837,8 +848,12 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { } } - fn load(&self, locator: &mut CrateLocator<'_>) -> Result<Option<LoadResult>, CrateError> { - let Some(library) = locator.maybe_load_library_crate()? else { + fn load( + &self, + locator: &CrateLocator<'_>, + crate_rejections: &mut CrateRejections, + ) -> Result<Option<LoadResult>, CrateError> { + let Some(library) = locator.maybe_load_library_crate(crate_rejections)? else { return Ok(None); }; 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 941f16bd960..c30cfd1fcf7 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -224,11 +224,11 @@ use rustc_data_structures::owned_slice::{OwnedSlice, slice_owned}; use rustc_data_structures::svh::Svh; use rustc_errors::{DiagArgValue, IntoDiagArg}; use rustc_fs_util::try_canonicalize; -use rustc_session::Session; use rustc_session::cstore::CrateSource; use rustc_session::filesearch::FileSearch; use rustc_session::search_paths::PathKind; use rustc_session::utils::CanonicalizedPath; +use rustc_session::{Session, config}; use rustc_span::{Span, Symbol}; use rustc_target::spec::{Target, TargetTuple}; use tempfile::Builder as TempFileBuilder; @@ -251,14 +251,11 @@ pub(crate) struct CrateLocator<'a> { exact_paths: Vec<CanonicalizedPath>, pub hash: Option<Svh>, extra_filename: Option<&'a str>, - pub target: &'a Target, - pub tuple: TargetTuple, - pub filesearch: &'a FileSearch, - pub is_proc_macro: bool, - - pub path_kind: PathKind, - // Mutable in-progress state or output. - crate_rejections: CrateRejections, + target: &'a Target, + tuple: TargetTuple, + filesearch: &'a FileSearch, + is_proc_macro: bool, + path_kind: PathKind, } #[derive(Clone, Debug)] @@ -346,34 +343,46 @@ impl<'a> CrateLocator<'a> { filesearch: sess.target_filesearch(), path_kind, is_proc_macro: false, - crate_rejections: CrateRejections::default(), } } - pub(crate) fn reset(&mut self) { - self.crate_rejections.via_hash.clear(); - self.crate_rejections.via_triple.clear(); - self.crate_rejections.via_kind.clear(); - self.crate_rejections.via_version.clear(); - self.crate_rejections.via_filename.clear(); - self.crate_rejections.via_invalid.clear(); + pub(crate) fn for_proc_macro(&mut self, sess: &'a Session, path_kind: PathKind) { + self.is_proc_macro = true; + self.target = &sess.host; + self.tuple = TargetTuple::from_tuple(config::host_tuple()); + self.filesearch = sess.host_filesearch(); + self.path_kind = path_kind; } - pub(crate) fn maybe_load_library_crate(&mut self) -> Result<Option<Library>, CrateError> { + pub(crate) fn for_target_proc_macro(&mut self, sess: &'a Session, path_kind: PathKind) { + self.is_proc_macro = true; + self.target = &sess.target; + self.tuple = sess.opts.target_triple.clone(); + self.filesearch = sess.target_filesearch(); + self.path_kind = path_kind; + } + + pub(crate) fn maybe_load_library_crate( + &self, + crate_rejections: &mut CrateRejections, + ) -> Result<Option<Library>, CrateError> { if !self.exact_paths.is_empty() { - return self.find_commandline_library(); + return self.find_commandline_library(crate_rejections); } let mut seen_paths = FxHashSet::default(); if let Some(extra_filename) = self.extra_filename { - if let library @ Some(_) = self.find_library_crate(extra_filename, &mut seen_paths)? { + if let library @ Some(_) = + self.find_library_crate(crate_rejections, extra_filename, &mut seen_paths)? + { return Ok(library); } } - self.find_library_crate("", &mut seen_paths) + self.find_library_crate(crate_rejections, "", &mut seen_paths) } fn find_library_crate( - &mut self, + &self, + crate_rejections: &mut CrateRejections, extra_prefix: &str, seen_paths: &mut FxHashSet<PathBuf>, ) -> Result<Option<Library>, CrateError> { @@ -437,8 +446,8 @@ impl<'a> CrateLocator<'a> { let (rlibs, rmetas, dylibs, interfaces) = candidates.entry(hash).or_default(); { - // As a perforamnce optimisation we canonicalize the path and skip - // ones we've already seeen. This allows us to ignore crates + // As a performance optimisation we canonicalize the path and skip + // ones we've already seen. This allows us to ignore crates // we know are exactual equal to ones we've already found. // Going to the same crate through different symlinks does not change the result. let path = try_canonicalize(&spf.path) @@ -465,7 +474,7 @@ impl<'a> CrateLocator<'a> { .flatten() { for (_, spf) in static_matches { - self.crate_rejections.via_kind.push(CrateMismatch { + crate_rejections.via_kind.push(CrateMismatch { path: spf.path.to_path_buf(), got: "static".to_string(), }); @@ -483,7 +492,9 @@ impl<'a> CrateLocator<'a> { // search is being performed for. let mut libraries = FxIndexMap::default(); for (_hash, (rlibs, rmetas, dylibs, interfaces)) in candidates { - if let Some((svh, lib)) = self.extract_lib(rlibs, rmetas, dylibs, interfaces)? { + if let Some((svh, lib)) = + self.extract_lib(crate_rejections, rlibs, rmetas, dylibs, interfaces)? + { libraries.insert(svh, lib); } } @@ -495,13 +506,11 @@ impl<'a> CrateLocator<'a> { 0 => Ok(None), 1 => Ok(Some(libraries.into_iter().next().unwrap().1)), _ => { - let mut libraries: Vec<_> = libraries.into_values().collect(); - - libraries.sort_by_cached_key(|lib| lib.source.paths().next().unwrap().clone()); - let candidates = libraries - .iter() + let mut candidates: Vec<PathBuf> = libraries + .into_values() .map(|lib| lib.source.paths().next().unwrap().clone()) - .collect::<Vec<_>>(); + .collect(); + candidates.sort(); Err(CrateError::MultipleCandidates( self.crate_name, @@ -514,7 +523,8 @@ impl<'a> CrateLocator<'a> { } fn extract_lib( - &mut self, + &self, + crate_rejections: &mut CrateRejections, rlibs: FxIndexMap<PathBuf, PathKind>, rmetas: FxIndexMap<PathBuf, PathKind>, dylibs: FxIndexMap<PathBuf, PathKind>, @@ -526,10 +536,11 @@ impl<'a> CrateLocator<'a> { // Make sure there's at most one rlib and at most one dylib. // // See comment in `extract_one` below. - let rmeta = self.extract_one(rmetas, CrateFlavor::Rmeta, &mut slot)?; - let rlib = self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot)?; - let sdylib_interface = self.extract_one(interfaces, CrateFlavor::SDylib, &mut slot)?; - let dylib = self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot)?; + let rmeta = self.extract_one(crate_rejections, rmetas, CrateFlavor::Rmeta, &mut slot)?; + let rlib = self.extract_one(crate_rejections, rlibs, CrateFlavor::Rlib, &mut slot)?; + let sdylib_interface = + self.extract_one(crate_rejections, interfaces, CrateFlavor::SDylib, &mut slot)?; + let dylib = self.extract_one(crate_rejections, dylibs, CrateFlavor::Dylib, &mut slot)?; if sdylib_interface.is_some() && dylib.is_none() { return Err(CrateError::FullMetadataNotFound(self.crate_name, CrateFlavor::SDylib)); @@ -563,7 +574,8 @@ impl<'a> CrateLocator<'a> { // // The `PathBuf` in `slot` will only be used for diagnostic purposes. fn extract_one( - &mut self, + &self, + crate_rejections: &mut CrateRejections, m: FxIndexMap<PathBuf, PathKind>, flavor: CrateFlavor, slot: &mut Option<(Svh, MetadataBlob, PathBuf, CrateFlavor)>, @@ -605,7 +617,7 @@ impl<'a> CrateLocator<'a> { Some(self.crate_name), ) { Ok(blob) => { - if let Some(h) = self.crate_matches(&blob, &lib) { + if let Some(h) = self.crate_matches(crate_rejections, &blob, &lib) { (h, blob) } else { info!("metadata mismatch"); @@ -620,7 +632,7 @@ impl<'a> CrateLocator<'a> { "Rejecting via version: expected {} got {}", expected_version, found_version ); - self.crate_rejections + crate_rejections .via_version .push(CrateMismatch { path: lib, got: found_version }); continue; @@ -635,7 +647,7 @@ impl<'a> CrateLocator<'a> { // The file was present and created by the same compiler version, but we // couldn't load it for some reason. Give a hard error instead of silently // ignoring it, but only if we would have given an error anyway. - self.crate_rejections.via_invalid.push(CrateMismatch { path: lib, got: err }); + crate_rejections.via_invalid.push(CrateMismatch { path: lib, got: err }); continue; } Err(err @ MetadataError::NotPresent(_)) => { @@ -713,7 +725,12 @@ impl<'a> CrateLocator<'a> { } } - fn crate_matches(&mut self, metadata: &MetadataBlob, libpath: &Path) -> Option<Svh> { + fn crate_matches( + &self, + crate_rejections: &mut CrateRejections, + metadata: &MetadataBlob, + libpath: &Path, + ) -> Option<Svh> { let header = metadata.get_header(); if header.is_proc_macro_crate != self.is_proc_macro { info!( @@ -730,7 +747,7 @@ impl<'a> CrateLocator<'a> { if header.triple != self.tuple { info!("Rejecting via crate triple: expected {} got {}", self.tuple, header.triple); - self.crate_rejections.via_triple.push(CrateMismatch { + crate_rejections.via_triple.push(CrateMismatch { path: libpath.to_path_buf(), got: header.triple.to_string(), }); @@ -741,7 +758,7 @@ impl<'a> CrateLocator<'a> { if let Some(expected_hash) = self.hash { if hash != expected_hash { info!("Rejecting via hash: expected {} got {}", expected_hash, hash); - self.crate_rejections + crate_rejections .via_hash .push(CrateMismatch { path: libpath.to_path_buf(), got: hash.to_string() }); return None; @@ -751,7 +768,10 @@ impl<'a> CrateLocator<'a> { Some(hash) } - fn find_commandline_library(&mut self) -> Result<Option<Library>, CrateError> { + fn find_commandline_library( + &self, + crate_rejections: &mut CrateRejections, + ) -> Result<Option<Library>, CrateError> { // First, filter out all libraries that look suspicious. We only accept // files which actually exist that have the correct naming scheme for // rlibs/dylibs. @@ -796,24 +816,28 @@ impl<'a> CrateLocator<'a> { dylibs.insert(loc_canon.clone(), PathKind::ExternFlag); continue; } - self.crate_rejections + crate_rejections .via_filename .push(CrateMismatch { path: loc_orig.clone(), got: String::new() }); } // Extract the dylib/rlib/rmeta triple. - self.extract_lib(rlibs, rmetas, dylibs, sdylib_interfaces) + self.extract_lib(crate_rejections, rlibs, rmetas, dylibs, sdylib_interfaces) .map(|opt| opt.map(|(_, lib)| lib)) } - pub(crate) fn into_error(self, dep_root: Option<CratePaths>) -> CrateError { + pub(crate) fn into_error( + self, + crate_rejections: CrateRejections, + dep_root: Option<CratePaths>, + ) -> CrateError { CrateError::LocatorCombined(Box::new(CombinedLocatorError { crate_name: self.crate_name, dep_root, triple: self.tuple, dll_prefix: self.target.dll_prefix.to_string(), dll_suffix: self.target.dll_suffix.to_string(), - crate_rejections: self.crate_rejections, + crate_rejections, })) } } @@ -993,7 +1017,7 @@ struct CrateMismatch { } #[derive(Clone, Debug, Default)] -struct CrateRejections { +pub(crate) struct CrateRejections { via_hash: Vec<CrateMismatch>, via_triple: Vec<CrateMismatch>, via_kind: Vec<CrateMismatch>, diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 2696c47c62c..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_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_symbols.decode((self, tcx))) + tcx.arena.alloc_from_iter(self.root.exported_generic_symbols.decode((self, tcx))) } fn get_macro(self, id: DefIndex, sess: &Session) -> ast::MacroDef { 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 d74918235b6..90bc427a19a 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -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, @@ -2360,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| { @@ -2427,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 0073deb18da..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} 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/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..d2cadc96b63 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), @@ -799,7 +799,7 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes> /// Initialize all previously uninitialized bytes in the entire allocation, and set /// provenance of everything to `Wildcard`. Before calling this, make sure all /// provenance in this allocation is exposed! - pub fn prepare_for_native_write(&mut self) -> AllocResult { + pub fn prepare_for_native_access(&mut self) { let full_range = AllocRange { start: Size::ZERO, size: Size::from_bytes(self.len()) }; // Overwrite uninitialized bytes with 0, to ensure we don't leak whatever their value happens to be. for chunk in self.init_mask.range_as_init_chunks(full_range) { @@ -814,13 +814,6 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes> // Set provenance of all bytes to wildcard. self.provenance.write_wildcards(self.len()); - - // Also expose the provenance of the interpreter-level allocation, so it can - // be written by FFI. The `black_box` is defensive programming as LLVM likes - // to (incorrectly) optimize away ptr2int casts whose result is unused. - std::hint::black_box(self.get_bytes_unchecked_raw_mut().expose_provenance()); - - Ok(()) } /// Remove all provenance in the given memory range. diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs index c9525df1f79..63608947eb3 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs @@ -120,7 +120,7 @@ impl<Prov: Provenance> ProvenanceMap<Prov> { } } - /// Check if here is ptr-sized provenance at the given index. + /// Check if there is ptr-sized provenance at the given index. /// Does not mean anything for bytewise provenance! But can be useful as an optimization. pub fn get_ptr(&self, offset: Size) -> Option<Prov> { self.ptrs.get(&offset).copied() diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 41a166083d0..8acb8fa9f80 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -116,7 +116,7 @@ impl<'tcx> From<ErrorHandled> for ValTreeCreationError<'tcx> { 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 + // An error occurred 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(); diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index ea2f84d46d7..da9e5bdbadd 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -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/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..e819aa2d8f8 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -262,7 +262,7 @@ pub struct Body<'tcx> { /// us to see the difference and forego optimization on the inlined promoted items. pub phase: MirPhase, - /// How many passses we have executed since starting the current phase. Used for debug output. + /// How many passes we have executed since starting the current phase. Used for debug output. pub pass_count: usize, pub source: MirSource<'tcx>, @@ -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..6039a03aa29 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, } @@ -381,7 +381,7 @@ pub enum StatementKind<'tcx> { /// computing these locals. /// /// If the local is already allocated, calling `StorageLive` again will implicitly free the - /// local and then allocate fresh uninitilized memory. If a local is already deallocated, + /// local and then allocate fresh uninitialized memory. If a local is already deallocated, /// calling `StorageDead` again is a NOP. StorageLive(Local), @@ -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 26a31cb055e..f138c5ca039 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -266,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 ddedea32112..8c20e71e26a 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; @@ -354,7 +355,7 @@ rustc_queries! { /// Returns whether the type alias given by `DefId` is lazy. /// /// I.e., if the type alias expands / ought to expand to a [free] [alias type] - /// instead of the underyling aliased type. + /// instead of the underlying aliased type. /// /// Relevant for features `lazy_type_alias` and `type_alias_impl_trait`. /// @@ -439,7 +440,6 @@ rustc_queries! { query predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { desc { |tcx| "computing predicates of `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } - feedable } query opaque_types_defined_by( @@ -1092,13 +1092,6 @@ rustc_queries! { separate_provide_extern } - /// Given an impl trait in trait `opaque_ty_def_id`, create and return the corresponding - /// associated item. - query associated_type_for_impl_trait_in_trait(opaque_ty_def_id: LocalDefId) -> LocalDefId { - desc { |tcx| "creating the associated item corresponding to the opaque type `{}`", tcx.def_path_str(opaque_ty_def_id.to_def_id()) } - cache_on_disk_if { true } - } - /// Given an `impl_id`, return the trait it implements along with some header information. /// Return `None` if this is an inherent impl. query impl_trait_header(impl_id: DefId) -> Option<ty::ImplTraitHeader<'tcx>> { @@ -1283,15 +1276,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 @@ -1481,6 +1474,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 +2309,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 d0e72a86d8a..730c1147684 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -380,11 +380,11 @@ pub enum ExprKind<'tcx> { }, /// A `#[loop_match] loop { state = 'blk: { match state { ... } } }` expression. LoopMatch { - /// The state variable that is updated, and also the scrutinee of the match. + /// The state variable that is updated. + /// The `match_data.scrutinee` is the same variable, but with a different span. state: ExprId, region_scope: region::Scope, - arms: Box<[ArmId]>, - match_span: Span, + match_data: Box<LoopMatchMatchData>, }, /// 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 `&&`). @@ -526,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 @@ -599,6 +599,14 @@ pub struct Arm<'tcx> { pub span: Span, } +/// The `match` part of a `#[loop_match]` +#[derive(Clone, Debug, HashStable)] +pub struct LoopMatchMatchData { + pub scrutinee: ExprId, + pub arms: Box<[ArmId]>, + pub span: Span, +} + #[derive(Copy, Clone, Debug, HashStable)] pub enum LogicalOp { /// The `&&` operator. diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index c9ef723aea4..dcfa6c4db32 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -2,6 +2,7 @@ use super::{ AdtExpr, AdtExprBase, Arm, Block, ClosureExpr, Expr, ExprKind, InlineAsmExpr, InlineAsmOperand, Pat, PatKind, Stmt, StmtKind, Thir, }; +use crate::thir::LoopMatchMatchData; /// Every `walk_*` method uses deconstruction to access fields of structs and /// enums. This will result in a compile error if a field is added, which makes @@ -83,7 +84,8 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( visitor.visit_pat(pat); } Loop { body } => visitor.visit_expr(&visitor.thir()[body]), - LoopMatch { state: scrutinee, ref arms, .. } | Match { scrutinee, ref arms, .. } => { + LoopMatch { match_data: box LoopMatchMatchData { scrutinee, ref arms, .. }, .. } + | Match { scrutinee, ref arms, .. } => { visitor.visit_expr(&visitor.thir()[scrutinee]); for &arm in &**arms { visitor.visit_arm(&visitor.thir()[arm]); 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/context.rs b/compiler/rustc_middle/src/ty/context.rs index 457a4f4d502..efa47b57cf3 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}; @@ -1648,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> { @@ -2310,7 +2287,7 @@ impl<'tcx> TyCtxt<'tcx> { } /// All traits in the crate graph, including those not visible to the user. - pub fn all_traits(self) -> impl Iterator<Item = DefId> { + pub fn all_traits_including_private(self) -> impl Iterator<Item = DefId> { iter::once(LOCAL_CRATE) .chain(self.crates(()).iter().copied()) .flat_map(move |cnum| self.traits(cnum).iter().copied()) diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 68adfb3cdb3..21b7500e46f 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -71,7 +71,7 @@ pub enum InstanceKind<'tcx> { /// - coroutines Item(DefId), - /// An intrinsic `fn` item (with`#[rustc_instrinsic]`). + /// An intrinsic `fn` item (with`#[rustc_intrinsic]`). /// /// Alongside `Virtual`, this is the only `InstanceKind` that does not have its own callable MIR. /// Instead, codegen and const eval "magically" evaluate calls to intrinsics purely in the @@ -445,10 +445,10 @@ impl<'tcx> fmt::Display for Instance<'tcx> { } } -// async_drop_in_place<T>::coroutine.poll, when T is a standart coroutine, +// async_drop_in_place<T>::coroutine.poll, when T is a standard coroutine, // should be resolved to this coroutine's future_drop_poll (through FutureDropPollShim proxy). // async_drop_in_place<async_drop_in_place<T>::coroutine>::coroutine.poll, -// when T is a standart coroutine, should be resolved to this coroutine's future_drop_poll. +// when T is a standard coroutine, should be resolved to this coroutine's future_drop_poll. // async_drop_in_place<async_drop_in_place<T>::coroutine>::coroutine.poll, // when T is not a coroutine, should be resolved to the innermost // async_drop_in_place<T>::coroutine's poll function (through FutureDropPollShim proxy) diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 90b832df281..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(..) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 1392d1d08fc..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, _) => { diff --git a/compiler/rustc_middle/src/ty/significant_drop_order.rs b/compiler/rustc_middle/src/ty/significant_drop_order.rs index 561f84192b4..5ada9ecc80c 100644 --- a/compiler/rustc_middle/src/ty/significant_drop_order.rs +++ b/compiler/rustc_middle/src/ty/significant_drop_order.rs @@ -70,7 +70,7 @@ fn true_significant_drop_ty<'tcx>( } } -/// Returns the list of types with a "potentially sigificant" that may be dropped +/// Returns the list of types with a "potentially significant" that may be dropped /// by dropping a value of type `ty`. #[instrument(level = "trace", skip(tcx, typing_env))] pub fn extract_component_raw<'tcx>( diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 3971ac13bbe..7a1890226c9 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1322,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()) } @@ -1629,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(..) @@ -1683,7 +1676,7 @@ impl<'tcx> Ty<'tcx> { /// This is particularly useful for getting the type of the result of /// [`UnOp::PtrMetadata`](crate::mir::UnOp::PtrMetadata). /// - /// Panics if `self` is not dereferencable. + /// Panics if `self` is not dereferenceable. #[track_caller] pub fn pointee_metadata_ty_or_projection(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { let Some(pointee_ty) = self.builtin_deref(true) else { @@ -1820,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, 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 99148504a87..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)) 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 9e07dd5da7e..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), + ))), + ), ); } @@ -789,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/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs index fe3d072fa88..82b883a99a1 100644 --- a/compiler/rustc_mir_build/src/builder/expr/into.rs +++ b/compiler/rustc_mir_build/src/builder/expr/into.rs @@ -245,7 +245,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None }) } - ExprKind::LoopMatch { state, region_scope, match_span, ref arms } => { + ExprKind::LoopMatch { + state, + region_scope, + match_data: box LoopMatchMatchData { box ref arms, span: match_span, scrutinee }, + } => { // Intuitively, this is a combination of a loop containing a labeled block // containing a match. // @@ -292,8 +296,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // 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; + unpack!(body_block = this.as_place_builder(body_block, scrutinee)); + let scrutinee_span = this.thir.exprs[scrutinee].span; let match_start_span = match_span.shrink_to_lo().to(scrutinee_span); let mut patterns = Vec::with_capacity(arms.len()); @@ -335,7 +339,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { move |this| { this.in_breakable_scope(None, state_place, expr_span, |this| { Some(this.in_const_continuable_scope( - arms.clone(), + Box::from(arms), built_tree.clone(), state_place, expr_span, diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 270a7d4b154..2c29b862841 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -646,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 @@ -666,7 +666,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // `<expr>`. ty::Invariant, ), - }, + ), ); self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard); @@ -828,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) @@ -2578,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, ), - }, + ), ); } } @@ -2970,6 +2970,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } Constructor::Wildcard => true, + // Opaque patterns must not be matched on structurally. + Constructor::Opaque(_) => false, + // These we may eventually support: Constructor::Struct | Constructor::Ref @@ -2980,8 +2983,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | Constructor::Str(_) => bug!("unsupported pattern constructor {:?}", pat.ctor()), // These should never occur here: - Constructor::Opaque(_) - | Constructor::Never + Constructor::Never | Constructor::NonExhaustive | Constructor::Hidden | Constructor::Missing diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs index 1d15e7e126f..405d47c7c79 100644 --- a/compiler/rustc_mir_build/src/builder/scope.rs +++ b/compiler/rustc_mir_build/src/builder/scope.rs @@ -431,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 { @@ -454,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 { @@ -1124,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 => { @@ -1138,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)), ); } } @@ -1880,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 => { @@ -1910,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/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 20e836f6bf2..16b49bf384c 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -1230,7 +1230,6 @@ pub(crate) struct ConstContinueMissingValue { #[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 5197e93fda7..b694409f327 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -983,8 +983,11 @@ impl<'tcx> ThirBuildCx<'tcx> { data: region::ScopeData::Node, }, - arms: arms.iter().map(|a| self.convert_arm(a)).collect(), - match_span: block_body_expr.span, + match_data: Box::new(LoopMatchMatchData { + scrutinee: self.mirror_expr(scrutinee), + arms: arms.iter().map(|a| self.convert_arm(a)).collect(), + span: block_body_expr.span, + }), } } else { let block_ty = self.typeck_results.node_type(body.hir_id); 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 41fbabc2539..b7b160c738d 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -6,7 +6,7 @@ use rustc_errors::codes::*; use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, struct_span_code_err}; use rustc_hir::def::*; use rustc_hir::def_id::LocalDefId; -use rustc_hir::{self as hir, BindingMode, ByRef, HirId}; +use rustc_hir::{self as hir, BindingMode, ByRef, HirId, MatchSource}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::Level; use rustc_middle::bug; @@ -154,6 +154,12 @@ impl<'p, 'tcx> Visitor<'p, 'tcx> for MatchVisitor<'p, 'tcx> { ExprKind::Match { scrutinee, box ref arms, match_source } => { self.check_match(scrutinee, arms, match_source, ex.span); } + ExprKind::LoopMatch { + match_data: box LoopMatchMatchData { scrutinee, box ref arms, span }, + .. + } => { + self.check_match(scrutinee, arms, MatchSource::Normal, span); + } ExprKind::Let { box ref pat, expr } => { self.check_let(pat, Some(expr), ex.span); } diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 003ad170861..6d617d43c2a 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -365,11 +365,11 @@ fn extend_type_not_partial_eq<'tcx>( struct UsedParamsNeedInstantiationVisitor<'tcx> { tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, - /// The user has written `impl PartialEq for Ty` which means it's non-structual. + /// The user has written `impl PartialEq for Ty` which means it's non-structural. adts_with_manual_partialeq: FxHashSet<Span>, /// The type has no `PartialEq` implementation, neither manual or derived. adts_without_partialeq: FxHashSet<Span>, - /// The user has written `impl PartialEq for Ty` which means it's non-structual, + /// The user has written `impl PartialEq for Ty` which means it's non-structural, /// but we don't have a span to point at, so we'll just add them as a `note`. manual: FxHashSet<Ty<'tcx>>, /// The type has no `PartialEq` implementation, neither manual or derived, but 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 1507b6b8c06..5efc4be2de2 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -318,18 +318,23 @@ 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 } => { + LoopMatch { state, region_scope, match_data } => { 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, "match_data:", depth_lvl + 1); + print_indented!(self, "LoopMatchMatchData {", depth_lvl + 2); + print_indented!(self, format!("span: {:?}", match_data.span), depth_lvl + 3); + print_indented!(self, "scrutinee:", depth_lvl + 3); + self.print_expr(match_data.scrutinee, depth_lvl + 4); + + print_indented!(self, "arms: [", depth_lvl + 3); + for arm_id in match_data.arms.iter() { + self.print_arm(*arm_id, depth_lvl + 4); } - print_indented!(self, "]", depth_lvl + 1); + print_indented!(self, "]", depth_lvl + 3); + print_indented!(self, "}", depth_lvl + 2); print_indented!(self, "}", depth_lvl); } Let { expr, pat } => { 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..33a87cb9873 --- /dev/null +++ b/compiler/rustc_mir_transform/src/check_enums.rs @@ -0,0 +1,522 @@ +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, + }, +} + +#[derive(Debug, Copy, Clone)] +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 comparisons 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_place = insert_discr_cast_to_u128( + tcx, + local_decls, + block_data, + source_op, + discr, + op_size, + None, + source_info, + ); + + // Mask out the bits of the discriminant type. + let mask = discr.size.unsigned_int_max(); + let discr_masked = + local_decls.push(LocalDecl::with_source_info(tcx.types.u128, source_info)).into(); + let rvalue = Rvalue::BinaryOp( + BinOp::BitAnd, + Box::new(( + Operand::Copy(discr_place), + Operand::Constant(Box::new(ConstOperand { + span: source_info.span, + user_ty: None, + const_: Const::Val(ConstValue::from_u128(mask), tcx.types.u128), + })), + )), + ); + block_data + .statements + .push(Statement::new(source_info, StatementKind::Assign(Box::new((discr_masked, rvalue))))); + + // Branch based on the discriminant value. + block_data.terminator = Some(Terminator { + source_info, + kind: TerminatorKind::SwitchInt { + discr: Operand::Copy(discr_masked), + targets: SwitchTargets::new( + discriminants + .into_iter() + .map(|discr_val| (discr.size.truncate(discr_val), 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_masked))), + // 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 against 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/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/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs index 0a839d91404..81d7b7ba02c 100644 --- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs +++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs @@ -239,7 +239,7 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>( body_def.explicit_predicates_of(tcx.explicit_predicates_of(coroutine_def_id)); body_def.generics_of(tcx.generics_of(coroutine_def_id).clone()); body_def.param_env(tcx.param_env(coroutine_def_id)); - body_def.predicates_of(tcx.predicates_of(coroutine_def_id)); + body_def.explicit_predicates_of(tcx.explicit_predicates_of(coroutine_def_id)); // The type of the coroutine is the `by_move_coroutine_ty`. body_def.type_of(ty::EarlyBinder::bind(by_move_coroutine_ty)); 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/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 b17b7f45000..6b11706d2b5 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -29,7 +29,7 @@ //! _b = some other value // also has VnIndex i //! ``` //! -//! We consider it to be replacable by: +//! We consider it to be replaceable by: //! ```ignore (MIR) //! _a = some value // has VnIndex i //! // some MIR @@ -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 d86daf937da..1c0fc774867 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; } } @@ -1127,10 +1127,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 } @@ -1143,19 +1143,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/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 1bd770a8526..2f0edf31162 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,7 +516,7 @@ 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. + // Because 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"); 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/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs index 368d5340ac3..d1c2d6b508f 100644 --- a/compiler/rustc_mir_transform/src/ref_prop.rs +++ b/compiler/rustc_mir_transform/src/ref_prop.rs @@ -138,7 +138,7 @@ fn compute_replacement<'tcx>( // reborrowed references. let mut storage_to_remove = DenseBitSet::new_empty(body.local_decls.len()); - let fully_replacable_locals = fully_replacable_locals(ssa); + let fully_replaceable_locals = fully_replaceable_locals(ssa); // Returns true iff we can use `place` as a pointee. // @@ -204,7 +204,7 @@ fn compute_replacement<'tcx>( let needs_unique = ty.is_mutable_ptr(); // If this a mutable reference that we cannot fully replace, mark it as unknown. - if needs_unique && !fully_replacable_locals.contains(local) { + if needs_unique && !fully_replaceable_locals.contains(local) { debug!("not fully replaceable"); continue; } @@ -303,7 +303,7 @@ fn compute_replacement<'tcx>( // This a reborrow chain, recursively allow the replacement. // - // This also allows to detect cases where `target.local` is not replacable, + // This also allows to detect cases where `target.local` is not replaceable, // and mark it as such. if let &[PlaceElem::Deref] = &target.projection[..] { assert!(perform_opt); @@ -313,7 +313,7 @@ fn compute_replacement<'tcx>( } else if perform_opt { self.allowed_replacements.insert((target.local, loc)); } else if needs_unique { - // This mutable reference is not fully replacable, so drop it. + // This mutable reference is not fully replaceable, so drop it. self.targets[place.local] = Value::Unknown; } } @@ -326,22 +326,22 @@ fn compute_replacement<'tcx>( /// Compute the set of locals that can be fully replaced. /// -/// We consider a local to be replacable iff it's only used in a `Deref` projection `*_local` or +/// We consider a local to be replaceable iff it's only used in a `Deref` projection `*_local` or /// non-use position (like storage statements and debuginfo). -fn fully_replacable_locals(ssa: &SsaLocals) -> DenseBitSet<Local> { - let mut replacable = DenseBitSet::new_empty(ssa.num_locals()); +fn fully_replaceable_locals(ssa: &SsaLocals) -> DenseBitSet<Local> { + let mut replaceable = DenseBitSet::new_empty(ssa.num_locals()); // First pass: for each local, whether its uses can be fully replaced. for local in ssa.locals() { if ssa.num_direct_uses(local) == 0 { - replacable.insert(local); + replaceable.insert(local); } } // Second pass: a local can only be fully replaced if all its copies can. - ssa.meet_copy_equivalence(&mut replacable); + ssa.meet_copy_equivalence(&mut replaceable); - replacable + replaceable } /// Utility to help performing substitution of `*pattern` by `target`. diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 6d45bbc6e16..cdbc74cdfa8 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -31,7 +31,7 @@ pub(super) fn provide(providers: &mut Providers) { providers.mir_shims = make_shim; } -// Replace Pin<&mut ImplCoroutine> accesses (_1.0) into Pin<&mut ProxyCoroutine> acceses +// Replace Pin<&mut ImplCoroutine> accesses (_1.0) into Pin<&mut ProxyCoroutine> accesses struct FixProxyFutureDropVisitor<'tcx> { tcx: TyCtxt<'tcx>, replace_to: Local, @@ -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 38da5c390ef..131064f9832 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -532,7 +532,7 @@ fn collect_items_rec<'tcx>( }); } // Only updating `usage_map` for used items as otherwise we may be inserting the same item - // multiple times (if it is first 'mentioned' and then later actuall used), and the usage map + // multiple times (if it is first 'mentioned' and then later actually used), and the usage map // logic does not like that. // This is part of the output of collection and hence only relevant for "used" items. // ("Mentioned" items are only considered internally during collection.) @@ -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); } } diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 49025673bbd..69851511fb1 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -893,7 +893,7 @@ fn mono_item_visibility<'tcx>( // * First is weak lang items. These are basically mechanisms for // libcore to forward-reference symbols defined later in crates like // the standard library or `#[panic_handler]` definitions. The - // definition of these weak lang items needs to be referencable by + // definition of these weak lang items needs to be referenceable by // libcore, so we're no longer a candidate for internalization. // Removal of these functions can't be done by LLVM but rather must be // done by the linker as it's a non-local decision. 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 5b6f9785272..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 @@ -997,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 0547eb77f8d..61f3f9367f0 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -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( @@ -75,7 +73,7 @@ where /// 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 + /// Instead, they only hold if the const conditions on the alias also hold. This is why /// we also register the const conditions of the alias after matching the goal against /// the assumption. fn consider_additional_alias_assumptions( diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs index cb7c498b94e..5ed316aa6b1 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs @@ -88,7 +88,7 @@ where /// This takes the `shallow_certainty` which represents whether we're confident /// that the final result of the current goal only depends on the nested goals. /// - /// In case this is `Certainy::Maybe`, there may still be additional nested goals + /// In case this is `Certainty::Maybe`, there may still be additional nested goals /// or inference constraints required for this candidate to be hold. The candidate /// always requires all already added constraints and nested goals. #[instrument(level = "trace", skip(self), ret)] 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 dd9ccadf6cf..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 @@ -429,22 +429,21 @@ 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); @@ -833,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())?; @@ -860,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/normalizes_to/inherent.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs index 26443c54e18..2bb1ac8f742 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs @@ -42,7 +42,7 @@ where // Right now this includes both the impl and the assoc item where bounds, // and I don't think the assoc item where-bounds are allowed to be coinductive. // - // Projecting to the IAT also "steps out the impl contructor", so we would have + // Projecting to the IAT also "steps out the impl constructor", so we would have // to be very careful when changing the impl where-clauses to be productive. self.add_goals( GoalSource::Misc, 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/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 8aaa8e9ca87..098dc9dbaf0 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -127,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( @@ -1302,7 +1301,7 @@ where D: SolverDelegate<Interner = I>, I: Interner, { - /// FIXME(#57893): For backwards compatability with the old trait solver implementation, + /// FIXME(#57893): For backwards compatibility with the old trait solver implementation, /// we need to handle overlap between builtin and user-written impls for trait objects. /// /// This overlap is unsound in general and something which we intend to fix separately. diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index f6e0b08b140..af9f8735549 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -512,6 +512,8 @@ parse_leading_underscore_unicode_escape_label = invalid start of unicode escape parse_left_arrow_operator = unexpected token: `<-` .suggestion = if you meant to write a comparison against a negative value, add a space in between `<` and `-` +parse_let_chain_pre_2024 = let chains are only allowed in Rust 2024 or later + parse_lifetime_after_mut = lifetime must precede `mut` .suggestion = place the lifetime before `mut` diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 0f0c5434800..7f1b0991f0c 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1779,6 +1779,13 @@ pub(crate) struct AsyncBoundModifierIn2015 { } #[derive(Diagnostic)] +#[diag(parse_let_chain_pre_2024)] +pub(crate) struct LetChainPre2024 { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] #[diag(parse_self_argument_pointer)] pub(crate) struct SelfArgumentPointer { #[primary_span] diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 3cedc86dc0d..3d89530f914 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -4117,7 +4117,7 @@ impl MutVisitor for CondChecker<'_> { LetChainsPolicy::AlwaysAllowed => (), LetChainsPolicy::EditionDependent { current_edition } => { if !current_edition.at_least_rust_2024() || !span.at_least_rust_2024() { - self.parser.psess.gated_spans.gate(sym::let_chains, span); + self.parser.dcx().emit_err(errors::LetChainPre2024 { span }); } } } diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index f181097813d..0c57a8cc5e1 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -305,8 +305,13 @@ impl<'a> Parser<'a> { let removal_span = kw.span.with_hi(self.token.span.lo()); let path = self.parse_path(PathStyle::Type)?; let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus(); - let kind = - self.parse_remaining_bounds_path(lifetime_defs, path, lo, parse_plus)?; + let kind = self.parse_remaining_bounds_path( + lifetime_defs, + path, + lo, + parse_plus, + ast::Parens::No, + )?; let err = self.dcx().create_err(errors::TransposeDynOrImpl { span: kw.span, kw: kw.name.as_str(), @@ -333,7 +338,13 @@ impl<'a> Parser<'a> { } else { let path = self.parse_path(PathStyle::Type)?; let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus(); - self.parse_remaining_bounds_path(lifetime_defs, path, lo, parse_plus)? + self.parse_remaining_bounds_path( + lifetime_defs, + path, + lo, + parse_plus, + ast::Parens::No, + )? } } } else if self.eat_keyword(exp!(Impl)) { @@ -413,9 +424,13 @@ impl<'a> Parser<'a> { let maybe_bounds = allow_plus == AllowPlus::Yes && self.token.is_like_plus(); match ty.kind { // `(TY_BOUND_NOPAREN) + BOUND + ...`. - TyKind::Path(None, path) if maybe_bounds => { - self.parse_remaining_bounds_path(ThinVec::new(), path, lo, true) - } + TyKind::Path(None, path) if maybe_bounds => self.parse_remaining_bounds_path( + ThinVec::new(), + path, + lo, + true, + ast::Parens::Yes, + ), // For `('a) + …`, we know that `'a` in type position already lead to an error being // emitted. To reduce output, let's indirectly suppress E0178 (bad `+` in type) and // other irrelevant consequential errors. @@ -495,12 +510,14 @@ impl<'a> Parser<'a> { path: ast::Path, lo: Span, parse_plus: bool, + parens: ast::Parens, ) -> PResult<'a, TyKind> { let poly_trait_ref = PolyTraitRef::new( generic_params, path, TraitBoundModifiers::NONE, lo.to(self.prev_token.span), + parens, ); let bounds = vec![GenericBound::Trait(poly_trait_ref)]; self.parse_remaining_bounds(bounds, parse_plus) @@ -796,16 +813,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()?; @@ -832,7 +843,7 @@ impl<'a> Parser<'a> { Ok(TyKind::MacCall(P(MacCall { path, args: self.parse_delim_args()? }))) } else if allow_plus == AllowPlus::Yes && self.check_plus() { // `Trait1 + Trait2 + 'a` - self.parse_remaining_bounds_path(ThinVec::new(), path, lo, true) + self.parse_remaining_bounds_path(ThinVec::new(), path, lo, true, ast::Parens::No) } else { // Just a type path. Ok(TyKind::Path(None, path)) @@ -898,10 +909,10 @@ impl<'a> Parser<'a> { fn parse_generic_bound(&mut self) -> PResult<'a, GenericBound> { let lo = self.token.span; let leading_token = self.prev_token; - let has_parens = self.eat(exp!(OpenParen)); + let parens = if self.eat(exp!(OpenParen)) { ast::Parens::Yes } else { ast::Parens::No }; let bound = if self.token.is_lifetime() { - self.parse_generic_lt_bound(lo, has_parens)? + self.parse_generic_lt_bound(lo, parens)? } else if self.eat_keyword(exp!(Use)) { // parse precise captures, if any. This is `use<'lt, 'lt, P, P>`; a list of // lifetimes and ident params (including SelfUpper). These are validated later @@ -910,7 +921,7 @@ impl<'a> Parser<'a> { let (args, args_span) = self.parse_precise_capturing_args()?; GenericBound::Use(args, use_span.to(args_span)) } else { - self.parse_generic_ty_bound(lo, has_parens, &leading_token)? + self.parse_generic_ty_bound(lo, parens, &leading_token)? }; Ok(bound) @@ -920,10 +931,14 @@ impl<'a> Parser<'a> { /// ```ebnf /// LT_BOUND = LIFETIME /// ``` - fn parse_generic_lt_bound(&mut self, lo: Span, has_parens: bool) -> PResult<'a, GenericBound> { + fn parse_generic_lt_bound( + &mut self, + lo: Span, + parens: ast::Parens, + ) -> PResult<'a, GenericBound> { let lt = self.expect_lifetime(); let bound = GenericBound::Outlives(lt); - if has_parens { + if let ast::Parens::Yes = parens { // FIXME(Centril): Consider not erroring here and accepting `('lt)` instead, // possibly introducing `GenericBound::Paren(P<GenericBound>)`? self.recover_paren_lifetime(lo)?; @@ -1071,7 +1086,7 @@ impl<'a> Parser<'a> { && self.look_ahead(1, |t| t.is_keyword(kw::Const)) && self.look_ahead(2, |t| *t == token::CloseBracket) { - let start = self.prev_token.span; + let start = self.token.span; self.bump(); self.expect_keyword(exp!(Const)).unwrap(); self.bump(); @@ -1096,7 +1111,7 @@ impl<'a> Parser<'a> { fn parse_generic_ty_bound( &mut self, lo: Span, - has_parens: bool, + parens: ast::Parens, leading_token: &Token, ) -> PResult<'a, GenericBound> { let (mut lifetime_defs, binder_span) = self.parse_late_bound_lifetime_defs()?; @@ -1122,7 +1137,7 @@ impl<'a> Parser<'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); + return self.parse_generic_lt_bound(lo, parens); } if let (more_lifetime_defs, Some(binder_span)) = self.parse_late_bound_lifetime_defs()? { @@ -1189,7 +1204,7 @@ impl<'a> Parser<'a> { self.recover_fn_trait_with_lifetime_params(&mut path, &mut lifetime_defs)?; } - if has_parens { + if let ast::Parens::Yes = parens { // Someone has written something like `&dyn (Trait + Other)`. The correct code // would be `&(dyn Trait + Other)` if self.token.is_like_plus() && leading_token.is_keyword(kw::Dyn) { @@ -1209,7 +1224,7 @@ impl<'a> Parser<'a> { } let poly_trait = - PolyTraitRef::new(lifetime_defs, path, modifiers, lo.to(self.prev_token.span)); + PolyTraitRef::new(lifetime_defs, path, modifiers, lo.to(self.prev_token.span), parens); Ok(GenericBound::Trait(poly_trait)) } diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 68d78af5943..4d64cdeb69a 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -298,10 +298,18 @@ fn emit_malformed_attribute( | sym::deprecated | sym::optimize | sym::cold + | sym::target_feature + | sym::rustc_allow_const_fn_unstable | 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_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index b1c7b0fcd6c..5a94d01e088 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -537,7 +537,7 @@ passes_no_sanitize = `#[no_sanitize({$attr_str})]` should be applied to {$accepted_kind} .label = not {$accepted_kind} -passes_non_exaustive_with_default_field_values = +passes_non_exhaustive_with_default_field_values = `#[non_exhaustive]` can't be used to annotate items with default field values .label = this struct has default field values @@ -618,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 diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 877bb9be289..87d46e3e506 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}; @@ -146,25 +146,25 @@ impl<'tcx> CheckAttrVisitor<'tcx> { 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, - syms.first().unwrap().1, - span, - target, - attrs, - ), - Attribute::Parsed(AttributeKind::AllowConstFnUnstable { .. }) => { - self.check_rustc_allow_const_fn_unstable(hir_id, attr, span, target) + Attribute::Parsed(AttributeKind::AllowInternalUnstable(_, first_span)) => { + self.check_allow_internal_unstable(hir_id, *first_span, span, target, attrs) + } + Attribute::Parsed(AttributeKind::AllowConstFnUnstable(_, first_span)) => { + self.check_rustc_allow_const_fn_unstable(hir_id, *first_span, span, target) } Attribute::Parsed(AttributeKind::Deprecation { .. }) => { self.check_deprecated(hir_id, attr, span, target) } + Attribute::Parsed(AttributeKind::TargetFeature(_, attr_span)) => { + self.check_target_feature(hir_id, *attr_span, span, target, attrs) + } Attribute::Parsed(AttributeKind::DocComment { .. }) => { /* `#[doc]` is actually a lot more than just doc comments, so is checked below*/ } 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) } @@ -177,6 +177,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { 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) } @@ -184,6 +187,10 @@ impl<'tcx> CheckAttrVisitor<'tcx> { 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 | AttributeKind::MacroTransparency(_), @@ -191,6 +198,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) } @@ -218,9 +228,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } [sym::non_exhaustive, ..] => self.check_non_exhaustive(hir_id, attr, span, target, item), [sym::marker, ..] => self.check_marker(hir_id, attr, span, target), - [sym::target_feature, ..] => { - self.check_target_feature(hir_id, attr, span, target, attrs) - } [sym::thread_local, ..] => self.check_thread_local(attr, span, target), [sym::doc, ..] => self.check_doc_attrs( attr, @@ -231,10 +238,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { &mut doc_aliases, ), [sym::no_link, ..] => self.check_no_link(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) @@ -283,8 +286,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) } @@ -299,7 +300,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) } @@ -811,7 +811,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { fn check_target_feature( &self, hir_id: HirId, - attr: &Attribute, + attr_span: Span, span: Span, target: Target, attrs: &[Attribute], @@ -829,7 +829,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let sig = self.tcx.hir_node(hir_id).fn_sig().unwrap(); self.dcx().emit_err(errors::LangItemWithTargetFeature { - attr_span: attr.span(), + attr_span, name: lang_item, sig_span: sig.span, }); @@ -841,7 +841,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr_span, errors::TargetFeatureOnStatement, ); } @@ -850,11 +850,11 @@ 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(), "target_feature"); + self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "target_feature"); } _ => { self.dcx().emit_err(errors::AttrShouldBeAppliedToFn { - attr_span: attr.span(), + attr_span, defn_span: span, on_crate: hir_id == CRATE_HIR_ID, }); @@ -1604,7 +1604,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 @@ -1612,27 +1619,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() }, + ); } } } @@ -1676,24 +1674,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - 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. @@ -1831,7 +1816,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// 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 @@ -1839,7 +1824,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 @@ -1847,7 +1832,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr_span, errors::LinkSection { span }, ); } @@ -2179,7 +2164,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { fn check_rustc_allow_const_fn_unstable( &self, hir_id: HirId, - attr: &Attribute, + attr_span: Span, span: Span, target: Target, ) { @@ -2191,15 +2176,9 @@ 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(), - "allow_internal_unstable", - ), + .inline_attr_str_error_with_macro_def(hir_id, attr_span, "allow_internal_unstable"), _ => { - self.tcx - .dcx() - .emit_err(errors::RustcAllowConstFnUnstable { attr_span: attr.span(), span }); + self.tcx.dcx().emit_err(errors::RustcAllowConstFnUnstable { attr_span, span }); } } } @@ -2333,8 +2312,20 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } return; } + AttributeKind::TargetFeature(features, span) if features.len() == 0 => { + self.tcx.emit_node_span_lint( + UNUSED_ATTRIBUTES, + hir_id, + *span, + errors::Unused { + attr_span: *span, + note: errors::UnusedNote::EmptyList { name: sym::target_feature }, + }, + ); + return; + } _ => {} - } + }; } // Warn on useless empty attributes. @@ -2346,7 +2337,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { sym::deny, sym::forbid, sym::feature, - sym::target_feature, ]) && attr.meta_item_list().is_some_and(|list| list.is_empty()) { errors::UnusedNote::EmptyList { name: attr.name().unwrap() } @@ -2842,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 ce43b2c281d..cdfd1a2b07e 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -1199,7 +1199,7 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) { let def_kind = tcx.def_kind(item.owner_id); let mut dead_codes = Vec::new(); - // Only diagnose unused assoc items in inherient impl and used trait, + // Only diagnose unused assoc items in inherent impl and used trait, // for unused assoc items in impls of trait, // we have diagnosed them in the trait if they are unused, // for unused assoc items in unused trait, diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index f89d925202c..3ede3c889c8 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -157,7 +157,7 @@ pub(crate) struct NonExhaustiveWrongLocation { } #[derive(Diagnostic)] -#[diag(passes_non_exaustive_with_default_field_values)] +#[diag(passes_non_exhaustive_with_default_field_values)] pub(crate) struct NonExhaustiveWithDefaultFieldValues { #[primary_span] pub attr_span: Span, @@ -502,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, @@ -536,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] diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index 53638f2a57d..c348cd508f9 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -70,7 +70,7 @@ //! # Constructors and fields //! //! In the value `Pair(Some(0), true)`, `Pair` is called the constructor of the value, and `Some(0)` -//! and `true` are its fields. Every matcheable value can be decomposed in this way. Examples of +//! and `true` are its fields. Every matchable value can be decomposed in this way. Examples of //! constructors are: `Some`, `None`, `(,)` (the 2-tuple constructor), `Foo {..}` (the constructor //! for a struct `Foo`), and `2` (the constructor for the number `2`). //! @@ -102,7 +102,7 @@ //! [`Constructor::is_covered_by`]. //! //! Note 1: variable bindings (like the `x` in `Some(x)`) match anything, so we treat them as wildcards. -//! Note 2: this only applies to matcheable values. For example a value of type `Rc<u64>` can't be +//! Note 2: this only applies to matchable values. For example a value of type `Rc<u64>` can't be //! deconstructed that way. //! //! diff --git a/compiler/rustc_query_impl/src/profiling_support.rs b/compiler/rustc_query_impl/src/profiling_support.rs index 7d80e54bf87..7be75ea88ac 100644 --- a/compiler/rustc_query_impl/src/profiling_support.rs +++ b/compiler/rustc_query_impl/src/profiling_support.rs @@ -259,4 +259,5 @@ pub fn alloc_self_profile_query_strings(tcx: TyCtxt<'_>) { for alloc in super::ALLOC_SELF_PROFILE_QUERY_STRINGS.iter() { alloc(tcx, &mut string_cache) } + tcx.sess.prof.store_query_cache_hits(); } diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index d4217e0aa54..04fc32a9b50 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -1342,7 +1342,7 @@ impl DepNodeColorMap { /// This tries to atomically mark a node green and assign `index` as the new /// index. This returns `Ok` if `index` gets assigned, otherwise it returns - /// the alreadly allocated index in `Err`. + /// the already allocated index in `Err`. #[inline] pub(super) fn try_mark_green( &self, diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 58942474e32..aa818cc9c46 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -432,6 +432,7 @@ resolve_undeclared_label = resolve_underscore_lifetime_is_reserved = `'_` cannot be used here .label = `'_` is a reserved lifetime name + .help = use another lifetime specifier resolve_unexpected_res_change_ty_to_const_param_sugg = you might have meant to write a const parameter here diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 6d3752c0c83..b34bcb38f84 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -878,12 +878,12 @@ pub(crate) struct MacroExpandedExternCrateCannotShadowExternArguments { #[derive(Diagnostic)] #[diag(resolve_elided_anonymous_lifetime_report_error, code = E0637)] -pub(crate) struct ElidedAnonymousLivetimeReportError { +pub(crate) struct ElidedAnonymousLifetimeReportError { #[primary_span] #[label] pub(crate) span: Span, #[subdiagnostic] - pub(crate) suggestion: Option<ElidedAnonymousLivetimeReportErrorSuggestion>, + pub(crate) suggestion: Option<ElidedAnonymousLifetimeReportErrorSuggestion>, } #[derive(Diagnostic)] @@ -897,7 +897,7 @@ pub(crate) struct LendingIteratorReportError { #[derive(Diagnostic)] #[diag(resolve_anonymous_lifetime_non_gat_report_error)] -pub(crate) struct AnonymousLivetimeNonGatReportError { +pub(crate) struct AnonymousLifetimeNonGatReportError { #[primary_span] #[label] pub(crate) lifetime: Span, @@ -908,7 +908,7 @@ pub(crate) struct AnonymousLivetimeNonGatReportError { resolve_elided_anonymous_lifetime_report_error_suggestion, applicability = "machine-applicable" )] -pub(crate) struct ElidedAnonymousLivetimeReportErrorSuggestion { +pub(crate) struct ElidedAnonymousLifetimeReportErrorSuggestion { #[suggestion_part(code = "for<'a> ")] pub(crate) lo: Span, #[suggestion_part(code = "'a ")] @@ -917,7 +917,7 @@ pub(crate) struct ElidedAnonymousLivetimeReportErrorSuggestion { #[derive(Diagnostic)] #[diag(resolve_explicit_anonymous_lifetime_report_error, code = E0637)] -pub(crate) struct ExplicitAnonymousLivetimeReportError { +pub(crate) struct ExplicitAnonymousLifetimeReportError { #[primary_span] #[label] pub(crate) span: Span, @@ -934,6 +934,7 @@ pub(crate) struct ImplicitElidedLifetimeNotAllowedHere { #[derive(Diagnostic)] #[diag(resolve_underscore_lifetime_is_reserved, code = E0637)] +#[help] pub(crate) struct UnderscoreLifetimeIsReserved { #[primary_span] #[label] diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 1b7a2c3bda0..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, } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index ac7bdda4195..c2bea4e0fdc 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1892,7 +1892,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { .. } = rib.kind { - Some(errors::ElidedAnonymousLivetimeReportErrorSuggestion { + Some(errors::ElidedAnonymousLifetimeReportErrorSuggestion { lo: span.shrink_to_lo(), hi: lifetime.ident.span.shrink_to_hi(), }) @@ -1918,18 +1918,18 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ty: ty.span, }); } else { - self.r.dcx().emit_err(errors::AnonymousLivetimeNonGatReportError { + self.r.dcx().emit_err(errors::AnonymousLifetimeNonGatReportError { lifetime: lifetime.ident.span, }); } } else { - self.r.dcx().emit_err(errors::ElidedAnonymousLivetimeReportError { + self.r.dcx().emit_err(errors::ElidedAnonymousLifetimeReportError { span: lifetime.ident.span, suggestion, }); } } else { - self.r.dcx().emit_err(errors::ExplicitAnonymousLivetimeReportError { + self.r.dcx().emit_err(errors::ExplicitAnonymousLifetimeReportError { span: lifetime.ident.span, }); }; diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index e7b8c988cd4..6230b8cfbec 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -3832,6 +3832,7 @@ fn mk_where_bound_predicate( ref_id: DUMMY_NODE_ID, }, span: DUMMY_SP, + parens: ast::Parens::No, })], }; diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index 3fe5db8ca54..f61cd1f0adf 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -627,7 +627,7 @@ pub fn source_span_for_markdown_range_inner( 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 + // then use that in our calculations for the span end let lo = sp.lo() + BytePos(match_start as u32); return Some(( sp.with_lo(lo).with_hi(lo + BytePos((md_range.end - md_range.start) as u32)), 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..1cb09e8a1ee 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 cannot 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/src/config.rs b/compiler/rustc_session/src/config.rs index 73bb0471c22..74e766a1e95 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -190,7 +190,7 @@ pub struct CoverageOptions { /// to keep supporting this flag, remove it. pub no_mir_spans: bool, - /// `-Zcoverage-options=discard-all-spans-in-codegen`: During codgen, + /// `-Zcoverage-options=discard-all-spans-in-codegen`: During codegen, /// discard all coverage spans as though they were invalid. Needed by /// regression tests for #133606, because we don't have an easy way to /// reproduce it from actual source code. diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index bad2581ae31..8386fe8dab0 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1545,7 +1545,7 @@ impl RemapFileNameExt for rustc_span::FileName { "one and only one scope should be passed to for_scope" ); if sess.opts.unstable_opts.remap_path_scope.contains(scope) { - self.prefer_remapped_unconditionaly() + self.prefer_remapped_unconditionally() } else { self.prefer_local() } 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 24351eee1c4..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, } } } diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index baa4c0681e8..3fa83cfc6a0 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -130,7 +130,11 @@ impl<'tcx> SmirCtxt<'tcx> { pub fn all_trait_decls(&self) -> stable_mir::TraitDecls { let mut tables = self.0.borrow_mut(); - tables.tcx.all_traits().map(|trait_def_id| tables.trait_def(trait_def_id)).collect() + tables + .tcx + .all_traits_including_private() + .map(|trait_def_id| tables.trait_def(trait_def_id)) + .collect() } pub fn trait_decls(&self, crate_num: CrateNum) -> stable_mir::TraitDecls { 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 7abec488151..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"), } } } 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 7f6237e7062..398738d1c38 100644 --- a/compiler/rustc_smir/src/stable_mir/ty.rs +++ b/compiler/rustc_smir/src/stable_mir/ty.rs @@ -1205,7 +1205,6 @@ pub enum BoundRegionKind { #[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum DynKind { Dyn, - DynStar, } #[derive(Clone, Debug, Eq, PartialEq, Serialize)] @@ -1601,7 +1600,7 @@ pub struct VariantIdx(usize); index_impl!(VariantIdx); crate_def! { - /// Hold infomation about an Opaque definition, particularly useful in `RPITIT`. + /// Hold information about an Opaque definition, particularly useful in `RPITIT`. #[derive(Serialize)] pub OpaqueDef; } 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..9b0e009b2cd 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; @@ -417,7 +418,7 @@ impl FileName { } } - pub fn prefer_remapped_unconditionaly(&self) -> FileNameDisplay<'_> { + pub fn prefer_remapped_unconditionally(&self) -> FileNameDisplay<'_> { FileNameDisplay { inner: self, display_pref: FileNameDisplayPreference::Remapped } } @@ -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 4be7c7ba510..d6537d49be7 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, @@ -607,10 +603,10 @@ symbols! { catch_unwind, cause, cdylib, - ceilf128, ceilf16, ceilf32, ceilf64, + ceilf128, cfg, cfg_accessible, cfg_attr, @@ -747,10 +743,10 @@ symbols! { copy, copy_closures, copy_nonoverlapping, - copysignf128, copysignf16, copysignf32, copysignf64, + copysignf128, core, core_panic, core_panic_2015_macro, @@ -763,10 +759,10 @@ symbols! { coroutine_state, coroutine_yield, coroutines, - cosf128, cosf16, cosf32, cosf64, + cosf128, count, coverage, coverage_attribute, @@ -874,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, @@ -928,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, @@ -958,9 +954,6 @@ symbols! { external, external_doc, f, - f128, - f128_epsilon, - f128_nan, f16, f16_epsilon, f16_nan, @@ -999,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, @@ -1024,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, @@ -1140,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, @@ -1165,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, @@ -1292,19 +1288,19 @@ 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, @@ -1334,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, @@ -1372,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, @@ -1586,6 +1582,7 @@ symbols! { panic_implementation, panic_in_cleanup, panic_info, + panic_invalid_enum_construction, panic_location, panic_misaligned_pointer_dereference, panic_nounwind, @@ -1633,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, @@ -1778,21 +1775,20 @@ symbols! { resume, return_position_impl_trait_in_trait, return_type_notation, - rhs, riscv_target_feature, rlib, ropi, 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, @@ -1972,14 +1968,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, @@ -2007,6 +2005,7 @@ symbols! { simd_relaxed_fma, simd_rem, simd_round, + simd_round_ties_even, simd_saturating_add, simd_saturating_sub, simd_scatter, @@ -2021,10 +2020,10 @@ symbols! { simd_with_exposed_provenance, simd_xor, since, - sinf128, sinf16, sinf32, sinf64, + sinf128, size, size_of, size_of_val, @@ -2046,10 +2045,10 @@ symbols! { specialization, speed, spotlight, - sqrtf128, sqrtf16, sqrtf32, sqrtf64, + sqrtf128, sreg, sreg_low16, sse, @@ -2127,10 +2126,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, @@ -2173,10 +2172,10 @@ symbols! { transparent_enums, transparent_unions, trivial_bounds, - truncf128, truncf16, truncf32, truncf64, + truncf128, try_blocks, try_capture, try_from, @@ -2205,12 +2204,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, @@ -2229,12 +2228,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, @@ -2387,6 +2386,7 @@ symbols! { zfh, zfhmin, zmm_reg, + // tidy-alphabetical-end } } @@ -2397,7 +2397,7 @@ pub const STDLIB_STABLE_CRATES: &[Symbol] = &[sym::std, sym::core, sym::alloc, s #[derive(Copy, Clone, Eq, HashStable_Generic, Encodable, Decodable)] pub struct Ident { // `name` should never be the empty symbol. If you are considering that, - // you are probably conflating "empty identifer with "no identifier" and + // you are probably conflating "empty identifier with "no identifier" and // you should use `Option<Ident>` instead. pub name: Symbol, pub span: Span, @@ -2582,7 +2582,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 @@ -2594,20 +2594,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 @@ -2620,7 +2623,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)) }) } @@ -2677,56 +2680,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() } } @@ -2821,9 +2898,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/callconv/s390x.rs b/compiler/rustc_target/src/callconv/s390x.rs index 1ba792c5acc..d2ae404b23b 100644 --- a/compiler/rustc_target/src/callconv/s390x.rs +++ b/compiler/rustc_target/src/callconv/s390x.rs @@ -46,7 +46,7 @@ where } if arg.layout.is_single_vector_element(cx, size) { - // pass non-transparant wrappers around a vector as `PassMode::Cast` + // pass non-transparent wrappers around a vector as `PassMode::Cast` arg.cast_to(Reg { kind: RegKind::Vector, size }); return; } diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs index 66733d5d4b8..b01ca989282 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs @@ -10,6 +10,7 @@ pub(crate) fn target() -> Target { base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::Inline; + base.abi = "elfv2".into(); base.llvm_abiname = "elfv2".into(); Target { diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs index ecf68ddff8c..bc7e445f3f8 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs @@ -10,6 +10,7 @@ pub(crate) fn target() -> Target { base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::Inline; + base.abi = "elfv1".into(); base.llvm_abiname = "elfv1".into(); Target { diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs index e205aef8285..4dc76f0936c 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs @@ -12,6 +12,7 @@ pub(crate) fn target() -> Target { base.stack_probes = StackProbeType::Inline; // FIXME(compiler-team#422): musl targets should be dynamically linked by default. base.crt_static_default = true; + base.abi = "elfv2".into(); base.llvm_abiname = "elfv2".into(); Target { diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs index bcb328020ee..9dc44aa05cc 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs @@ -10,6 +10,7 @@ pub(crate) fn target() -> Target { base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::Inline; + base.abi = "elfv2".into(); base.llvm_abiname = "elfv2".into(); Target { diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs index 37c888ba514..10072f8092d 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs @@ -10,6 +10,7 @@ pub(crate) fn target() -> Target { base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::Inline; + base.abi = "elfv1".into(); base.llvm_abiname = "elfv1".into(); Target { diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs index 3096c4d14ad..a7f4e0eabb0 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs @@ -8,6 +8,7 @@ pub(crate) fn target() -> Target { base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::Inline; + base.abi = "elfv2".into(); base.llvm_abiname = "elfv2".into(); Target { diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs index 9e406af53b5..af5704b51ba 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs @@ -8,6 +8,7 @@ pub(crate) fn target() -> Target { base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::Inline; + base.abi = "elfv2".into(); base.llvm_abiname = "elfv2".into(); Target { diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs index f145c5b8c14..26ee6a68c6a 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs @@ -10,6 +10,7 @@ pub(crate) fn target() -> Target { base.stack_probes = StackProbeType::Inline; // FIXME(compiler-team#422): musl targets should be dynamically linked by default. base.crt_static_default = true; + base.abi = "elfv2".into(); base.llvm_abiname = "elfv2".into(); Target { diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index 1071105522d..62f1d908601 100644 --- a/compiler/rustc_trait_selection/Cargo.toml +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -8,6 +8,7 @@ edition = "2024" itertools = "0.12" rustc_abi = { path = "../rustc_abi" } 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_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs index 0a4a9144c94..bff5e9128cb 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 @@ -1,3 +1,4 @@ +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect}; use rustc_errors::{Diag, MultiSpan, pluralize}; use rustc_hir as hir; @@ -8,7 +9,7 @@ use rustc_middle::ty::fast_reject::DeepRejectCtxt; use rustc_middle::ty::print::{FmtPrinter, Printer}; use rustc_middle::ty::{self, Ty, suggest_constraining_type_param}; use rustc_span::def_id::DefId; -use rustc_span::{BytePos, Span, Symbol, sym}; +use rustc_span::{BytePos, Span, Symbol}; use tracing::debug; use crate::error_reporting::TypeErrCtxt; @@ -353,26 +354,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() @@ -555,8 +536,7 @@ impl<T> Trait<T> for X { } } TypeError::TargetFeatureCast(def_id) => { - let target_spans = - tcx.get_attrs(def_id, sym::target_feature).map(|attr| attr.span()); + let target_spans = find_attr!(tcx.get_all_attrs(def_id), AttributeKind::TargetFeature(.., span) => *span); diag.note( "functions with `#[target_feature]` can only be coerced to `unsafe` function pointers" ); 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 02edf482795..28d572b303a 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 @@ -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(_) => { @@ -1850,7 +1855,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let trait_def_id = trait_pred.def_id(); let trait_name = self.tcx.item_name(trait_def_id); let crate_name = self.tcx.crate_name(trait_def_id.krate); - if let Some(other_trait_def_id) = self.tcx.all_traits().find(|def_id| { + if let Some(other_trait_def_id) = self.tcx.all_traits_including_private().find(|def_id| { trait_name == self.tcx.item_name(trait_def_id) && trait_def_id.krate != def_id.krate && crate_name == self.tcx.crate_name(def_id.krate) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 2bbf90ed3ed..362052e9fdb 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -4432,7 +4432,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { candidate_impls: &[ImplCandidate<'tcx>], span: Span, ) { - // We can only suggest the slice coersion for function and binary operation arguments, + // We can only suggest the slice coercion for function and binary operation arguments, // since the suggestion would make no sense in turbofish or call let (ObligationCauseCode::BinOp { .. } | ObligationCauseCode::FunctionArg { .. }) = obligation.cause.code() diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 7bf49056e29..90cdf75265d 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -643,7 +643,7 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { // Do not suggest constraining the `&self` param, but rather the return type. // If that is wrong (because it is not sufficient), a follow up error will tell the // user to fix it. This way we lower the chances of *over* constraining, but still - // get the cake of "correctly" contrained in two steps. + // get the cake of "correctly" constrained in two steps. visitor.visit_ty_unambig(self.ty_sup); } visitor.visit_ty_unambig(self.ty_sub); diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index 8d049fedf23..9a4f3887bbb 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -31,7 +31,7 @@ use crate::traits::{ /// /// Currently that is `Self` in supertraits. This is needed /// because `dyn_compatibility_violations` can't be used during -/// type collection, as type collection is needed for `dyn_compatiblity_violations` itself. +/// type collection, as type collection is needed for `dyn_compatibility_violations` itself. #[instrument(level = "debug", skip(tcx), ret)] pub fn hir_ty_lowering_dyn_compatibility_violations( tcx: TyCtxt<'_>, diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs index fc95e42d67f..176d308de91 100644 --- a/compiler/rustc_trait_selection/src/traits/effects.rs +++ b/compiler/rustc_trait_selection/src/traits/effects.rs @@ -44,6 +44,12 @@ pub fn evaluate_host_effect_obligation<'tcx>( Err(EvaluationFailure::NoSolution) => {} } + match evaluate_host_effect_from_conditionally_const_item_bounds(selcx, obligation) { + Ok(result) => return Ok(result), + Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous), + Err(EvaluationFailure::NoSolution) => {} + } + match evaluate_host_effect_from_item_bounds(selcx, obligation) { Ok(result) => return Ok(result), Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous), @@ -56,7 +62,7 @@ pub fn evaluate_host_effect_obligation<'tcx>( Err(EvaluationFailure::NoSolution) => {} } - match evaluate_host_effect_from_selection_candiate(selcx, obligation) { + match evaluate_host_effect_from_selection_candidate(selcx, obligation) { Ok(result) => return Ok(result), Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous), Err(EvaluationFailure::NoSolution) => {} @@ -153,7 +159,9 @@ fn evaluate_host_effect_from_bounds<'tcx>( } } -fn evaluate_host_effect_from_item_bounds<'tcx>( +/// Assembles constness bounds from `~const` item bounds on alias types, which only +/// hold if the `~const` where bounds also hold and the parent trait is `~const`. +fn evaluate_host_effect_from_conditionally_const_item_bounds<'tcx>( selcx: &mut SelectionContext<'_, 'tcx>, obligation: &HostEffectObligation<'tcx>, ) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> { @@ -232,6 +240,63 @@ fn evaluate_host_effect_from_item_bounds<'tcx>( } } +/// Assembles constness bounds "normal" item bounds on aliases, which may include +/// unconditionally `const` bounds that are *not* conditional and thus always hold. +fn evaluate_host_effect_from_item_bounds<'tcx>( + selcx: &mut SelectionContext<'_, 'tcx>, + obligation: &HostEffectObligation<'tcx>, +) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> { + let infcx = selcx.infcx; + let tcx = infcx.tcx; + let drcx = DeepRejectCtxt::relate_rigid_rigid(selcx.tcx()); + let mut candidate = None; + + let mut consider_ty = obligation.predicate.self_ty(); + while let ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) = *consider_ty.kind() { + for clause in tcx.item_bounds(alias_ty.def_id).iter_instantiated(tcx, alias_ty.args) { + let bound_clause = clause.kind(); + let ty::ClauseKind::HostEffect(data) = bound_clause.skip_binder() else { + continue; + }; + let data = bound_clause.rebind(data); + if data.skip_binder().trait_ref.def_id != obligation.predicate.trait_ref.def_id { + continue; + } + + if !drcx.args_may_unify( + obligation.predicate.trait_ref.args, + data.skip_binder().trait_ref.args, + ) { + continue; + } + + let is_match = + infcx.probe(|_| match_candidate(selcx, obligation, data, true, |_, _| {}).is_ok()); + + if is_match { + if candidate.is_some() { + return Err(EvaluationFailure::Ambiguous); + } else { + candidate = Some(data); + } + } + } + + if kind != ty::Projection { + break; + } + + consider_ty = alias_ty.self_ty(); + } + + if let Some(data) = candidate { + Ok(match_candidate(selcx, obligation, data, true, |_, _| {}) + .expect("candidate matched before, so it should match again")) + } else { + Err(EvaluationFailure::NoSolution) + } +} + fn evaluate_host_effect_from_builtin_impls<'tcx>( selcx: &mut SelectionContext<'_, 'tcx>, obligation: &HostEffectObligation<'tcx>, @@ -333,7 +398,7 @@ fn evaluate_host_effect_for_destruct_goal<'tcx>( .collect()) } -fn evaluate_host_effect_from_selection_candiate<'tcx>( +fn evaluate_host_effect_from_selection_candidate<'tcx>( selcx: &mut SelectionContext<'_, 'tcx>, obligation: &HostEffectObligation<'tcx>, ) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 43806d3977b..91c41544f78 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -481,7 +481,7 @@ pub enum EvaluateConstErr { /// some unevaluated constant with either generic parameters or inference variables in its /// generic arguments. HasGenericsOrInfers, - /// The type this constant evalauted to is not valid for use in const generics. This should + /// The type this constant evaluated to is not valid for use in const generics. This should /// always result in an error when checking the constant is correctly typed for the parameter /// it is an argument to, so a bug is delayed when encountering this. InvalidConstParamTy(ErrorGuaranteed), diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 3eca77b43a8..3a369f13e79 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -904,7 +904,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let goal_kind = self.tcx().async_fn_trait_kind_from_def_id(obligation.predicate.def_id()).unwrap(); - // If we have not yet determiend the `ClosureKind` of the closure or coroutine-closure, + // If we have not yet determined the `ClosureKind` of the closure or coroutine-closure, // then additionally register an `AsyncFnKindHelper` goal which will fail if the kind // is constrained to an insufficient type later on. if let Some(closure_kind) = self.infcx.shallow_resolve(kind_ty).to_opt_closure_kind() { diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 316b4dfc15f..af3641c22ed 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2129,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_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index f14a45aa1e3..a65f9b347dc 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -1,9 +1,8 @@ -use rustc_data_structures::fx::FxIndexSet; +use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; use rustc_hir::definitions::{DefPathData, DisambiguatorState}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{self as hir, AmbigArg}; use rustc_middle::query::Providers; use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt}; use rustc_middle::{bug, span_bug}; @@ -14,7 +13,6 @@ pub(crate) fn provide(providers: &mut Providers) { associated_item_def_ids, associated_items, associated_types_for_impl_traits_in_associated_fn, - associated_type_for_impl_trait_in_trait, impl_item_implementor_ids, ..*providers }; @@ -160,20 +158,22 @@ fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::A container: ty::AssocItemContainer::Impl, } } -struct RPITVisitor { - rpits: FxIndexSet<LocalDefId>, +struct RPITVisitor<'tcx> { + tcx: TyCtxt<'tcx>, + synthetics: Vec<LocalDefId>, + data: DefPathData, + disambiguator: DisambiguatorState, } -impl<'tcx> Visitor<'tcx> for RPITVisitor { - fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) { - if let hir::TyKind::OpaqueDef(opaq) = ty.kind - && self.rpits.insert(opaq.def_id) - { - for bound in opaq.bounds { - intravisit::walk_param_bound(self, bound); - } - } - intravisit::walk_ty(self, ty) +impl<'tcx> Visitor<'tcx> for RPITVisitor<'tcx> { + fn visit_opaque_ty(&mut self, opaque: &'tcx hir::OpaqueTy<'tcx>) -> Self::Result { + self.synthetics.push(associated_type_for_impl_trait_in_trait( + self.tcx, + opaque.def_id, + self.data, + &mut self.disambiguator, + )); + intravisit::walk_opaque_ty(self, opaque) } } @@ -194,14 +194,18 @@ fn associated_types_for_impl_traits_in_associated_fn( match tcx.def_kind(parent_def_id) { DefKind::Trait => { - let mut visitor = RPITVisitor { rpits: FxIndexSet::default() }; - if let Some(output) = tcx.hir_get_fn_output(fn_def_id) { + let data = DefPathData::AnonAssocTy(tcx.item_name(fn_def_id.to_def_id())); + let mut visitor = RPITVisitor { + tcx, + synthetics: vec![], + data, + disambiguator: DisambiguatorState::with(parent_def_id, data, 0), + }; visitor.visit_fn_ret_ty(output); - - tcx.arena.alloc_from_iter(visitor.rpits.iter().map(|opaque_ty_def_id| { - tcx.associated_type_for_impl_trait_in_trait(opaque_ty_def_id).to_def_id() - })) + tcx.arena.alloc_from_iter( + visitor.synthetics.into_iter().map(|def_id| def_id.to_def_id()), + ) } else { &[] } @@ -211,7 +215,6 @@ fn associated_types_for_impl_traits_in_associated_fn( let Some(trait_fn_def_id) = tcx.associated_item(fn_def_id).trait_item_def_id else { return &[]; }; - tcx.arena.alloc_from_iter( tcx.associated_types_for_impl_traits_in_associated_fn(trait_fn_def_id).iter().map( move |&trait_assoc_def_id| { @@ -236,6 +239,8 @@ fn associated_types_for_impl_traits_in_associated_fn( fn associated_type_for_impl_trait_in_trait( tcx: TyCtxt<'_>, opaque_ty_def_id: LocalDefId, + data: DefPathData, + disambiguator: &mut DisambiguatorState, ) -> LocalDefId { let (hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. } | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. }) = @@ -246,22 +251,15 @@ fn associated_type_for_impl_trait_in_trait( let trait_def_id = tcx.local_parent(fn_def_id); assert_eq!(tcx.def_kind(trait_def_id), DefKind::Trait); - // Collect all opaque types in return position for the method and use - // the index as the disambiguator to make an unique def path. - let mut visitor = RPITVisitor { rpits: FxIndexSet::default() }; - visitor.visit_fn_ret_ty(tcx.hir_get_fn_output(fn_def_id).unwrap()); - let disambiguator = visitor.rpits.get_index_of(&opaque_ty_def_id).unwrap().try_into().unwrap(); - let span = tcx.def_span(opaque_ty_def_id); // Also use the method name to create an unique def path. - let data = DefPathData::AnonAssocTy(tcx.item_name(fn_def_id.to_def_id())); let trait_assoc_ty = tcx.at(span).create_def( trait_def_id, // No name because this is an anonymous associated type. None, DefKind::AssocTy, Some(data), - &mut DisambiguatorState::with(trait_def_id, data, disambiguator), + disambiguator, ); let local_def_id = trait_assoc_ty.def_id(); diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index 60f8bd9d83a..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); 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/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index 3b4482146d4..3b313edea6f 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -179,7 +179,7 @@ impl<'tcx> OpaqueTypeCollector<'tcx> { } } - /// Checks the `#[define_opaque]` attributes on items and collectes opaques to define + /// Checks the `#[define_opaque]` attributes on items and collects opaques to define /// from the referenced types. #[instrument(level = "trace", skip(self))] fn collect_taits_from_defines_attr(&mut self) { diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 553f5e0e1b5..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` @@ -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 177bad96595..7ffcf7b5d96 100644 --- a/compiler/rustc_type_ir/src/elaborate.rs +++ b/compiler/rustc_type_ir/src/elaborate.rs @@ -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..6c77a90250a 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -13,7 +13,7 @@ use crate::{self as ty, Interner}; /// slightly different typing rules depending on the current context. See the /// doc comment for each variant for how and why they are used. /// -/// In most cases you can get the correct typing mode automically via: +/// In most cases you can get the correct typing mode automatically via: /// - `mir::Body::typing_mode` /// - `rustc_lint::LateContext::typing_mode` /// @@ -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 272fca5b026..2754d40fd36 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -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, } } } 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/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 8941360d2d0..7433c215e6f 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -390,8 +390,8 @@ impl PathsToNested { /// /// They are used when checking whether reevaluating a global cache /// would encounter a cycle or use a provisional cache entry given the -/// currentl search graph state. We need to disable the global cache -/// in this case as it could otherwise result in behaviorial differences. +/// current search graph state. We need to disable the global cache +/// in this case as it could otherwise result in behavioral differences. /// Cycles can impact behavior. The cycle ABA may have different final /// results from a the cycle BAB depending on the cycle root. /// @@ -513,7 +513,7 @@ pub struct SearchGraph<D: Delegate<Cx = X>, X: Cx = <D as Delegate>::Cx> { /// /// `nested_goals` are only used when checking whether global cache entries /// are applicable. This only cares about whether a goal is actually accessed. -/// Given that the usage of the provisional cache is fully determinstic, we +/// Given that the usage of the provisional cache is fully deterministic, we /// don't need to track the nested goals used while computing a provisional /// cache entry. enum UpdateParentGoalCtxt<'a, X: Cx> { 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(), |
