diff options
Diffstat (limited to 'compiler')
438 files changed, 4725 insertions, 3536 deletions
diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index c863acde7b0..f3af031ade4 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -79,7 +79,8 @@ pub trait LayoutCalculator { { // `ReprOptions.layout_seed` is a deterministic seed that we can use to // randomize field ordering with - let mut rng = Xoshiro128StarStar::seed_from_u64(repr.field_shuffle_seed); + let mut rng = + Xoshiro128StarStar::seed_from_u64(repr.field_shuffle_seed.as_u64()); // Shuffle the ordering of the fields optimizing.shuffle(&mut rng); @@ -461,8 +462,8 @@ pub trait LayoutCalculator { let all_indices = variants.indices(); let needs_disc = |index: VariantIdx| index != largest_variant_index && !absent(&variants[index]); - let niche_variants = all_indices.clone().find(|v| needs_disc(*v)).unwrap().index() - ..=all_indices.rev().find(|v| needs_disc(*v)).unwrap().index(); + let niche_variants = all_indices.clone().find(|v| needs_disc(*v)).unwrap() + ..=all_indices.rev().find(|v| needs_disc(*v)).unwrap(); let count = niche_variants.size_hint().1.unwrap() as u128; @@ -560,8 +561,7 @@ pub trait LayoutCalculator { tag: niche_scalar, tag_encoding: TagEncoding::Niche { untagged_variant: largest_variant_index, - niche_variants: (VariantIdx::new(*niche_variants.start()) - ..=VariantIdx::new(*niche_variants.end())), + niche_variants, niche_start, }, tag_field: 0, diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index b0c0ee942ea..a5cdaa547d8 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -9,9 +9,10 @@ use std::str::FromStr; use bitflags::bitflags; use rustc_data_structures::intern::Interned; +use rustc_data_structures::stable_hasher::Hash64; #[cfg(feature = "nightly")] use rustc_data_structures::stable_hasher::StableOrd; -use rustc_index::vec::{Idx, IndexSlice, IndexVec}; +use rustc_index::vec::{IndexSlice, IndexVec}; #[cfg(feature = "nightly")] use rustc_macros::HashStable_Generic; #[cfg(feature = "nightly")] @@ -77,12 +78,12 @@ pub struct ReprOptions { pub flags: ReprFlags, /// The seed to be used for randomizing a type's layout /// - /// Note: This could technically be a `[u8; 16]` (a `u128`) which would + /// Note: This could technically be a `Hash128` which would /// be the "most accurate" hash as it'd encompass the item and crate /// hash without loss, but it does pay the price of being larger. - /// Everything's a tradeoff, a `u64` seed should be sufficient for our + /// Everything's a tradeoff, a 64-bit seed should be sufficient for our /// purposes (primarily `-Z randomize-layout`) - pub field_shuffle_seed: u64, + pub field_shuffle_seed: Hash64, } impl ReprOptions { @@ -665,15 +666,12 @@ impl Align { format!("`{}` is too large", align) } - let mut bytes = align; - let mut pow2: u8 = 0; - while (bytes & 1) == 0 { - pow2 += 1; - bytes >>= 1; - } - if bytes != 1 { + let tz = align.trailing_zeros(); + if align != (1 << tz) { return Err(not_power_of_2(align)); } + + let pow2 = tz as u8; if pow2 > Self::MAX.pow2 { return Err(too_large(align)); } diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index df1a716755b..1e4d3ba47f4 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1271,6 +1271,7 @@ impl Expr { ExprKind::Continue(..) => ExprPrecedence::Continue, ExprKind::Ret(..) => ExprPrecedence::Ret, ExprKind::InlineAsm(..) => ExprPrecedence::InlineAsm, + ExprKind::OffsetOf(..) => ExprPrecedence::OffsetOf, ExprKind::MacCall(..) => ExprPrecedence::Mac, ExprKind::Struct(..) => ExprPrecedence::Struct, ExprKind::Repeat(..) => ExprPrecedence::Repeat, @@ -1298,17 +1299,17 @@ impl Expr { /// To a first-order approximation, is this a pattern? pub fn is_approximately_pattern(&self) -> bool { - match &self.peel_parens().kind { + matches!( + &self.peel_parens().kind, ExprKind::Array(_) - | ExprKind::Call(_, _) - | ExprKind::Tup(_) - | ExprKind::Lit(_) - | ExprKind::Range(_, _, _) - | ExprKind::Underscore - | ExprKind::Path(_, _) - | ExprKind::Struct(_) => true, - _ => false, - } + | ExprKind::Call(_, _) + | ExprKind::Tup(_) + | ExprKind::Lit(_) + | ExprKind::Range(_, _, _) + | ExprKind::Underscore + | ExprKind::Path(_, _) + | ExprKind::Struct(_) + ) } } @@ -1469,6 +1470,9 @@ pub enum ExprKind { /// Output of the `asm!()` macro. InlineAsm(P<InlineAsm>), + /// Output of the `offset_of!()` macro. + OffsetOf(P<Ty>, P<[Ident]>), + /// A macro invocation; pre-expansion. MacCall(P<MacCall>), diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 23c32fa96ca..b07ed1d1c74 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -10,7 +10,6 @@ )] #![feature(associated_type_bounds)] #![feature(box_patterns)] -#![feature(const_default_impls)] #![feature(const_trait_impl)] #![feature(if_let_guard)] #![feature(let_chains)] diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 694d31d8f1f..99f1f4bd968 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1456,6 +1456,12 @@ pub fn noop_visit_expr<T: MutVisitor>( } ExprKind::InlineAsm(asm) => vis.visit_inline_asm(asm), ExprKind::FormatArgs(fmt) => vis.visit_format_args(fmt), + ExprKind::OffsetOf(container, fields) => { + vis.visit_ty(container); + for field in fields.iter_mut() { + vis.visit_ident(field); + } + } ExprKind::MacCall(mac) => vis.visit_mac_call(mac), ExprKind::Struct(se) => { let StructExpr { qself, path, fields, rest } = se.deref_mut(); diff --git a/compiler/rustc_ast/src/node_id.rs b/compiler/rustc_ast/src/node_id.rs index daa82996b3d..d16741757d1 100644 --- a/compiler/rustc_ast/src/node_id.rs +++ b/compiler/rustc_ast/src/node_id.rs @@ -9,14 +9,14 @@ rustc_index::newtype_index! { /// /// [`DefId`]: rustc_span::def_id::DefId #[debug_format = "NodeId({})"] - pub struct NodeId {} + pub struct NodeId { + /// The [`NodeId`] used to represent the root of the crate. + const CRATE_NODE_ID = 0; + } } rustc_data_structures::define_id_collections!(NodeMap, NodeSet, NodeMapEntry, NodeId); -/// The [`NodeId`] used to represent the root of the crate. -pub const CRATE_NODE_ID: NodeId = NodeId::from_u32(0); - /// When parsing and at the beginning of doing expansions, we initially give all AST nodes /// this dummy AST [`NodeId`]. Then, during a later phase of expansion, we renumber them /// to have small, positive IDs. diff --git a/compiler/rustc_ast/src/ptr.rs b/compiler/rustc_ast/src/ptr.rs index 4b2850336a0..0140fb752bf 100644 --- a/compiler/rustc_ast/src/ptr.rs +++ b/compiler/rustc_ast/src/ptr.rs @@ -126,7 +126,8 @@ impl<S: Encoder, T: Encodable<S>> Encodable<S> for P<T> { } impl<T> P<[T]> { - pub const fn new() -> P<[T]> { + // FIXME(const-hack) make this const again + pub fn new() -> P<[T]> { P { ptr: Box::default() } } diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs index 3893875e9a4..24b4bd8623f 100644 --- a/compiler/rustc_ast/src/util/parser.rs +++ b/compiler/rustc_ast/src/util/parser.rs @@ -269,6 +269,7 @@ pub enum ExprPrecedence { Index, Try, InlineAsm, + OffsetOf, Mac, FormatArgs, @@ -335,7 +336,8 @@ impl ExprPrecedence { | ExprPrecedence::Try | ExprPrecedence::InlineAsm | ExprPrecedence::Mac - | ExprPrecedence::FormatArgs => PREC_POSTFIX, + | ExprPrecedence::FormatArgs + | ExprPrecedence::OffsetOf => PREC_POSTFIX, // Never need parens ExprPrecedence::Array diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index ac9b321b71c..8a6b5d5c905 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -909,6 +909,12 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { ExprKind::Paren(subexpression) => visitor.visit_expr(subexpression), ExprKind::InlineAsm(asm) => visitor.visit_inline_asm(asm), ExprKind::FormatArgs(f) => visitor.visit_format_args(f), + ExprKind::OffsetOf(container, fields) => { + visitor.visit_ty(container); + for &field in fields { + visitor.visit_ident(field); + } + } ExprKind::Yield(optional_expression) => { walk_list!(visitor, visit_expr, optional_expression); } diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml index eb2e82d7988..6b0da256505 100644 --- a/compiler/rustc_ast_lowering/Cargo.toml +++ b/compiler/rustc_ast_lowering/Cargo.toml @@ -12,6 +12,7 @@ rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_hir = { path = "../rustc_hir" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_index = { path = "../rustc_index" } rustc_middle = { path = "../rustc_middle" } rustc_macros = { path = "../rustc_macros" } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 1b1c4765bc0..6863100d9ba 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -121,12 +121,16 @@ impl<'hir> LoweringContext<'_, 'hir> { LitKind::Err } }; - hir::ExprKind::Lit(respan(self.lower_span(e.span), lit_kind)) + let lit = self.arena.alloc(respan(self.lower_span(e.span), lit_kind)); + hir::ExprKind::Lit(lit) + } + ExprKind::IncludedBytes(bytes) => { + let lit = self.arena.alloc(respan( + self.lower_span(e.span), + LitKind::ByteStr(bytes.clone(), StrStyle::Cooked), + )); + hir::ExprKind::Lit(lit) } - ExprKind::IncludedBytes(bytes) => hir::ExprKind::Lit(respan( - self.lower_span(e.span), - LitKind::ByteStr(bytes.clone(), StrStyle::Cooked), - )), ExprKind::Cast(expr, ty) => { let expr = self.lower_expr(expr); let ty = @@ -285,6 +289,13 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ExprKind::InlineAsm(self.lower_inline_asm(e.span, asm)) } ExprKind::FormatArgs(fmt) => self.lower_format_args(e.span, fmt), + ExprKind::OffsetOf(container, fields) => hir::ExprKind::OffsetOf( + self.lower_ty( + container, + &mut ImplTraitContext::Disallowed(ImplTraitPosition::OffsetOf), + ), + self.arena.alloc_from_iter(fields.iter().map(|&ident| self.lower_ident(ident))), + ), ExprKind::Struct(se) => { let rest = match &se.rest { StructRest::Base(e) => Some(self.lower_expr(e)), @@ -1746,40 +1757,31 @@ impl<'hir> LoweringContext<'_, 'hir> { } pub(super) fn expr_usize(&mut self, sp: Span, value: usize) -> hir::Expr<'hir> { - self.expr( - sp, - hir::ExprKind::Lit(hir::Lit { - span: sp, - node: ast::LitKind::Int( - value as u128, - ast::LitIntType::Unsigned(ast::UintTy::Usize), - ), - }), - ) + let lit = self.arena.alloc(hir::Lit { + span: sp, + node: ast::LitKind::Int(value as u128, ast::LitIntType::Unsigned(ast::UintTy::Usize)), + }); + self.expr(sp, hir::ExprKind::Lit(lit)) } pub(super) fn expr_u32(&mut self, sp: Span, value: u32) -> hir::Expr<'hir> { - self.expr( - sp, - hir::ExprKind::Lit(hir::Lit { - span: sp, - node: ast::LitKind::Int(value.into(), ast::LitIntType::Unsigned(ast::UintTy::U32)), - }), - ) + let lit = self.arena.alloc(hir::Lit { + span: sp, + node: ast::LitKind::Int(value.into(), ast::LitIntType::Unsigned(ast::UintTy::U32)), + }); + self.expr(sp, hir::ExprKind::Lit(lit)) } pub(super) fn expr_char(&mut self, sp: Span, value: char) -> hir::Expr<'hir> { - self.expr(sp, hir::ExprKind::Lit(hir::Lit { span: sp, node: ast::LitKind::Char(value) })) + let lit = self.arena.alloc(hir::Lit { span: sp, node: ast::LitKind::Char(value) }); + self.expr(sp, hir::ExprKind::Lit(lit)) } pub(super) fn expr_str(&mut self, sp: Span, value: Symbol) -> hir::Expr<'hir> { - self.expr( - sp, - hir::ExprKind::Lit(hir::Lit { - span: sp, - node: ast::LitKind::Str(value, ast::StrStyle::Cooked), - }), - ) + let lit = self + .arena + .alloc(hir::Lit { span: sp, node: ast::LitKind::Str(value, ast::StrStyle::Cooked) }); + self.expr(sp, hir::ExprKind::Lit(lit)) } pub(super) fn expr_call_mut( diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index c41bdc44093..ccf481cb9b3 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -220,19 +220,19 @@ fn make_argument<'hir>( /// Generates: /// /// ```text -/// <core::fmt::rt::v1::Count>::Is(…) +/// <core::fmt::rt::Count>::Is(…) /// ``` /// /// or /// /// ```text -/// <core::fmt::rt::v1::Count>::Param(…) +/// <core::fmt::rt::Count>::Param(…) /// ``` /// /// or /// /// ```text -/// <core::fmt::rt::v1::Count>::Implied +/// <core::fmt::rt::Count>::Implied /// ``` fn make_count<'hir>( ctx: &mut LoweringContext<'_, 'hir>, @@ -278,13 +278,13 @@ fn make_count<'hir>( /// Generates /// /// ```text -/// <core::fmt::rt::v1::Argument::new( +/// <core::fmt::rt::Placeholder::new( /// …usize, // position /// '…', // fill -/// <core::fmt::rt::v1::Alignment>::…, // alignment +/// <core::fmt::rt::Alignment>::…, // alignment /// …u32, // flags -/// <core::fmt::rt::v1::Count::…>, // width -/// <core::fmt::rt::v1::Count::…>, // precision +/// <core::fmt::rt::Count::…>, // width +/// <core::fmt::rt::Count::…>, // precision /// ) /// ``` fn make_format_spec<'hir>( diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index f89e254a2f5..08e7a4dfe5d 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -89,9 +89,9 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { lctx.with_hir_id_owner(owner, |lctx| f(lctx)); for (def_id, info) in lctx.children { - self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom); - debug_assert!(matches!(self.owners[def_id], hir::MaybeOwner::Phantom)); - self.owners[def_id] = info; + let owner = self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom); + debug_assert!(matches!(owner, hir::MaybeOwner::Phantom)); + *owner = info; } } @@ -99,8 +99,8 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { &mut self, def_id: LocalDefId, ) -> hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>> { - self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom); - if let hir::MaybeOwner::Phantom = self.owners[def_id] { + let owner = self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom); + if let hir::MaybeOwner::Phantom = owner { let node = self.ast_index[def_id]; match node { AstOwner::NonOwner => {} @@ -138,12 +138,10 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { // Evaluate with the lifetimes in `params` in-scope. // This is used to track which lifetimes have already been defined, // and which need to be replicated when lowering an async fn. - match parent_hir.node().expect_item().kind { - hir::ItemKind::Impl(hir::Impl { of_trait, .. }) => { - lctx.is_in_trait_impl = of_trait.is_some(); - } - _ => {} - }; + + if let hir::ItemKind::Impl(impl_) = parent_hir.node().expect_item().kind { + lctx.is_in_trait_impl = impl_.of_trait.is_some(); + } match ctxt { AssocCtxt::Trait => hir::OwnerNode::TraitItem(lctx.lower_trait_item(item)), diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index f7ae96b7c4a..c969d709608 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -55,13 +55,13 @@ use rustc_data_structures::sync::Lrc; use rustc_errors::{ DiagnosticArgFromDisplay, DiagnosticMessage, Handler, StashKey, SubdiagnosticMessage, }; +use rustc_fluent_macro::fluent_messages; use rustc_hir as hir; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; use rustc_hir::definitions::DefPathData; use rustc_hir::{ConstArg, GenericArg, ItemLocalId, ParamName, TraitCandidate}; use rustc_index::vec::{Idx, IndexSlice, IndexVec}; -use rustc_macros::fluent_messages; use rustc_middle::{ span_bug, ty::{ResolverAstLowering, TyCtxt}, @@ -283,6 +283,7 @@ enum ImplTraitPosition { FieldTy, Cast, ImplSelf, + OffsetOf, } impl std::fmt::Display for ImplTraitPosition { @@ -313,6 +314,7 @@ impl std::fmt::Display for ImplTraitPosition { ImplTraitPosition::FieldTy => "field types", ImplTraitPosition::Cast => "cast types", ImplTraitPosition::ImplSelf => "impl headers", + ImplTraitPosition::OffsetOf => "`offset_of!` params", }; write!(f, "{name}") @@ -332,10 +334,7 @@ enum FnDeclKind { impl FnDeclKind { fn param_impl_trait_allowed(&self) -> bool { - match self { - FnDeclKind::Fn | FnDeclKind::Inherent | FnDeclKind::Impl | FnDeclKind::Trait => true, - _ => false, - } + matches!(self, FnDeclKind::Fn | FnDeclKind::Inherent | FnDeclKind::Impl | FnDeclKind::Trait) } fn return_impl_trait_allowed(&self, tcx: TyCtxt<'_>) -> bool { @@ -371,8 +370,8 @@ fn index_crate<'a>( krate: &'a Crate, ) -> IndexVec<LocalDefId, AstOwner<'a>> { let mut indexer = Indexer { node_id_to_def_id, index: IndexVec::new() }; - indexer.index.ensure_contains_elem(CRATE_DEF_ID, || AstOwner::NonOwner); - indexer.index[CRATE_DEF_ID] = AstOwner::Crate(krate); + *indexer.index.ensure_contains_elem(CRATE_DEF_ID, || AstOwner::NonOwner) = + AstOwner::Crate(krate); visit::walk_crate(&mut indexer, krate); return indexer.index; @@ -389,22 +388,21 @@ fn index_crate<'a>( fn visit_item(&mut self, item: &'a ast::Item) { let def_id = self.node_id_to_def_id[&item.id]; - self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner); - self.index[def_id] = AstOwner::Item(item); + *self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner) = AstOwner::Item(item); visit::walk_item(self, item) } fn visit_assoc_item(&mut self, item: &'a ast::AssocItem, ctxt: visit::AssocCtxt) { let def_id = self.node_id_to_def_id[&item.id]; - self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner); - self.index[def_id] = AstOwner::AssocItem(item, ctxt); + *self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner) = + AstOwner::AssocItem(item, ctxt); visit::walk_assoc_item(self, item, ctxt); } fn visit_foreign_item(&mut self, item: &'a ast::ForeignItem) { let def_id = self.node_id_to_def_id[&item.id]; - self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner); - self.index[def_id] = AstOwner::ForeignItem(item); + *self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner) = + AstOwner::ForeignItem(item); visit::walk_foreign_item(self, item); } } diff --git a/compiler/rustc_ast_passes/Cargo.toml b/compiler/rustc_ast_passes/Cargo.toml index 8bd212073a6..eb736123520 100644 --- a/compiler/rustc_ast_passes/Cargo.toml +++ b/compiler/rustc_ast_passes/Cargo.toml @@ -12,6 +12,7 @@ rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } rustc_macros = { path = "../rustc_macros" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_parse = { path = "../rustc_parse" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index a349fe6a3c4..ffca37ae9d5 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -231,7 +231,7 @@ ast_passes_feature_on_non_nightly = `#![feature]` may not be used on the {$chann .suggestion = remove the attribute .stable_since = the feature `{$name}` has been stable since `{$since}` and no longer requires an attribute to enable -ast_passes_incompatbile_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed +ast_passes_incompatible_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed .help = remove one of these features ast_passes_show_span = {$msg} diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 27bbd237961..1732865f0bb 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -677,7 +677,7 @@ impl AddToDiagnostic for StableFeature { } #[derive(Diagnostic)] -#[diag(ast_passes_incompatbile_features)] +#[diag(ast_passes_incompatible_features)] #[help] pub struct IncompatibleFeatures { #[primary_span] diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs index e2c666604b3..7db413c5bbd 100644 --- a/compiler/rustc_ast_passes/src/lib.rs +++ b/compiler/rustc_ast_passes/src/lib.rs @@ -13,7 +13,7 @@ #![deny(rustc::diagnostic_outside_of_impl)] use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; -use rustc_macros::fluent_messages; +use rustc_fluent_macro::fluent_messages; pub mod ast_validation; mod errors; diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 776bf54244e..aeb0c762020 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -549,6 +549,26 @@ impl<'a> State<'a> { self.end(); self.pclose(); } + ast::ExprKind::OffsetOf(container, fields) => { + // FIXME: This should have its own syntax, distinct from a macro invocation. + self.word("offset_of!"); + self.popen(); + self.rbox(0, Inconsistent); + self.print_type(container); + self.word(","); + self.space(); + + if let Some((&first, rest)) = fields.split_first() { + self.print_ident(first); + + for &field in rest { + self.word("."); + self.print_ident(field); + } + } + + self.end(); + } ast::ExprKind::MacCall(m) => self.print_mac(m), ast::ExprKind::Paren(e) => { self.popen(); diff --git a/compiler/rustc_attr/Cargo.toml b/compiler/rustc_attr/Cargo.toml index 6349ddf31d1..2c4c3a0c263 100644 --- a/compiler/rustc_attr/Cargo.toml +++ b/compiler/rustc_attr/Cargo.toml @@ -9,6 +9,7 @@ edition = "2021" rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_serialize = { path = "../rustc_serialize" } rustc_errors = { path = "../rustc_errors" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_span = { path = "../rustc_span" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_feature = { path = "../rustc_feature" } diff --git a/compiler/rustc_attr/src/lib.rs b/compiler/rustc_attr/src/lib.rs index 49818c14f27..cfed2acfb3a 100644 --- a/compiler/rustc_attr/src/lib.rs +++ b/compiler/rustc_attr/src/lib.rs @@ -12,7 +12,7 @@ extern crate rustc_macros; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; -use rustc_macros::fluent_messages; +use rustc_fluent_macro::fluent_messages; mod builtin; mod session_diagnostics; diff --git a/compiler/rustc_borrowck/Cargo.toml b/compiler/rustc_borrowck/Cargo.toml index 87c113f3e30..56a9deb6aab 100644 --- a/compiler/rustc_borrowck/Cargo.toml +++ b/compiler/rustc_borrowck/Cargo.toml @@ -15,12 +15,12 @@ rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_graphviz = { path = "../rustc_graphviz" } rustc_hir = { path = "../rustc_hir" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_index = { path = "../rustc_index" } rustc_infer = { path = "../rustc_infer" } rustc_lexer = { path = "../rustc_lexer" } rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } -rustc_const_eval = { path = "../rustc_const_eval" } rustc_mir_dataflow = { path = "../rustc_mir_dataflow" } rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } diff --git a/compiler/rustc_borrowck/messages.ftl b/compiler/rustc_borrowck/messages.ftl index a3b6b5e8138..0b8123c9703 100644 --- a/compiler/rustc_borrowck/messages.ftl +++ b/compiler/rustc_borrowck/messages.ftl @@ -56,18 +56,6 @@ borrowck_returned_lifetime_short = borrowck_used_impl_require_static = the used `impl` has a `'static` requirement -borrowck_capture_kind_label = - capture is {$kind_desc} because of use here - -borrowck_var_borrow_by_use_place_in_generator = - borrow occurs due to use of {$place} in closure in generator - -borrowck_var_borrow_by_use_place_in_closure = - borrow occurs due to use of {$place} in closure - -borrowck_var_borrow_by_use_place = - borrow occurs due to use of {$place} - borrowck_borrow_due_to_use_generator = borrow occurs due to use in generator @@ -101,12 +89,63 @@ borrowck_capture_mut = borrowck_capture_move = capture is moved because of use here +borrowck_var_borrow_by_use_place_in_generator = + {$is_single_var -> + *[true] borrow occurs + [false] borrows occur + } due to use of {$place} in generator + +borrowck_var_borrow_by_use_place_in_closure = + {$is_single_var -> + *[true] borrow occurs + [false] borrows occur + } due to use of {$place} in closure + +borrowck_var_borrow_by_use_in_generator = + borrow occurs due to use in generator + +borrowck_var_borrow_by_use_in_closure = + borrow occurs due to use in closure + borrowck_var_move_by_use_place_in_generator = move occurs due to use of {$place} in generator borrowck_var_move_by_use_place_in_closure = move occurs due to use of {$place} in closure +borrowck_var_move_by_use_in_generator = + move occurs due to use in generator + +borrowck_var_move_by_use_in_closure = + move occurs due to use in closure + +borrowck_partial_var_move_by_use_in_generator = + variable {$is_partial -> + [true] partially moved + *[false] moved + } due to use in generator + +borrowck_partial_var_move_by_use_in_closure = + variable {$is_partial -> + [true] partially moved + *[false] moved + } due to use in closure + +borrowck_var_first_borrow_by_use_place_in_generator = + first borrow occurs due to use of {$place} in generator + +borrowck_var_first_borrow_by_use_place_in_closure = + first borrow occurs due to use of {$place} in closure + +borrowck_var_second_borrow_by_use_place_in_generator = + second borrow occurs due to use of {$place} in generator + +borrowck_var_second_borrow_by_use_place_in_closure = + second borrow occurs due to use of {$place} in closure + +borrowck_var_mutable_borrow_by_use_place_in_closure = + mutable borrow occurs due to use of {$place} in closure + borrowck_cannot_move_when_borrowed = cannot move out of {$place -> [value] value @@ -127,3 +166,90 @@ borrowck_opaque_type_non_generic_param = [true] cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type *[other] this generic parameter must be used with a generic {$kind} parameter } + +borrowck_moved_due_to_call = + {$place_name} {$is_partial -> + [true] partially moved + *[false] moved + } due to this {$is_loop_message -> + [true] call, in previous iteration of loop + *[false] call + } + +borrowck_moved_due_to_usage_in_operator = + {$place_name} {$is_partial -> + [true] partially moved + *[false] moved + } due to usage in {$is_loop_message -> + [true] operator, in previous iteration of loop + *[false] operator + } + +borrowck_moved_due_to_implicit_into_iter_call = + {$place_name} {$is_partial -> + [true] partially moved + *[false] moved + } due to this implicit call to {$is_loop_message -> + [true] `.into_iter()`, in previous iteration of loop + *[false] `.into_iter()` + } + +borrowck_moved_due_to_method_call = + {$place_name} {$is_partial -> + [true] partially moved + *[false] moved + } due to this method {$is_loop_message -> + [true] call, in previous iteration of loop + *[false] call + } + +borrowck_value_moved_here = + value {$is_partial -> + [true] partially moved + *[false] moved + } {$is_move_msg -> + [true] into closure here + *[false] here + }{$is_loop_message -> + [true] , in previous iteration of loop + *[false] {""} + } + +borrowck_consider_borrow_type_contents = + help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents + +borrowck_moved_a_fn_once_in_call = + this value implements `FnOnce`, which causes it to be moved when called + +borrowck_calling_operator_moves_lhs = + calling this operator moves the left-hand side + +borrowck_func_take_self_moved_place = + `{$func}` takes ownership of the receiver `self`, which moves {$place_name} + +borrowck_suggest_iterate_over_slice = + consider iterating over a slice of the `{$ty}`'s content to avoid moving into the `for` loop + +borrowck_suggest_create_freash_reborrow = + consider reborrowing the `Pin` instead of moving it + +borrowck_value_capture_here = + value captured {$is_within -> + [true] here by generator + *[false] here + } + +borrowck_move_out_place_here = + {$place} is moved here + +borrowck_closure_invoked_twice = + closure cannot be invoked more than once because it moves the variable `{$place_name}` out of its environment + +borrowck_closure_moved_twice = + closure cannot be moved more than once as it is not `Copy` due to moving the variable `{$place_name}` out of its environment + +borrowck_ty_no_impl_copy = + {$is_partial_move -> + [true] partial move + *[false] move + } occurs because {$place} has type `{$ty}`, which does not implement the `Copy` trait diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs index 2bbb9618dbf..acca1a1477f 100644 --- a/compiler/rustc_borrowck/src/borrowck_errors.rs +++ b/compiler/rustc_borrowck/src/borrowck_errors.rs @@ -469,6 +469,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { } #[rustc_lint_diagnostics] + #[track_caller] pub(crate) fn struct_span_err_with_code<S: Into<MultiSpan>>( &self, sp: S, diff --git a/compiler/rustc_borrowck/src/consumers.rs b/compiler/rustc_borrowck/src/consumers.rs index cb1a6522223..cd200aaa277 100644 --- a/compiler/rustc_borrowck/src/consumers.rs +++ b/compiler/rustc_borrowck/src/consumers.rs @@ -6,7 +6,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_index::vec::IndexSlice; use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt}; use rustc_middle::mir::Body; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::TyCtxt; pub use super::{ facts::{AllFacts as PoloniusInput, RustcFacts}, @@ -28,12 +28,9 @@ pub use super::{ /// that shows how to do this at `tests/run-make/obtain-borrowck/`. /// /// * Polonius is highly unstable, so expect regular changes in its signature or other details. -pub fn get_body_with_borrowck_facts( - tcx: TyCtxt<'_>, - def: ty::WithOptConstParam<LocalDefId>, -) -> BodyWithBorrowckFacts<'_> { +pub fn get_body_with_borrowck_facts(tcx: TyCtxt<'_>, def: LocalDefId) -> BodyWithBorrowckFacts<'_> { let (input_body, promoted) = tcx.mir_promoted(def); - let infcx = tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(def.did)).build(); + let infcx = tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(def)).build(); let input_body: &Body<'_> = &input_body.borrow(); let promoted: &IndexSlice<_, _> = &promoted.borrow(); *super::do_mir_borrowck(&infcx, input_body, promoted, true).1.unwrap() diff --git a/compiler/rustc_borrowck/src/def_use.rs b/compiler/rustc_borrowck/src/def_use.rs index 9e9f0b4b4ad..6259722b694 100644 --- a/compiler/rustc_borrowck/src/def_use.rs +++ b/compiler/rustc_borrowck/src/def_use.rs @@ -52,12 +52,16 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> { PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) | PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow) | + // `PlaceMention` and `AscribeUserType` both evaluate the place, which must not + // contain dangling references. + PlaceContext::NonUse(NonUseContext::PlaceMention) | + PlaceContext::NonUse(NonUseContext::AscribeUserTy) | + PlaceContext::MutatingUse(MutatingUseContext::AddressOf) | PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) | PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect) | PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) | PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) | - PlaceContext::NonUse(NonUseContext::AscribeUserTy) | PlaceContext::MutatingUse(MutatingUseContext::Retag) => Some(DefUse::Use), @@ -72,8 +76,6 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> { PlaceContext::MutatingUse(MutatingUseContext::Drop) => Some(DefUse::Drop), - // This statement exists to help unsafeck. It does not require the place to be live. - PlaceContext::NonUse(NonUseContext::PlaceMention) => None, // Debug info is neither def nor use. PlaceContext::NonUse(NonUseContext::VarDebugInfo) => None, diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 75a3dd0c0f3..2320901a053 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1,5 +1,6 @@ +use std::iter; + use either::Either; -use rustc_const_eval::util::CallKind; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{ @@ -11,6 +12,7 @@ use rustc_hir::intravisit::{walk_block, walk_expr, Visitor}; use rustc_hir::{AsyncGeneratorKind, GeneratorKind, LangItem}; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::ObligationCause; +use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::{ self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory, @@ -18,20 +20,19 @@ use rustc_middle::mir::{ ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm, }; use rustc_middle::ty::{self, suggest_constraining_type_params, PredicateKind, Ty}; +use rustc_middle::util::CallKind; use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex}; use rustc_span::def_id::LocalDefId; use rustc_span::hygiene::DesugaringKind; -use rustc_span::symbol::{kw, sym}; +use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{BytePos, Span, Symbol}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::ObligationCtxt; use crate::borrow_set::TwoPhaseActivation; use crate::borrowck_errors; - use crate::diagnostics::conflict_errors::StorageDeadOrDrop::LocalStorageDead; -use crate::diagnostics::find_all_local_uses; -use crate::diagnostics::mutability_errors::mut_borrow_of_mutable_ref; +use crate::diagnostics::{find_all_local_uses, CapturedMessageOpt}; use crate::{ borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf, InitializationRequiringAction, MirBorrowckCtxt, PrefixSet, WriteKind, @@ -183,13 +184,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let move_spans = self.move_spans(moved_place.as_ref(), move_out.source); let move_span = move_spans.args_or_use(); - let move_msg = if move_spans.for_closure() { " into closure" } else { "" }; + let is_move_msg = move_spans.for_closure(); - let loop_message = if location == move_out.source || move_site.traversed_back_edge { - ", in previous iteration of loop" - } else { - "" - }; + let is_loop_message = location == move_out.source || move_site.traversed_back_edge; if location == move_out.source { is_loop_move = true; @@ -206,17 +203,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); } + let msg_opt = CapturedMessageOpt { + is_partial_move, + is_loop_message, + is_move_msg, + is_loop_move, + maybe_reinitialized_locations_is_empty: maybe_reinitialized_locations + .is_empty(), + }; self.explain_captures( &mut err, span, move_span, move_spans, *moved_place, - partially_str, - loop_message, - move_msg, - is_loop_move, - maybe_reinitialized_locations.is_empty(), + msg_opt, ); } seen_spans.insert(move_span); @@ -282,12 +283,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } if needs_note { - let span = if let Some(local) = place.as_local() { - Some(self.body.local_decls[local].source_info.span) + if let Some(local) = place.as_local() { + let span = self.body.local_decls[local].source_info.span; + err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label { + is_partial_move, + ty, + place: ¬e_msg, + span, + }); } else { - None + err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Note { + is_partial_move, + ty, + place: ¬e_msg, + }); }; - self.note_type_does_not_implement_copy(&mut err, ¬e_msg, ty, span, partial_str); } if let UseSpans::FnSelfUse { @@ -827,11 +837,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { borrow_spans.var_path_only_subdiag(&mut err, crate::InitializationRequiringAction::Borrow); - move_spans.var_span_label( - &mut err, - format!("move occurs due to use{}", move_spans.describe()), - "moved", - ); + move_spans.var_subdiag(None, &mut err, None, |kind, var_span| { + use crate::session_diagnostics::CaptureVarCause::*; + match kind { + Some(_) => MoveUseInGenerator { var_span }, + None => MoveUseInClosure { var_span }, + } + }); self.explain_why_borrow_contains_point(location, borrow, None) .add_explanation_to_diagnostic( @@ -868,13 +880,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { borrow_span, &self.describe_any_place(borrow.borrowed_place.as_ref()), ); - borrow_spans.var_subdiag(&mut err, Some(borrow.kind), |kind, var_span| { + borrow_spans.var_subdiag(None, &mut err, Some(borrow.kind), |kind, var_span| { use crate::session_diagnostics::CaptureVarCause::*; let place = &borrow.borrowed_place; let desc_place = self.describe_any_place(place.as_ref()); match kind { - Some(_) => BorrowUsePlaceGenerator { place: desc_place, var_span }, - None => BorrowUsePlaceClosure { place: desc_place, var_span }, + Some(_) => { + BorrowUsePlaceGenerator { place: desc_place, var_span, is_single_var: true } + } + None => BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: true }, } }); @@ -946,7 +960,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &msg_borrow, None, ); - self.suggest_binding_for_closure_capture_self( + self.suggest_binding_for_closure_capture_self(&mut err, &issued_spans); + self.suggest_using_closure_argument_instead_of_capture( &mut err, issued_borrow.borrowed_place, &issued_spans, @@ -969,6 +984,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { place, issued_borrow.borrowed_place, ); + self.suggest_using_closure_argument_instead_of_capture( + &mut err, + issued_borrow.borrowed_place, + &issued_spans, + ); err } @@ -988,16 +1008,26 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { immutable_section_description, "mutably borrow", ); - borrow_spans.var_span_label( + borrow_spans.var_subdiag( + None, &mut err, - format!( - "borrow occurs due to use of {}{}", - desc_place, - borrow_spans.describe(), - ), - "immutable", + Some(BorrowKind::Unique), + |kind, var_span| { + use crate::session_diagnostics::CaptureVarCause::*; + match kind { + Some(_) => BorrowUsePlaceGenerator { + place: desc_place, + var_span, + is_single_var: true, + }, + None => BorrowUsePlaceClosure { + place: desc_place, + var_span, + is_single_var: true, + }, + } + }, ); - return err; } else { first_borrow_desc = "immutable "; @@ -1070,32 +1100,48 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { }; if issued_spans == borrow_spans { - borrow_spans.var_span_label( - &mut err, - format!("borrows occur due to use of {}{}", desc_place, borrow_spans.describe(),), - gen_borrow_kind.describe_mutability(), - ); + borrow_spans.var_subdiag(None, &mut err, Some(gen_borrow_kind), |kind, var_span| { + use crate::session_diagnostics::CaptureVarCause::*; + match kind { + Some(_) => BorrowUsePlaceGenerator { + place: desc_place, + var_span, + is_single_var: false, + }, + None => { + BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: false } + } + } + }); } else { - let borrow_place = &issued_borrow.borrowed_place; - let borrow_place_desc = self.describe_any_place(borrow_place.as_ref()); - issued_spans.var_span_label( + issued_spans.var_subdiag( + Some(&self.infcx.tcx.sess.parse_sess.span_diagnostic), &mut err, - format!( - "first borrow occurs due to use of {}{}", - borrow_place_desc, - issued_spans.describe(), - ), - issued_borrow.kind.describe_mutability(), + Some(issued_borrow.kind), + |kind, var_span| { + use crate::session_diagnostics::CaptureVarCause::*; + let borrow_place = &issued_borrow.borrowed_place; + let borrow_place_desc = self.describe_any_place(borrow_place.as_ref()); + match kind { + Some(_) => { + FirstBorrowUsePlaceGenerator { place: borrow_place_desc, var_span } + } + None => FirstBorrowUsePlaceClosure { place: borrow_place_desc, var_span }, + } + }, ); - borrow_spans.var_span_label( + borrow_spans.var_subdiag( + Some(&self.infcx.tcx.sess.parse_sess.span_diagnostic), &mut err, - format!( - "second borrow occurs due to use of {}{}", - desc_place, - borrow_spans.describe(), - ), - gen_borrow_kind.describe_mutability(), + Some(gen_borrow_kind), + |kind, var_span| { + use crate::session_diagnostics::CaptureVarCause::*; + match kind { + Some(_) => SecondBorrowUsePlaceGenerator { place: desc_place, var_span }, + None => SecondBorrowUsePlaceClosure { place: desc_place, var_span }, + } + }, ); } @@ -1229,22 +1275,160 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } - fn suggest_binding_for_closure_capture_self( + /// Suggest using closure argument instead of capture. + /// + /// For example: + /// ```ignore (illustrative) + /// struct S; + /// + /// impl S { + /// fn call(&mut self, f: impl Fn(&mut Self)) { /* ... */ } + /// fn x(&self) {} + /// } + /// + /// let mut v = S; + /// v.call(|this: &mut S| v.x()); + /// // ^\ ^-- help: try using the closure argument: `this` + /// // *-- error: cannot borrow `v` as mutable because it is also borrowed as immutable + /// ``` + fn suggest_using_closure_argument_instead_of_capture( &self, err: &mut Diagnostic, borrowed_place: Place<'tcx>, issued_spans: &UseSpans<'tcx>, ) { - let UseSpans::ClosureUse { capture_kind_span, .. } = issued_spans else { return }; - let hir = self.infcx.tcx.hir(); + let &UseSpans::ClosureUse { capture_kind_span, .. } = issued_spans else { return }; + let tcx = self.infcx.tcx; + let hir = tcx.hir(); - // check whether the borrowed place is capturing `self` by mut reference + // Get the type of the local that we are trying to borrow let local = borrowed_place.local; - let Some(_) = self - .body - .local_decls - .get(local) - .map(|l| mut_borrow_of_mutable_ref(l, self.local_names[local])) else { return }; + let local_ty = self.body.local_decls[local].ty; + + // Get the body the error happens in + let Some(body_id) = hir.get(self.mir_hir_id()).body_id() else { return }; + + let body_expr = hir.body(body_id).value; + + struct ClosureFinder<'hir> { + hir: rustc_middle::hir::map::Map<'hir>, + borrow_span: Span, + res: Option<(&'hir hir::Expr<'hir>, &'hir hir::Closure<'hir>)>, + /// The path expression with the `borrow_span` span + error_path: Option<(&'hir hir::Expr<'hir>, &'hir hir::QPath<'hir>)>, + } + impl<'hir> Visitor<'hir> for ClosureFinder<'hir> { + type NestedFilter = OnlyBodies; + + fn nested_visit_map(&mut self) -> Self::Map { + self.hir + } + + fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) { + if let hir::ExprKind::Path(qpath) = &ex.kind + && ex.span == self.borrow_span + { + self.error_path = Some((ex, qpath)); + } + + if let hir::ExprKind::Closure(closure) = ex.kind + && ex.span.contains(self.borrow_span) + // To support cases like `|| { v.call(|this| v.get()) }` + // FIXME: actually support such cases (need to figure out how to move from the capture place to original local) + && self.res.as_ref().map_or(true, |(prev_res, _)| prev_res.span.contains(ex.span)) + { + self.res = Some((ex, closure)); + } + + hir::intravisit::walk_expr(self, ex); + } + } + + // Find the closure that most tightly wraps `capture_kind_span` + let mut finder = + ClosureFinder { hir, borrow_span: capture_kind_span, res: None, error_path: None }; + finder.visit_expr(body_expr); + let Some((closure_expr, closure)) = finder.res else { return }; + + let typeck_results = tcx.typeck(self.mir_def_id()); + + // Check that the parent of the closure is a method call, + // with receiver matching with local's type (modulo refs) + let parent = hir.parent_id(closure_expr.hir_id); + if let hir::Node::Expr(parent) = hir.get(parent) { + if let hir::ExprKind::MethodCall(_, recv, ..) = parent.kind { + let recv_ty = typeck_results.expr_ty(recv); + + if recv_ty.peel_refs() != local_ty { + return; + } + } + } + + // Get closure's arguments + let ty::Closure(_, substs) = typeck_results.expr_ty(closure_expr).kind() else { unreachable!() }; + let sig = substs.as_closure().sig(); + let tupled_params = + tcx.erase_late_bound_regions(sig.inputs().iter().next().unwrap().map_bound(|&b| b)); + let ty::Tuple(params) = tupled_params.kind() else { return }; + + // Find the first argument with a matching type, get its name + let Some((_, this_name)) = params + .iter() + .zip(hir.body_param_names(closure.body)) + .find(|(param_ty, name)|{ + // FIXME: also support deref for stuff like `Rc` arguments + param_ty.peel_refs() == local_ty && name != &Ident::empty() + }) + else { return }; + + let spans; + if let Some((_path_expr, qpath)) = finder.error_path + && let hir::QPath::Resolved(_, path) = qpath + && let hir::def::Res::Local(local_id) = path.res + { + // Find all references to the problematic variable in this closure body + + struct VariableUseFinder { + local_id: hir::HirId, + spans: Vec<Span>, + } + impl<'hir> Visitor<'hir> for VariableUseFinder { + fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) { + if let hir::ExprKind::Path(qpath) = &ex.kind + && let hir::QPath::Resolved(_, path) = qpath + && let hir::def::Res::Local(local_id) = path.res + && local_id == self.local_id + { + self.spans.push(ex.span); + } + + hir::intravisit::walk_expr(self, ex); + } + } + + let mut finder = VariableUseFinder { local_id, spans: Vec::new() }; + finder.visit_expr(hir.body(closure.body).value); + + spans = finder.spans; + } else { + spans = vec![capture_kind_span]; + } + + err.multipart_suggestion( + "try using the closure argument", + iter::zip(spans, iter::repeat(this_name.to_string())).collect(), + Applicability::MaybeIncorrect, + ); + } + + fn suggest_binding_for_closure_capture_self( + &self, + err: &mut Diagnostic, + issued_spans: &UseSpans<'tcx>, + ) { + let UseSpans::ClosureUse { capture_kind_span, .. } = issued_spans else { return }; + let hir = self.infcx.tcx.hir(); struct ExpressionFinder<'hir> { capture_span: Span, @@ -1731,9 +1915,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err.span_label(borrow_span, "borrowed value does not live long enough"); err.span_label(drop_span, format!("`{}` dropped here while still borrowed", name)); - let within = if borrow_spans.for_generator() { " by generator" } else { "" }; - - borrow_spans.args_span_label(&mut err, format!("value captured here{}", within)); + borrow_spans.args_subdiag(&mut err, |args_span| { + crate::session_diagnostics::CaptureArgLabel::Capture { + is_within: borrow_spans.for_generator(), + args_span, + } + }); explanation.add_explanation_to_diagnostic( self.infcx.tcx, @@ -1947,9 +2134,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { None, ); - let within = if borrow_spans.for_generator() { " by generator" } else { "" }; - - borrow_spans.args_span_label(&mut err, format!("value captured here{}", within)); + borrow_spans.args_subdiag(&mut err, |args_span| { + crate::session_diagnostics::CaptureArgLabel::Capture { + is_within: borrow_spans.for_generator(), + args_span, + } + }); err } @@ -2382,11 +2572,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { section, "assign", ); - loan_spans.var_span_label( - &mut err, - format!("borrow occurs due to use{}", loan_spans.describe()), - loan.kind.describe_mutability(), - ); + + loan_spans.var_subdiag(None, &mut err, Some(loan.kind), |kind, var_span| { + use crate::session_diagnostics::CaptureVarCause::*; + match kind { + Some(_) => BorrowUseInGenerator { var_span }, + None => BorrowUseInClosure { var_span }, + } + }); self.buffer_error(err); @@ -2396,11 +2589,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let mut err = self.cannot_assign_to_borrowed(span, loan_span, &descr_place); - loan_spans.var_span_label( - &mut err, - format!("borrow occurs due to use{}", loan_spans.describe()), - loan.kind.describe_mutability(), - ); + loan_spans.var_subdiag(None, &mut err, Some(loan.kind), |kind, var_span| { + use crate::session_diagnostics::CaptureVarCause::*; + match kind { + Some(_) => BorrowUseInGenerator { var_span }, + None => BorrowUseInClosure { var_span }, + } + }); self.explain_why_borrow_contains_point(location, loan, None).add_explanation_to_diagnostic( self.infcx.tcx, @@ -2424,7 +2619,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Some((method_did, method_substs)), ) = ( &self.body[loan.reserve_location.block].terminator, - rustc_const_eval::util::find_self_call( + rustc_middle::util::find_self_call( tcx, self.body, loan.assigned_place.local, diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 110354a20d8..4a85df9f8c0 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -1,7 +1,10 @@ //! Borrow checker diagnostics. +use crate::session_diagnostics::{ + CaptureArgLabel, CaptureReasonLabel, CaptureReasonNote, CaptureReasonSuggest, CaptureVarCause, + CaptureVarKind, CaptureVarPathUseCause, OnClosureNote, +}; use itertools::Itertools; -use rustc_const_eval::util::{call_kind, CallDesugaringKind}; use rustc_errors::{Applicability, Diagnostic}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, Namespace}; @@ -15,6 +18,7 @@ use rustc_middle::mir::{ }; use rustc_middle::ty::print::Print; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; +use rustc_middle::util::{call_kind, CallDesugaringKind}; use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult}; use rustc_span::def_id::LocalDefId; use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP}; @@ -45,7 +49,7 @@ pub(crate) use mutability_errors::AccessKind; pub(crate) use outlives_suggestion::OutlivesSuggestionBuilder; pub(crate) use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors}; pub(crate) use region_name::{RegionName, RegionNameSource}; -pub(crate) use rustc_const_eval::util::CallKind; +pub(crate) use rustc_middle::util::CallKind; pub(super) struct DescribePlaceOpt { pub including_downcast: bool, @@ -117,13 +121,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() { let did = did.expect_local(); if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) { - diag.span_note( - *span, - &format!( - "closure cannot be invoked more than once because it moves the \ - variable `{}` out of its environment", - ty::place_to_string_for_capture(self.infcx.tcx, hir_place) - ), + diag.eager_subdiagnostic( + &self.infcx.tcx.sess.parse_sess.span_diagnostic, + OnClosureNote::InvokedTwice { + place_name: &ty::place_to_string_for_capture( + self.infcx.tcx, + hir_place, + ), + span: *span, + }, ); return true; } @@ -137,13 +143,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind() { let did = did.expect_local(); if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) { - diag.span_note( - *span, - &format!( - "closure cannot be moved more than once as it is not `Copy` due to \ - moving the variable `{}` out of its environment", - ty::place_to_string_for_capture(self.infcx.tcx, hir_place) - ), + diag.eager_subdiagnostic( + &self.infcx.tcx.sess.parse_sess.span_diagnostic, + OnClosureNote::MovedTwice { + place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place), + span: *span, + }, ); return true; } @@ -380,25 +385,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } - /// Add a note that a type does not implement `Copy` - pub(super) fn note_type_does_not_implement_copy( - &self, - err: &mut Diagnostic, - place_desc: &str, - ty: Ty<'tcx>, - span: Option<Span>, - move_prefix: &str, - ) { - let message = format!( - "{move_prefix}move occurs because {place_desc} has type `{ty}`, which does not implement the `Copy` trait", - ); - if let Some(span) = span { - err.span_label(span, message); - } else { - err.note(&message); - } - } - pub(super) fn borrowed_content_source( &self, deref_base: PlaceRef<'tcx>, @@ -582,9 +568,13 @@ impl UseSpans<'_> { } /// Add a span label to the arguments of the closure, if it exists. - pub(super) fn args_span_label(self, err: &mut Diagnostic, message: impl Into<String>) { + pub(super) fn args_subdiag( + self, + err: &mut Diagnostic, + f: impl FnOnce(Span) -> CaptureArgLabel, + ) { if let UseSpans::ClosureUse { args_span, .. } = self { - err.span_label(args_span, message); + err.subdiagnostic(f(args_span)); } } @@ -595,8 +585,8 @@ impl UseSpans<'_> { err: &mut Diagnostic, action: crate::InitializationRequiringAction, ) { - use crate::session_diagnostics::CaptureVarPathUseCause::*; use crate::InitializationRequiringAction::*; + use CaptureVarPathUseCause::*; if let UseSpans::ClosureUse { generator_kind, path_span, .. } = self { match generator_kind { Some(_) => { @@ -619,34 +609,14 @@ impl UseSpans<'_> { } } - /// Add a span label to the use of the captured variable, if it exists. - pub(super) fn var_span_label( - self, - err: &mut Diagnostic, - message: impl Into<String>, - kind_desc: impl Into<String>, - ) { - if let UseSpans::ClosureUse { capture_kind_span, path_span, .. } = self { - if capture_kind_span == path_span { - err.span_label(capture_kind_span, message); - } else { - let capture_kind_label = - format!("capture is {} because of use here", kind_desc.into()); - let path_label = message; - err.span_label(capture_kind_span, capture_kind_label); - err.span_label(path_span, path_label); - } - } - } - /// Add a subdiagnostic to the use of the captured variable, if it exists. pub(super) fn var_subdiag( self, + handler: Option<&rustc_errors::Handler>, err: &mut Diagnostic, kind: Option<rustc_middle::mir::BorrowKind>, - f: impl Fn(Option<GeneratorKind>, Span) -> crate::session_diagnostics::CaptureVarCause, + f: impl FnOnce(Option<GeneratorKind>, Span) -> CaptureVarCause, ) { - use crate::session_diagnostics::CaptureVarKind::*; if let UseSpans::ClosureUse { generator_kind, capture_kind_span, path_span, .. } = self { if capture_kind_span != path_span { err.subdiagnostic(match kind { @@ -654,17 +624,21 @@ impl UseSpans<'_> { rustc_middle::mir::BorrowKind::Shared | rustc_middle::mir::BorrowKind::Shallow | rustc_middle::mir::BorrowKind::Unique => { - Immute { kind_span: capture_kind_span } + CaptureVarKind::Immut { kind_span: capture_kind_span } } rustc_middle::mir::BorrowKind::Mut { .. } => { - Mut { kind_span: capture_kind_span } + CaptureVarKind::Mut { kind_span: capture_kind_span } } }, - None => Move { kind_span: capture_kind_span }, + None => CaptureVarKind::Move { kind_span: capture_kind_span }, }); }; - err.subdiagnostic(f(generator_kind, path_span)); + let diag = f(generator_kind, path_span); + match handler { + Some(hd) => err.eager_subdiagnostic(hd, diag), + None => err.subdiagnostic(diag), + }; } } @@ -684,20 +658,6 @@ impl UseSpans<'_> { } } - /// Describe the span associated with a use of a place. - pub(super) fn describe(&self) -> &str { - match *self { - UseSpans::ClosureUse { generator_kind, .. } => { - if generator_kind.is_some() { - " in generator" - } else { - " in closure" - } - } - _ => "", - } - } - pub(super) fn or_else<F>(self, if_other: F) -> Self where F: FnOnce() -> Self, @@ -788,6 +748,15 @@ impl<'tcx> BorrowedContentSource<'tcx> { } } +///helper struct for explain_captures() +struct CapturedMessageOpt { + is_partial_move: bool, + is_loop_message: bool, + is_move_msg: bool, + is_loop_move: bool, + maybe_reinitialized_locations_is_empty: bool, +} + impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// Finds the spans associated to a move or copy of move_place at location. pub(super) fn move_spans( @@ -874,7 +843,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { }) = &self.body[location.block].terminator { let Some((method_did, method_substs)) = - rustc_const_eval::util::find_self_call( + rustc_middle::util::find_self_call( self.infcx.tcx, &self.body, target_temp, @@ -1027,12 +996,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { move_span: Span, move_spans: UseSpans<'tcx>, moved_place: Place<'tcx>, - partially_str: &str, - loop_message: &str, - move_msg: &str, - is_loop_move: bool, - maybe_reinitialized_locations_is_empty: bool, + msg_opt: CapturedMessageOpt, ) { + let CapturedMessageOpt { + is_partial_move: is_partial, + is_loop_message, + is_move_msg, + is_loop_move, + maybe_reinitialized_locations_is_empty, + } = msg_opt; if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans { let place_name = self .describe_place(moved_place.as_ref()) @@ -1042,30 +1014,26 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { CallKind::FnCall { fn_trait_id, .. } if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() => { - err.span_label( + err.subdiagnostic(CaptureReasonLabel::Call { fn_call_span, - &format!( - "{place_name} {partially_str}moved due to this call{loop_message}", - ), - ); - err.span_note( - var_span, - "this value implements `FnOnce`, which causes it to be moved when called", - ); + place_name: &place_name, + is_partial, + is_loop_message, + }); + err.subdiagnostic(CaptureReasonNote::FnOnceMoveInCall { var_span }); } CallKind::Operator { self_arg, .. } => { let self_arg = self_arg.unwrap(); - err.span_label( + err.subdiagnostic(CaptureReasonLabel::OperatorUse { fn_call_span, - &format!( - "{place_name} {partially_str}moved due to usage in operator{loop_message}", - ), - ); + place_name: &place_name, + is_partial, + is_loop_message, + }); if self.fn_self_span_reported.insert(fn_span) { - err.span_note( - self_arg.span, - "calling this operator moves the left-hand side", - ); + err.subdiagnostic(CaptureReasonNote::LhsMoveByOperator { + span: self_arg.span, + }); } } CallKind::Normal { self_arg, desugaring, method_did, method_substs } => { @@ -1086,23 +1054,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { _ => false, }; if suggest { - err.span_suggestion_verbose( - move_span.shrink_to_lo(), - &format!( - "consider iterating over a slice of the `{ty}`'s content to \ - avoid moving into the `for` loop", - ), - "&", - Applicability::MaybeIncorrect, - ); + err.subdiagnostic(CaptureReasonSuggest::IterateSlice { + ty, + span: move_span.shrink_to_lo(), + }); } - err.span_label( + err.subdiagnostic(CaptureReasonLabel::ImplicitCall { fn_call_span, - &format!( - "{place_name} {partially_str}moved due to this implicit call to `.into_iter()`{loop_message}", - ), - ); + place_name: &place_name, + is_partial, + is_loop_message, + }); // If the moved place was a `&mut` ref, then we can // suggest to reborrow it where it was moved, so it // will still be valid by the time we get to the usage. @@ -1125,13 +1088,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } } else { - err.span_label( + err.subdiagnostic(CaptureReasonLabel::MethodCall { fn_call_span, - &format!( - "{place_name} {partially_str}moved due to this method call{loop_message}", - ), - ); - + place_name: &place_name, + is_partial, + is_loop_message, + }); let infcx = tcx.infer_ctxt().build(); // Erase and shadow everything that could be passed to the new infcx. let ty = tcx.erase_regions(moved_place.ty(self.body, tcx).ty); @@ -1147,12 +1109,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ) && infcx.can_eq(self.param_env, ty, self_ty) { - err.span_suggestion_verbose( - fn_call_span.shrink_to_lo(), - "consider reborrowing the `Pin` instead of moving it", - "as_mut().".to_string(), - Applicability::MaybeIncorrect, - ); + err.eager_subdiagnostic( + &self.infcx.tcx.sess.parse_sess.span_diagnostic, + CaptureReasonSuggest::FreshReborrow { + span: fn_call_span.shrink_to_lo(), + }); } if let Some(clone_trait) = tcx.lang_items().clone_trait() && let trait_ref = tcx.mk_trait_ref(clone_trait, [ty]) @@ -1177,10 +1138,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // error messages. if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) { let func = tcx.def_path_str(method_did); - err.span_note( - self_arg.span, - &format!("`{func}` takes ownership of the receiver `self`, which moves {place_name}") - ); + err.subdiagnostic(CaptureReasonNote::FuncTakeSelf { + func, + place_name, + span: self_arg.span, + }); } let parent_did = tcx.parent(method_did); let parent_self_ty = @@ -1194,30 +1156,28 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result)) }); if is_option_or_result && maybe_reinitialized_locations_is_empty { - err.span_label( - var_span, - "help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents", - ); + err.subdiagnostic(CaptureReasonLabel::BorrowContent { var_span }); } } // Other desugarings takes &self, which cannot cause a move _ => {} } } else { - if move_span != span || !loop_message.is_empty() { - err.span_label( + if move_span != span || is_loop_message { + err.subdiagnostic(CaptureReasonLabel::MovedHere { move_span, - format!("value {partially_str}moved{move_msg} here{loop_message}"), - ); + is_partial, + is_move_msg, + is_loop_message, + }); } // If the move error occurs due to a loop, don't show // another message for the same span - if loop_message.is_empty() { - move_spans.var_span_label( - err, - format!("variable {partially_str}moved due to use{}", move_spans.describe()), - "moved", - ); + if !is_loop_message { + move_spans.var_subdiag(None, err, None, |kind, var_span| match kind { + Some(_) => CaptureVarCause::PartialMoveUseInGenerator { var_span, is_partial }, + None => CaptureVarCause::PartialMoveUseInClosure { var_span, is_partial }, + }) } } } diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 3662bec0c76..67af96a71e3 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -6,6 +6,7 @@ use rustc_mir_dataflow::move_paths::{ }; use rustc_span::{BytePos, Span}; +use crate::diagnostics::CapturedMessageOpt; use crate::diagnostics::{DescribePlaceOpt, UseSpans}; use crate::prefixes::PrefixSet; use crate::MirBorrowckCtxt; @@ -397,10 +398,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } }; + let msg_opt = CapturedMessageOpt { + is_partial_move: false, + is_loop_message: false, + is_move_msg: false, + is_loop_move: false, + maybe_reinitialized_locations_is_empty: true, + }; if let Some(use_spans) = use_spans { - self.explain_captures( - &mut err, span, span, use_spans, move_place, "", "", "", false, true, - ); + self.explain_captures(&mut err, span, span, use_spans, move_place, msg_opt); } err } @@ -416,13 +422,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { None => "value".to_string(), }; - self.note_type_does_not_implement_copy( - err, - &place_desc, - place_ty, - Some(span), - "", - ); + err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label { + is_partial_move: false, + ty: place_ty, + place: &place_desc, + span, + }); } else { binds_to.sort(); binds_to.dedup(); @@ -444,9 +449,19 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { Some(desc) => format!("`{desc}`"), None => "value".to_string(), }; - self.note_type_does_not_implement_copy(err, &place_desc, place_ty, Some(span), ""); + err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label { + is_partial_move: false, + ty: place_ty, + place: &place_desc, + span, + }); - use_spans.args_span_label(err, format!("{place_desc} is moved here")); + use_spans.args_subdiag(err, |args_span| { + crate::session_diagnostics::CaptureArgLabel::MoveOutPlace { + place: place_desc, + args_span, + } + }); } } } @@ -534,13 +549,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } if binds_to.len() == 1 { - self.note_type_does_not_implement_copy( - err, - &format!("`{}`", self.local_names[*local].unwrap()), - bind_to.ty, - Some(binding_span), - "", - ); + let place_desc = &format!("`{}`", self.local_names[*local].unwrap()); + err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label { + is_partial_move: false, + ty: bind_to.ty, + place: &place_desc, + span: binding_span, + }); } } diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 9d904009650..e3d81194ac8 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -15,8 +15,8 @@ use rustc_span::{sym, BytePos, Span}; use rustc_target::abi::FieldIdx; use crate::diagnostics::BorrowedContentSource; +use crate::util::FindAssignments; use crate::MirBorrowckCtxt; -use rustc_const_eval::util::collect_writes::FindAssignments; #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub(crate) enum AccessKind { @@ -231,14 +231,18 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } if suggest { - borrow_spans.var_span_label( - &mut err, - format!( - "mutable borrow occurs due to use of {} in closure", - self.describe_any_place(access_place.as_ref()), - ), - "mutable", - ); + borrow_spans.var_subdiag( + None, + &mut err, + Some(mir::BorrowKind::Mut { allow_two_phase_borrow: false }), + |_kind, var_span| { + let place = self.describe_any_place(access_place.as_ref()); + crate::session_diagnostics::CaptureVarCause::MutableBorrowUsePlaceClosure { + place, + var_span, + } + }, + ); } borrow_span } @@ -1143,7 +1147,7 @@ pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option< // suggest removing the `&mut`. // // Deliberately fall into this case for all implicit self types, - // so that we don't fall in to the next case with them. + // so that we don't fall into the next case with them. kind == hir::ImplicitSelfKind::MutRef } _ if Some(kw::SelfLower) == local_name => { @@ -1231,7 +1235,7 @@ fn suggest_ampmut<'tcx>( } } - let (suggestability, highlight_span) = match opt_ty_info { + let (suggestibility, highlight_span) = match opt_ty_info { // if this is a variable binding with an explicit type, // try to highlight that for the suggestion. Some(ty_span) => (true, ty_span), @@ -1252,7 +1256,7 @@ fn suggest_ampmut<'tcx>( let ty_mut = local_decl.ty.builtin_deref(true).unwrap(); assert_eq!(ty_mut.mutbl, hir::Mutability::Not); ( - suggestability, + suggestibility, highlight_span, if local_decl.ty.is_ref() { format!("&mut {}", ty_mut.ty) diff --git a/compiler/rustc_borrowck/src/diagnostics/var_name.rs b/compiler/rustc_borrowck/src/diagnostics/var_name.rs index 376415e3d32..aa7cf3578ea 100644 --- a/compiler/rustc_borrowck/src/diagnostics/var_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/var_name.rs @@ -3,7 +3,7 @@ use crate::region_infer::RegionInferenceContext; use crate::Upvar; -use rustc_index::vec::{Idx, IndexSlice}; +use rustc_index::vec::IndexSlice; use rustc_middle::mir::{Body, Local}; use rustc_middle::ty::{RegionVid, TyCtxt}; use rustc_span::source_map::Span; @@ -117,7 +117,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { argument_index: usize, ) -> (Option<Symbol>, Span) { let implicit_inputs = self.universal_regions().defining_ty.implicit_inputs(); - let argument_local = Local::new(implicit_inputs + argument_index + 1); + let argument_local = Local::from_usize(implicit_inputs + argument_index + 1); debug!("get_argument_name_and_span_for_region: argument_local={argument_local:?}"); let argument_name = local_names[argument_local]; diff --git a/compiler/rustc_borrowck/src/facts.rs b/compiler/rustc_borrowck/src/facts.rs index 02ffb51fbb7..87fad9a355d 100644 --- a/compiler/rustc_borrowck/src/facts.rs +++ b/compiler/rustc_borrowck/src/facts.rs @@ -4,7 +4,6 @@ use crate::location::{LocationIndex, LocationTable}; use crate::BorrowIndex; use polonius_engine::AllFacts as PoloniusFacts; use polonius_engine::Atom; -use rustc_index::vec::Idx; use rustc_middle::mir::Local; use rustc_middle::ty::{RegionVid, TyCtxt}; use rustc_mir_dataflow::move_paths::MovePathIndex; @@ -93,13 +92,13 @@ impl AllFactsExt for AllFacts { impl Atom for BorrowIndex { fn index(self) -> usize { - Idx::index(self) + self.as_usize() } } impl Atom for LocationIndex { fn index(self) -> usize { - Idx::index(self) + self.as_usize() } } diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs index 498d254da65..06986f848bf 100644 --- a/compiler/rustc_borrowck/src/invalidation.rs +++ b/compiler/rustc_borrowck/src/invalidation.rs @@ -79,7 +79,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { } // Only relevant for mir typeck StatementKind::AscribeUserType(..) - // Only relevant for unsafeck + // Only relevant for liveness and unsafeck | StatementKind::PlaceMention(..) // Doesn't have any language semantics | StatementKind::Coverage(..) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index a4b285a34fa..5bf3e7632ac 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -20,6 +20,7 @@ extern crate tracing; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::graph::dominators::Dominators; use rustc_errors::{Diagnostic, DiagnosticBuilder, DiagnosticMessage, SubdiagnosticMessage}; +use rustc_fluent_macro::fluent_messages; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_index::bit_set::ChunkedBitSet; @@ -27,7 +28,6 @@ use rustc_index::vec::{IndexSlice, IndexVec}; use rustc_infer::infer::{ DefiningAnchor, InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt, }; -use rustc_macros::fluent_messages; use rustc_middle::mir::{ traversal, Body, ClearCrossCrate, Local, Location, Mutability, NonDivergingIntrinsic, Operand, Place, PlaceElem, PlaceRef, VarDebugInfoContents, @@ -88,6 +88,7 @@ mod session_diagnostics; mod type_check; mod universal_regions; mod used_muts; +mod util; /// A public API provided for the Rust compiler consumers. pub mod consumers; @@ -118,24 +119,12 @@ impl<'tcx> TyCtxtConsts<'tcx> { } pub fn provide(providers: &mut Providers) { - *providers = Providers { - mir_borrowck: |tcx, did| { - if let Some(def) = ty::WithOptConstParam::try_lookup(did, tcx) { - tcx.mir_borrowck_const_arg(def) - } else { - mir_borrowck(tcx, ty::WithOptConstParam::unknown(did)) - } - }, - mir_borrowck_const_arg: |tcx, (did, param_did)| { - mir_borrowck(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) }) - }, - ..*providers - }; + *providers = Providers { mir_borrowck, ..*providers }; } -fn mir_borrowck(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> &BorrowCheckResult<'_> { +fn mir_borrowck(tcx: TyCtxt<'_>, def: LocalDefId) -> &BorrowCheckResult<'_> { let (input_body, promoted) = tcx.mir_promoted(def); - debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id())); + debug!("run query mir_borrowck: {}", tcx.def_path_str(def.to_def_id())); if input_body.borrow().should_skip() { debug!("Skipping borrowck because of injected body"); @@ -149,7 +138,7 @@ fn mir_borrowck(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> &Bor return tcx.arena.alloc(result); } - let hir_owner = tcx.hir().local_def_id_to_hir_id(def.did).owner; + let hir_owner = tcx.hir().local_def_id_to_hir_id(def).owner; let infcx = tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(hir_owner.def_id)).build(); @@ -166,19 +155,19 @@ fn mir_borrowck(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> &Bor /// If `return_body_with_facts` is true, then return the body with non-erased /// region ids on which the borrow checking was performed together with Polonius /// facts. -#[instrument(skip(infcx, input_body, input_promoted), fields(id=?input_body.source.with_opt_param().as_local().unwrap()), level = "debug")] +#[instrument(skip(infcx, input_body, input_promoted), fields(id=?input_body.source.def_id()), level = "debug")] fn do_mir_borrowck<'tcx>( infcx: &InferCtxt<'tcx>, input_body: &Body<'tcx>, input_promoted: &IndexSlice<Promoted, Body<'tcx>>, return_body_with_facts: bool, ) -> (BorrowCheckResult<'tcx>, Option<Box<BodyWithBorrowckFacts<'tcx>>>) { - let def = input_body.source.with_opt_param().as_local().unwrap(); + let def = input_body.source.def_id().expect_local(); debug!(?def); let tcx = infcx.tcx; let infcx = BorrowckInferCtxt::new(infcx); - let param_env = tcx.param_env(def.did); + let param_env = tcx.param_env(def); let mut local_names = IndexVec::from_elem(None, &input_body.local_decls); for var_debug_info in &input_body.var_debug_info { @@ -206,7 +195,7 @@ fn do_mir_borrowck<'tcx>( errors.set_tainted_by_errors(e); } let upvars: Vec<_> = tcx - .closure_captures(def.did) + .closure_captures(def) .iter() .map(|&captured_place| { let capture = captured_place.info.capture_kind; @@ -248,7 +237,7 @@ fn do_mir_borrowck<'tcx>( .iterate_to_fixpoint() .into_results_cursor(&body); - let locals_are_invalidated_at_exit = tcx.hir().body_owner_kind(def.did).is_fn_or_closure(); + let locals_are_invalidated_at_exit = tcx.hir().body_owner_kind(def).is_fn_or_closure(); let borrow_set = Rc::new(BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &mdpe.move_data)); @@ -528,7 +517,7 @@ impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> { where F: Fn() -> RegionCtxt, { - let next_region = self.infcx.next_nll_region_var(origin.clone()); + let next_region = self.infcx.next_nll_region_var(origin); let vid = next_region.as_var(); if cfg!(debug_assertions) && !self.inside_canonicalization_ctxt() { @@ -676,7 +665,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx } // Only relevant for mir typeck StatementKind::AscribeUserType(..) - // Only relevant for unsafeck + // Only relevant for liveness and unsafeck | StatementKind::PlaceMention(..) // Doesn't have any language semantics | StatementKind::Coverage(..) diff --git a/compiler/rustc_borrowck/src/location.rs b/compiler/rustc_borrowck/src/location.rs index 288b7d85be2..08fa912f368 100644 --- a/compiler/rustc_borrowck/src/location.rs +++ b/compiler/rustc_borrowck/src/location.rs @@ -1,6 +1,6 @@ #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] -use rustc_index::vec::{Idx, IndexVec}; +use rustc_index::vec::IndexVec; use rustc_middle::mir::{BasicBlock, Body, Location}; /// Maps between a MIR Location, which identifies a particular @@ -50,19 +50,19 @@ impl LocationTable { } pub fn all_points(&self) -> impl Iterator<Item = LocationIndex> { - (0..self.num_points).map(LocationIndex::new) + (0..self.num_points).map(LocationIndex::from_usize) } pub fn start_index(&self, location: Location) -> LocationIndex { let Location { block, statement_index } = location; let start_index = self.statements_before_block[block]; - LocationIndex::new(start_index + statement_index * 2) + LocationIndex::from_usize(start_index + statement_index * 2) } pub fn mid_index(&self, location: Location) -> LocationIndex { let Location { block, statement_index } = location; let start_index = self.statements_before_block[block]; - LocationIndex::new(start_index + statement_index * 2 + 1) + LocationIndex::from_usize(start_index + statement_index * 2 + 1) } pub fn to_location(&self, index: LocationIndex) -> RichLocation { diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 59a3ab3189d..78bdf00a69c 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -7,8 +7,8 @@ use rustc_hir::def_id::LocalDefId; use rustc_index::vec::IndexSlice; use rustc_middle::mir::{create_dump_file, dump_enabled, dump_mir, PassWhere}; use rustc_middle::mir::{ - BasicBlock, Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location, - Promoted, + Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location, Promoted, + START_BLOCK, }; use rustc_middle::ty::{self, OpaqueHiddenType, TyCtxt}; use rustc_span::symbol::sym; @@ -61,7 +61,7 @@ pub(crate) fn replace_regions_in_mir<'tcx>( body: &mut Body<'tcx>, promoted: &mut IndexSlice<Promoted, Body<'tcx>>, ) -> UniversalRegions<'tcx> { - let def = body.source.with_opt_param().as_local().unwrap(); + let def = body.source.def_id().expect_local(); debug!(?def); @@ -94,8 +94,8 @@ fn populate_polonius_move_facts( } } - let fn_entry_start = location_table - .start_index(Location { block: BasicBlock::from_u32(0u32), statement_index: 0 }); + let fn_entry_start = + location_table.start_index(Location { block: START_BLOCK, statement_index: 0 }); // initialized_at for init in move_data.inits.iter() { diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs index a3678929099..bb95101845f 100644 --- a/compiler/rustc_borrowck/src/session_diagnostics.rs +++ b/compiler/rustc_borrowck/src/session_diagnostics.rs @@ -184,7 +184,7 @@ pub(crate) enum CaptureVarPathUseCause { #[derive(Subdiagnostic)] pub(crate) enum CaptureVarKind { #[label(borrowck_capture_immute)] - Immute { + Immut { #[primary_span] kind_span: Span, }, @@ -204,16 +204,80 @@ pub(crate) enum CaptureVarKind { pub(crate) enum CaptureVarCause { #[label(borrowck_var_borrow_by_use_place_in_generator)] BorrowUsePlaceGenerator { + is_single_var: bool, place: String, #[primary_span] var_span: Span, }, #[label(borrowck_var_borrow_by_use_place_in_closure)] BorrowUsePlaceClosure { + is_single_var: bool, place: String, #[primary_span] var_span: Span, }, + #[label(borrowck_var_borrow_by_use_in_generator)] + BorrowUseInGenerator { + #[primary_span] + var_span: Span, + }, + #[label(borrowck_var_borrow_by_use_in_closure)] + BorrowUseInClosure { + #[primary_span] + var_span: Span, + }, + #[label(borrowck_var_move_by_use_in_generator)] + MoveUseInGenerator { + #[primary_span] + var_span: Span, + }, + #[label(borrowck_var_move_by_use_in_closure)] + MoveUseInClosure { + #[primary_span] + var_span: Span, + }, + #[label(borrowck_var_first_borrow_by_use_place_in_generator)] + FirstBorrowUsePlaceGenerator { + place: String, + #[primary_span] + var_span: Span, + }, + #[label(borrowck_var_first_borrow_by_use_place_in_closure)] + FirstBorrowUsePlaceClosure { + place: String, + #[primary_span] + var_span: Span, + }, + #[label(borrowck_var_second_borrow_by_use_place_in_generator)] + SecondBorrowUsePlaceGenerator { + place: String, + #[primary_span] + var_span: Span, + }, + #[label(borrowck_var_second_borrow_by_use_place_in_closure)] + SecondBorrowUsePlaceClosure { + place: String, + #[primary_span] + var_span: Span, + }, + #[label(borrowck_var_mutable_borrow_by_use_place_in_closure)] + MutableBorrowUsePlaceClosure { + place: String, + #[primary_span] + var_span: Span, + }, + #[label(borrowck_partial_var_move_by_use_in_generator)] + PartialMoveUseInGenerator { + #[primary_span] + var_span: Span, + is_partial: bool, + }, + #[label(borrowck_partial_var_move_by_use_in_closure)] + PartialMoveUseInClosure { + #[primary_span] + var_span: Span, + is_partial: bool, + }, } #[derive(Diagnostic)] @@ -239,3 +303,144 @@ pub(crate) struct NonGenericOpaqueTypeParam<'a, 'tcx> { #[label] pub param_span: Span, } + +#[derive(Subdiagnostic)] +pub(crate) enum CaptureReasonLabel<'a> { + #[label(borrowck_moved_due_to_call)] + Call { + #[primary_span] + fn_call_span: Span, + place_name: &'a str, + is_partial: bool, + is_loop_message: bool, + }, + #[label(borrowck_moved_due_to_usage_in_operator)] + OperatorUse { + #[primary_span] + fn_call_span: Span, + place_name: &'a str, + is_partial: bool, + is_loop_message: bool, + }, + #[label(borrowck_moved_due_to_implicit_into_iter_call)] + ImplicitCall { + #[primary_span] + fn_call_span: Span, + place_name: &'a str, + is_partial: bool, + is_loop_message: bool, + }, + #[label(borrowck_moved_due_to_method_call)] + MethodCall { + #[primary_span] + fn_call_span: Span, + place_name: &'a str, + is_partial: bool, + is_loop_message: bool, + }, + #[label(borrowck_value_moved_here)] + MovedHere { + #[primary_span] + move_span: Span, + is_partial: bool, + is_move_msg: bool, + is_loop_message: bool, + }, + #[label(borrowck_consider_borrow_type_contents)] + BorrowContent { + #[primary_span] + var_span: Span, + }, +} + +#[derive(Subdiagnostic)] +pub(crate) enum CaptureReasonNote { + #[note(borrowck_moved_a_fn_once_in_call)] + FnOnceMoveInCall { + #[primary_span] + var_span: Span, + }, + #[note(borrowck_calling_operator_moves_lhs)] + LhsMoveByOperator { + #[primary_span] + span: Span, + }, + #[note(borrowck_func_take_self_moved_place)] + FuncTakeSelf { + func: String, + place_name: String, + #[primary_span] + span: Span, + }, +} + +#[derive(Subdiagnostic)] +pub(crate) enum CaptureReasonSuggest<'tcx> { + #[suggestion( + borrowck_suggest_iterate_over_slice, + applicability = "maybe-incorrect", + code = "&", + style = "verbose" + )] + IterateSlice { + ty: Ty<'tcx>, + #[primary_span] + span: Span, + }, + #[suggestion( + borrowck_suggest_create_freash_reborrow, + applicability = "maybe-incorrect", + code = "as_mut().", + style = "verbose" + )] + FreshReborrow { + #[primary_span] + span: Span, + }, +} + +#[derive(Subdiagnostic)] +pub(crate) enum CaptureArgLabel { + #[label(borrowck_value_capture_here)] + Capture { + is_within: bool, + #[primary_span] + args_span: Span, + }, + #[label(borrowck_move_out_place_here)] + MoveOutPlace { + place: String, + #[primary_span] + args_span: Span, + }, +} + +#[derive(Subdiagnostic)] +pub(crate) enum OnClosureNote<'a> { + #[note(borrowck_closure_invoked_twice)] + InvokedTwice { + place_name: &'a str, + #[primary_span] + span: Span, + }, + #[note(borrowck_closure_moved_twice)] + MovedTwice { + place_name: &'a str, + #[primary_span] + span: Span, + }, +} + +#[derive(Subdiagnostic)] +pub(crate) enum TypeNoCopy<'a, 'tcx> { + #[label(borrowck_ty_no_impl_copy)] + Label { + is_partial_move: bool, + ty: Ty<'tcx>, + place: &'a str, + #[primary_span] + span: Span, + }, + #[note(borrowck_ty_no_impl_copy)] + Note { is_partial_move: bool, ty: Ty<'tcx>, place: &'a str }, +} diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index 17e702eb8c5..9250b8d3eaf 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -7,7 +7,6 @@ //! `RETURN_PLACE` the MIR arguments) are always fully normalized (and //! contain revealed `impl Trait` values). -use rustc_index::vec::Idx; use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty}; @@ -83,7 +82,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } // In MIR, argument N is stored in local N+1. - let local = Local::new(argument_index + 1); + let local = Local::from_usize(argument_index + 1); let mir_input_ty = body.local_decls[local].ty; diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 375eca1b29d..7cb0cec82c7 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -394,7 +394,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { self.cx.ascribe_user_type( constant.literal.ty(), UserType::TypeOf( - uv.def.did, + uv.def, UserSubsts { substs: uv.substs, user_self_ty: None }, ), locations.span(&self.cx.body), @@ -1766,7 +1766,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { if let Some(uv) = maybe_uneval { if uv.promoted.is_none() { let tcx = self.tcx(); - let def_id = uv.def.def_id_for_type_of(); + let def_id = uv.def; if tcx.def_kind(def_id) == DefKind::InlineConst { let def_id = def_id.expect_local(); let predicates = @@ -2306,7 +2306,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Rvalue::AddressOf(..) | Rvalue::ThreadLocalRef(..) | Rvalue::Len(..) - | Rvalue::Discriminant(..) => {} + | Rvalue::Discriminant(..) + | Rvalue::NullaryOp(NullOp::OffsetOf(..), _) => {} } } diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 70fddb1057c..ef37c01cef8 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -19,7 +19,7 @@ use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; use rustc_hir::BodyOwnerKind; -use rustc_index::vec::{Idx, IndexVec}; +use rustc_index::vec::IndexVec; use rustc_infer::infer::NllRegionVariableOrigin; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{self, InlineConstSubsts, InlineConstSubstsParts, RegionVid, Ty, TyCtxt}; @@ -226,7 +226,7 @@ impl<'tcx> UniversalRegions<'tcx> { /// known between those regions. pub fn new( infcx: &BorrowckInferCtxt<'_, 'tcx>, - mir_def: ty::WithOptConstParam<LocalDefId>, + mir_def: LocalDefId, param_env: ty::ParamEnv<'tcx>, ) -> Self { UniversalRegionsBuilder { infcx, mir_def, param_env }.build() @@ -289,7 +289,7 @@ impl<'tcx> UniversalRegions<'tcx> { /// Returns an iterator over all the RegionVids corresponding to /// universally quantified free regions. pub fn universal_regions(&self) -> impl Iterator<Item = RegionVid> { - (FIRST_GLOBAL_INDEX..self.num_universals).map(RegionVid::new) + (FIRST_GLOBAL_INDEX..self.num_universals).map(RegionVid::from_usize) } /// Returns `true` if `r` is classified as an local region. @@ -388,7 +388,7 @@ impl<'tcx> UniversalRegions<'tcx> { struct UniversalRegionsBuilder<'cx, 'tcx> { infcx: &'cx BorrowckInferCtxt<'cx, 'tcx>, - mir_def: ty::WithOptConstParam<LocalDefId>, + mir_def: LocalDefId, param_env: ty::ParamEnv<'tcx>, } @@ -417,12 +417,12 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let mut indices = self.compute_indices(fr_static, defining_ty); debug!("build: indices={:?}", indices); - let typeck_root_def_id = self.infcx.tcx.typeck_root_def_id(self.mir_def.did.to_def_id()); + let typeck_root_def_id = self.infcx.tcx.typeck_root_def_id(self.mir_def.to_def_id()); // If this is a 'root' body (not a closure/generator/inline const), then // there are no extern regions, so the local regions start at the same // position as the (empty) sub-list of extern regions - let first_local_index = if self.mir_def.did.to_def_id() == typeck_root_def_id { + let first_local_index = if self.mir_def.to_def_id() == typeck_root_def_id { first_extern_index } else { // If this is a closure, generator, or inline-const, then the late-bound regions from the enclosing @@ -433,7 +433,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { // } for_each_late_bound_region_in_recursive_scope( self.infcx.tcx, - self.infcx.tcx.local_parent(self.mir_def.did), + self.infcx.tcx.local_parent(self.mir_def), |r| { debug!(?r); if !indices.indices.contains_key(&r) { @@ -462,13 +462,13 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let inputs_and_output = self.infcx.replace_bound_regions_with_nll_infer_vars( FR, - self.mir_def.did, + self.mir_def, bound_inputs_and_output, &mut indices, ); // Converse of above, if this is a function/closure then the late-bound regions declared on its // signature are local. - for_each_late_bound_region_in_item(self.infcx.tcx, self.mir_def.did, |r| { + for_each_late_bound_region_in_item(self.infcx.tcx, self.mir_def, |r| { debug!(?r); if !indices.indices.contains_key(&r) { let region_vid = { @@ -492,7 +492,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { if self.infcx.tcx.fn_sig(def_id).skip_binder().c_variadic() { let va_list_did = self.infcx.tcx.require_lang_item( LangItem::VaList, - Some(self.infcx.tcx.def_span(self.mir_def.did)), + Some(self.infcx.tcx.def_span(self.mir_def)), ); let reg_vid = self @@ -544,11 +544,11 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { /// see `DefiningTy` for details. fn defining_ty(&self) -> DefiningTy<'tcx> { let tcx = self.infcx.tcx; - let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.did.to_def_id()); + let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.to_def_id()); - match tcx.hir().body_owner_kind(self.mir_def.did) { + match tcx.hir().body_owner_kind(self.mir_def) { BodyOwnerKind::Closure | BodyOwnerKind::Fn => { - let defining_ty = tcx.type_of(self.mir_def.def_id_for_type_of()).subst_identity(); + let defining_ty = tcx.type_of(self.mir_def).subst_identity(); debug!("defining_ty (pre-replacement): {:?}", defining_ty); @@ -562,9 +562,9 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { } ty::FnDef(def_id, substs) => DefiningTy::FnDef(def_id, substs), _ => span_bug!( - tcx.def_span(self.mir_def.did), + tcx.def_span(self.mir_def), "expected defining type for `{:?}`: `{:?}`", - self.mir_def.did, + self.mir_def, defining_ty ), } @@ -572,10 +572,10 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { BodyOwnerKind::Const | BodyOwnerKind::Static(..) => { let identity_substs = InternalSubsts::identity_for_item(tcx, typeck_root_def_id); - if self.mir_def.did.to_def_id() == typeck_root_def_id { + if self.mir_def.to_def_id() == typeck_root_def_id { let substs = self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs); - DefiningTy::Const(self.mir_def.did.to_def_id(), substs) + DefiningTy::Const(self.mir_def.to_def_id(), substs) } else { // FIXME this line creates a dependency between borrowck and typeck. // @@ -587,15 +587,15 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { // below), so that `type_of(inline_const_def_id).substs(substs)` uses the // proper type with NLL infer vars. let ty = tcx - .typeck(self.mir_def.did) - .node_type(tcx.local_def_id_to_hir_id(self.mir_def.did)); + .typeck(self.mir_def) + .node_type(tcx.local_def_id_to_hir_id(self.mir_def)); let substs = InlineConstSubsts::new( tcx, InlineConstSubstsParts { parent_substs: identity_substs, ty }, ) .substs; let substs = self.infcx.replace_free_regions_with_nll_infer_vars(FR, substs); - DefiningTy::InlineConst(self.mir_def.did.to_def_id(), substs) + DefiningTy::InlineConst(self.mir_def.to_def_id(), substs) } } } @@ -611,7 +611,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { defining_ty: DefiningTy<'tcx>, ) -> UniversalRegionIndices<'tcx> { let tcx = self.infcx.tcx; - let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.did.to_def_id()); + let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.to_def_id()); let identity_substs = InternalSubsts::identity_for_item(tcx, typeck_root_def_id); let fr_substs = match defining_ty { DefiningTy::Closure(_, substs) @@ -647,7 +647,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let tcx = self.infcx.tcx; match defining_ty { DefiningTy::Closure(def_id, substs) => { - assert_eq!(self.mir_def.did.to_def_id(), def_id); + assert_eq!(self.mir_def.to_def_id(), def_id); let closure_sig = substs.as_closure().sig(); let inputs_and_output = closure_sig.inputs_and_output(); let bound_vars = tcx.mk_bound_variable_kinds_from_iter( @@ -682,7 +682,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { } DefiningTy::Generator(def_id, substs, movability) => { - assert_eq!(self.mir_def.did.to_def_id(), def_id); + assert_eq!(self.mir_def.to_def_id(), def_id); let resume_ty = substs.as_generator().resume_ty(); let output = substs.as_generator().return_ty(); let generator_ty = tcx.mk_generator(def_id, substs, movability); @@ -700,14 +700,14 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { DefiningTy::Const(def_id, _) => { // For a constant body, there are no inputs, and one // "output" (the type of the constant). - assert_eq!(self.mir_def.did.to_def_id(), def_id); - let ty = tcx.type_of(self.mir_def.def_id_for_type_of()).subst_identity(); + assert_eq!(self.mir_def.to_def_id(), def_id); + let ty = tcx.type_of(self.mir_def).subst_identity(); let ty = indices.fold_to_region_vids(tcx, ty); ty::Binder::dummy(tcx.mk_type_list(&[ty])) } DefiningTy::InlineConst(def_id, substs) => { - assert_eq!(self.mir_def.did.to_def_id(), def_id); + assert_eq!(self.mir_def.to_def_id(), def_id); let ty = substs.as_inline_const().ty(); ty::Binder::dummy(tcx.mk_type_list(&[ty])) } diff --git a/compiler/rustc_const_eval/src/util/collect_writes.rs b/compiler/rustc_borrowck/src/util/collect_writes.rs index 8d92bb35938..8d92bb35938 100644 --- a/compiler/rustc_const_eval/src/util/collect_writes.rs +++ b/compiler/rustc_borrowck/src/util/collect_writes.rs diff --git a/compiler/rustc_borrowck/src/util/mod.rs b/compiler/rustc_borrowck/src/util/mod.rs new file mode 100644 index 00000000000..7377d4de727 --- /dev/null +++ b/compiler/rustc_borrowck/src/util/mod.rs @@ -0,0 +1,3 @@ +mod collect_writes; + +pub use collect_writes::FindAssignments; diff --git a/compiler/rustc_builtin_macros/Cargo.toml b/compiler/rustc_builtin_macros/Cargo.toml index 336e14ef966..5f6441660e3 100644 --- a/compiler/rustc_builtin_macros/Cargo.toml +++ b/compiler/rustc_builtin_macros/Cargo.toml @@ -17,6 +17,7 @@ rustc_feature = { path = "../rustc_feature" } rustc_lexer = { path = "../rustc_lexer" } rustc_lint_defs = { path = "../rustc_lint_defs" } rustc_macros = { path = "../rustc_macros" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_parse_format = { path = "../rustc_parse_format" } rustc_parse = { path = "../rustc_parse" } rustc_session = { path = "../rustc_session" } diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 43187c32709..ee2aca6fc93 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -147,3 +147,6 @@ builtin_macros_format_pos_mismatch = {$n} positional {$n -> [one] argument *[more] arguments } in format string, but {$desc} +builtin_macros_offset_of_expected_field = expected field + +builtin_macros_offset_of_expected_two_args = expected 2 arguments diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index c9e3cd486f8..090e00616fb 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -301,6 +301,7 @@ impl<'cx, 'a> Context<'cx, 'a> { | ExprKind::If(_, _, _) | ExprKind::IncludedBytes(..) | ExprKind::InlineAsm(_) + | ExprKind::OffsetOf(_, _) | ExprKind::Let(_, _, _) | ExprKind::Lit(_) | ExprKind::Loop(_, _, _) diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index f0fc61d7c4f..f17df5b0a83 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -141,13 +141,7 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult< args: args .named_args() .iter() - .filter_map(|a| { - if let Some(ident) = a.kind.ident() { - Some((a, ident)) - } else { - None - } - }) + .filter_map(|a| a.kind.ident().map(|ident| (a, ident))) .map(|(arg, n)| n.span.to(arg.expr.span)) .collect(), }); diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index e326c37635a..b6170161d6b 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -24,7 +24,7 @@ use crate::deriving::*; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtensionKind}; use rustc_expand::proc_macro::BangProcMacro; -use rustc_macros::fluent_messages; +use rustc_fluent_macro::fluent_messages; use rustc_span::symbol::sym; mod assert; @@ -44,6 +44,7 @@ mod format; mod format_foreign; mod global_allocator; mod log_syntax; +mod offset_of; mod source_util; mod test; mod trace_macros; @@ -91,6 +92,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { line: source_util::expand_line, log_syntax: log_syntax::expand_log_syntax, module_path: source_util::expand_mod, + offset_of: offset_of::expand_offset_of, option_env: env::expand_option_env, core_panic: edition_panic::expand_panic, std_panic: edition_panic::expand_panic, diff --git a/compiler/rustc_builtin_macros/src/offset_of.rs b/compiler/rustc_builtin_macros/src/offset_of.rs new file mode 100644 index 00000000000..0ef3e000e41 --- /dev/null +++ b/compiler/rustc_builtin_macros/src/offset_of.rs @@ -0,0 +1,99 @@ +use rustc_ast as ast; +use rustc_ast::ptr::P; +use rustc_ast::token; +use rustc_ast::tokenstream::TokenStream; +use rustc_errors::PResult; +use rustc_expand::base::{self, *}; +use rustc_macros::Diagnostic; +use rustc_parse::parser::Parser; +use rustc_span::{symbol::Ident, Span}; + +#[derive(Diagnostic)] +#[diag(builtin_macros_offset_of_expected_field)] +struct ExpectedField { + #[primary_span] + span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_offset_of_expected_two_args)] +struct ExpectedTwoArgs { + #[primary_span] + span: Span, +} + +fn parse_field<'a>(cx: &ExtCtxt<'a>, p: &mut Parser<'a>) -> PResult<'a, Ident> { + let token = p.token.uninterpolate(); + let field = match token.kind { + token::Ident(name, _) => Ident::new(name, token.span), + token::Literal(token::Lit { kind: token::Integer, symbol, suffix: None }) => { + Ident::new(symbol, token.span) + } + _ => return Err(cx.create_err(ExpectedField { span: p.token.span })), + }; + + p.bump(); + + Ok(field) +} + +fn parse_args<'a>( + cx: &mut ExtCtxt<'a>, + sp: Span, + tts: TokenStream, +) -> PResult<'a, (P<ast::Ty>, P<[Ident]>)> { + let mut p = cx.new_parser_from_tts(tts); + + let container = p.parse_ty()?; + + p.expect(&token::Comma)?; + + if p.eat(&token::Eof) { + return Err(cx.create_err(ExpectedTwoArgs { span: sp })); + } + + let mut fields = Vec::new(); + + loop { + let field = parse_field(cx, &mut p)?; + fields.push(field); + + if p.eat(&token::Dot) { + continue; + } + + p.eat(&token::Comma); + + if !p.eat(&token::Eof) { + return Err(cx.create_err(ExpectedTwoArgs { span: sp })); + } + + break; + } + + Ok((container, fields.into())) +} + +pub fn expand_offset_of<'cx>( + cx: &'cx mut ExtCtxt<'_>, + sp: Span, + tts: TokenStream, +) -> Box<dyn base::MacResult + 'cx> { + match parse_args(cx, sp, tts) { + Ok((container, fields)) => { + let expr = P(ast::Expr { + id: ast::DUMMY_NODE_ID, + kind: ast::ExprKind::OffsetOf(container, fields), + span: sp, + attrs: ast::AttrVec::new(), + tokens: None, + }); + + MacEager::expr(expr) + } + Err(mut err) => { + err.emit(); + DummyResult::any(sp) + } + } +} diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index f5301f9f7f1..f481290583e 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -781,12 +781,15 @@ fn codegen_stmt<'tcx>( let operand = operand.load_scalar(fx); lval.write_cvalue(fx, CValue::by_val(operand, box_layout)); } - Rvalue::NullaryOp(null_op, ty) => { + Rvalue::NullaryOp(ref null_op, ty) => { assert!(lval.layout().ty.is_sized(fx.tcx, ParamEnv::reveal_all())); let layout = fx.layout_of(fx.monomorphize(ty)); let val = match null_op { NullOp::SizeOf => layout.size.bytes(), NullOp::AlignOf => layout.align.abi.bytes(), + NullOp::OffsetOf(fields) => { + layout.offset_of_subfield(fx, fields.iter().map(|f| f.index())).bytes() + } }; let val = CValue::const_val(fx, fx.layout_of(fx.tcx.types.usize), val.into()); lval.write_cvalue(fx, val); diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index e87f4e25891..aacf37bb5b7 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -91,7 +91,7 @@ pub(crate) fn eval_mir_constant<'tcx>( ), }, ConstantKind::Unevaluated(mir::UnevaluatedConst { def, .. }, _) - if fx.tcx.is_static(def.did) => + if fx.tcx.is_static(def) => { span_bug!(constant.span, "MIR constant refers to static"); } diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index be710fefe49..1a20dbcebd4 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -27,6 +27,7 @@ extern crate rustc_attr; extern crate rustc_codegen_ssa; extern crate rustc_data_structures; extern crate rustc_errors; +extern crate rustc_fluent_macro; extern crate rustc_hir; extern crate rustc_macros; extern crate rustc_metadata; @@ -76,7 +77,7 @@ use rustc_codegen_ssa::target_features::supported_target_features; use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{DiagnosticMessage, ErrorGuaranteed, Handler, SubdiagnosticMessage}; -use rustc_macros::fluent_messages; +use rustc_fluent_macro::fluent_messages; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::ty::TyCtxt; diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index a7ba2f8b695..bdea565a5a6 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -22,6 +22,7 @@ rustc_attr = { path = "../rustc_attr" } rustc_codegen_ssa = { path = "../rustc_codegen_ssa" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_fs_util = { path = "../rustc_fs_util" } rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index 4f8b5abd901..9127fba388b 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -10,7 +10,7 @@ use crate::value::Value; use rustc_ast::Mutability; use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::*; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher}; use rustc_hir::def_id::DefId; use rustc_middle::bug; use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar}; @@ -261,7 +261,7 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { let hash = self.tcx.with_stable_hashing_context(|mut hcx| { let mut hasher = StableHasher::new(); alloc.hash_stable(&mut hcx, &mut hasher); - hasher.finish::<u128>() + hasher.finish::<Hash128>() }); llvm::set_value_name(value, format!("alloc_{hash:032x}").as_bytes()); } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs index ff2b005d757..aaf5dbd9930 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs @@ -22,9 +22,9 @@ pub fn insert_reference_to_gdb_debug_scripts_section_global(bx: &mut Builder<'_, bx.const_bitcast(get_or_insert_gdb_debug_scripts_section_global(bx), bx.type_i8p()); // Load just the first byte as that's all that's necessary to force // LLVM to keep around the reference to the global. - let volative_load_instruction = bx.volatile_load(bx.type_i8(), gdb_debug_scripts_section); + let volatile_load_instruction = bx.volatile_load(bx.type_i8(), gdb_debug_scripts_section); unsafe { - llvm::LLVMSetAlignment(volative_load_instruction, 1); + llvm::LLVMSetAlignment(volatile_load_instruction, 1); } } } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 21a0a60b012..25fe3cb265d 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -29,7 +29,6 @@ use rustc_hir::def::CtorKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_middle::bug; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; -use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{ self, AdtKind, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt, Visibility, }; @@ -1182,12 +1181,12 @@ fn build_generic_type_param_di_nodes<'ll, 'tcx>( let names = get_parameter_names(cx, generics); let template_params: SmallVec<_> = iter::zip(substs, names) .filter_map(|(kind, name)| { - if let GenericArgKind::Type(ty) = kind.unpack() { + kind.as_type().map(|ty| { let actual_type = cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty); let actual_type_di_node = type_di_node(cx, actual_type); let name = name.as_str(); - Some(unsafe { + unsafe { llvm::LLVMRustDIBuilderCreateTemplateTypeParameter( DIB(cx), None, @@ -1195,10 +1194,8 @@ fn build_generic_type_param_di_nodes<'ll, 'tcx>( name.len(), actual_type_di_node, ) - }) - } else { - None - } + } + }) }) .collect(); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs index 69443b9b828..38ad42370d3 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs @@ -62,7 +62,7 @@ const SINGLE_VARIANT_VIRTUAL_DISR: u64 = 0; /// In CPP-like mode, we generate a union with a field for each variant and an /// explicit tag field. The field of each variant has a struct type -/// that encodes the discrimiant of the variant and it's data layout. +/// that encodes the discriminant of the variant and it's data layout. /// The union also has a nested enumeration type that is only used for encoding /// variant names in an efficient way. Its enumerator values do _not_ correspond /// to the enum's discriminant values. diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index d56c414cf65..dfc226db57b 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -21,12 +21,13 @@ use rustc_codegen_ssa::debuginfo::type_names; use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext, VariableKind}; use rustc_codegen_ssa::traits::*; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::stable_hasher::Hash128; use rustc_data_structures::sync::Lrc; use rustc_hir::def_id::{DefId, DefIdMap}; use rustc_index::vec::IndexVec; use rustc_middle::mir; use rustc_middle::ty::layout::LayoutOf; -use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; +use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TypeVisitableExt}; use rustc_session::config::{self, DebugInfo}; use rustc_session::Session; @@ -61,7 +62,7 @@ pub struct CodegenUnitDebugContext<'ll, 'tcx> { llcontext: &'ll llvm::Context, llmod: &'ll llvm::Module, builder: &'ll mut DIBuilder<'ll>, - created_files: RefCell<FxHashMap<Option<(u128, SourceFileHash)>, &'ll DIFile>>, + created_files: RefCell<FxHashMap<Option<(Hash128, SourceFileHash)>, &'ll DIFile>>, type_map: metadata::TypeMap<'ll, 'tcx>, namespace_map: RefCell<DefIdMap<&'ll DIScope>>, @@ -460,12 +461,12 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { let names = get_parameter_names(cx, generics); iter::zip(substs, names) .filter_map(|(kind, name)| { - if let GenericArgKind::Type(ty) = kind.unpack() { + kind.as_type().map(|ty| { let actual_type = cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty); let actual_type_metadata = type_di_node(cx, actual_type); let name = name.as_str(); - Some(unsafe { + unsafe { Some(llvm::LLVMRustDIBuilderCreateTemplateTypeParameter( DIB(cx), None, @@ -473,10 +474,8 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { name.len(), actual_type_metadata, )) - }) - } else { - None - } + } + }) }) .collect() } else { diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 33d66bcd237..00b2dc1287a 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -34,7 +34,7 @@ use rustc_codegen_ssa::ModuleCodegen; use rustc_codegen_ssa::{CodegenResults, CompiledModule}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{DiagnosticMessage, ErrorGuaranteed, FatalError, Handler, SubdiagnosticMessage}; -use rustc_macros::fluent_messages; +use rustc_fluent_macro::fluent_messages; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::ty::query::Providers; @@ -69,7 +69,7 @@ mod declare; mod errors; mod intrinsic; -// The following is a work around that replaces `pub mod llvm;` and that fixes issue 53912. +// The following is a workaround that replaces `pub mod llvm;` and that fixes issue 53912. #[path = "llvm/mod.rs"] mod llvm_; pub mod llvm { diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 09f3fe02165..c95148013eb 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -552,6 +552,7 @@ pub enum ArchiveKind { K_BSD, K_DARWIN, K_COFF, + K_AIXBIG, } // LLVMRustThinLTOData diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index f820e752371..4f5cc575da6 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -137,6 +137,7 @@ impl FromStr for ArchiveKind { "bsd" => Ok(ArchiveKind::K_BSD), "darwin" => Ok(ArchiveKind::K_DARWIN), "coff" => Ok(ArchiveKind::K_COFF), + "aix_big" => Ok(ArchiveKind::K_AIXBIG), _ => Err(()), } } diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index c55991e00d3..bd1ac6b7bad 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" test = false [dependencies] -ar_archive_writer = "0.1.1" +ar_archive_writer = "0.1.3" bitflags = "1.2.1" cc = "1.0.69" itertools = "0.10.1" @@ -29,6 +29,7 @@ rustc_span = { path = "../rustc_span" } rustc_middle = { path = "../rustc_middle" } rustc_type_ir = { path = "../rustc_type_ir" } rustc_attr = { path = "../rustc_attr" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_symbol_mangling = { path = "../rustc_symbol_mangling" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 243be0e1f70..85a96e3e89c 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -148,7 +148,7 @@ codegen_ssa_processing_dymutil_failed = processing debug info with `dsymutil` fa codegen_ssa_unable_to_run_dsymutil = unable to run `dsymutil`: {$error} -codegen_ssa_stripping_debu_info_failed = stripping debug info with `{$util}` failed: {$status} +codegen_ssa_stripping_debug_info_failed = stripping debug info with `{$util}` failed: {$status} .note = {$output} codegen_ssa_unable_to_run = unable to run `{$util}`: {$error} diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index 66ec8f5f57d..1c464b3eca4 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -233,6 +233,7 @@ impl<'a> ArArchiveBuilder<'a> { "bsd" => ArchiveKind::Bsd, "darwin" => ArchiveKind::Darwin, "coff" => ArchiveKind::Coff, + "aix_big" => ArchiveKind::AixBig, kind => { self.sess.emit_fatal(UnknownArchiveKind { kind }); } diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index dbf30e42ae4..bda0cf764e5 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -333,7 +333,7 @@ fn exported_symbols_provider_local( match *mono_item { MonoItem::Fn(Instance { def: InstanceDef::Item(def), substs }) => { if substs.non_erasable_generics().next().is_some() { - let symbol = ExportedSymbol::Generic(def.did, substs); + let symbol = ExportedSymbol::Generic(def, substs); symbols.push(( symbol, SymbolExportInfo { diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 2dda4cd1694..c80347448cb 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -872,7 +872,7 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>( let load_from_incr_comp_dir = |output_path: PathBuf, saved_path: &str| { let source_file = in_incr_comp_dir(&incr_comp_session_dir, saved_path); debug!( - "copying pre-existing module `{}` from {:?} to {}", + "copying preexisting module `{}` from {:?} to {}", module.name, source_file, output_path.display() diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 8542bab689d..9bfe426c007 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -156,7 +156,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { None => { // Unfortunately, unconditionally using `llvm.used` causes // issues in handling `.init_array` with the gold linker, - // but using `llvm.compiler.used` caused a nontrival amount + // but using `llvm.compiler.used` caused a nontrivial amount // of unintentional ecosystem breakage -- particularly on // Mach-O targets. // diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index f2469fde3b6..03f33d8d8aa 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -12,7 +12,7 @@ // * `"` is treated as the start of a string. use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher}; use rustc_hir::def_id::DefId; use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData}; use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Mutability}; @@ -675,8 +675,7 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S hcx.while_hashing_spans(false, |hcx| { ct.to_valtree().hash_stable(hcx, &mut hasher) }); - let hash: u64 = hasher.finish(); - hash + hasher.finish::<Hash64>() }); if cpp_like_debuginfo(tcx) { diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 66e7e314f79..44931766678 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -424,7 +424,7 @@ pub struct UnableToRunDsymutil { } #[derive(Diagnostic)] -#[diag(codegen_ssa_stripping_debu_info_failed)] +#[diag(codegen_ssa_stripping_debug_info_failed)] #[note] pub struct StrippingDebugInfoFailed<'a> { pub util: &'a str, diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 0ab12314b3c..26d55618b49 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -25,8 +25,8 @@ use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; +use rustc_fluent_macro::fluent_messages; use rustc_hir::def_id::CrateNum; -use rustc_macros::fluent_messages; use rustc_middle::dep_graph::WorkProduct; use rustc_middle::middle::dependency_format::Dependencies; use rustc_middle::middle::exported_symbols::SymbolExportKind; diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs index 2421acab471..81b49afb883 100644 --- a/compiler/rustc_codegen_ssa/src/meth.rs +++ b/compiler/rustc_codegen_ssa/src/meth.rs @@ -67,10 +67,10 @@ impl<'a, 'tcx> VirtualIndex { /// ref of the type. fn expect_dyn_trait_in_self(ty: Ty<'_>) -> ty::PolyExistentialTraitRef<'_> { for arg in ty.peel_refs().walk() { - if let GenericArgKind::Type(ty) = arg.unpack() { - if let ty::Dynamic(data, _, _) = ty.kind() { - return data.principal().expect("expected principal trait object"); - } + if let GenericArgKind::Type(ty) = arg.unpack() + && let ty::Dynamic(data, _, _) = ty.kind() + { + return data.principal().expect("expected principal trait object"); } } diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index dd86977817f..a0a8246be15 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -12,7 +12,6 @@ use crate::MemFlags; use rustc_ast as ast; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_hir::lang_items::LangItem; -use rustc_index::vec::Idx; use rustc_middle::mir::{self, AssertKind, SwitchTargets}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; @@ -369,7 +368,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if self.fn_abi.c_variadic { // The `VaList` "spoofed" argument is just after all the real arguments. let va_list_arg_idx = self.fn_abi.args.len(); - match self.locals[mir::Local::new(1 + va_list_arg_idx)] { + match self.locals[mir::Local::from_usize(1 + va_list_arg_idx)] { LocalRef::Place(va_list) => { bx.va_end(va_list.llval); } diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index d88226f5db0..94de19a9c29 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -12,6 +12,7 @@ use rustc_middle::mir::Operand; use rustc_middle::ty::cast::{CastTy, IntTy}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, adjustment::PointerCast, Instance, Ty, TyCtxt}; +use rustc_session::config::OptLevel; use rustc_span::source_map::{Span, DUMMY_SP}; use rustc_target::abi::{self, FIRST_VARIANT}; @@ -231,10 +232,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { (ScalarOrZst::Scalar(in_scalar), ScalarOrZst::Scalar(out_scalar)) if in_scalar.size(self.cx) == out_scalar.size(self.cx) => { + let operand_bty = bx.backend_type(operand.layout); let cast_bty = bx.backend_type(cast); - Some(OperandValue::Immediate( - self.transmute_immediate(bx, imm, in_scalar, out_scalar, cast_bty), - )) + Some(OperandValue::Immediate(self.transmute_immediate( + bx, + imm, + in_scalar, + operand_bty, + out_scalar, + cast_bty, + ))) } _ => None, } @@ -250,11 +257,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { && in_a.size(self.cx) == out_a.size(self.cx) && in_b.size(self.cx) == out_b.size(self.cx) { + let in_a_ibty = bx.scalar_pair_element_backend_type(operand.layout, 0, false); + let in_b_ibty = bx.scalar_pair_element_backend_type(operand.layout, 1, false); let out_a_ibty = bx.scalar_pair_element_backend_type(cast, 0, false); let out_b_ibty = bx.scalar_pair_element_backend_type(cast, 1, false); Some(OperandValue::Pair( - self.transmute_immediate(bx, imm_a, in_a, out_a, out_a_ibty), - self.transmute_immediate(bx, imm_b, in_b, out_b, out_b_ibty), + self.transmute_immediate(bx, imm_a, in_a, in_a_ibty, out_a, out_a_ibty), + self.transmute_immediate(bx, imm_b, in_b, in_b_ibty, out_b, out_b_ibty), )) } else { None @@ -273,6 +282,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx: &mut Bx, mut imm: Bx::Value, from_scalar: abi::Scalar, + from_backend_ty: Bx::Type, to_scalar: abi::Scalar, to_backend_ty: Bx::Type, ) -> Bx::Value { @@ -280,6 +290,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { use abi::Primitive::*; imm = bx.from_immediate(imm); + + // When scalars are passed by value, there's no metadata recording their + // valid ranges. For example, `char`s are passed as just `i32`, with no + // way for LLVM to know that they're 0x10FFFF at most. Thus we assume + // the range of the input value too, not just the output range. + self.assume_scalar_range(bx, imm, from_scalar, from_backend_ty); + imm = match (from_scalar.primitive(), to_scalar.primitive()) { (Int(..) | F32 | F64, Int(..) | F32 | F64) => bx.bitcast(imm, to_backend_ty), (Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty), @@ -294,10 +311,55 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.bitcast(int_imm, to_backend_ty) } }; + self.assume_scalar_range(bx, imm, to_scalar, to_backend_ty); imm = bx.to_immediate_scalar(imm, to_scalar); imm } + fn assume_scalar_range( + &self, + bx: &mut Bx, + imm: Bx::Value, + scalar: abi::Scalar, + backend_ty: Bx::Type, + ) { + if matches!(self.cx.sess().opts.optimize, OptLevel::No | OptLevel::Less) + // For now, the critical niches are all over `Int`eger values. + // Should floating-point values or pointers ever get more complex + // niches, then this code will probably want to handle them too. + || !matches!(scalar.primitive(), abi::Primitive::Int(..)) + || scalar.is_always_valid(self.cx) + { + return; + } + + let abi::WrappingRange { start, end } = scalar.valid_range(self.cx); + + if start <= end { + if start > 0 { + let low = bx.const_uint_big(backend_ty, start); + let cmp = bx.icmp(IntPredicate::IntUGE, imm, low); + bx.assume(cmp); + } + + let type_max = scalar.size(self.cx).unsigned_int_max(); + if end < type_max { + let high = bx.const_uint_big(backend_ty, end); + let cmp = bx.icmp(IntPredicate::IntULE, imm, high); + bx.assume(cmp); + } + } else { + let low = bx.const_uint_big(backend_ty, start); + let cmp_low = bx.icmp(IntPredicate::IntUGE, imm, low); + + let high = bx.const_uint_big(backend_ty, end); + let cmp_high = bx.icmp(IntPredicate::IntULE, imm, high); + + let or = bx.or(cmp_low, cmp_high); + bx.assume(or); + } + } + pub fn codegen_rvalue_unsized( &mut self, bx: &mut Bx, @@ -604,13 +666,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } - mir::Rvalue::NullaryOp(null_op, ty) => { + mir::Rvalue::NullaryOp(ref null_op, ty) => { let ty = self.monomorphize(ty); assert!(bx.cx().type_is_sized(ty)); let layout = bx.cx().layout_of(ty); let val = match null_op { mir::NullOp::SizeOf => layout.size.bytes(), mir::NullOp::AlignOf => layout.align.abi.bytes(), + mir::NullOp::OffsetOf(fields) => { + layout.offset_of_subfield(bx.cx(), fields.iter().map(|f| f.index())).bytes() + } }; let val = bx.cx().const_usize(val); let tcx = self.cx.tcx(); diff --git a/compiler/rustc_const_eval/Cargo.toml b/compiler/rustc_const_eval/Cargo.toml index 98ac36c1ced..74030a43c50 100644 --- a/compiler/rustc_const_eval/Cargo.toml +++ b/compiler/rustc_const_eval/Cargo.toml @@ -14,6 +14,7 @@ rustc_attr = { path = "../rustc_attr" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_hir = { path = "../rustc_hir" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_index = { path = "../rustc_index" } rustc_infer = { path = "../rustc_infer" } rustc_macros = { path = "../rustc_macros" } 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 4bd6fe19931..99f180f475d 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -296,12 +296,12 @@ pub fn eval_to_allocation_raw_provider<'tcx>( } let cid = key.value; - let def = cid.instance.def.with_opt_param(); - let is_static = tcx.is_static(def.did); + let def = cid.instance.def.def_id(); + let is_static = tcx.is_static(def); let mut ecx = InterpCx::new( tcx, - tcx.def_span(def.did), + tcx.def_span(def), key.param_env, // Statics (and promoteds inside statics) may access other statics, because unlike consts // they do not have to behave "as if" they were evaluated at runtime. diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index a5dfd1072f0..814b67b46ec 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -375,9 +375,9 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> { match instance { ty::InstanceDef::Item(def) => { - if ecx.tcx.is_ctfe_mir_available(def.did) { - Ok(ecx.tcx.mir_for_ctfe_opt_const_arg(def)) - } else if ecx.tcx.def_kind(def.did) == DefKind::AssocConst { + if ecx.tcx.is_ctfe_mir_available(def) { + Ok(ecx.tcx.mir_for_ctfe(def)) + } else if ecx.tcx.def_kind(def) == DefKind::AssocConst { let guar = ecx.tcx.sess.delay_span_bug( rustc_span::DUMMY_SP, "This is likely a const item that is missing from its impl", @@ -386,7 +386,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, } else { // `find_mir_or_eval_fn` checks that this is a const fn before even calling us, // so this should be unreachable. - let path = ecx.tcx.def_path_str(def.did); + let path = ecx.tcx.def_path_str(def); bug!("trying to call extern function `{path}` at compile-time"); } } @@ -410,9 +410,9 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, // Execution might have wandered off into other crates, so we cannot do a stability- // sensitive check here. But we can at least rule out functions that are not const // at all. - if !ecx.tcx.is_const_fn_raw(def.did) { + if !ecx.tcx.is_const_fn_raw(def) { // allow calling functions inside a trait marked with #[const_trait]. - if !ecx.tcx.is_const_default_method(def.did) { + if !ecx.tcx.is_const_default_method(def) { // We certainly do *not* want to actually call the fn // though, so be sure we return here. throw_unsup_format!("calling non-const function `{}`", instance) diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs index 557e721249d..015a9beab83 100644 --- a/compiler/rustc_const_eval/src/interpret/discriminant.rs +++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs @@ -211,18 +211,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let variant_index_relative = u32::try_from(variant_index_relative) .expect("we checked that this fits into a u32"); // Then computing the absolute variant idx should not overflow any more. - let variant_index = variants_start - .checked_add(variant_index_relative) - .expect("overflow computing absolute variant idx"); - let variants_len = op + let variant_index = VariantIdx::from_u32( + variants_start + .checked_add(variant_index_relative) + .expect("overflow computing absolute variant idx"), + ); + let variants = op .layout .ty .ty_adt_def() .expect("tagged layout for non adt") - .variants() - .len(); - assert!(usize::try_from(variant_index).unwrap() < variants_len); - VariantIdx::from_u32(variant_index) + .variants(); + assert!(variant_index < variants.next_index()); + variant_index } else { untagged_variant } diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 3e58a58aef7..6030498e946 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -132,11 +132,10 @@ pub struct Frame<'mir, 'tcx, Prov: Provenance = AllocId, Extra = ()> { } /// What we store about a frame in an interpreter backtrace. -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct FrameInfo<'tcx> { pub instance: ty::Instance<'tcx>, pub span: Span, - pub lint_root: Option<hir::HirId>, } #[derive(Clone, Copy, Eq, PartialEq, Debug)] // Miri debug-prints these @@ -462,10 +461,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { instance: ty::InstanceDef<'tcx>, promoted: Option<mir::Promoted>, ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> { - let def = instance.with_opt_param(); trace!("load mir(instance={:?}, promoted={:?})", instance, promoted); let body = if let Some(promoted) = promoted { - &self.tcx.promoted_mir_opt_const_arg(def)[promoted] + let def = instance.def_id(); + &self.tcx.promoted_mir(def)[promoted] } else { M::load_mir(self, instance)? }; @@ -503,13 +502,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// The `substs` are assumed to already be in our interpreter "universe" (param_env). pub(super) fn resolve( &self, - def: ty::WithOptConstParam<DefId>, + def: DefId, substs: SubstsRef<'tcx>, ) -> InterpResult<'tcx, ty::Instance<'tcx>> { trace!("resolve: {:?}, {:#?}", def, substs); trace!("param_env: {:#?}", self.param_env); trace!("substs: {:#?}", substs); - match ty::Instance::resolve_opt_const_arg(*self.tcx, self.param_env, def, substs) { + match ty::Instance::resolve(*self.tcx, self.param_env, def, substs) { Ok(Some(instance)) => Ok(instance), Ok(None) => throw_inval!(TooGeneric), @@ -947,10 +946,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // This deliberately does *not* honor `requires_caller_location` since it is used for much // more than just panics. for frame in stack.iter().rev() { - let lint_root = frame.lint_root(); let span = frame.current_span(); - - frames.push(FrameInfo { span, instance: frame.instance, lint_root }); + frames.push(FrameInfo { span, instance: frame.instance }); } trace!("generate stacktrace: {:#?}", frames); frames diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 26fb041b455..eada75ae391 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -75,7 +75,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>( } sym::type_id => { ensure_monomorphic_enough(tcx, tp_ty)?; - ConstValue::from_u64(tcx.type_id_hash(tp_ty)) + ConstValue::from_u64(tcx.type_id_hash(tp_ty).as_u64()) } sym::variant_count => match tp_ty.kind() { // Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough. diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 0291cca7378..b448e3a24c6 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -104,7 +104,7 @@ pub trait Machine<'mir, 'tcx>: Sized { type FrameExtra; /// Extra data stored in every allocation. - type AllocExtra: Debug + Clone + 'static; + type AllocExtra: Debug + Clone + 'tcx; /// Type for the bytes of the allocation. type Bytes: AllocBytes + 'static; diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index a3764a7d142..d5b6a581a79 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -215,7 +215,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.allocate_raw_ptr(alloc, kind) } - /// This can fail only of `alloc` contains provenance. + /// This can fail only if `alloc` contains provenance. pub fn allocate_raw_ptr( &mut self, alloc: Allocation, @@ -807,9 +807,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { DumpAllocs { ecx: self, allocs } } - /// Print leaked memory. Allocations reachable from `static_roots` or a `Global` allocation - /// are not considered leaked. Leaks whose kind `may_leak()` returns true are not reported. - pub fn leak_report(&self, static_roots: &[AllocId]) -> usize { + /// Find leaked allocations. Allocations reachable from `static_roots` or a `Global` allocation + /// are not considered leaked, as well as leaks whose kind's `may_leak()` returns true. + pub fn find_leaked_allocations( + &self, + static_roots: &[AllocId], + ) -> Vec<(AllocId, MemoryKind<M::MemoryKind>, Allocation<M::Provenance, M::AllocExtra, M::Bytes>)> + { // Collect the set of allocations that are *reachable* from `Global` allocations. let reachable = { let mut reachable = FxHashSet::default(); @@ -833,14 +837,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }; // All allocations that are *not* `reachable` and *not* `may_leak` are considered leaking. - let leaks: Vec<_> = self.memory.alloc_map.filter_map_collect(|&id, &(kind, _)| { - if kind.may_leak() || reachable.contains(&id) { None } else { Some(id) } - }); - let n = leaks.len(); - if n > 0 { - eprintln!("The following memory was leaked: {:?}", self.dump_allocs(leaks)); - } - n + self.memory.alloc_map.filter_map_collect(|id, (kind, alloc)| { + if kind.may_leak() || reachable.contains(id) { + None + } else { + Some((*id, *kind, alloc.clone())) + } + }) } } diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 9a366364e76..319b80d66e1 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -113,8 +113,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Intrinsic(box intrinsic) => self.emulate_nondiverging_intrinsic(intrinsic)?, - // Statements we do not track. - PlaceMention(..) | AscribeUserType(..) => {} + // Evaluate the place expression, without reading from it. + PlaceMention(box place) => { + let _ = self.eval_place(*place)?; + } + + // This exists purely to guide borrowck lifetime inference, and does not have + // an operational effect. + AscribeUserType(..) => {} // Currently, Miri discards Coverage statements. Coverage statements are only injected // via an optional compile time MIR pass and have no side effects. Since Coverage @@ -280,20 +286,23 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.write_immediate(*val, &dest)?; } - NullaryOp(null_op, ty) => { + NullaryOp(ref null_op, ty) => { let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty)?; let layout = self.layout_of(ty)?; - if layout.is_unsized() { + if let mir::NullOp::SizeOf | mir::NullOp::AlignOf = null_op && layout.is_unsized() { // FIXME: This should be a span_bug (#80742) self.tcx.sess.delay_span_bug( self.frame().current_span(), - &format!("Nullary MIR operator called for unsized type {}", ty), + &format!("{null_op:?} MIR operator called for unsized type {ty}"), ); throw_inval!(SizeOfUnsizedType(ty)); } let val = match null_op { mir::NullOp::SizeOf => layout.size.bytes(), mir::NullOp::AlignOf => layout.align.abi.bytes(), + mir::NullOp::OffsetOf(fields) => { + layout.offset_of_subfield(self, fields.iter().map(|f| f.index())).bytes() + } }; self.write_scalar(Scalar::from_target_usize(val, self), &dest)?; } diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index a07702f7d9b..df387920010 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -83,8 +83,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { (fn_val, self.fn_abi_of_fn_ptr(fn_sig_binder, extra_args)?, false) } ty::FnDef(def_id, substs) => { - let instance = - self.resolve(ty::WithOptConstParam::unknown(def_id), substs)?; + let instance = self.resolve(def_id, substs)?; ( FnVal::Instance(instance), self.fn_abi_of_instance(instance, extra_args)?, diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index bf2b4ee69ab..7cb19744987 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -36,7 +36,7 @@ where ty::Closure(def_id, substs) | ty::Generator(def_id, substs, ..) | ty::FnDef(def_id, substs) => { - let instance = ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)); + let instance = ty::InstanceDef::Item(def_id); let unused_params = self.tcx.unused_generic_params(instance); for (index, subst) in substs.into_iter().enumerate() { let index = index diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 93b5273e1b1..e06b634cdc3 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -784,7 +784,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> Abi::Scalar(scalar_layout) => { if !scalar_layout.is_uninit_valid() { // There is something to check here. - let scalar = self.read_scalar(op, "initiailized scalar value")?; + let scalar = self.read_scalar(op, "initialized scalar value")?; self.visit_scalar(scalar, scalar_layout)?; } } @@ -794,7 +794,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> // the other must be init. if !a_layout.is_uninit_valid() && !b_layout.is_uninit_valid() { let (a, b) = - self.read_immediate(op, "initiailized scalar value")?.to_scalar_pair(); + self.read_immediate(op, "initialized scalar value")?.to_scalar_pair(); self.visit_scalar(a, a_layout)?; self.visit_scalar(b, b_layout)?; } diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 5ab389d04c7..1b66eca97a5 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -34,7 +34,7 @@ pub mod transform; pub mod util; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; -use rustc_macros::fluent_messages; +use rustc_fluent_macro::fluent_messages; use rustc_middle::ty; use rustc_middle::ty::query::Providers; diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 9dad9479053..696c4517700 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -558,7 +558,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { Rvalue::Cast(_, _, _) => {} - Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {} + Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_), _) => {} Rvalue::ShallowInitBox(_, _) => {} Rvalue::UnaryOp(_, operand) => { @@ -874,7 +874,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { debug!("Resolving ({:?}) -> {:?}", callee, instance); if let Ok(Some(func)) = instance { if let InstanceDef::Item(def) = func.def { - callee = def.did; + callee = def; } } } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index c0f5b3725b3..6c11edb742c 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -14,6 +14,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; use rustc_middle::ty::{suggest_constraining_type_param, Adt, Closure, FnDef, FnPtr, Param, Ty}; use rustc_middle::ty::{Binder, TraitRef}; +use rustc_middle::util::{call_kind, CallDesugaringKind, CallKind}; use rustc_session::parse::feature_err; use rustc_span::symbol::sym; use rustc_span::{BytePos, Pos, Span, Symbol}; @@ -21,7 +22,6 @@ use rustc_trait_selection::traits::SelectionContext; use super::ConstCx; use crate::errors; -use crate::util::{call_kind, CallDesugaringKind, CallKind}; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Status { @@ -610,10 +610,11 @@ pub struct RawPtrComparison; impl<'tcx> NonConstOp<'tcx> for RawPtrComparison { fn build_error( &self, - _: &ConstCx<'_, 'tcx>, + ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - span_bug!(span, "raw ptr comparison should already be caught in the trait system"); + // FIXME(const_trait_impl): revert to span_bug? + ccx.tcx.sess.create_err(errors::RawPtrComparisonErr { span }) } } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index 6758cba2eed..bf688f2b34e 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -364,9 +364,8 @@ where assert!(promoted.is_none() || Q::ALLOW_PROMOTED); // Don't peek inside trait associated constants. - if promoted.is_none() && cx.tcx.trait_of_item(def.did).is_none() { - assert_eq!(def.const_param_did, None, "expected associated const: {def:?}"); - let qualifs = cx.tcx.at(constant.span).mir_const_qualif(def.did); + if promoted.is_none() && cx.tcx.trait_of_item(def).is_none() { + let qualifs = cx.tcx.at(constant.span).mir_const_qualif(def); if !Q::in_qualifs(&qualifs) { return false; diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index 7919aed097a..e978e344283 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -514,6 +514,7 @@ impl<'tcx> Validator<'_, 'tcx> { Rvalue::NullaryOp(op, _) => match op { NullOp::SizeOf => {} NullOp::AlignOf => {} + NullOp::OffsetOf(_) => {} }, Rvalue::ShallowInitBox(_, _) => return Err(Unpromotable), @@ -828,7 +829,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { } fn promote_candidate(mut self, candidate: Candidate, next_promoted_id: usize) -> Body<'tcx> { - let def = self.source.source.with_opt_param(); + let def = self.source.source.def_id(); let mut rvalue = { let promoted = &mut self.promoted; let promoted_id = Promoted::new(next_promoted_id); @@ -836,7 +837,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { let mut promoted_operand = |ty, span| { promoted.span = span; promoted.local_decls[RETURN_PLACE] = LocalDecl::new(ty, span); - let substs = tcx.erase_regions(InternalSubsts::identity_for_item(tcx, def.did)); + let substs = tcx.erase_regions(InternalSubsts::identity_for_item(tcx, def)); let uneval = mir::UnevaluatedConst { def, substs, promoted: Some(promoted_id) }; Operand::Constant(Box::new(Constant { diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index d4bed97380b..b8809d29c77 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -8,9 +8,10 @@ use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor}; use rustc_middle::mir::{ traversal, BasicBlock, BinOp, Body, BorrowKind, CastKind, CopyNonOverlapping, Local, Location, - MirPass, MirPhase, NonDivergingIntrinsic, Operand, Place, PlaceElem, PlaceRef, ProjectionElem, - RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind, Terminator, - TerminatorKind, UnOp, UnwindAction, VarDebugInfo, VarDebugInfoContents, START_BLOCK, + MirPass, MirPhase, NonDivergingIntrinsic, NullOp, Operand, Place, PlaceElem, PlaceRef, + ProjectionElem, RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind, + Terminator, TerminatorKind, UnOp, UnwindAction, VarDebugInfo, VarDebugInfoContents, + START_BLOCK, }; use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt}; use rustc_mir_dataflow::impls::MaybeStorageLive; @@ -262,7 +263,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // We sometimes have to use `defining_opaque_types` for subtyping // to succeed here and figuring out how exactly that should work // is annoying. It is harmless enough to just not validate anything - // in that case. We still check this after analysis as all opque + // in that case. We still check this after analysis as all opaque // types have been revealed at this point. if (src, dest).has_opaque_types() { return true; @@ -711,10 +712,54 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } } + Rvalue::NullaryOp(NullOp::OffsetOf(fields), container) => { + let fail_out_of_bounds = |this: &Self, location, field, ty| { + this.fail(location, format!("Out of bounds field {field:?} for {ty:?}")); + }; + + let mut current_ty = *container; + + for field in fields.iter() { + match current_ty.kind() { + ty::Tuple(fields) => { + let Some(&f_ty) = fields.get(field.as_usize()) else { + fail_out_of_bounds(self, location, field, current_ty); + return; + }; + + current_ty = self.tcx.normalize_erasing_regions(self.param_env, f_ty); + } + ty::Adt(adt_def, substs) => { + if adt_def.is_enum() { + self.fail( + location, + format!("Cannot get field offset from enum {current_ty:?}"), + ); + return; + } + + let Some(field) = adt_def.non_enum_variant().fields.get(field) else { + fail_out_of_bounds(self, location, field, current_ty); + return; + }; + + let f_ty = field.ty(self.tcx, substs); + current_ty = self.tcx.normalize_erasing_regions(self.param_env, f_ty); + } + _ => { + self.fail( + location, + format!("Cannot get field offset from non-adt type {current_ty:?}"), + ); + return; + } + } + } + } Rvalue::Repeat(_, _) | Rvalue::ThreadLocalRef(_) | Rvalue::AddressOf(_, _) - | Rvalue::NullaryOp(_, _) + | Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) | Rvalue::Discriminant(_) => {} } self.super_rvalue(rvalue, location); @@ -757,14 +802,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } } - StatementKind::PlaceMention(..) => { - if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { - self.fail( - location, - "`PlaceMention` should have been removed after drop lowering phase", - ); - } - } StatementKind::AscribeUserType(..) => { if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { self.fail( @@ -874,6 +911,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { StatementKind::StorageDead(_) | StatementKind::Coverage(_) | StatementKind::ConstEvalCounter + | StatementKind::PlaceMention(..) | StatementKind::Nop => {} } diff --git a/compiler/rustc_const_eval/src/util/mod.rs b/compiler/rustc_const_eval/src/util/mod.rs index c0aabd77cee..7641f560714 100644 --- a/compiler/rustc_const_eval/src/util/mod.rs +++ b/compiler/rustc_const_eval/src/util/mod.rs @@ -1,14 +1,9 @@ mod alignment; -mod call_kind; mod check_validity_requirement; -pub mod collect_writes; mod compare_types; -mod find_self_call; mod type_name; pub use self::alignment::is_disaligned; -pub use self::call_kind::{call_kind, CallDesugaringKind, CallKind}; pub use self::check_validity_requirement::check_validity_requirement; pub use self::compare_types::{is_equal_up_to_subtyping, is_subtype}; -pub use self::find_self_call::find_self_call; pub use self::type_name::type_name; diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 2102f09c56a..39f4bc63c88 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -21,7 +21,6 @@ rustc-hash = "1.1.0" rustc_index = { path = "../rustc_index", package = "rustc_index" } rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } -serde_json = "1.0.59" smallvec = { version = "1.8.1", features = [ "const_generics", "union", diff --git a/compiler/rustc_data_structures/src/aligned.rs b/compiler/rustc_data_structures/src/aligned.rs new file mode 100644 index 00000000000..0e5ecfd9bff --- /dev/null +++ b/compiler/rustc_data_structures/src/aligned.rs @@ -0,0 +1,33 @@ +use std::ptr::Alignment; + +/// Returns the ABI-required minimum alignment of a type in bytes. +/// +/// This is equivalent to [`mem::align_of`], but also works for some unsized +/// types (e.g. slices or rustc's `List`s). +/// +/// [`mem::align_of`]: std::mem::align_of +pub const fn align_of<T: ?Sized + Aligned>() -> Alignment { + T::ALIGN +} + +/// A type with a statically known alignment. +/// +/// # Safety +/// +/// `Self::ALIGN` must be equal to the alignment of `Self`. For sized types it +/// is [`mem::align_of<Self>()`], for unsized types it depends on the type, for +/// example `[T]` has alignment of `T`. +/// +/// [`mem::align_of<Self>()`]: std::mem::align_of +pub unsafe trait Aligned { + /// Alignment of `Self`. + const ALIGN: Alignment; +} + +unsafe impl<T> Aligned for T { + const ALIGN: Alignment = Alignment::of::<Self>(); +} + +unsafe impl<T> Aligned for [T] { + const ALIGN: Alignment = Alignment::of::<T>(); +} diff --git a/compiler/rustc_data_structures/src/fingerprint.rs b/compiler/rustc_data_structures/src/fingerprint.rs index b6e866f15ef..6fa76981408 100644 --- a/compiler/rustc_data_structures/src/fingerprint.rs +++ b/compiler/rustc_data_structures/src/fingerprint.rs @@ -1,4 +1,4 @@ -use crate::stable_hasher; +use crate::stable_hasher::{Hash64, StableHasher, StableHasherResult}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use std::hash::{Hash, Hasher}; @@ -9,32 +9,49 @@ mod tests; #[repr(C)] pub struct Fingerprint(u64, u64); -impl Fingerprint { - pub const ZERO: Fingerprint = Fingerprint(0, 0); +pub trait FingerprintComponent { + fn as_u64(&self) -> u64; +} +impl FingerprintComponent for Hash64 { #[inline] - pub fn new(_0: u64, _1: u64) -> Fingerprint { - Fingerprint(_0, _1) + fn as_u64(&self) -> u64 { + Hash64::as_u64(*self) + } +} + +impl FingerprintComponent for u64 { + #[inline] + fn as_u64(&self) -> u64 { + *self } +} + +impl Fingerprint { + pub const ZERO: Fingerprint = Fingerprint(0, 0); #[inline] - pub fn from_smaller_hash(hash: u64) -> Fingerprint { - Fingerprint(hash, hash) + pub fn new<A, B>(_0: A, _1: B) -> Fingerprint + where + A: FingerprintComponent, + B: FingerprintComponent, + { + Fingerprint(_0.as_u64(), _1.as_u64()) } #[inline] - pub fn to_smaller_hash(&self) -> u64 { + pub fn to_smaller_hash(&self) -> Hash64 { // Even though both halves of the fingerprint are expected to be good // quality hash values, let's still combine the two values because the // Fingerprints in DefPathHash have the StableCrateId portion which is // the same for all DefPathHashes from the same crate. Combining the // two halves makes sure we get a good quality hash in such cases too. - self.0.wrapping_mul(3).wrapping_add(self.1) + Hash64::new(self.0.wrapping_mul(3).wrapping_add(self.1)) } #[inline] - pub fn as_value(&self) -> (u64, u64) { - (self.0, self.1) + pub fn split(&self) -> (Hash64, Hash64) { + (Hash64::new(self.0), Hash64::new(self.1)) } #[inline] @@ -131,9 +148,9 @@ impl FingerprintHasher for crate::unhash::Unhasher { } } -impl stable_hasher::StableHasherResult for Fingerprint { +impl StableHasherResult for Fingerprint { #[inline] - fn finish(hasher: stable_hasher::StableHasher) -> Self { + fn finish(hasher: StableHasher) -> Self { let (_0, _1) = hasher.finalize(); Fingerprint(_0, _1) } diff --git a/compiler/rustc_data_structures/src/fingerprint/tests.rs b/compiler/rustc_data_structures/src/fingerprint/tests.rs index 9b0783e33ab..09ec2622a65 100644 --- a/compiler/rustc_data_structures/src/fingerprint/tests.rs +++ b/compiler/rustc_data_structures/src/fingerprint/tests.rs @@ -1,11 +1,12 @@ use super::*; +use crate::stable_hasher::Hash64; // Check that `combine_commutative` is order independent. #[test] fn combine_commutative_is_order_independent() { - let a = Fingerprint::new(0xf6622fb349898b06, 0x70be9377b2f9c610); - let b = Fingerprint::new(0xa9562bf5a2a5303c, 0x67d9b6c82034f13d); - let c = Fingerprint::new(0x0d013a27811dbbc3, 0x9a3f7b3d9142ec43); + let a = Fingerprint::new(Hash64::new(0xf6622fb349898b06), Hash64::new(0x70be9377b2f9c610)); + let b = Fingerprint::new(Hash64::new(0xa9562bf5a2a5303c), Hash64::new(0x67d9b6c82034f13d)); + let c = Fingerprint::new(Hash64::new(0x0d013a27811dbbc3), Hash64::new(0x9a3f7b3d9142ec43)); let permutations = [(a, b, c), (a, c, b), (b, a, c), (b, c, a), (c, a, b), (c, b, a)]; let f = a.combine_commutative(b).combine_commutative(c); for p in &permutations { diff --git a/compiler/rustc_data_structures/src/hashes.rs b/compiler/rustc_data_structures/src/hashes.rs new file mode 100644 index 00000000000..ad068cdbc98 --- /dev/null +++ b/compiler/rustc_data_structures/src/hashes.rs @@ -0,0 +1,132 @@ +//! rustc encodes a lot of hashes. If hashes are stored as `u64` or `u128`, a `derive(Encodable)` +//! will apply varint encoding to the hashes, which is less efficient than directly encoding the 8 +//! or 16 bytes of the hash. +//! +//! The types in this module represent 64-bit or 128-bit hashes produced by a `StableHasher`. +//! `Hash64` and `Hash128` expose some utilty functions to encourage users to not extract the inner +//! hash value as an integer type and accidentally apply varint encoding to it. +//! +//! In contrast with `Fingerprint`, users of these types cannot and should not attempt to construct +//! and decompose these types into constitutent pieces. The point of these types is only to +//! connect the fact that they can only be produced by a `StableHasher` to their +//! `Encode`/`Decode` impls. + +use crate::stable_hasher::{StableHasher, StableHasherResult}; +use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; +use std::fmt; +use std::ops::BitXorAssign; + +#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)] +pub struct Hash64 { + inner: u64, +} + +impl Hash64 { + pub const ZERO: Hash64 = Hash64 { inner: 0 }; + + #[inline] + pub(crate) fn new(n: u64) -> Self { + Self { inner: n } + } + + #[inline] + pub fn as_u64(self) -> u64 { + self.inner + } +} + +impl BitXorAssign<u64> for Hash64 { + #[inline] + fn bitxor_assign(&mut self, rhs: u64) { + self.inner ^= rhs; + } +} + +impl<S: Encoder> Encodable<S> for Hash64 { + #[inline] + fn encode(&self, s: &mut S) { + s.emit_raw_bytes(&self.inner.to_le_bytes()); + } +} + +impl<D: Decoder> Decodable<D> for Hash64 { + #[inline] + fn decode(d: &mut D) -> Self { + Self { inner: u64::from_le_bytes(d.read_raw_bytes(8).try_into().unwrap()) } + } +} + +impl StableHasherResult for Hash64 { + #[inline] + fn finish(hasher: StableHasher) -> Self { + Self { inner: hasher.finalize().0 } + } +} + +impl fmt::Debug for Hash64 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.inner.fmt(f) + } +} + +impl fmt::LowerHex for Hash64 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::LowerHex::fmt(&self.inner, f) + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)] +pub struct Hash128 { + inner: u128, +} + +impl Hash128 { + #[inline] + pub fn truncate(self) -> Hash64 { + Hash64 { inner: self.inner as u64 } + } + + #[inline] + pub fn wrapping_add(self, other: Self) -> Self { + Self { inner: self.inner.wrapping_add(other.inner) } + } + + #[inline] + pub fn as_u128(self) -> u128 { + self.inner + } +} + +impl<S: Encoder> Encodable<S> for Hash128 { + #[inline] + fn encode(&self, s: &mut S) { + s.emit_raw_bytes(&self.inner.to_le_bytes()); + } +} + +impl<D: Decoder> Decodable<D> for Hash128 { + #[inline] + fn decode(d: &mut D) -> Self { + Self { inner: u128::from_le_bytes(d.read_raw_bytes(16).try_into().unwrap()) } + } +} + +impl StableHasherResult for Hash128 { + #[inline] + fn finish(hasher: StableHasher) -> Self { + let (_0, _1) = hasher.finalize(); + Self { inner: u128::from(_0) | (u128::from(_1) << 64) } + } +} + +impl fmt::Debug for Hash128 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.inner.fmt(f) + } +} + +impl fmt::LowerHex for Hash128 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::LowerHex::fmt(&self.inner, f) + } +} diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index e373bd18402..426d2c4034b 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -29,10 +29,13 @@ #![feature(get_mut_unchecked)] #![feature(lint_reasons)] #![feature(unwrap_infallible)] +#![feature(strict_provenance)] +#![feature(ptr_alignment_type)] #![allow(rustc::default_hash_types)] #![allow(rustc::potential_query_instability)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] +#![deny(unsafe_op_in_unsafe_fn)] #[macro_use] extern crate tracing; @@ -82,7 +85,9 @@ pub mod transitive_relation; pub mod vec_linked_list; pub mod work_queue; pub use atomic_ref::AtomicRef; +pub mod aligned; pub mod frozen; +mod hashes; pub mod owned_slice; pub mod sso; pub mod steal; diff --git a/compiler/rustc_data_structures/src/memmap.rs b/compiler/rustc_data_structures/src/memmap.rs index ef37a606f31..ca908671ae5 100644 --- a/compiler/rustc_data_structures/src/memmap.rs +++ b/compiler/rustc_data_structures/src/memmap.rs @@ -13,7 +13,8 @@ pub struct Mmap(Vec<u8>); impl Mmap { #[inline] pub unsafe fn map(file: File) -> io::Result<Self> { - memmap2::Mmap::map(&file).map(Mmap) + // Safety: this is in fact not safe. + unsafe { memmap2::Mmap::map(&file).map(Mmap) } } } diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs index 1ed584eafad..572bd4ac21c 100644 --- a/compiler/rustc_data_structures/src/profiling.rs +++ b/compiler/rustc_data_structures/src/profiling.rs @@ -87,6 +87,7 @@ use crate::fx::FxHashMap; use std::borrow::Borrow; use std::collections::hash_map::Entry; use std::error::Error; +use std::fmt::Display; use std::fs; use std::intrinsics::unlikely; use std::path::Path; @@ -97,7 +98,6 @@ use std::time::{Duration, Instant}; pub use measureme::EventId; use measureme::{EventIdBuilder, Profiler, SerializableString, StringId}; use parking_lot::RwLock; -use serde_json::json; use smallvec::SmallVec; bitflags::bitflags! { @@ -557,7 +557,7 @@ impl SelfProfiler { let crate_name = crate_name.unwrap_or("unknown-crate"); // HACK(eddyb) we need to pad the PID, strange as it may seem, as its // length can behave as a source of entropy for heap addresses, when - // ASLR is disabled and the heap is otherwise determinic. + // ASLR is disabled and the heap is otherwise deterministic. let pid: u32 = process::id(); let filename = format!("{crate_name}-{pid:07}.rustc_profile"); let path = output_directory.join(&filename); @@ -763,6 +763,31 @@ impl Drop for VerboseTimingGuard<'_> { } } +struct JsonTimePassesEntry<'a> { + pass: &'a str, + time: f64, + start_rss: Option<usize>, + end_rss: Option<usize>, +} + +impl Display for JsonTimePassesEntry<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self { pass: what, time, start_rss, end_rss } = self; + write!(f, r#"{{"pass":"{what}","time":{time},"rss_start":"#).unwrap(); + match start_rss { + Some(rss) => write!(f, "{rss}")?, + None => write!(f, "null")?, + } + write!(f, r#","rss_end":"#)?; + match end_rss { + Some(rss) => write!(f, "{rss}")?, + None => write!(f, "null")?, + } + write!(f, "}}")?; + Ok(()) + } +} + pub fn print_time_passes_entry( what: &str, dur: Duration, @@ -772,13 +797,10 @@ pub fn print_time_passes_entry( ) { match format { TimePassesFormat::Json => { - let json = json!({ - "pass": what, - "time": dur.as_secs_f64(), - "rss_start": start_rss, - "rss_end": end_rss, - }); - eprintln!("time: {json}"); + let entry = + JsonTimePassesEntry { pass: what, time: dur.as_secs_f64(), start_rss, end_rss }; + + eprintln!(r#"time: {entry}"#); return; } TimePassesFormat::Text => (), @@ -894,3 +916,6 @@ cfg_if! { } } } + +#[cfg(test)] +mod tests; diff --git a/compiler/rustc_data_structures/src/profiling/tests.rs b/compiler/rustc_data_structures/src/profiling/tests.rs new file mode 100644 index 00000000000..2b09de085da --- /dev/null +++ b/compiler/rustc_data_structures/src/profiling/tests.rs @@ -0,0 +1,19 @@ +use super::JsonTimePassesEntry; + +#[test] +fn with_rss() { + let entry = + JsonTimePassesEntry { pass: "typeck", time: 56.1, start_rss: Some(10), end_rss: Some(20) }; + + assert_eq!(entry.to_string(), r#"{"pass":"typeck","time":56.1,"rss_start":10,"rss_end":20}"#) +} + +#[test] +fn no_rss() { + let entry = JsonTimePassesEntry { pass: "typeck", time: 56.1, start_rss: None, end_rss: None }; + + assert_eq!( + entry.to_string(), + r#"{"pass":"typeck","time":56.1,"rss_start":null,"rss_end":null}"# + ) +} diff --git a/compiler/rustc_data_structures/src/sip128.rs b/compiler/rustc_data_structures/src/sip128.rs index d849fe0373f..4a0ed87f77c 100644 --- a/compiler/rustc_data_structures/src/sip128.rs +++ b/compiler/rustc_data_structures/src/sip128.rs @@ -96,28 +96,30 @@ macro_rules! compress { unsafe fn copy_nonoverlapping_small(src: *const u8, dst: *mut u8, count: usize) { debug_assert!(count <= 8); - if count == 8 { - ptr::copy_nonoverlapping(src, dst, 8); - return; - } + unsafe { + if count == 8 { + ptr::copy_nonoverlapping(src, dst, 8); + return; + } - let mut i = 0; - if i + 3 < count { - ptr::copy_nonoverlapping(src.add(i), dst.add(i), 4); - i += 4; - } + let mut i = 0; + if i + 3 < count { + ptr::copy_nonoverlapping(src.add(i), dst.add(i), 4); + i += 4; + } - if i + 1 < count { - ptr::copy_nonoverlapping(src.add(i), dst.add(i), 2); - i += 2 - } + if i + 1 < count { + ptr::copy_nonoverlapping(src.add(i), dst.add(i), 2); + i += 2 + } - if i < count { - *dst.add(i) = *src.add(i); - i += 1; - } + if i < count { + *dst.add(i) = *src.add(i); + i += 1; + } - debug_assert_eq!(i, count); + debug_assert_eq!(i, count); + } } // # Implementation @@ -232,38 +234,40 @@ impl SipHasher128 { // overflow) if it wasn't already. #[inline(never)] unsafe fn short_write_process_buffer<const LEN: usize>(&mut self, bytes: [u8; LEN]) { - let nbuf = self.nbuf; - debug_assert!(LEN <= 8); - debug_assert!(nbuf < BUFFER_SIZE); - debug_assert!(nbuf + LEN >= BUFFER_SIZE); - debug_assert!(nbuf + LEN < BUFFER_WITH_SPILL_SIZE); + unsafe { + let nbuf = self.nbuf; + debug_assert!(LEN <= 8); + debug_assert!(nbuf < BUFFER_SIZE); + debug_assert!(nbuf + LEN >= BUFFER_SIZE); + debug_assert!(nbuf + LEN < BUFFER_WITH_SPILL_SIZE); + + // Copy first part of input into end of buffer, possibly into spill + // element. The memcpy call is optimized away because the size is known. + let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf); + ptr::copy_nonoverlapping(bytes.as_ptr(), dst, LEN); + + // Process buffer. + for i in 0..BUFFER_CAPACITY { + let elem = self.buf.get_unchecked(i).assume_init().to_le(); + self.state.v3 ^= elem; + Sip13Rounds::c_rounds(&mut self.state); + self.state.v0 ^= elem; + } - // Copy first part of input into end of buffer, possibly into spill - // element. The memcpy call is optimized away because the size is known. - let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf); - ptr::copy_nonoverlapping(bytes.as_ptr(), dst, LEN); - - // Process buffer. - for i in 0..BUFFER_CAPACITY { - let elem = self.buf.get_unchecked(i).assume_init().to_le(); - self.state.v3 ^= elem; - Sip13Rounds::c_rounds(&mut self.state); - self.state.v0 ^= elem; + // Copy remaining input into start of buffer by copying LEN - 1 + // elements from spill (at most LEN - 1 bytes could have overflowed + // into the spill). The memcpy call is optimized away because the size + // is known. And the whole copy is optimized away for LEN == 1. + let dst = self.buf.as_mut_ptr() as *mut u8; + let src = self.buf.get_unchecked(BUFFER_SPILL_INDEX) as *const _ as *const u8; + ptr::copy_nonoverlapping(src, dst, LEN - 1); + + // This function should only be called when the write fills the buffer. + // Therefore, when LEN == 1, the new `self.nbuf` must be zero. + // LEN is statically known, so the branch is optimized away. + self.nbuf = if LEN == 1 { 0 } else { nbuf + LEN - BUFFER_SIZE }; + self.processed += BUFFER_SIZE; } - - // Copy remaining input into start of buffer by copying LEN - 1 - // elements from spill (at most LEN - 1 bytes could have overflowed - // into the spill). The memcpy call is optimized away because the size - // is known. And the whole copy is optimized away for LEN == 1. - let dst = self.buf.as_mut_ptr() as *mut u8; - let src = self.buf.get_unchecked(BUFFER_SPILL_INDEX) as *const _ as *const u8; - ptr::copy_nonoverlapping(src, dst, LEN - 1); - - // This function should only be called when the write fills the buffer. - // Therefore, when LEN == 1, the new `self.nbuf` must be zero. - // LEN is statically known, so the branch is optimized away. - self.nbuf = if LEN == 1 { 0 } else { nbuf + LEN - BUFFER_SIZE }; - self.processed += BUFFER_SIZE; } // A write function for byte slices. @@ -301,57 +305,59 @@ impl SipHasher128 { // containing the byte offset `self.nbuf`. #[inline(never)] unsafe fn slice_write_process_buffer(&mut self, msg: &[u8]) { - let length = msg.len(); - let nbuf = self.nbuf; - debug_assert!(nbuf < BUFFER_SIZE); - debug_assert!(nbuf + length >= BUFFER_SIZE); - - // Always copy first part of input into current element of buffer. - // This function should only be called when the write fills the buffer, - // so we know that there is enough input to fill the current element. - let valid_in_elem = nbuf % ELEM_SIZE; - let needed_in_elem = ELEM_SIZE - valid_in_elem; - - let src = msg.as_ptr(); - let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf); - copy_nonoverlapping_small(src, dst, needed_in_elem); - - // Process buffer. + unsafe { + let length = msg.len(); + let nbuf = self.nbuf; + debug_assert!(nbuf < BUFFER_SIZE); + debug_assert!(nbuf + length >= BUFFER_SIZE); + + // Always copy first part of input into current element of buffer. + // This function should only be called when the write fills the buffer, + // so we know that there is enough input to fill the current element. + let valid_in_elem = nbuf % ELEM_SIZE; + let needed_in_elem = ELEM_SIZE - valid_in_elem; + + let src = msg.as_ptr(); + let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf); + copy_nonoverlapping_small(src, dst, needed_in_elem); + + // Process buffer. + + // Using `nbuf / ELEM_SIZE + 1` rather than `(nbuf + needed_in_elem) / + // ELEM_SIZE` to show the compiler that this loop's upper bound is > 0. + // We know that is true, because last step ensured we have a full + // element in the buffer. + let last = nbuf / ELEM_SIZE + 1; + + for i in 0..last { + let elem = self.buf.get_unchecked(i).assume_init().to_le(); + self.state.v3 ^= elem; + Sip13Rounds::c_rounds(&mut self.state); + self.state.v0 ^= elem; + } - // Using `nbuf / ELEM_SIZE + 1` rather than `(nbuf + needed_in_elem) / - // ELEM_SIZE` to show the compiler that this loop's upper bound is > 0. - // We know that is true, because last step ensured we have a full - // element in the buffer. - let last = nbuf / ELEM_SIZE + 1; + // Process the remaining element-sized chunks of input. + let mut processed = needed_in_elem; + let input_left = length - processed; + let elems_left = input_left / ELEM_SIZE; + let extra_bytes_left = input_left % ELEM_SIZE; + + for _ in 0..elems_left { + let elem = (msg.as_ptr().add(processed) as *const u64).read_unaligned().to_le(); + self.state.v3 ^= elem; + Sip13Rounds::c_rounds(&mut self.state); + self.state.v0 ^= elem; + processed += ELEM_SIZE; + } - for i in 0..last { - let elem = self.buf.get_unchecked(i).assume_init().to_le(); - self.state.v3 ^= elem; - Sip13Rounds::c_rounds(&mut self.state); - self.state.v0 ^= elem; - } + // Copy remaining input into start of buffer. + let src = msg.as_ptr().add(processed); + let dst = self.buf.as_mut_ptr() as *mut u8; + copy_nonoverlapping_small(src, dst, extra_bytes_left); - // Process the remaining element-sized chunks of input. - let mut processed = needed_in_elem; - let input_left = length - processed; - let elems_left = input_left / ELEM_SIZE; - let extra_bytes_left = input_left % ELEM_SIZE; - - for _ in 0..elems_left { - let elem = (msg.as_ptr().add(processed) as *const u64).read_unaligned().to_le(); - self.state.v3 ^= elem; - Sip13Rounds::c_rounds(&mut self.state); - self.state.v0 ^= elem; - processed += ELEM_SIZE; + self.nbuf = extra_bytes_left; + self.processed += nbuf + processed; } - - // Copy remaining input into start of buffer. - let src = msg.as_ptr().add(processed); - let dst = self.buf.as_mut_ptr() as *mut u8; - copy_nonoverlapping_small(src, dst, extra_bytes_left); - - self.nbuf = extra_bytes_left; - self.processed += nbuf + processed; } #[inline] diff --git a/compiler/rustc_data_structures/src/sso/map.rs b/compiler/rustc_data_structures/src/sso/map.rs index 89b8c852649..99581ed2375 100644 --- a/compiler/rustc_data_structures/src/sso/map.rs +++ b/compiler/rustc_data_structures/src/sso/map.rs @@ -256,12 +256,9 @@ impl<K: Eq + Hash, V> SsoHashMap<K, V> { pub fn remove(&mut self, key: &K) -> Option<V> { match self { SsoHashMap::Array(array) => { - if let Some(index) = array.iter().position(|(k, _v)| k == key) { - Some(array.swap_remove(index).1) - } else { - None - } + array.iter().position(|(k, _v)| k == key).map(|index| array.swap_remove(index).1) } + SsoHashMap::Map(map) => map.remove(key), } } diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs index 3ed1de1bc3c..b2bd0bfe714 100644 --- a/compiler/rustc_data_structures/src/stable_hasher.rs +++ b/compiler/rustc_data_structures/src/stable_hasher.rs @@ -2,6 +2,7 @@ use crate::sip128::SipHasher128; use rustc_index::bit_set; use rustc_index::vec; use smallvec::SmallVec; +use std::fmt; use std::hash::{BuildHasher, Hash, Hasher}; use std::marker::PhantomData; use std::mem; @@ -9,6 +10,8 @@ use std::mem; #[cfg(test)] mod tests; +pub use crate::hashes::{Hash128, Hash64}; + /// When hashing something that ends up affecting properties like symbol names, /// we want these symbol names to be calculated independently of other factors /// like what architecture you're compiling *from*. @@ -20,8 +23,8 @@ pub struct StableHasher { state: SipHasher128, } -impl ::std::fmt::Debug for StableHasher { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl fmt::Debug for StableHasher { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?}", self.state) } } @@ -42,21 +45,6 @@ impl StableHasher { } } -impl StableHasherResult for u128 { - #[inline] - fn finish(hasher: StableHasher) -> Self { - let (_0, _1) = hasher.finalize(); - u128::from(_0) | (u128::from(_1) << 64) - } -} - -impl StableHasherResult for u64 { - #[inline] - fn finish(hasher: StableHasher) -> Self { - hasher.finalize().0 - } -} - impl StableHasher { #[inline] pub fn finalize(self) -> (u64, u64) { @@ -107,7 +95,8 @@ impl Hasher for StableHasher { #[inline] fn write_u128(&mut self, i: u128) { - self.state.write(&i.to_le_bytes()); + self.write_u64(i as u64); + self.write_u64((i >> 64) as u64); } #[inline] @@ -286,6 +275,9 @@ impl_stable_traits_for_trivial_type!(i128); impl_stable_traits_for_trivial_type!(char); impl_stable_traits_for_trivial_type!(()); +impl_stable_traits_for_trivial_type!(Hash64); +impl_stable_traits_for_trivial_type!(Hash128); + impl<CTX> HashStable<CTX> for ! { fn hash_stable(&self, _ctx: &mut CTX, _hasher: &mut StableHasher) { unreachable!() @@ -668,7 +660,7 @@ fn stable_hash_reduce<HCX, I, C, F>( .map(|value| { let mut hasher = StableHasher::new(); hash_function(&mut hasher, hcx, value); - hasher.finish::<u128>() + hasher.finish::<Hash128>() }) .reduce(|accum, value| accum.wrapping_add(value)); hash.hash_stable(hcx, hasher); diff --git a/compiler/rustc_data_structures/src/stable_hasher/tests.rs b/compiler/rustc_data_structures/src/stable_hasher/tests.rs index a98b1bc3626..c8921f6a778 100644 --- a/compiler/rustc_data_structures/src/stable_hasher/tests.rs +++ b/compiler/rustc_data_structures/src/stable_hasher/tests.rs @@ -72,7 +72,7 @@ fn test_hash_isize() { assert_eq!(h.finalize(), expected); } -fn hash<T: HashStable<()>>(t: &T) -> u128 { +fn hash<T: HashStable<()>>(t: &T) -> Hash128 { let mut h = StableHasher::new(); let ctx = &mut (); t.hash_stable(ctx, &mut h); diff --git a/compiler/rustc_data_structures/src/svh.rs b/compiler/rustc_data_structures/src/svh.rs index 61654b9e8f5..a3d2724fcdb 100644 --- a/compiler/rustc_data_structures/src/svh.rs +++ b/compiler/rustc_data_structures/src/svh.rs @@ -5,40 +5,30 @@ //! mismatches where we have two versions of the same crate that were //! compiled from distinct sources. -use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; +use crate::fingerprint::Fingerprint; use std::fmt; -use std::hash::{Hash, Hasher}; use crate::stable_hasher; -#[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Encodable, Decodable, Hash)] pub struct Svh { - hash: u64, + hash: Fingerprint, } impl Svh { /// Creates a new `Svh` given the hash. If you actually want to /// compute the SVH from some HIR, you want the `calculate_svh` /// function found in `rustc_incremental`. - pub fn new(hash: u64) -> Svh { + pub fn new(hash: Fingerprint) -> Svh { Svh { hash } } pub fn as_u64(&self) -> u64 { - self.hash + self.hash.to_smaller_hash().as_u64() } pub fn to_string(&self) -> String { - format!("{:016x}", self.hash) - } -} - -impl Hash for Svh { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.hash.to_le().hash(state); + format!("{:016x}", self.hash.to_smaller_hash()) } } @@ -48,18 +38,6 @@ impl fmt::Display for Svh { } } -impl<S: Encoder> Encodable<S> for Svh { - fn encode(&self, s: &mut S) { - s.emit_u64(self.as_u64().to_le()); - } -} - -impl<D: Decoder> Decodable<D> for Svh { - fn decode(d: &mut D) -> Svh { - Svh::new(u64::from_le(d.read_u64())) - } -} - impl<T> stable_hasher::HashStable<T> for Svh { #[inline] fn hash_stable(&self, ctx: &mut T, hasher: &mut stable_hasher::StableHasher) { diff --git a/compiler/rustc_data_structures/src/tagged_ptr.rs b/compiler/rustc_data_structures/src/tagged_ptr.rs index 651bc556c98..8568aac67c0 100644 --- a/compiler/rustc_data_structures/src/tagged_ptr.rs +++ b/compiler/rustc_data_structures/src/tagged_ptr.rs @@ -3,166 +3,262 @@ //! In order to utilize the pointer packing, you must have two types: a pointer, //! and a tag. //! -//! The pointer must implement the `Pointer` trait, with the primary requirement -//! being conversion to and from a usize. Note that the pointer must be -//! dereferenceable, so raw pointers generally cannot implement the `Pointer` -//! trait. This implies that the pointer must also be nonzero. +//! The pointer must implement the [`Pointer`] trait, with the primary +//! requirement being convertible to and from a raw pointer. Note that the +//! pointer must be dereferenceable, so raw pointers generally cannot implement +//! the [`Pointer`] trait. This implies that the pointer must also be non-null. //! -//! Many common pointer types already implement the `Pointer` trait. +//! Many common pointer types already implement the [`Pointer`] trait. //! -//! The tag must implement the `Tag` trait. We assert that the tag and `Pointer` -//! are compatible at compile time. +//! The tag must implement the [`Tag`] trait. +//! +//! We assert that the tag and the [`Pointer`] types are compatible at compile +//! time. -use std::mem::ManuallyDrop; use std::ops::Deref; +use std::ptr::NonNull; use std::rc::Rc; use std::sync::Arc; +use crate::aligned::Aligned; + mod copy; mod drop; pub use copy::CopyTaggedPtr; pub use drop::TaggedPtr; -/// This describes the pointer type encapsulated by TaggedPtr. +/// This describes the pointer type encapsulated by [`TaggedPtr`] and +/// [`CopyTaggedPtr`]. /// /// # Safety /// -/// The usize returned from `into_usize` must be a valid, dereferenceable, -/// pointer to `<Self as Deref>::Target`. Note that pointers to `Pointee` must -/// be thin, even though `Pointee` may not be sized. +/// The pointer returned from [`into_ptr`] must be a [valid], pointer to +/// [`<Self as Deref>::Target`]. /// -/// Note that the returned pointer from `into_usize` should be castable to `&mut -/// <Self as Deref>::Target` if `Pointer: DerefMut`. +/// Note that if `Self` implements [`DerefMut`] the pointer returned from +/// [`into_ptr`] must be valid for writes (and thus calling [`NonNull::as_mut`] +/// on it must be safe). /// -/// The BITS constant must be correct. At least `BITS` bits, least-significant, -/// must be zero on all returned pointers from `into_usize`. +/// The [`BITS`] constant must be correct. [`BITS`] least-significant bits, +/// must be zero on all pointers returned from [`into_ptr`]. /// -/// For example, if the alignment of `Pointee` is 2, then `BITS` should be 1. +/// For example, if the alignment of [`Self::Target`] is 2, then `BITS` should be 1. +/// +/// [`BITS`]: Pointer::BITS +/// [`into_ptr`]: Pointer::into_ptr +/// [valid]: std::ptr#safety +/// [`<Self as Deref>::Target`]: Deref::Target +/// [`Self::Target`]: Deref::Target +/// [`DerefMut`]: std::ops::DerefMut pub unsafe trait Pointer: Deref { + /// Number of unused (always zero) **least-significant bits** in this + /// pointer, usually related to the pointees alignment. + /// + /// For example if [`BITS`] = `2`, then given `ptr = Self::into_ptr(..)`, + /// `ptr.addr() & 0b11 == 0` must be true. + /// /// Most likely the value you want to use here is the following, unless - /// your Pointee type is unsized (e.g., `ty::List<T>` in rustc) in which - /// case you'll need to manually figure out what the right type to pass to - /// align_of is. + /// your [`Self::Target`] type is unsized (e.g., `ty::List<T>` in rustc) + /// or your pointer is over/under aligned, in which case you'll need to + /// manually figure out what the right type to pass to [`bits_for`] is, or + /// what the value to set here. /// - /// ```ignore UNSOLVED (what to do about the Self) + /// ```rust /// # use std::ops::Deref; - /// std::mem::align_of::<<Self as Deref>::Target>().trailing_zeros() as usize; + /// # use rustc_data_structures::tagged_ptr::bits_for; + /// # struct T; + /// # impl Deref for T { type Target = u8; fn deref(&self) -> &u8 { &0 } } + /// # impl T { + /// const BITS: u32 = bits_for::<<Self as Deref>::Target>(); + /// # } /// ``` - const BITS: usize; - fn into_usize(self) -> usize; + /// + /// [`BITS`]: Pointer::BITS + /// [`Self::Target`]: Deref::Target + const BITS: u32; - /// # Safety + /// Turns this pointer into a raw, non-null pointer. + /// + /// The inverse of this function is [`from_ptr`]. /// - /// The passed `ptr` must be returned from `into_usize`. + /// This function guarantees that the least-significant [`Self::BITS`] bits + /// are zero. /// - /// This acts as `ptr::read` semantically, it should not be called more than - /// once on non-`Copy` `Pointer`s. - unsafe fn from_usize(ptr: usize) -> Self; + /// [`from_ptr`]: Pointer::from_ptr + /// [`Self::BITS`]: Pointer::BITS + fn into_ptr(self) -> NonNull<Self::Target>; - /// This provides a reference to the `Pointer` itself, rather than the - /// `Deref::Target`. It is used for cases where we want to call methods that - /// may be implement differently for the Pointer than the Pointee (e.g., - /// `Rc::clone` vs cloning the inner value). + /// Re-creates the original pointer, from a raw pointer returned by [`into_ptr`]. /// /// # Safety /// - /// The passed `ptr` must be returned from `into_usize`. - unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R; + /// The passed `ptr` must be returned from [`into_ptr`]. + /// + /// This acts as [`ptr::read::<Self>()`] semantically, it should not be called more than + /// once on non-[`Copy`] `Pointer`s. + /// + /// [`into_ptr`]: Pointer::into_ptr + /// [`ptr::read::<Self>()`]: std::ptr::read + unsafe fn from_ptr(ptr: NonNull<Self::Target>) -> Self; } -/// This describes tags that the `TaggedPtr` struct can hold. +/// This describes tags that the [`TaggedPtr`] struct can hold. /// /// # Safety /// -/// The BITS constant must be correct. +/// The [`BITS`] constant must be correct. +/// +/// No more than [`BITS`] least-significant bits may be set in the returned usize. /// -/// No more than `BITS` least significant bits may be set in the returned usize. +/// [`BITS`]: Tag::BITS pub unsafe trait Tag: Copy { - const BITS: usize; + /// Number of least-significant bits in the return value of [`into_usize`] + /// which may be non-zero. In other words this is the bit width of the + /// value. + /// + /// [`into_usize`]: Tag::into_usize + const BITS: u32; + /// Turns this tag into an integer. + /// + /// The inverse of this function is [`from_usize`]. + /// + /// This function guarantees that only the least-significant [`Self::BITS`] + /// bits can be non-zero. + /// + /// [`from_usize`]: Tag::from_usize + /// [`Self::BITS`]: Tag::BITS fn into_usize(self) -> usize; + /// Re-creates the tag from the integer returned by [`into_usize`]. + /// /// # Safety /// - /// The passed `tag` must be returned from `into_usize`. + /// The passed `tag` must be returned from [`into_usize`]. + /// + /// [`into_usize`]: Tag::into_usize unsafe fn from_usize(tag: usize) -> Self; } -unsafe impl<T> Pointer for Box<T> { - const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize; +unsafe impl<T: ?Sized + Aligned> Pointer for Box<T> { + const BITS: u32 = bits_for::<Self::Target>(); + #[inline] - fn into_usize(self) -> usize { - Box::into_raw(self) as usize + fn into_ptr(self) -> NonNull<T> { + // Safety: pointers from `Box::into_raw` are valid & non-null + unsafe { NonNull::new_unchecked(Box::into_raw(self)) } } + #[inline] - unsafe fn from_usize(ptr: usize) -> Self { - Box::from_raw(ptr as *mut T) - } - unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R { - let raw = ManuallyDrop::new(Self::from_usize(ptr)); - f(&raw) + unsafe fn from_ptr(ptr: NonNull<T>) -> Self { + // Safety: `ptr` comes from `into_ptr` which calls `Box::into_raw` + unsafe { Box::from_raw(ptr.as_ptr()) } } } -unsafe impl<T> Pointer for Rc<T> { - const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize; +unsafe impl<T: ?Sized + Aligned> Pointer for Rc<T> { + const BITS: u32 = bits_for::<Self::Target>(); + #[inline] - fn into_usize(self) -> usize { - Rc::into_raw(self) as usize + fn into_ptr(self) -> NonNull<T> { + // Safety: pointers from `Rc::into_raw` are valid & non-null + unsafe { NonNull::new_unchecked(Rc::into_raw(self).cast_mut()) } + } + + #[inline] + unsafe fn from_ptr(ptr: NonNull<T>) -> Self { + // Safety: `ptr` comes from `into_ptr` which calls `Rc::into_raw` + unsafe { Rc::from_raw(ptr.as_ptr()) } } +} + +unsafe impl<T: ?Sized + Aligned> Pointer for Arc<T> { + const BITS: u32 = bits_for::<Self::Target>(); + #[inline] - unsafe fn from_usize(ptr: usize) -> Self { - Rc::from_raw(ptr as *const T) + fn into_ptr(self) -> NonNull<T> { + // Safety: pointers from `Arc::into_raw` are valid & non-null + unsafe { NonNull::new_unchecked(Arc::into_raw(self).cast_mut()) } } - unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R { - let raw = ManuallyDrop::new(Self::from_usize(ptr)); - f(&raw) + + #[inline] + unsafe fn from_ptr(ptr: NonNull<T>) -> Self { + // Safety: `ptr` comes from `into_ptr` which calls `Arc::into_raw` + unsafe { Arc::from_raw(ptr.as_ptr()) } } } -unsafe impl<T> Pointer for Arc<T> { - const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize; +unsafe impl<'a, T: 'a + ?Sized + Aligned> Pointer for &'a T { + const BITS: u32 = bits_for::<Self::Target>(); + #[inline] - fn into_usize(self) -> usize { - Arc::into_raw(self) as usize + fn into_ptr(self) -> NonNull<T> { + NonNull::from(self) } + #[inline] - unsafe fn from_usize(ptr: usize) -> Self { - Arc::from_raw(ptr as *const T) - } - unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R { - let raw = ManuallyDrop::new(Self::from_usize(ptr)); - f(&raw) + unsafe fn from_ptr(ptr: NonNull<T>) -> Self { + // Safety: + // `ptr` comes from `into_ptr` which gets the pointer from a reference + unsafe { ptr.as_ref() } } } -unsafe impl<'a, T: 'a> Pointer for &'a T { - const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize; +unsafe impl<'a, T: 'a + ?Sized + Aligned> Pointer for &'a mut T { + const BITS: u32 = bits_for::<Self::Target>(); + #[inline] - fn into_usize(self) -> usize { - self as *const T as usize + fn into_ptr(self) -> NonNull<T> { + NonNull::from(self) } + #[inline] - unsafe fn from_usize(ptr: usize) -> Self { - &*(ptr as *const T) - } - unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R { - f(&*(&ptr as *const usize as *const Self)) + unsafe fn from_ptr(mut ptr: NonNull<T>) -> Self { + // Safety: + // `ptr` comes from `into_ptr` which gets the pointer from a reference + unsafe { ptr.as_mut() } } } -unsafe impl<'a, T: 'a> Pointer for &'a mut T { - const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize; - #[inline] +/// Returns the number of bits available for use for tags in a pointer to `T` +/// (this is based on `T`'s alignment). +pub const fn bits_for<T: ?Sized + Aligned>() -> u32 { + crate::aligned::align_of::<T>().as_nonzero().trailing_zeros() +} + +/// A tag type used in [`CopyTaggedPtr`] and [`TaggedPtr`] tests. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[cfg(test)] +enum Tag2 { + B00 = 0b00, + B01 = 0b01, + B10 = 0b10, + B11 = 0b11, +} + +#[cfg(test)] +unsafe impl Tag for Tag2 { + const BITS: u32 = 2; + fn into_usize(self) -> usize { - self as *mut T as usize + self as _ } - #[inline] - unsafe fn from_usize(ptr: usize) -> Self { - &mut *(ptr as *mut T) + + unsafe fn from_usize(tag: usize) -> Self { + match tag { + 0b00 => Tag2::B00, + 0b01 => Tag2::B01, + 0b10 => Tag2::B10, + 0b11 => Tag2::B11, + _ => unreachable!(), + } } - unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R { - f(&*(&ptr as *const usize as *const Self)) +} + +#[cfg(test)] +impl<HCX> crate::stable_hasher::HashStable<HCX> for Tag2 { + fn hash_stable(&self, hcx: &mut HCX, hasher: &mut crate::stable_hasher::StableHasher) { + (*self as u8).hash_stable(hcx, hasher); } } diff --git a/compiler/rustc_data_structures/src/tagged_ptr/copy.rs b/compiler/rustc_data_structures/src/tagged_ptr/copy.rs index e1d3e0bd35a..691e92f196a 100644 --- a/compiler/rustc_data_structures/src/tagged_ptr/copy.rs +++ b/compiler/rustc_data_structures/src/tagged_ptr/copy.rs @@ -1,78 +1,92 @@ use super::{Pointer, Tag}; use crate::stable_hasher::{HashStable, StableHasher}; use std::fmt; +use std::hash::{Hash, Hasher}; use std::marker::PhantomData; +use std::mem::ManuallyDrop; use std::num::NonZeroUsize; +use std::ops::{Deref, DerefMut}; +use std::ptr::NonNull; -/// A `Copy` TaggedPtr. +/// A [`Copy`] tagged pointer. /// -/// You should use this instead of the `TaggedPtr` type in all cases where -/// `P: Copy`. +/// This is essentially `{ pointer: P, tag: T }` packed in a single pointer. +/// +/// You should use this instead of the [`TaggedPtr`] type in all cases where +/// `P` implements [`Copy`]. /// /// If `COMPARE_PACKED` is true, then the pointers will be compared and hashed without -/// unpacking. Otherwise we don't implement PartialEq/Eq/Hash; if you want that, -/// wrap the TaggedPtr. +/// unpacking. Otherwise we don't implement [`PartialEq`], [`Eq`] and [`Hash`]; +/// if you want that, wrap the [`CopyTaggedPtr`]. +/// +/// [`TaggedPtr`]: crate::tagged_ptr::TaggedPtr pub struct CopyTaggedPtr<P, T, const COMPARE_PACKED: bool> where P: Pointer, T: Tag, { - packed: NonZeroUsize, - data: PhantomData<(P, T)>, -} - -impl<P, T, const COMPARE_PACKED: bool> Copy for CopyTaggedPtr<P, T, COMPARE_PACKED> -where - P: Pointer, - T: Tag, - P: Copy, -{ -} - -impl<P, T, const COMPARE_PACKED: bool> Clone for CopyTaggedPtr<P, T, COMPARE_PACKED> -where - P: Pointer, - T: Tag, - P: Copy, -{ - fn clone(&self) -> Self { - *self - } + /// This is semantically a pair of `pointer: P` and `tag: T` fields, + /// however we pack them in a single pointer, to save space. + /// + /// We pack the tag into the **most**-significant bits of the pointer to + /// ease retrieval of the value. A left shift is a multiplication and + /// those are embeddable in instruction encoding, for example: + /// + /// ```asm + /// // (<https://godbolt.org/z/jqcYPWEr3>) + /// example::shift_read3: + /// mov eax, dword ptr [8*rdi] + /// ret + /// + /// example::mask_read3: + /// and rdi, -8 + /// mov eax, dword ptr [rdi] + /// ret + /// ``` + /// + /// This is ASM outputted by rustc for reads of values behind tagged + /// pointers for different approaches of tagging: + /// - `shift_read3` uses `<< 3` (the tag is in the most-significant bits) + /// - `mask_read3` uses `& !0b111` (the tag is in the least-significant bits) + /// + /// The shift approach thus produces less instructions and is likely faster + /// (see <https://godbolt.org/z/Y913sMdWb>). + /// + /// Encoding diagram: + /// ```text + /// [ packed.addr ] + /// [ tag ] [ pointer.addr >> T::BITS ] <-- usize::BITS - T::BITS bits + /// ^ + /// | + /// T::BITS bits + /// ``` + /// + /// The tag can be retrieved by `packed.addr() >> T::BITS` and the pointer + /// can be retrieved by `packed.map_addr(|addr| addr << T::BITS)`. + packed: NonNull<P::Target>, + tag_ghost: PhantomData<T>, } -// We pack the tag into the *upper* bits of the pointer to ease retrieval of the -// value; a left shift is a multiplication and those are embeddable in -// instruction encoding. -impl<P, T, const COMPARE_PACKED: bool> CopyTaggedPtr<P, T, COMPARE_PACKED> +// Note that even though `CopyTaggedPtr` is only really expected to work with +// `P: Copy`, can't add `P: Copy` bound, because `CopyTaggedPtr` is used in the +// `TaggedPtr`'s implementation. +impl<P, T, const CP: bool> CopyTaggedPtr<P, T, CP> where P: Pointer, T: Tag, { - const TAG_BIT_SHIFT: usize = usize::BITS as usize - T::BITS; - const ASSERTION: () = { - assert!(T::BITS <= P::BITS); - // Used for the transmute_copy's below - assert!(std::mem::size_of::<&P::Target>() == std::mem::size_of::<usize>()); - }; - + /// Tags `pointer` with `tag`. + /// + /// Note that this leaks `pointer`: it won't be dropped when + /// `CopyTaggedPtr` is dropped. If you have a pointer with a significant + /// drop, use [`TaggedPtr`] instead. + /// + /// [`TaggedPtr`]: crate::tagged_ptr::TaggedPtr pub fn new(pointer: P, tag: T) -> Self { - // Trigger assert! - let () = Self::ASSERTION; - let packed_tag = tag.into_usize() << Self::TAG_BIT_SHIFT; - - Self { - // SAFETY: We know that the pointer is non-null, as it must be - // dereferenceable per `Pointer` safety contract. - packed: unsafe { - NonZeroUsize::new_unchecked((P::into_usize(pointer) >> T::BITS) | packed_tag) - }, - data: PhantomData, - } + Self { packed: Self::pack(P::into_ptr(pointer), tag), tag_ghost: PhantomData } } - pub(super) fn pointer_raw(&self) -> usize { - self.packed.get() << T::BITS - } + /// Retrieves the pointer. pub fn pointer(self) -> P where P: Copy, @@ -81,66 +95,138 @@ where // // Note that this isn't going to double-drop or anything because we have // P: Copy - unsafe { P::from_usize(self.pointer_raw()) } - } - pub fn pointer_ref(&self) -> &P::Target { - // SAFETY: pointer_raw returns the original pointer - unsafe { std::mem::transmute_copy(&self.pointer_raw()) } - } - pub fn pointer_mut(&mut self) -> &mut P::Target - where - P: std::ops::DerefMut, - { - // SAFETY: pointer_raw returns the original pointer - unsafe { std::mem::transmute_copy(&self.pointer_raw()) } + unsafe { P::from_ptr(self.pointer_raw()) } } + + /// Retrieves the tag. #[inline] pub fn tag(&self) -> T { - unsafe { T::from_usize(self.packed.get() >> Self::TAG_BIT_SHIFT) } + // Unpack the tag, according to the `self.packed` encoding scheme + let tag = self.packed.addr().get() >> Self::TAG_BIT_SHIFT; + + // Safety: + // The shift retrieves the original value from `T::into_usize`, + // satisfying `T::from_usize`'s preconditions. + unsafe { T::from_usize(tag) } } + + /// Sets the tag to a new value. #[inline] pub fn set_tag(&mut self, tag: T) { - let mut packed = self.packed.get(); - let new_tag = T::into_usize(tag) << Self::TAG_BIT_SHIFT; - let tag_mask = (1 << T::BITS) - 1; - packed &= !(tag_mask << Self::TAG_BIT_SHIFT); - packed |= new_tag; - self.packed = unsafe { NonZeroUsize::new_unchecked(packed) }; + self.packed = Self::pack(self.pointer_raw(), tag); + } + + const TAG_BIT_SHIFT: u32 = usize::BITS - T::BITS; + const ASSERTION: () = { assert!(T::BITS <= P::BITS) }; + + /// Pack pointer `ptr` that comes from [`P::into_ptr`] with a `tag`, + /// according to `self.packed` encoding scheme. + /// + /// [`P::into_ptr`]: Pointer::into_ptr + fn pack(ptr: NonNull<P::Target>, tag: T) -> NonNull<P::Target> { + // Trigger assert! + let () = Self::ASSERTION; + + let packed_tag = tag.into_usize() << Self::TAG_BIT_SHIFT; + + ptr.map_addr(|addr| { + // Safety: + // - The pointer is `NonNull` => it's address is `NonZeroUsize` + // - `P::BITS` least significant bits are always zero (`Pointer` contract) + // - `T::BITS <= P::BITS` (from `Self::ASSERTION`) + // + // Thus `addr >> T::BITS` is guaranteed to be non-zero. + // + // `{non_zero} | packed_tag` can't make the value zero. + + let packed = (addr.get() >> T::BITS) | packed_tag; + unsafe { NonZeroUsize::new_unchecked(packed) } + }) + } + + /// Retrieves the original raw pointer from `self.packed`. + pub(super) fn pointer_raw(&self) -> NonNull<P::Target> { + self.packed.map_addr(|addr| unsafe { NonZeroUsize::new_unchecked(addr.get() << T::BITS) }) + } + + /// This provides a reference to the `P` pointer itself, rather than the + /// `Deref::Target`. It is used for cases where we want to call methods + /// that may be implement differently for the Pointer than the Pointee + /// (e.g., `Rc::clone` vs cloning the inner value). + pub(super) fn with_pointer_ref<R>(&self, f: impl FnOnce(&P) -> R) -> R { + // Safety: + // - `self.raw.pointer_raw()` is originally returned from `P::into_ptr` + // and as such is valid for `P::from_ptr`. + // - This also allows us to not care whatever `f` panics or not. + // - Even though we create a copy of the pointer, we store it inside + // `ManuallyDrop` and only access it by-ref, so we don't double-drop. + // + // Semantically this is just `f(&self.pointer)` (where `self.pointer` + // is non-packed original pointer). + // + // Note that even though `CopyTaggedPtr` is only really expected to + // work with `P: Copy`, we have to assume `P: ?Copy`, because + // `CopyTaggedPtr` is used in the `TaggedPtr`'s implementation. + let ptr = unsafe { ManuallyDrop::new(P::from_ptr(self.pointer_raw())) }; + f(&ptr) } } -impl<P, T, const COMPARE_PACKED: bool> std::ops::Deref for CopyTaggedPtr<P, T, COMPARE_PACKED> +impl<P, T, const CP: bool> Copy for CopyTaggedPtr<P, T, CP> +where + P: Pointer + Copy, + T: Tag, +{ +} + +impl<P, T, const CP: bool> Clone for CopyTaggedPtr<P, T, CP> +where + P: Pointer + Copy, + T: Tag, +{ + fn clone(&self) -> Self { + *self + } +} + +impl<P, T, const CP: bool> Deref for CopyTaggedPtr<P, T, CP> where P: Pointer, T: Tag, { type Target = P::Target; + fn deref(&self) -> &Self::Target { - self.pointer_ref() + // Safety: + // `pointer_raw` returns the original pointer from `P::into_ptr` which, + // by the `Pointer`'s contract, must be valid. + unsafe { self.pointer_raw().as_ref() } } } -impl<P, T, const COMPARE_PACKED: bool> std::ops::DerefMut for CopyTaggedPtr<P, T, COMPARE_PACKED> +impl<P, T, const CP: bool> DerefMut for CopyTaggedPtr<P, T, CP> where - P: Pointer + std::ops::DerefMut, + P: Pointer + DerefMut, T: Tag, { fn deref_mut(&mut self) -> &mut Self::Target { - self.pointer_mut() + // Safety: + // `pointer_raw` returns the original pointer from `P::into_ptr` which, + // by the `Pointer`'s contract, must be valid for writes if + // `P: DerefMut`. + unsafe { self.pointer_raw().as_mut() } } } -impl<P, T, const COMPARE_PACKED: bool> fmt::Debug for CopyTaggedPtr<P, T, COMPARE_PACKED> +impl<P, T, const CP: bool> fmt::Debug for CopyTaggedPtr<P, T, CP> where - P: Pointer, - P::Target: fmt::Debug, + P: Pointer + fmt::Debug, T: Tag + fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("CopyTaggedPtr") - .field("pointer", &self.pointer_ref()) - .field("tag", &self.tag()) - .finish() + self.with_pointer_ref(|ptr| { + f.debug_struct("CopyTaggedPtr").field("pointer", ptr).field("tag", &self.tag()).finish() + }) } } @@ -161,25 +247,73 @@ where { } -impl<P, T> std::hash::Hash for CopyTaggedPtr<P, T, true> +impl<P, T> Hash for CopyTaggedPtr<P, T, true> where P: Pointer, T: Tag, { - fn hash<H: std::hash::Hasher>(&self, state: &mut H) { + fn hash<H: Hasher>(&self, state: &mut H) { self.packed.hash(state); } } -impl<P, T, HCX, const COMPARE_PACKED: bool> HashStable<HCX> for CopyTaggedPtr<P, T, COMPARE_PACKED> +impl<P, T, HCX, const CP: bool> HashStable<HCX> for CopyTaggedPtr<P, T, CP> where P: Pointer + HashStable<HCX>, T: Tag + HashStable<HCX>, { fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) { - unsafe { - Pointer::with_ref(self.pointer_raw(), |p: &P| p.hash_stable(hcx, hasher)); - } + self.with_pointer_ref(|ptr| ptr.hash_stable(hcx, hasher)); self.tag().hash_stable(hcx, hasher); } } + +// Safety: +// `CopyTaggedPtr<P, T, ..>` is semantically just `{ ptr: P, tag: T }`, as such +// it's ok to implement `Sync` as long as `P: Sync, T: Sync` +unsafe impl<P, T, const CP: bool> Sync for CopyTaggedPtr<P, T, CP> +where + P: Sync + Pointer, + T: Sync + Tag, +{ +} + +// Safety: +// `CopyTaggedPtr<P, T, ..>` is semantically just `{ ptr: P, tag: T }`, as such +// it's ok to implement `Send` as long as `P: Send, T: Send` +unsafe impl<P, T, const CP: bool> Send for CopyTaggedPtr<P, T, CP> +where + P: Send + Pointer, + T: Send + Tag, +{ +} + +/// Test that `new` does not compile if there is not enough alignment for the +/// tag in the pointer. +/// +/// ```compile_fail,E0080 +/// use rustc_data_structures::tagged_ptr::{CopyTaggedPtr, Tag}; +/// +/// #[derive(Copy, Clone, Debug, PartialEq, Eq)] +/// enum Tag2 { B00 = 0b00, B01 = 0b01, B10 = 0b10, B11 = 0b11 }; +/// +/// unsafe impl Tag for Tag2 { +/// const BITS: u32 = 2; +/// +/// fn into_usize(self) -> usize { todo!() } +/// unsafe fn from_usize(tag: usize) -> Self { todo!() } +/// } +/// +/// let value = 12u16; +/// let reference = &value; +/// let tag = Tag2::B01; +/// +/// let _ptr = CopyTaggedPtr::<_, _, true>::new(reference, tag); +/// ``` +// For some reason miri does not get the compile error +// probably it `check`s instead of `build`ing? +#[cfg(not(miri))] +const _: () = (); + +#[cfg(test)] +mod tests; diff --git a/compiler/rustc_data_structures/src/tagged_ptr/copy/tests.rs b/compiler/rustc_data_structures/src/tagged_ptr/copy/tests.rs new file mode 100644 index 00000000000..bfcc2e603de --- /dev/null +++ b/compiler/rustc_data_structures/src/tagged_ptr/copy/tests.rs @@ -0,0 +1,50 @@ +use std::ptr; + +use crate::stable_hasher::{HashStable, StableHasher}; +use crate::tagged_ptr::{CopyTaggedPtr, Pointer, Tag, Tag2}; + +#[test] +fn smoke() { + let value = 12u32; + let reference = &value; + let tag = Tag2::B01; + + let ptr = tag_ptr(reference, tag); + + assert_eq!(ptr.tag(), tag); + assert_eq!(*ptr, 12); + assert!(ptr::eq(ptr.pointer(), reference)); + + let copy = ptr; + + let mut ptr = ptr; + ptr.set_tag(Tag2::B00); + assert_eq!(ptr.tag(), Tag2::B00); + + assert_eq!(copy.tag(), tag); + assert_eq!(*copy, 12); + assert!(ptr::eq(copy.pointer(), reference)); +} + +#[test] +fn stable_hash_hashes_as_tuple() { + let hash_packed = { + let mut hasher = StableHasher::new(); + tag_ptr(&12, Tag2::B11).hash_stable(&mut (), &mut hasher); + + hasher.finalize() + }; + + let hash_tupled = { + let mut hasher = StableHasher::new(); + (&12, Tag2::B11).hash_stable(&mut (), &mut hasher); + hasher.finalize() + }; + + assert_eq!(hash_packed, hash_tupled); +} + +/// Helper to create tagged pointers without specifying `COMPARE_PACKED` if it does not matter. +fn tag_ptr<P: Pointer, T: Tag>(ptr: P, tag: T) -> CopyTaggedPtr<P, T, true> { + CopyTaggedPtr::new(ptr, tag) +} diff --git a/compiler/rustc_data_structures/src/tagged_ptr/drop.rs b/compiler/rustc_data_structures/src/tagged_ptr/drop.rs index b0315c93d93..d418c06b7eb 100644 --- a/compiler/rustc_data_structures/src/tagged_ptr/drop.rs +++ b/compiler/rustc_data_structures/src/tagged_ptr/drop.rs @@ -1,14 +1,21 @@ -use super::{Pointer, Tag}; -use crate::stable_hasher::{HashStable, StableHasher}; use std::fmt; +use std::hash::{Hash, Hasher}; +use std::ops::{Deref, DerefMut}; use super::CopyTaggedPtr; +use super::{Pointer, Tag}; +use crate::stable_hasher::{HashStable, StableHasher}; -/// A TaggedPtr implementing `Drop`. +/// A tagged pointer that supports pointers that implement [`Drop`]. +/// +/// This is essentially `{ pointer: P, tag: T }` packed in a single pointer. +/// +/// You should use [`CopyTaggedPtr`] instead of the this type in all cases +/// where `P` implements [`Copy`]. /// /// If `COMPARE_PACKED` is true, then the pointers will be compared and hashed without -/// unpacking. Otherwise we don't implement PartialEq/Eq/Hash; if you want that, -/// wrap the TaggedPtr. +/// unpacking. Otherwise we don't implement [`PartialEq`], [`Eq`] and [`Hash`]; +/// if you want that, wrap the [`TaggedPtr`]. pub struct TaggedPtr<P, T, const COMPARE_PACKED: bool> where P: Pointer, @@ -17,58 +24,61 @@ where raw: CopyTaggedPtr<P, T, COMPARE_PACKED>, } -impl<P, T, const COMPARE_PACKED: bool> Clone for TaggedPtr<P, T, COMPARE_PACKED> -where - P: Pointer + Clone, - T: Tag, -{ - fn clone(&self) -> Self { - unsafe { Self::new(P::with_ref(self.raw.pointer_raw(), |p| p.clone()), self.raw.tag()) } - } -} - -// We pack the tag into the *upper* bits of the pointer to ease retrieval of the -// value; a right shift is a multiplication and those are embeddable in -// instruction encoding. -impl<P, T, const COMPARE_PACKED: bool> TaggedPtr<P, T, COMPARE_PACKED> +impl<P, T, const CP: bool> TaggedPtr<P, T, CP> where P: Pointer, T: Tag, { + /// Tags `pointer` with `tag`. pub fn new(pointer: P, tag: T) -> Self { TaggedPtr { raw: CopyTaggedPtr::new(pointer, tag) } } - pub fn pointer_ref(&self) -> &P::Target { - self.raw.pointer_ref() - } + /// Retrieves the tag. pub fn tag(&self) -> T { self.raw.tag() } + + /// Sets the tag to a new value. + pub fn set_tag(&mut self, tag: T) { + self.raw.set_tag(tag) + } } -impl<P, T, const COMPARE_PACKED: bool> std::ops::Deref for TaggedPtr<P, T, COMPARE_PACKED> +impl<P, T, const CP: bool> Clone for TaggedPtr<P, T, CP> +where + P: Pointer + Clone, + T: Tag, +{ + fn clone(&self) -> Self { + let ptr = self.raw.with_pointer_ref(P::clone); + + Self::new(ptr, self.tag()) + } +} + +impl<P, T, const CP: bool> Deref for TaggedPtr<P, T, CP> where P: Pointer, T: Tag, { type Target = P::Target; fn deref(&self) -> &Self::Target { - self.raw.pointer_ref() + self.raw.deref() } } -impl<P, T, const COMPARE_PACKED: bool> std::ops::DerefMut for TaggedPtr<P, T, COMPARE_PACKED> +impl<P, T, const CP: bool> DerefMut for TaggedPtr<P, T, CP> where - P: Pointer + std::ops::DerefMut, + P: Pointer + DerefMut, T: Tag, { fn deref_mut(&mut self) -> &mut Self::Target { - self.raw.pointer_mut() + self.raw.deref_mut() } } -impl<P, T, const COMPARE_PACKED: bool> Drop for TaggedPtr<P, T, COMPARE_PACKED> +impl<P, T, const CP: bool> Drop for TaggedPtr<P, T, CP> where P: Pointer, T: Tag, @@ -76,22 +86,20 @@ where fn drop(&mut self) { // No need to drop the tag, as it's Copy unsafe { - drop(P::from_usize(self.raw.pointer_raw())); + drop(P::from_ptr(self.raw.pointer_raw())); } } } -impl<P, T, const COMPARE_PACKED: bool> fmt::Debug for TaggedPtr<P, T, COMPARE_PACKED> +impl<P, T, const CP: bool> fmt::Debug for TaggedPtr<P, T, CP> where - P: Pointer, - P::Target: fmt::Debug, + P: Pointer + fmt::Debug, T: Tag + fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TaggedPtr") - .field("pointer", &self.pointer_ref()) - .field("tag", &self.tag()) - .finish() + self.raw.with_pointer_ref(|ptr| { + f.debug_struct("TaggedPtr").field("pointer", ptr).field("tag", &self.tag()).finish() + }) } } @@ -112,17 +120,17 @@ where { } -impl<P, T> std::hash::Hash for TaggedPtr<P, T, true> +impl<P, T> Hash for TaggedPtr<P, T, true> where P: Pointer, T: Tag, { - fn hash<H: std::hash::Hasher>(&self, state: &mut H) { + fn hash<H: Hasher>(&self, state: &mut H) { self.raw.hash(state); } } -impl<P, T, HCX, const COMPARE_PACKED: bool> HashStable<HCX> for TaggedPtr<P, T, COMPARE_PACKED> +impl<P, T, HCX, const CP: bool> HashStable<HCX> for TaggedPtr<P, T, CP> where P: Pointer + HashStable<HCX>, T: Tag + HashStable<HCX>, @@ -131,3 +139,33 @@ where self.raw.hash_stable(hcx, hasher); } } + +/// Test that `new` does not compile if there is not enough alignment for the +/// tag in the pointer. +/// +/// ```compile_fail,E0080 +/// use rustc_data_structures::tagged_ptr::{TaggedPtr, Tag}; +/// +/// #[derive(Copy, Clone, Debug, PartialEq, Eq)] +/// enum Tag2 { B00 = 0b00, B01 = 0b01, B10 = 0b10, B11 = 0b11 }; +/// +/// unsafe impl Tag for Tag2 { +/// const BITS: u32 = 2; +/// +/// fn into_usize(self) -> usize { todo!() } +/// unsafe fn from_usize(tag: usize) -> Self { todo!() } +/// } +/// +/// let value = 12u16; +/// let reference = &value; +/// let tag = Tag2::B01; +/// +/// let _ptr = TaggedPtr::<_, _, true>::new(reference, tag); +/// ``` +// For some reason miri does not get the compile error +// probably it `check`s instead of `build`ing? +#[cfg(not(miri))] +const _: () = (); + +#[cfg(test)] +mod tests; diff --git a/compiler/rustc_data_structures/src/tagged_ptr/drop/tests.rs b/compiler/rustc_data_structures/src/tagged_ptr/drop/tests.rs new file mode 100644 index 00000000000..2c17d678d3a --- /dev/null +++ b/compiler/rustc_data_structures/src/tagged_ptr/drop/tests.rs @@ -0,0 +1,71 @@ +use std::{ptr, sync::Arc}; + +use crate::tagged_ptr::{Pointer, Tag, Tag2, TaggedPtr}; + +#[test] +fn smoke() { + let value = 12u32; + let reference = &value; + let tag = Tag2::B01; + + let ptr = tag_ptr(reference, tag); + + assert_eq!(ptr.tag(), tag); + assert_eq!(*ptr, 12); + + let clone = ptr.clone(); + assert_eq!(clone.tag(), tag); + assert_eq!(*clone, 12); + + let mut ptr = ptr; + ptr.set_tag(Tag2::B00); + assert_eq!(ptr.tag(), Tag2::B00); + + assert_eq!(clone.tag(), tag); + assert_eq!(*clone, 12); + assert!(ptr::eq(&*ptr, &*clone)) +} + +#[test] +fn boxed() { + let value = 12u32; + let boxed = Box::new(value); + let tag = Tag2::B01; + + let ptr = tag_ptr(boxed, tag); + + assert_eq!(ptr.tag(), tag); + assert_eq!(*ptr, 12); + + let clone = ptr.clone(); + assert_eq!(clone.tag(), tag); + assert_eq!(*clone, 12); + + let mut ptr = ptr; + ptr.set_tag(Tag2::B00); + assert_eq!(ptr.tag(), Tag2::B00); + + assert_eq!(clone.tag(), tag); + assert_eq!(*clone, 12); + assert!(!ptr::eq(&*ptr, &*clone)) +} + +#[test] +fn arclones() { + let value = 12u32; + let arc = Arc::new(value); + let tag = Tag2::B01; + + let ptr = tag_ptr(arc, tag); + + assert_eq!(ptr.tag(), tag); + assert_eq!(*ptr, 12); + + let clone = ptr.clone(); + assert!(ptr::eq(&*ptr, &*clone)) +} + +/// Helper to create tagged pointers without specifying `COMPARE_PACKED` if it does not matter. +fn tag_ptr<P: Pointer, T: Tag>(ptr: P, tag: T) -> TaggedPtr<P, T, true> { + TaggedPtr::new(ptr, tag) +} diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index 73a1f79a020..cc4c5a0cacd 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -18,6 +18,7 @@ rustc_const_eval = { path = "../rustc_const_eval" } rustc_error_messages = { path = "../rustc_error_messages" } rustc_expand = { path = "../rustc_expand" } rustc_hir_typeck = { path = "../rustc_hir_typeck" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_incremental = { path = "../rustc_incremental" } rustc_infer = { path = "../rustc_infer" } rustc_mir_build = { path = "../rustc_mir_build" } diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index b9f0e756e65..1a80b4fc314 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -28,10 +28,10 @@ use rustc_errors::{ DiagnosticMessage, ErrorGuaranteed, PResult, SubdiagnosticMessage, TerminalUrl, }; use rustc_feature::find_gated_cfg; +use rustc_fluent_macro::fluent_messages; use rustc_interface::util::{self, collect_crate_types, get_codegen_backend}; use rustc_interface::{interface, Queries}; use rustc_lint::LintStore; -use rustc_macros::fluent_messages; use rustc_metadata::locator; use rustc_session::config::{nightly_options, CG_OPTIONS, Z_OPTIONS}; use rustc_session::config::{ErrorOutputType, Input, OutputType, PrintRequest, TrimmedDefPaths}; diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs index 446c6832cb7..ee64b18d3f6 100644 --- a/compiler/rustc_driver_impl/src/pretty.rs +++ b/compiler/rustc_driver_impl/src/pretty.rs @@ -488,12 +488,7 @@ fn print_with_analysis(tcx: TyCtxt<'_>, ppm: PpMode) -> Result<(), ErrorGuarante abort_on_err(rustc_hir_analysis::check_crate(tcx), tcx.sess); debug!("pretty printing THIR tree"); for did in tcx.hir().body_owners() { - let _ = writeln!( - out, - "{:?}:\n{}\n", - did, - tcx.thir_tree(ty::WithOptConstParam::unknown(did)) - ); + let _ = writeln!(out, "{:?}:\n{}\n", did, tcx.thir_tree(did)); } out } @@ -503,12 +498,7 @@ fn print_with_analysis(tcx: TyCtxt<'_>, ppm: PpMode) -> Result<(), ErrorGuarante abort_on_err(rustc_hir_analysis::check_crate(tcx), tcx.sess); debug!("pretty printing THIR flat"); for did in tcx.hir().body_owners() { - let _ = writeln!( - out, - "{:?}:\n{}\n", - did, - tcx.thir_flat(ty::WithOptConstParam::unknown(did)) - ); + let _ = writeln!(out, "{:?}:\n{}\n", did, tcx.thir_flat(did)); } out } diff --git a/compiler/rustc_error_codes/src/error_codes/E0026.md b/compiler/rustc_error_codes/src/error_codes/E0026.md index 72c575aabb6..f485112cca2 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0026.md +++ b/compiler/rustc_error_codes/src/error_codes/E0026.md @@ -1,4 +1,4 @@ -A struct pattern attempted to extract a non-existent field from a struct. +A struct pattern attempted to extract a nonexistent field from a struct. Erroneous code example: diff --git a/compiler/rustc_error_codes/src/error_codes/E0208.md b/compiler/rustc_error_codes/src/error_codes/E0208.md index 1ae01106f20..c6db9b5d61b 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0208.md +++ b/compiler/rustc_error_codes/src/error_codes/E0208.md @@ -32,7 +32,7 @@ error: [-, o] This error is deliberately triggered with the `#[rustc_variance]` attribute (`#![feature(rustc_attrs)]` must be enabled) and helps to show you the variance of the type's generic parameters. You can read more about variance and -subtyping in [this section of the Rustnomicon]. For a more in depth look at +subtyping in [this section of the Rustonomicon]. For a more in depth look at variance (including a more complete list of common variances) see [this section of the Reference]. For information on how variance is implemented in the compiler, see [this section of `rustc-dev-guide`]. @@ -41,6 +41,6 @@ This error can be easily fixed by removing the `#[rustc_variance]` attribute, the compiler's suggestion to comment it out can be applied automatically with `rustfix`. -[this section of the Rustnomicon]: https://doc.rust-lang.org/nomicon/subtyping.html +[this section of the Rustonomicon]: https://doc.rust-lang.org/nomicon/subtyping.html [this section of the Reference]: https://doc.rust-lang.org/reference/subtyping.html#variance [this section of `rustc-dev-guide`]: https://rustc-dev-guide.rust-lang.org/variance.html diff --git a/compiler/rustc_error_codes/src/error_codes/E0311.md b/compiler/rustc_error_codes/src/error_codes/E0311.md index 08159d3f469..c1104a88a76 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0311.md +++ b/compiler/rustc_error_codes/src/error_codes/E0311.md @@ -29,7 +29,7 @@ If `no_restriction()` were to use `&T` instead of `&()` as an argument, the compiler would have added an implied bound, causing this to compile. This error can be resolved by explicitly naming the elided lifetime for `x` and -then explicily requiring that the generic parameter `T` outlives that lifetime: +then explicitly requiring that the generic parameter `T` outlives that lifetime: ``` fn no_restriction<'a, T: 'a>(x: &'a ()) -> &'a () { diff --git a/compiler/rustc_error_codes/src/error_codes/E0457.md b/compiler/rustc_error_codes/src/error_codes/E0457.md index 53d384d36c4..2c33d1e6a24 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0457.md +++ b/compiler/rustc_error_codes/src/error_codes/E0457.md @@ -1,6 +1,6 @@ Plugin `..` only found in rlib format, but must be available in dylib format. -Erroronous code example: +Erroneous code example: `rlib-plugin.rs` ```ignore (needs-linkage-with-other-tests) diff --git a/compiler/rustc_error_codes/src/error_codes/E0576.md b/compiler/rustc_error_codes/src/error_codes/E0576.md index 8eead4e7e3b..300a57a1985 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0576.md +++ b/compiler/rustc_error_codes/src/error_codes/E0576.md @@ -10,7 +10,7 @@ trait Hello { } ``` -In this example, we tried to use the non-existent associated type `You` of the +In this example, we tried to use the nonexistent associated type `You` of the `Hello` trait. To fix this error, use an existing associated type: ``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0609.md b/compiler/rustc_error_codes/src/error_codes/E0609.md index a9db34f474e..0f5ac94e6d5 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0609.md +++ b/compiler/rustc_error_codes/src/error_codes/E0609.md @@ -1,4 +1,4 @@ -Attempted to access a non-existent field in a struct. +Attempted to access a nonexistent field in a struct. Erroneous code example: diff --git a/compiler/rustc_error_messages/Cargo.toml b/compiler/rustc_error_messages/Cargo.toml index 27783d60be4..481c94266f2 100644 --- a/compiler/rustc_error_messages/Cargo.toml +++ b/compiler/rustc_error_messages/Cargo.toml @@ -11,6 +11,7 @@ fluent-syntax = "0.11" intl-memoizer = "0.5.1" rustc_baked_icu_data = { path = "../rustc_baked_icu_data" } rustc_data_structures = { path = "../rustc_data_structures" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } rustc_macros = { path = "../rustc_macros" } diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 6f319b96f2f..88d94c93bf5 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -12,7 +12,8 @@ use fluent_bundle::FluentResource; use fluent_syntax::parser::ParserError; use icu_provider_adapters::fallback::{LocaleFallbackProvider, LocaleFallbacker}; use rustc_data_structures::sync::Lrc; -use rustc_macros::{fluent_messages, Decodable, Encodable}; +use rustc_fluent_macro::fluent_messages; +use rustc_macros::{Decodable, Encodable}; use rustc_span::Span; use std::borrow::Cow; use std::error::Error; diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index e1ead08ea66..46ace8eb2dd 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -10,6 +10,7 @@ tracing = "0.1" rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_error_messages = { path = "../rustc_error_messages" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } rustc_macros = { path = "../rustc_macros" } diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index fe44799efdb..2498ae2b7bc 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -1336,6 +1336,7 @@ impl EmitterWriter { // see? for (text, style) in msg.iter() { let text = self.translate_message(text, args).map_err(Report::new).unwrap(); + let text = &normalize_whitespace(&text); let lines = text.split('\n').collect::<Vec<_>>(); if lines.len() > 1 { for (i, line) in lines.iter().enumerate() { @@ -1980,7 +1981,7 @@ impl EmitterWriter { } if let DisplaySuggestion::Add = show_code_change && is_item_attribute { // The suggestion adds an entire line of code, ending on a newline, so we'll also - // print the *following* line, to provide context of what we're advicing people to + // print the *following* line, to provide context of what we're advising people to // do. Otherwise you would only see contextless code that can be confused for // already existing code, despite the colors and UI elements. // We special case `#[derive(_)]\n` and other attribute suggestions, because those diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index d20b168904d..b65a636d770 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -31,15 +31,15 @@ use Level::*; use emitter::{is_case_difference, Emitter, EmitterWriter}; use registry::Registry; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; -use rustc_data_structures::stable_hasher::StableHasher; +use rustc_data_structures::stable_hasher::{Hash128, StableHasher}; use rustc_data_structures::sync::{self, Lock, Lrc}; use rustc_data_structures::AtomicRef; pub use rustc_error_messages::{ fallback_fluent_bundle, fluent_bundle, DelayDm, DiagnosticMessage, FluentBundle, LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagnosticMessage, }; +use rustc_fluent_macro::fluent_messages; pub use rustc_lint_defs::{pluralize, Applicability}; -use rustc_macros::fluent_messages; use rustc_span::source_map::SourceMap; pub use rustc_span::ErrorGuaranteed; use rustc_span::{Loc, Span}; @@ -427,7 +427,7 @@ struct HandlerInner { /// This set contains a hash of every diagnostic that has been emitted by /// this handler. These hashes is used to avoid emitting the same error /// twice. - emitted_diagnostics: FxHashSet<u128>, + emitted_diagnostics: FxHashSet<Hash128>, /// Stashed diagnostics emitted in one stage of the compiler that may be /// stolen by other stages (e.g. to improve them and add more information). diff --git a/compiler/rustc_expand/Cargo.toml b/compiler/rustc_expand/Cargo.toml index c971714e05b..2dae0e3f53c 100644 --- a/compiler/rustc_expand/Cargo.toml +++ b/compiler/rustc_expand/Cargo.toml @@ -16,6 +16,7 @@ rustc_attr = { path = "../rustc_attr" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_lexer = { path = "../rustc_lexer" } rustc_lint_defs = { path = "../rustc_lint_defs" } rustc_macros = { path = "../rustc_macros" } diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index ced7531c3fe..83a5043b0aa 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -21,7 +21,7 @@ extern crate tracing; extern crate proc_macro as pm; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; -use rustc_macros::fluent_messages; +use rustc_fluent_macro::fluent_messages; mod placeholders; mod proc_macro_server; diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 5679cdcbbd0..3aeb2edb54c 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -341,7 +341,7 @@ pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>( Success(named_matches) => { debug!("Parsed arm successfully"); // The matcher was `Success(..)`ful. - // Merge the gated spans from parsing the matcher with the pre-existing ones. + // Merge the gated spans from parsing the matcher with the preexisting ones. sess.gated_spans.merge(gated_spans_snapshot); return Ok((i, named_matches)); @@ -873,7 +873,7 @@ impl<'tt> FirstSets<'tt> { } } -// Most `mbe::TokenTree`s are pre-existing in the matcher, but some are defined +// Most `mbe::TokenTree`s are preexisting in the matcher, but some are defined // implicitly, such as opening/closing delimiters and sequence repetition ops. // This type encapsulates both kinds. It implements `Clone` while avoiding the // need for `mbe::TokenTree` to implement `Clone`. diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 341ae18541b..1e7d07bc22d 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -18,7 +18,7 @@ use rustc_span::def_id::CrateNum; use rustc_span::symbol::{self, sym, Symbol}; use rustc_span::{BytePos, FileName, Pos, SourceFile, Span}; use smallvec::{smallvec, SmallVec}; -use std::ops::Bound; +use std::ops::{Bound, Range}; trait FromInternal<T> { fn from_internal(x: T) -> Self; @@ -634,6 +634,15 @@ impl server::Span for Rustc<'_, '_> { span.source_callsite() } + fn byte_range(&mut self, span: Self::Span) -> Range<usize> { + let source_map = self.sess().source_map(); + + let relative_start_pos = source_map.lookup_byte_offset(span.lo()).pos; + let relative_end_pos = source_map.lookup_byte_offset(span.hi()).pos; + + Range { start: relative_start_pos.0 as usize, end: relative_end_pos.0 as usize } + } + fn start(&mut self, span: Self::Span) -> LineColumn { let loc = self.sess().source_map().lookup_char_pos(span.lo()); LineColumn { line: loc.line, column: loc.col.to_usize() } diff --git a/compiler/rustc_expand/src/tests.rs b/compiler/rustc_expand/src/tests.rs index 480d95b77e9..8a5e09475ff 100644 --- a/compiler/rustc_expand/src/tests.rs +++ b/compiler/rustc_expand/src/tests.rs @@ -513,7 +513,7 @@ error: foo } #[test] -fn non_overlaping() { +fn non_overlapping() { test_harness( r#" fn foo() { @@ -552,7 +552,7 @@ error: foo } #[test] -fn overlaping_start_and_end() { +fn overlapping_start_and_end() { test_harness( r#" fn foo() { diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 568c289e2f7..c978d6472c8 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -141,7 +141,7 @@ declare_features! ( /// Allows using `#[on_unimplemented(..)]` on traits. /// (Moved to `rustc_attrs`.) (removed, on_unimplemented, "1.40.0", None, None, None), - /// A way to temporarily opt out of opt in copy. This will *never* be accepted. + /// A way to temporarily opt out of opt-in copy. This will *never* be accepted. (removed, opt_out_copy, "1.0.0", None, None, None), /// Allows features specific to OIBIT (now called auto traits). /// Renamed to `auto_traits`. diff --git a/compiler/rustc_fluent_macro/Cargo.toml b/compiler/rustc_fluent_macro/Cargo.toml new file mode 100644 index 00000000000..a45559af713 --- /dev/null +++ b/compiler/rustc_fluent_macro/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "rustc_fluent_macro" +version = "0.1.0" +edition = "2021" + +[lib] +proc-macro = true + +[dependencies] +annotate-snippets = "0.9" +fluent-bundle = "0.15.2" +fluent-syntax = "0.11" +synstructure = "0.13.0" +syn = { version = "2", features = ["full"] } +proc-macro2 = "1" +quote = "1" +unic-langid = { version = "0.9.0", features = ["macros"] } diff --git a/compiler/rustc_macros/src/diagnostics/fluent.rs b/compiler/rustc_fluent_macro/src/fluent.rs index 607d51f5608..9dffc9a7645 100644 --- a/compiler/rustc_macros/src/diagnostics/fluent.rs +++ b/compiler/rustc_fluent_macro/src/fluent.rs @@ -68,7 +68,7 @@ fn failed(crate_name: &Ident) -> proc_macro::TokenStream { .into() } -/// See [rustc_macros::fluent_messages]. +/// See [rustc_fluent_macro::fluent_messages]. pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let crate_name = std::env::var("CARGO_PKG_NAME") // If `CARGO_PKG_NAME` is missing, then we're probably running in a test, so use diff --git a/compiler/rustc_fluent_macro/src/lib.rs b/compiler/rustc_fluent_macro/src/lib.rs new file mode 100644 index 00000000000..a01643cd67d --- /dev/null +++ b/compiler/rustc_fluent_macro/src/lib.rs @@ -0,0 +1,64 @@ +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![feature(proc_macro_diagnostic)] +#![feature(proc_macro_span)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] +#![allow(rustc::default_hash_types)] + +use proc_macro::TokenStream; + +mod fluent; + +/// Implements the `fluent_messages` macro, which performs compile-time validation of the +/// compiler's Fluent resources (i.e. that the resources parse and don't multiply define the same +/// messages) and generates constants that make using those messages in diagnostics more ergonomic. +/// +/// For example, given the following invocation of the macro.. +/// +/// ```ignore (rust) +/// fluent_messages! { "./typeck.ftl" } +/// ``` +/// ..where `typeck.ftl` has the following contents.. +/// +/// ```fluent +/// typeck_field_multiply_specified_in_initializer = +/// field `{$ident}` specified more than once +/// .label = used more than once +/// .label_previous_use = first use of `{$ident}` +/// ``` +/// ...then the macro parse the Fluent resource, emitting a diagnostic if it fails to do so, and +/// will generate the following code: +/// +/// ```ignore (rust) +/// pub static DEFAULT_LOCALE_RESOURCE: &'static [&'static str] = include_str!("./typeck.ftl"); +/// +/// mod fluent_generated { +/// mod typeck { +/// pub const field_multiply_specified_in_initializer: DiagnosticMessage = +/// DiagnosticMessage::fluent("typeck_field_multiply_specified_in_initializer"); +/// pub const field_multiply_specified_in_initializer_label_previous_use: DiagnosticMessage = +/// DiagnosticMessage::fluent_attr( +/// "typeck_field_multiply_specified_in_initializer", +/// "previous_use_label" +/// ); +/// } +/// } +/// ``` +/// When emitting a diagnostic, the generated constants can be used as follows: +/// +/// ```ignore (rust) +/// let mut err = sess.struct_span_err( +/// span, +/// fluent::typeck::field_multiply_specified_in_initializer +/// ); +/// err.span_default_label(span); +/// err.span_label( +/// previous_use_span, +/// fluent::typeck::field_multiply_specified_in_initializer_label_previous_use +/// ); +/// err.emit(); +/// ``` +#[proc_macro] +pub fn fluent_messages(input: TokenStream) -> TokenStream { + fluent::fluent_messages(input) +} diff --git a/compiler/rustc_hir/src/arena.rs b/compiler/rustc_hir/src/arena.rs index c89e7eb75f8..3e5b3c498ee 100644 --- a/compiler/rustc_hir/src/arena.rs +++ b/compiler/rustc_hir/src/arena.rs @@ -51,6 +51,7 @@ macro_rules! arena_types { [] type_binding: rustc_hir::TypeBinding<'tcx>, [] variant: rustc_hir::Variant<'tcx>, [] where_predicate: rustc_hir::WherePredicate<'tcx>, + [] lit: rustc_hir::Lit, ]); ) } diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 8c58129c800..30bf8c2ad10 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -234,10 +234,7 @@ impl DefKind { #[inline] pub fn is_fn_like(self) -> bool { - match self { - DefKind::Fn | DefKind::AssocFn | DefKind::Closure | DefKind::Generator => true, - _ => false, - } + matches!(self, DefKind::Fn | DefKind::AssocFn | DefKind::Closure | DefKind::Generator) } /// Whether `query get_codegen_attrs` should be used with this definition. diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index 8ceb176491b..5a5a1e44f12 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -9,7 +9,7 @@ use crate::def_id::{CrateNum, DefIndex, LocalDefId, StableCrateId, CRATE_DEF_IND use crate::def_path_hash_map::DefPathHashMap; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::stable_hasher::StableHasher; +use rustc_data_structures::stable_hasher::{Hash64, StableHasher}; use rustc_index::vec::IndexVec; use rustc_span::symbol::{kw, sym, Symbol}; @@ -130,7 +130,7 @@ impl DefKey { disambiguator.hash(&mut hasher); - let local_hash: u64 = hasher.finish(); + let local_hash = hasher.finish(); // Construct the new DefPathHash, making sure that the `crate_id` // portion of the hash is properly copied from the parent. This way the @@ -325,7 +325,7 @@ impl Definitions { }, }; - let parent_hash = DefPathHash::new(stable_crate_id, 0); + let parent_hash = DefPathHash::new(stable_crate_id, Hash64::ZERO); let def_path_hash = key.compute_stable_hash(parent_hash); // Create the root definition. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 35a72f868fb..52ed9660256 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1715,6 +1715,7 @@ impl Expr<'_> { ExprKind::Continue(..) => ExprPrecedence::Continue, ExprKind::Ret(..) => ExprPrecedence::Ret, ExprKind::InlineAsm(..) => ExprPrecedence::InlineAsm, + ExprKind::OffsetOf(..) => ExprPrecedence::OffsetOf, ExprKind::Struct(..) => ExprPrecedence::Struct, ExprKind::Repeat(..) => ExprPrecedence::Repeat, ExprKind::Yield(..) => ExprPrecedence::Yield, @@ -1774,6 +1775,7 @@ impl Expr<'_> { | ExprKind::Loop(..) | ExprKind::Assign(..) | ExprKind::InlineAsm(..) + | ExprKind::OffsetOf(..) | ExprKind::AssignOp(..) | ExprKind::Lit(_) | ExprKind::ConstBlock(..) @@ -1818,7 +1820,7 @@ impl Expr<'_> { pub fn can_have_side_effects(&self) -> bool { match self.peel_drop_temps().kind { - ExprKind::Path(_) | ExprKind::Lit(_) => false, + ExprKind::Path(_) | ExprKind::Lit(_) | ExprKind::OffsetOf(..) => false, ExprKind::Type(base, _) | ExprKind::Unary(_, base) | ExprKind::Field(base, _) @@ -1957,10 +1959,10 @@ pub enum ExprKind<'hir> { /// A unary operation (e.g., `!x`, `*x`). Unary(UnOp, &'hir Expr<'hir>), /// A literal (e.g., `1`, `"foo"`). - Lit(Lit), + Lit(&'hir Lit), /// A cast (e.g., `foo as f64`). Cast(&'hir Expr<'hir>, &'hir Ty<'hir>), - /// A type reference (e.g., `Foo`). + /// A type ascription (e.g., `x: Foo`). See RFC 3307. Type(&'hir Expr<'hir>, &'hir Ty<'hir>), /// Wraps the expression in a terminating scope. /// This makes it semantically equivalent to `{ let _t = expr; _t }`. @@ -2022,6 +2024,9 @@ pub enum ExprKind<'hir> { /// Inline assembly (from `asm!`), with its outputs and inputs. InlineAsm(&'hir InlineAsm<'hir>), + /// Field offset (`offset_of!`) + OffsetOf(&'hir Ty<'hir>, &'hir [Ident]), + /// A struct or struct-like variant literal expression. /// /// E.g., `Foo {x: 1, y: 2}`, or `Foo {x: 1, .. base}`, @@ -3146,7 +3151,6 @@ impl<'hir> Item<'hir> { (ty, gen) } - /// An opaque `impl Trait` type alias, e.g., `type Foo = impl Bar;`. /// Expect an [`ItemKind::OpaqueTy`] or panic. #[track_caller] pub fn expect_opaque_ty(&self) -> &OpaqueTy<'hir> { @@ -3168,7 +3172,6 @@ impl<'hir> Item<'hir> { (data, gen) } - /// A union definition, e.g., `union Foo<A, B> {x: A, y: B}`. /// Expect an [`ItemKind::Union`] or panic. #[track_caller] pub fn expect_union(&self) -> (&VariantData<'hir>, &'hir Generics<'hir>) { @@ -3531,12 +3534,20 @@ impl<'hir> OwnerNode<'hir> { pub fn body_id(&self) -> Option<BodyId> { match self { - OwnerNode::TraitItem(TraitItem { - kind: TraitItemKind::Fn(_, TraitFn::Provided(body_id)), + OwnerNode::Item(Item { + kind: + ItemKind::Static(_, _, body) | ItemKind::Const(_, body) | ItemKind::Fn(_, _, body), .. }) - | OwnerNode::ImplItem(ImplItem { kind: ImplItemKind::Fn(_, body_id), .. }) - | OwnerNode::Item(Item { kind: ItemKind::Fn(.., body_id), .. }) => Some(*body_id), + | OwnerNode::TraitItem(TraitItem { + kind: + TraitItemKind::Fn(_, TraitFn::Provided(body)) | TraitItemKind::Const(_, Some(body)), + .. + }) + | OwnerNode::ImplItem(ImplItem { + kind: ImplItemKind::Fn(_, body) | ImplItemKind::Const(_, body), + .. + }) => Some(*body), _ => None, } } @@ -3731,12 +3742,27 @@ impl<'hir> Node<'hir> { pub fn body_id(&self) -> Option<BodyId> { match self { - Node::TraitItem(TraitItem { - kind: TraitItemKind::Fn(_, TraitFn::Provided(body_id)), + Node::Item(Item { + kind: + ItemKind::Static(_, _, body) | ItemKind::Const(_, body) | ItemKind::Fn(_, _, body), .. }) - | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(_, body_id), .. }) - | Node::Item(Item { kind: ItemKind::Fn(.., body_id), .. }) => Some(*body_id), + | Node::TraitItem(TraitItem { + kind: + TraitItemKind::Fn(_, TraitFn::Provided(body)) | TraitItemKind::Const(_, Some(body)), + .. + }) + | Node::ImplItem(ImplItem { + kind: ImplItemKind::Fn(_, body) | ImplItemKind::Const(_, body), + .. + }) + | Node::Expr(Expr { + kind: + ExprKind::ConstBlock(AnonConst { body, .. }) + | ExprKind::Closure(Closure { body, .. }) + | ExprKind::Repeat(_, ArrayLen::Body(AnonConst { body, .. })), + .. + }) => Some(*body), _ => None, } } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 234256ab553..df0047d82e1 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -786,6 +786,10 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) ExprKind::InlineAsm(ref asm) => { visitor.visit_inline_asm(asm, expression.hir_id); } + ExprKind::OffsetOf(ref container, ref fields) => { + visitor.visit_ty(container); + walk_list!(visitor, visit_ident, fields.iter().copied()); + } ExprKind::Yield(ref subexpression, _) => { visitor.visit_expr(subexpression); } diff --git a/compiler/rustc_hir/src/tests.rs b/compiler/rustc_hir/src/tests.rs index d4791150947..c7ac01b3334 100644 --- a/compiler/rustc_hir/src/tests.rs +++ b/compiler/rustc_hir/src/tests.rs @@ -1,4 +1,5 @@ use crate::definitions::{DefKey, DefPathData, DisambiguatedDefPathData}; +use rustc_data_structures::stable_hasher::Hash64; use rustc_span::def_id::{DefPathHash, StableCrateId}; use rustc_span::edition::Edition; use rustc_span::{create_session_if_not_set_then, Symbol}; @@ -24,7 +25,7 @@ fn def_path_hash_depends_on_crate_id() { assert_ne!(h0.local_hash(), h1.local_hash()); fn mk_test_hash(stable_crate_id: StableCrateId) -> DefPathHash { - let parent_hash = DefPathHash::new(stable_crate_id, 0); + let parent_hash = DefPathHash::new(stable_crate_id, Hash64::ZERO); let key = DefKey { parent: None, diff --git a/compiler/rustc_hir_analysis/Cargo.toml b/compiler/rustc_hir_analysis/Cargo.toml index fab16b80fb5..f56cedebfb0 100644 --- a/compiler/rustc_hir_analysis/Cargo.toml +++ b/compiler/rustc_hir_analysis/Cargo.toml @@ -15,6 +15,7 @@ rustc_attr = { path = "../rustc_attr" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_hir = { path = "../rustc_hir" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_target = { path = "../rustc_target" } rustc_session = { path = "../rustc_session" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } @@ -23,7 +24,7 @@ rustc_span = { path = "../rustc_span" } rustc_index = { path = "../rustc_index" } rustc_infer = { path = "../rustc_infer" } rustc_trait_selection = { path = "../rustc_trait_selection" } -rustc_lint = { path = "../rustc_lint" } +rustc_lint_defs = { path = "../rustc_lint_defs" } rustc_type_ir = { path = "../rustc_type_ir" } rustc_feature = { path = "../rustc_feature" } thin-vec = "0.2.12" diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 8d1156c1771..992316edb63 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -447,14 +447,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { handle_ty_args(has_default, &inf.to_ty()) } (GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => { - ty::Const::from_opt_const_arg_anon_const( - tcx, - ty::WithOptConstParam { - did: ct.value.def_id, - const_param_did: Some(param.def_id), - }, - ) - .into() + let did = ct.value.def_id; + tcx.feed_anon_const_type(did, tcx.type_of(param.def_id)); + ty::Const::from_anon_const(tcx, did).into() } (&GenericParamDefKind::Const { .. }, hir::GenericArg::Infer(inf)) => { let ty = tcx @@ -2061,7 +2056,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { err.note("enum variants can't have type parameters"); let type_name = tcx.item_name(adt_def.did()); let msg = format!( - "you might have meant to specity type parameters on enum \ + "you might have meant to specify type parameters on enum \ `{type_name}`" ); let Some(args) = assoc_segment.args else { return; }; diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 0bb98fdf2a2..51ec5dd7a28 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -15,7 +15,7 @@ use rustc_infer::infer::opaque_types::ConstrainOpaqueTypeRegionVisitor; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt}; use rustc_infer::traits::{Obligation, TraitEngineExt as _}; -use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS; +use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS; use rustc_middle::hir::nested_filter; use rustc_middle::middle::stability::EvalResult; use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES}; @@ -863,7 +863,7 @@ fn check_impl_items_against_trait<'tcx>( if !missing_items.is_empty() { let full_impl_span = tcx.hir().span_with_body(tcx.hir().local_def_id_to_hir_id(impl_id)); - missing_items_err(tcx, tcx.def_span(impl_id), &missing_items, full_impl_span); + missing_items_err(tcx, impl_id, &missing_items, full_impl_span); } if let Some(missing_items) = must_implement_one_of { diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 5d119a7737a..fe87aae8ed1 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -579,7 +579,7 @@ fn compare_asyncness<'tcx>( pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( tcx: TyCtxt<'tcx>, impl_m_def_id: LocalDefId, -) -> Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed> { +) -> Result<&'tcx FxHashMap<DefId, ty::EarlyBinder<Ty<'tcx>>>, ErrorGuaranteed> { let impl_m = tcx.opt_associated_item(impl_m_def_id.to_def_id()).unwrap(); let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap(); let impl_trait_ref = @@ -782,14 +782,14 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( }) }); debug!(%ty); - collected_tys.insert(def_id, ty); + collected_tys.insert(def_id, ty::EarlyBinder(ty)); } Err(err) => { let reported = tcx.sess.delay_span_bug( return_span, format!("could not fully resolve: {ty} => {err:?}"), ); - collected_tys.insert(def_id, tcx.ty_error(reported)); + collected_tys.insert(def_id, ty::EarlyBinder(tcx.ty_error(reported))); } } } @@ -1317,7 +1317,7 @@ fn compare_number_of_generics<'tcx>( impl_count, kind, pluralize!(impl_count), - suffix.unwrap_or_else(String::new), + suffix.unwrap_or_default(), ), ); } diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 8fe4c44fca4..4b3f3cf169d 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -198,7 +198,7 @@ fn report_forbidden_specialization(tcx: TyCtxt<'_>, impl_item: DefId, parent_imp fn missing_items_err( tcx: TyCtxt<'_>, - impl_span: Span, + impl_def_id: LocalDefId, missing_items: &[ty::AssocItem], full_impl_span: Span, ) { @@ -211,6 +211,7 @@ fn missing_items_err( .collect::<Vec<_>>() .join("`, `"); + let impl_span = tcx.def_span(impl_def_id); let mut err = struct_span_err!( tcx.sess, impl_span, @@ -229,7 +230,11 @@ fn missing_items_err( tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(|| String::new()); for &trait_item in missing_items { - let snippet = suggestion_signature(trait_item, tcx); + let snippet = suggestion_signature( + tcx, + trait_item, + tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity(), + ); let code = format!("{}{}\n{}", padding, snippet, padding); let msg = format!("implement the missing item: `{snippet}`"); let appl = Applicability::HasPlaceholders; @@ -301,11 +306,11 @@ fn default_body_is_unstable( /// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions. fn bounds_from_generic_predicates<'tcx>( tcx: TyCtxt<'tcx>, - predicates: ty::GenericPredicates<'tcx>, + predicates: impl IntoIterator<Item = (ty::Predicate<'tcx>, Span)>, ) -> (String, String) { let mut types: FxHashMap<Ty<'tcx>, Vec<DefId>> = FxHashMap::default(); let mut projections = vec![]; - for (predicate, _) in predicates.predicates { + for (predicate, _) in predicates { debug!("predicate {:?}", predicate); let bound_predicate = predicate.kind(); match bound_predicate.skip_binder() { @@ -367,7 +372,7 @@ fn fn_sig_suggestion<'tcx>( tcx: TyCtxt<'tcx>, sig: ty::FnSig<'tcx>, ident: Ident, - predicates: ty::GenericPredicates<'tcx>, + predicates: impl IntoIterator<Item = (ty::Predicate<'tcx>, Span)>, assoc: ty::AssocItem, ) -> String { let args = sig @@ -436,7 +441,17 @@ pub fn ty_kind_suggestion(ty: Ty<'_>) -> Option<&'static str> { /// Return placeholder code for the given associated item. /// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a /// structured suggestion. -fn suggestion_signature(assoc: ty::AssocItem, tcx: TyCtxt<'_>) -> String { +fn suggestion_signature<'tcx>( + tcx: TyCtxt<'tcx>, + assoc: ty::AssocItem, + impl_trait_ref: ty::TraitRef<'tcx>, +) -> String { + let substs = ty::InternalSubsts::identity_for_item(tcx, assoc.def_id).rebase_onto( + tcx, + assoc.container_id(tcx), + impl_trait_ref.with_self_ty(tcx, tcx.types.self_param).substs, + ); + match assoc.kind { ty::AssocKind::Fn => { // We skip the binder here because the binder would deanonymize all @@ -445,16 +460,22 @@ fn suggestion_signature(assoc: ty::AssocItem, tcx: TyCtxt<'_>) -> String { // regions just fine, showing `fn(&MyType)`. fn_sig_suggestion( tcx, - tcx.fn_sig(assoc.def_id).subst_identity().skip_binder(), + tcx.fn_sig(assoc.def_id).subst(tcx, substs).skip_binder(), assoc.ident(tcx), - tcx.predicates_of(assoc.def_id), + tcx.predicates_of(assoc.def_id).instantiate_own(tcx, substs), assoc, ) } - ty::AssocKind::Type => format!("type {} = Type;", assoc.name), + ty::AssocKind::Type => { + let (generics, where_clauses) = bounds_from_generic_predicates( + tcx, + tcx.predicates_of(assoc.def_id).instantiate_own(tcx, substs), + ); + format!("type {}{generics} = /* Type */{where_clauses};", assoc.name) + } ty::AssocKind::Const => { let ty = tcx.type_of(assoc.def_id).subst_identity(); - let val = ty_kind_suggestion(ty).unwrap_or("value"); + let val = ty_kind_suggestion(ty).unwrap_or("todo!()"); format!("const {}: {} = {};", assoc.name, ty, val) } } diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 0f40cca9427..611ce13b739 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -74,16 +74,15 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) { debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type); - let span = match tcx.hir().expect_item(impl_did).kind { - ItemKind::Impl(hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. }) => return, - ItemKind::Impl(impl_) => impl_.self_ty.span, - _ => bug!("expected Copy impl item"), + let span = match tcx.hir().expect_item(impl_did).expect_impl() { + hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. } => return, + hir::Impl { self_ty, .. } => self_ty.span, }; let cause = traits::ObligationCause::misc(span, impl_did); match type_allowed_to_implement_copy(tcx, param_env, self_type, cause) { Ok(()) => {} - Err(CopyImplementationError::InfrigingFields(fields)) => { + Err(CopyImplementationError::InfringingFields(fields)) => { let mut err = struct_span_err!( tcx.sess, span, diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index cbbaf8f857d..36e294e8aa2 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -55,7 +55,6 @@ fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { pub fn provide(providers: &mut Providers) { resolve_bound_vars::provide(providers); *providers = Providers { - opt_const_param_of: type_of::opt_const_param_of, type_of: type_of::type_of, item_bounds: item_bounds::item_bounds, explicit_item_bounds: item_bounds::explicit_item_bounds, @@ -1457,10 +1456,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( } fn is_foreign_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { - match tcx.hir().get_by_def_id(def_id) { - Node::ForeignItem(..) => true, - _ => false, - } + matches!(tcx.hir().get_by_def_id(def_id), Node::ForeignItem(..)) } fn generator_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<hir::GeneratorKind> { diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 9358ed61292..8c414521b76 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -645,9 +645,8 @@ pub(super) fn implied_predicates_with_filter( }; // Combine the two lists to form the complete set of superbounds: - let implied_bounds = &*tcx - .arena - .alloc_from_iter(superbounds.predicates().into_iter().chain(where_bounds_that_match)); + let implied_bounds = + &*tcx.arena.alloc_from_iter(superbounds.predicates().chain(where_bounds_that_match)); debug!(?implied_bounds); // Now require that immediate supertraits are converted, diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index e758fe95d9c..3cb217335bd 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -1333,7 +1333,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { // We may fail to resolve higher-ranked lifetimes that are mentioned by APIT. // AST-based resolution does not care for impl-trait desugaring, which are the - // responibility of lowering. This may create a mismatch between the resolution + // responsibility of lowering. This may create a mismatch between the resolution // AST found (`region_def_id`) which points to HRTB, and what HIR allows. // ``` // fn foo(x: impl for<'a> Trait<'a, Assoc = impl Copy + 'a>) {} diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index c173bd913a8..d7d509e5394 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -1,6 +1,6 @@ use rustc_errors::{Applicability, StashKey}; use rustc_hir as hir; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit; use rustc_hir::intravisit::Visitor; use rustc_hir::{HirId, Node}; @@ -16,22 +16,81 @@ use super::ItemCtxt; use super::{bad_placeholder, is_suggestable_infer_ty}; use crate::errors::UnconstrainedOpaqueType; -/// Computes the relevant generic parameter for a potential generic const argument. -/// -/// This should be called using the query `tcx.opt_const_param_of`. -pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<DefId> { +fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { use hir::*; let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - match tcx.hir().get(hir_id) { - Node::AnonConst(_) => (), - _ => return None, - }; + let Node::AnonConst(_) = tcx.hir().get(hir_id) else { panic!() }; let parent_node_id = tcx.hir().parent_id(hir_id); let parent_node = tcx.hir().get(parent_node_id); let (generics, arg_idx) = match parent_node { + // Easy case: arrays repeat expressions. + Node::Ty(&Ty { kind: TyKind::Array(_, ref constant), .. }) + | Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. }) + if constant.hir_id() == hir_id => + { + return tcx.types.usize + } + Node::Ty(&Ty { kind: TyKind::Typeof(ref e), .. }) if e.hir_id == hir_id => { + return tcx.typeck(def_id).node_type(e.hir_id) + } + Node::Expr(&Expr { kind: ExprKind::ConstBlock(ref anon_const), .. }) + if anon_const.hir_id == hir_id => + { + let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); + return substs.as_inline_const().ty() + } + Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. }) + | Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. }) + if asm.operands.iter().any(|(op, _op_sp)| match op { + hir::InlineAsmOperand::Const { anon_const } + | hir::InlineAsmOperand::SymFn { anon_const } => anon_const.hir_id == hir_id, + _ => false, + }) => + { + return tcx.typeck(def_id).node_type(hir_id) + } + Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => { + return tcx + .adt_def(tcx.hir().get_parent_item(hir_id)) + .repr() + .discr_type() + .to_ty(tcx) + } + Node::GenericParam(&GenericParam { + def_id: param_def_id, + kind: GenericParamKind::Const { default: Some(ct), .. }, + .. + }) if ct.hir_id == hir_id => { + return tcx.type_of(param_def_id) + .no_bound_vars() + .expect("const parameter types cannot be generic") + } + + Node::TypeBinding(binding @ &TypeBinding { hir_id: binding_id, .. }) + if let Node::TraitRef(trait_ref) = tcx.hir().get( + tcx.hir().parent_id(binding_id) + ) => + { + let Some(trait_def_id) = trait_ref.trait_def_id() else { + return tcx.ty_error_with_message(tcx.def_span(def_id), "Could not find trait"); + }; + let assoc_items = tcx.associated_items(trait_def_id); + let assoc_item = assoc_items.find_by_name_and_kind( + tcx, binding.ident, ty::AssocKind::Const, def_id.to_def_id(), + ); + return if let Some(assoc_item) = assoc_item { + tcx.type_of(assoc_item.def_id) + .no_bound_vars() + .expect("const parameter types cannot be generic") + } else { + // FIXME(associated_const_equality): add a useful error message here. + tcx.ty_error_with_message(tcx.def_span(def_id), "Could not find associated const on trait") + } + } + // This match arm is for when the def_id appears in a GAT whose // path can't be resolved without typechecking e.g. // @@ -86,11 +145,10 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< (generics, arg_index) } else { // I dont think it's possible to reach this but I'm not 100% sure - BoxyUwU - tcx.sess.delay_span_bug( + return tcx.ty_error_with_message( tcx.def_span(def_id), "unexpected non-GAT usage of an anon const", ); - return None; } } Node::Expr(&Expr { @@ -103,7 +161,12 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< // This may fail in case the method/path does not actually exist. // As there is no relevant param for `def_id`, we simply return // `None` here. - let type_dependent_def = tables.type_dependent_def_id(parent_node_id)?; + let Some(type_dependent_def) = tables.type_dependent_def_id(parent_node_id) else { + return tcx.ty_error_with_message( + tcx.def_span(def_id), + &format!("unable to find type-dependent def for {:?}", parent_node_id), + ); + }; let idx = segment .args .and_then(|args| { @@ -140,19 +203,17 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< if let Some(path) = get_path_containing_arg_in_pat(pat, hir_id) { path } else { - tcx.sess.delay_span_bug( + return tcx.ty_error_with_message( tcx.def_span(def_id), &format!("unable to find const parent for {} in pat {:?}", hir_id, pat), ); - return None; } } _ => { - tcx.sess.delay_span_bug( + return tcx.ty_error_with_message( tcx.def_span(def_id), &format!("unexpected const parent path {:?}", parent_node), ); - return None; } }; @@ -171,32 +232,34 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< .position(|ct| ct.hir_id == hir_id) .map(|idx| (idx, seg))) }) else { - tcx.sess.delay_span_bug( + return tcx.ty_error_with_message( tcx.def_span(def_id), "no arg matching AnonConst in path", ); - return None; }; let generics = match tcx.res_generics_def_id(segment.res) { Some(def_id) => tcx.generics_of(def_id), None => { - tcx.sess.delay_span_bug( + return tcx.ty_error_with_message( tcx.def_span(def_id), &format!("unexpected anon const res {:?} in path: {:?}", segment.res, path), ); - return None; } }; (generics, arg_index) } - _ => return None, + + _ => return tcx.ty_error_with_message( + tcx.def_span(def_id), + &format!("unexpected const parent in type_of(): {parent_node:?}"), + ), }; debug!(?parent_node); debug!(?generics, ?arg_idx); - generics + if let Some(param_def_id) = generics .params .iter() .filter(|param| param.kind.is_ty_or_const()) @@ -211,6 +274,14 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< } _ => None, }) + { + tcx.type_of(param_def_id).no_bound_vars().expect("const parameter types cannot be generic") + } else { + return tcx.ty_error_with_message( + tcx.def_span(def_id), + &format!("const generic parameter not found in {generics:?} at position {arg_idx:?}"), + ); + } } fn get_path_containing_arg_in_pat<'hir>( @@ -251,7 +322,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty match tcx.collect_return_position_impl_trait_in_trait_tys(fn_def_id) { Ok(map) => { let assoc_item = tcx.associated_item(def_id); - return ty::EarlyBinder(map[&assoc_item.trait_item_def_id.unwrap()]); + return map[&assoc_item.trait_item_def_id.unwrap()]; } Err(_) => { return ty::EarlyBinder(tcx.ty_error_with_message( @@ -415,143 +486,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty tcx.typeck(def_id).node_type(hir_id) } - Node::AnonConst(_) if let Some(param) = tcx.opt_const_param_of(def_id) => { - // We defer to `type_of` of the corresponding parameter - // for generic arguments. - tcx.type_of(param).subst_identity() - } - - Node::AnonConst(_) => { - let parent_node = tcx.hir().get_parent(hir_id); - match parent_node { - Node::Ty(Ty { kind: TyKind::Array(_, constant), .. }) - | Node::Expr(Expr { kind: ExprKind::Repeat(_, constant), .. }) - if constant.hir_id() == hir_id => - { - tcx.types.usize - } - Node::Ty(Ty { kind: TyKind::Typeof(e), .. }) if e.hir_id == hir_id => { - tcx.typeck(def_id).node_type(e.hir_id) - } - - Node::Expr(Expr { kind: ExprKind::ConstBlock(anon_const), .. }) - if anon_const.hir_id == hir_id => - { - let substs = InternalSubsts::identity_for_item(tcx, def_id); - substs.as_inline_const().ty() - } - - Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. }) - | Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. }) - if asm.operands.iter().any(|(op, _op_sp)| match op { - hir::InlineAsmOperand::Const { anon_const } - | hir::InlineAsmOperand::SymFn { anon_const } => { - anon_const.hir_id == hir_id - } - _ => false, - }) => - { - tcx.typeck(def_id).node_type(hir_id) - } - - Node::Variant(Variant { disr_expr: Some(e), .. }) if e.hir_id == hir_id => { - tcx.adt_def(tcx.hir().get_parent_item(hir_id)).repr().discr_type().to_ty(tcx) - } - - Node::TypeBinding(TypeBinding { - hir_id: binding_id, - kind: TypeBindingKind::Equality { term: Term::Const(e) }, - ident, - .. - }) if let Node::TraitRef(trait_ref) = tcx.hir().get_parent(*binding_id) - && e.hir_id == hir_id => - { - let Some(trait_def_id) = trait_ref.trait_def_id() else { - return ty::EarlyBinder(tcx.ty_error_with_message(DUMMY_SP, "Could not find trait")); - }; - let assoc_items = tcx.associated_items(trait_def_id); - let assoc_item = assoc_items.find_by_name_and_kind( - tcx, - *ident, - ty::AssocKind::Const, - def_id.to_def_id(), - ); - if let Some(assoc_item) = assoc_item { - tcx.type_of(assoc_item.def_id) - .no_bound_vars() - .expect("const parameter types cannot be generic") - } else { - // FIXME(associated_const_equality): add a useful error message here. - tcx.ty_error_with_message( - DUMMY_SP, - "Could not find associated const on trait", - ) - } - } - - Node::TypeBinding(TypeBinding { - hir_id: binding_id, - gen_args, - kind, - ident, - .. - }) if let Node::TraitRef(trait_ref) = tcx.hir().get_parent(*binding_id) - && let Some((idx, _)) = - gen_args.args.iter().enumerate().find(|(_, arg)| { - if let GenericArg::Const(ct) = arg { - ct.value.hir_id == hir_id - } else { - false - } - }) => - { - let Some(trait_def_id) = trait_ref.trait_def_id() else { - return ty::EarlyBinder(tcx.ty_error_with_message(DUMMY_SP, "Could not find trait")); - }; - let assoc_items = tcx.associated_items(trait_def_id); - let assoc_item = assoc_items.find_by_name_and_kind( - tcx, - *ident, - match kind { - // I think `<A: T>` type bindings requires that `A` is a type - TypeBindingKind::Constraint { .. } - | TypeBindingKind::Equality { term: Term::Ty(..) } => { - ty::AssocKind::Type - } - TypeBindingKind::Equality { term: Term::Const(..) } => { - ty::AssocKind::Const - } - }, - def_id.to_def_id(), - ); - if let Some(assoc_item) = assoc_item - && let param = &tcx.generics_of(assoc_item.def_id).params[idx] - && matches!(param.kind, ty::GenericParamDefKind::Const { .. }) - { - tcx.type_of(param.def_id) - .no_bound_vars() - .expect("const parameter types cannot be generic") - } else { - // FIXME(associated_const_equality): add a useful error message here. - tcx.ty_error_with_message( - DUMMY_SP, - "Could not find const param on associated item", - ) - } - } - - Node::GenericParam(&GenericParam { - def_id: param_def_id, - kind: GenericParamKind::Const { default: Some(ct), .. }, - .. - }) if ct.hir_id == hir_id => tcx.type_of(param_def_id).subst_identity(), - - x => tcx.ty_error_with_message( - DUMMY_SP, - &format!("unexpected const parent in type_of(): {x:?}"), - ), - } - } + Node::AnonConst(_) => anon_const_type_of(tcx, def_id), Node::GenericParam(param) => match ¶m.kind { GenericParamKind::Type { default: Some(ty), .. } diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 27e56180349..4c28e28f964 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -99,10 +99,10 @@ mod variance; use rustc_errors::ErrorGuaranteed; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; +use rustc_fluent_macro::fluent_messages; use rustc_hir as hir; use rustc_hir::Node; use rustc_infer::infer::TyCtxtInferExt; -use rustc_macros::fluent_messages; use rustc_middle::middle; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index 0a45119ff05..4d240e90b14 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -105,7 +105,7 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc if let ty::RegionKind::ReEarlyBound(ebr) = r.kind() { self.variances[ebr.index as usize] = ty::Invariant; } - r.super_visit_with(self) + ControlFlow::Continue(()) } #[instrument(level = "trace", skip(self), ret)] diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 74f5b359021..2db4f1e50d4 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1551,6 +1551,23 @@ impl<'a> State<'a> { self.word("asm!"); self.print_inline_asm(asm); } + hir::ExprKind::OffsetOf(container, ref fields) => { + self.word("offset_of!("); + self.print_type(container); + self.word(","); + self.space(); + + if let Some((&first, rest)) = fields.split_first() { + self.print_ident(first); + + for &field in rest { + self.word("."); + self.print_ident(field); + } + } + + self.word(")"); + } hir::ExprKind::Yield(expr, _) => { self.word_space("yield"); self.print_expr_maybe_paren(expr, parser::PREC_JUMP); diff --git a/compiler/rustc_hir_typeck/Cargo.toml b/compiler/rustc_hir_typeck/Cargo.toml index 093f9bb8448..13e1ea31c4d 100644 --- a/compiler/rustc_hir_typeck/Cargo.toml +++ b/compiler/rustc_hir_typeck/Cargo.toml @@ -12,6 +12,7 @@ rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_graphviz = { path = "../rustc_graphviz" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_index = { path = "../rustc_index" } rustc_infer = { path = "../rustc_infer" } rustc_hir = { path = "../rustc_hir" } diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 2c537bf4064..6d40df7d0cc 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -3,21 +3,6 @@ hir_typeck_field_multiply_specified_in_initializer = .label = used more than once .previous_use_label = first use of `{$ident}` -hir_typeck_copy_impl_on_type_with_dtor = - the trait `Copy` cannot be implemented for this type; the type has a destructor - .label = `Copy` not allowed on types with destructors - -hir_typeck_multiple_relaxed_default_bounds = - type parameter has more than one relaxed default bound, only one is supported - -hir_typeck_copy_impl_on_non_adt = - the trait `Copy` cannot be implemented for this type - .label = type is not a structure or enumeration - -hir_typeck_trait_object_declared_with_no_traits = - at least one trait is required for an object type - .alias_span = this alias does not contain a trait - hir_typeck_functional_record_update_on_non_struct = functional record update syntax requires a struct diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 8fa3bcd68c3..507c24d540c 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -976,7 +976,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Attempt to coerce an expression to a type, and return the /// adjusted type of the expression, if successful. /// Adjustments are only recorded if the coercion succeeded. - /// The expressions *must not* have any pre-existing adjustments. + /// The expressions *must not* have any preexisting adjustments. pub fn try_coerce( &self, expr: &hir::Expr<'_>, @@ -1340,7 +1340,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { } /// As an optimization, you can create a `CoerceMany` with a - /// pre-existing slice of expressions. In this case, you are + /// preexisting slice of expressions. In this case, you are /// expected to pass each element in the slice to `coerce(...)` in /// order. This is used with arrays in particular to avoid /// needlessly cloning the slice. diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 13442c31649..525acfdaa81 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -17,7 +17,6 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, Article, AssocItem, Ty, TypeAndMut, TypeFoldable}; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{BytePos, Span, DUMMY_SP}; -use rustc_target::abi::FieldIdx; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::ObligationCause; @@ -875,7 +874,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { variant.fields.len() == 1 }) .filter_map(|variant| { - let sole_field = &variant.fields[FieldIdx::from_u32(0)]; + let sole_field = &variant.single_field(); let field_is_local = sole_field.did.is_local(); let field_is_accessible = diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 3eee2278dca..5be78416e61 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -108,7 +108,7 @@ pub enum ExpectedReturnTypeLabel<'tcx> { #[derive(Diagnostic)] #[diag(hir_typeck_missing_parentheses_in_range, code = "E0689")] -pub struct MissingParentheseInRange { +pub struct MissingParenthesesInRange { #[primary_span] #[label(hir_typeck_missing_parentheses_in_range)] pub span: Span, diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 6ffa0134f3d..3ffc583d43f 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -38,6 +38,7 @@ use rustc_infer::infer; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::InferOk; +use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::ObligationCause; use rustc_middle::middle::stability; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase}; @@ -53,6 +54,8 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_target::abi::FieldIdx; use rustc_target::spec::abi::Abi::RustIntrinsic; use rustc_trait_selection::infer::InferCtxtExt; +use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; +use rustc_trait_selection::traits::ObligationCtxt; use rustc_trait_selection::traits::{self, ObligationCauseCode}; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -306,6 +309,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.deferred_asm_checks.borrow_mut().push((asm, expr.hir_id)); self.check_expr_asm(asm) } + ExprKind::OffsetOf(container, ref fields) => { + self.check_offset_of(container, fields, expr) + } ExprKind::Break(destination, ref expr_opt) => { self.check_expr_break(destination, expr_opt.as_deref(), expr) } @@ -1735,10 +1741,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { self.check_expr_has_type_or_error(base_expr, adt_ty, |_| { let base_ty = self.typeck_results.borrow().expr_ty(*base_expr); - let same_adt = match (adt_ty.kind(), base_ty.kind()) { - (ty::Adt(adt, _), ty::Adt(base_adt, _)) if adt == base_adt => true, - _ => false, - }; + let same_adt = matches!((adt_ty.kind(), base_ty.kind()), + (ty::Adt(adt, _), ty::Adt(base_adt, _)) if adt == base_adt); if self.tcx.sess.is_nightly_build() && same_adt { feature_err( &self.tcx.sess.parse_sess, @@ -2449,15 +2453,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { base_did: DefId, return_ty: Option<Ty<'tcx>>, ) -> ErrorGuaranteed { - let struct_path = self.tcx().def_path_str(base_did); - let kind_name = self.tcx().def_descr(base_did); - let mut err = struct_span_err!( - self.tcx().sess, - field.span, - E0616, - "field `{field}` of {kind_name} `{struct_path}` is private", - ); - err.span_label(field.span, "private field"); + let mut err = self.private_field_err(field, base_did); + // Also check if an accessible method exists, which is often what is meant. if self.method_exists(field, expr_t, expr.hir_id, false, return_ty) && !self.expr_in_place(expr.hir_id) @@ -2697,6 +2694,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err } + fn private_field_err( + &self, + field: Ident, + base_did: DefId, + ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { + let struct_path = self.tcx().def_path_str(base_did); + let kind_name = self.tcx().def_descr(base_did); + let mut err = struct_span_err!( + self.tcx().sess, + field.span, + E0616, + "field `{field}` of {kind_name} `{struct_path}` is private", + ); + err.span_label(field.span, "private field"); + + err + } + pub(crate) fn get_field_candidates_considering_privacy( &self, span: Span, @@ -2802,6 +2817,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { element_ty } None => { + // Attempt to *shallowly* search for an impl which matches, + // but has nested obligations which are unsatisfied. + for (base_t, _) in self.autoderef(base.span, base_t).silence_errors() { + if let Some((_, index_ty, element_ty)) = + self.find_and_report_unsatisfied_index_impl(expr.hir_id, base, base_t) + { + self.demand_coerce(idx, idx_t, index_ty, None, AllowTwoPhase::No); + return element_ty; + } + } + let mut err = type_error_struct!( self.tcx.sess, expr.span, @@ -2845,6 +2871,82 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + /// Try to match an implementation of `Index` against a self type, and report + /// the unsatisfied predicates that result from confirming this impl. + /// + /// Given an index expression, sometimes the `Self` type shallowly but does not + /// deeply satisfy an impl predicate. Instead of simply saying that the type + /// does not support being indexed, we want to point out exactly what nested + /// predicates cause this to be, so that the user can add them to fix their code. + fn find_and_report_unsatisfied_index_impl( + &self, + index_expr_hir_id: HirId, + base_expr: &hir::Expr<'_>, + base_ty: Ty<'tcx>, + ) -> Option<(ErrorGuaranteed, Ty<'tcx>, Ty<'tcx>)> { + let index_trait_def_id = self.tcx.lang_items().index_trait()?; + let index_trait_output_def_id = self.tcx.get_diagnostic_item(sym::IndexOutput)?; + + let mut relevant_impls = vec![]; + self.tcx.for_each_relevant_impl(index_trait_def_id, base_ty, |impl_def_id| { + relevant_impls.push(impl_def_id); + }); + let [impl_def_id] = relevant_impls[..] else { + // Only report unsatisfied impl predicates if there's one impl + return None; + }; + + self.commit_if_ok(|_| { + let ocx = ObligationCtxt::new_in_snapshot(self); + let impl_substs = self.fresh_substs_for_item(base_expr.span, impl_def_id); + let impl_trait_ref = + self.tcx.impl_trait_ref(impl_def_id).unwrap().subst(self.tcx, impl_substs); + let cause = self.misc(base_expr.span); + + // Match the impl self type against the base ty. If this fails, + // we just skip this impl, since it's not particularly useful. + let impl_trait_ref = ocx.normalize(&cause, self.param_env, impl_trait_ref); + ocx.eq(&cause, self.param_env, impl_trait_ref.self_ty(), base_ty)?; + + // Register the impl's predicates. One of these predicates + // must be unsatisfied, or else we wouldn't have gotten here + // in the first place. + ocx.register_obligations(traits::predicates_for_generics( + |idx, span| { + traits::ObligationCause::new( + base_expr.span, + self.body_id, + if span.is_dummy() { + traits::ExprItemObligation(impl_def_id, index_expr_hir_id, idx) + } else { + traits::ExprBindingObligation(impl_def_id, span, index_expr_hir_id, idx) + }, + ) + }, + self.param_env, + self.tcx.predicates_of(impl_def_id).instantiate(self.tcx, impl_substs), + )); + + // Normalize the output type, which we can use later on as the + // return type of the index expression... + let element_ty = ocx.normalize( + &cause, + self.param_env, + self.tcx.mk_projection(index_trait_output_def_id, impl_trait_ref.substs), + ); + + let errors = ocx.select_where_possible(); + // There should be at least one error reported. If not, we + // will still delay a span bug in `report_fulfillment_errors`. + Ok::<_, NoSolution>(( + self.err_ctxt().report_fulfillment_errors(&errors), + impl_trait_ref.substs.type_at(1), + element_ty, + )) + }) + .ok() + } + fn point_at_index_if_possible( &self, errors: &mut Vec<traits::FulfillmentError<'tcx>>, @@ -2954,4 +3056,78 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.mk_unit() } } + + fn check_offset_of( + &self, + container: &'tcx hir::Ty<'tcx>, + fields: &[Ident], + expr: &'tcx hir::Expr<'tcx>, + ) -> Ty<'tcx> { + let container = self.to_ty(container).normalized; + + let mut field_indices = Vec::with_capacity(fields.len()); + let mut current_container = container; + + for &field in fields { + let container = self.structurally_resolved_type(expr.span, current_container); + + match container.kind() { + ty::Adt(container_def, substs) if !container_def.is_enum() => { + let block = self.tcx.hir().local_def_id_to_hir_id(self.body_id); + let (ident, def_scope) = + self.tcx.adjust_ident_and_get_scope(field, container_def.did(), block); + + let fields = &container_def.non_enum_variant().fields; + if let Some((index, field)) = fields + .iter_enumerated() + .find(|(_, f)| f.ident(self.tcx).normalize_to_macros_2_0() == ident) + { + let field_ty = self.field_ty(expr.span, field, substs); + + // FIXME: DSTs with static alignment should be allowed + self.require_type_is_sized(field_ty, expr.span, traits::MiscObligation); + + if field.vis.is_accessible_from(def_scope, self.tcx) { + self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None); + } else { + self.private_field_err(ident, container_def.did()).emit(); + } + + // Save the index of all fields regardless of their visibility in case + // of error recovery. + field_indices.push(index); + current_container = field_ty; + + continue; + } + } + ty::Tuple(tys) => { + let fstr = field.as_str(); + + if let Ok(index) = fstr.parse::<usize>() { + if fstr == index.to_string() { + if let Some(&field_ty) = tys.get(index) { + field_indices.push(index.into()); + current_container = field_ty; + + continue; + } + } + } + } + _ => (), + }; + + self.no_such_field_err(field, container, expr.hir_id).emit(); + + break; + } + + self.typeck_results + .borrow_mut() + .offset_of_data_mut() + .insert(expr.hir_id, (container, field_indices)); + + self.tcx.types.usize + } } diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index ee1c6fbfd65..94b6a0f8f47 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -300,6 +300,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { hir::ExprKind::Continue(..) | hir::ExprKind::Lit(..) | hir::ExprKind::ConstBlock(..) + | hir::ExprKind::OffsetOf(..) | hir::ExprKind::Err(_) => {} hir::ExprKind::Loop(blk, ..) => { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index f736f7a9620..2b5af4bc81b 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -420,9 +420,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ast_c: &hir::AnonConst, param_def_id: DefId, ) -> ty::Const<'tcx> { - let const_def = - ty::WithOptConstParam { did: ast_c.def_id, const_param_did: Some(param_def_id) }; - let c = ty::Const::from_opt_const_arg_anon_const(self.tcx, const_def); + let did = ast_c.def_id; + self.tcx.feed_anon_const_type(did, self.tcx.type_of(param_def_id)); + let c = ty::Const::from_anon_const(self.tcx, did); self.register_wf_obligation( c.into(), self.tcx.hir().span(ast_c.hir_id), @@ -827,7 +827,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } QPath::TypeRelative(ref qself, ref segment) => { // Don't use `self.to_ty`, since this will register a WF obligation. - // If we're trying to call a non-existent method on a trait + // If we're trying to call a nonexistent method on a trait // (e.g. `MyTrait::missing_method`), then resolution will // give us a `QPath::TypeRelative` with a trait object as // `qself`. In that case, we want to avoid registering a WF obligation diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs index f879ccbb3af..56c94505727 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs @@ -164,24 +164,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at] + .into_iter() + .flatten() { - if let Some(param) = param { - let refined_expr = self.point_at_field_if_possible( - def_id, - param, - variant_def_id, - fields, - ); - - match refined_expr { - None => {} - Some((refined_expr, _)) => { - error.obligation.cause.span = refined_expr - .span - .find_ancestor_in_same_ctxt(error.obligation.cause.span) - .unwrap_or(refined_expr.span); - return true; - } + let refined_expr = + self.point_at_field_if_possible(def_id, param, variant_def_id, fields); + + match refined_expr { + None => {} + Some((refined_expr, _)) => { + error.obligation.cause.span = refined_expr + .span + .find_ancestor_in_same_ctxt(error.obligation.cause.span) + .unwrap_or(refined_expr.span); + return true; } } } @@ -334,7 +330,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// expression mentioned. /// /// `blame_specific_arg_if_possible` will find the most-specific expression anywhere inside - /// the provided function call expression, and mark it as responsible for the fullfillment + /// the provided function call expression, and mark it as responsible for the fulfillment /// error. fn blame_specific_arg_if_possible( &self, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index c6fd0b61035..3ba679df3ed 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -17,7 +17,6 @@ use rustc_infer::infer; use rustc_infer::infer::error_reporting::TypeErrCtxt; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; -use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt}; use rustc_session::Session; use rustc_span::symbol::Ident; @@ -250,16 +249,12 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { } fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> { - if let Some(param) = param { - if let GenericArgKind::Type(ty) = self.var_for_def(span, param).unpack() { - return ty; - } - unreachable!() - } else { - self.next_ty_var(TypeVariableOrigin { + match param { + Some(param) => self.var_for_def(span, param).as_type().unwrap(), + None => self.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span, - }) + }), } } @@ -269,16 +264,12 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { param: Option<&ty::GenericParamDef>, span: Span, ) -> Const<'tcx> { - if let Some(param) = param { - if let GenericArgKind::Const(ct) = self.var_for_def(span, param).unpack() { - return ct; - } - unreachable!() - } else { - self.next_const_var( + match param { + Some(param) => self.var_for_def(span, param).as_const().unwrap(), + None => self.next_const_var( ty, ConstVariableOrigin { kind: ConstVariableOriginKind::ConstInference, span }, - ) + ), } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 5fda4e191c2..eef2b5009c8 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -794,7 +794,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; }; - // get all where BoundPredicates here, because they are used in to cases below + // get all where BoundPredicates here, because they are used in two cases below let where_predicates = predicates .iter() .filter_map(|p| match p { @@ -1252,7 +1252,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 { return false; }; + let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(*span) else { return false; }; if !(snippet.starts_with("0x") || snippet.starts_with("0X")) { return false; } @@ -1311,7 +1311,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/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs index 3e9a9ce1b31..28c44aa5703 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs @@ -215,6 +215,7 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> { | ExprKind::Continue(..) | ExprKind::Ret(..) | ExprKind::InlineAsm(..) + | ExprKind::OffsetOf(..) | ExprKind::Struct(..) | ExprKind::Repeat(..) | ExprKind::Yield(..) @@ -485,6 +486,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> { | ExprKind::Field(..) | ExprKind::Index(..) | ExprKind::InlineAsm(..) + | ExprKind::OffsetOf(..) | ExprKind::Let(..) | ExprKind::Lit(..) | ExprKind::Path(..) diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs index f7b493bc224..d3685d21f25 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs @@ -268,8 +268,7 @@ impl DropRangesBuilder { fn node_mut(&mut self, id: PostOrderId) -> &mut NodeInfo { let size = self.num_values(); - self.nodes.ensure_contains_elem(id, || NodeInfo::new(size)); - &mut self.nodes[id] + self.nodes.ensure_contains_elem(id, || NodeInfo::new(size)) } fn add_control_edge(&mut self, from: PostOrderId, to: PostOrderId) { diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs index f3971080443..8feef332de8 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs @@ -650,7 +650,7 @@ fn check_must_not_suspend_ty<'tcx>( }, ) } - // If drop tracking is enabled, we want to look through references, since the referrent + // If drop tracking is enabled, we want to look through references, since the referent // may not be considered live across the await point. ty::Ref(_region, ty, _mutability) if fcx.sess().opts.unstable_opts.drop_tracking => { let descr_pre = &format!("{}reference{} to ", data.descr_pre, plural_suffix); diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs index 106f5bcd755..0fdb29a5e48 100644 --- a/compiler/rustc_hir_typeck/src/intrinsicck.rs +++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs @@ -4,7 +4,7 @@ use rustc_hir as hir; use rustc_index::vec::Idx; use rustc_middle::ty::layout::{LayoutError, SizeSkeleton}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; -use rustc_target::abi::{FieldIdx, Pointer, VariantIdx}; +use rustc_target::abi::{Pointer, VariantIdx}; use super::FnCtxt; @@ -28,7 +28,7 @@ fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { } if def.variant(data_idx).fields.len() == 1 { - return def.variant(data_idx).fields[FieldIdx::from_u32(0)].ty(tcx, substs); + return def.variant(data_idx).single_field().ty(tcx, substs); } } diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 45890abad92..08d3593f91f 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -59,6 +59,7 @@ use rustc_errors::{ struct_span_err, DiagnosticId, DiagnosticMessage, ErrorGuaranteed, MultiSpan, SubdiagnosticMessage, }; +use rustc_fluent_macro::fluent_messages; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::Visitor; @@ -66,7 +67,6 @@ use rustc_hir::{HirIdMap, Node}; use rustc_hir_analysis::astconv::AstConv; use rustc_hir_analysis::check::check_abi; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_macros::fluent_messages; use rustc_middle::traits; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -156,21 +156,9 @@ fn typeck_item_bodies(tcx: TyCtxt<'_>, (): ()) { tcx.hir().par_body_owners(|body_owner_def_id| tcx.ensure().typeck(body_owner_def_id)); } -fn typeck_const_arg<'tcx>( - tcx: TyCtxt<'tcx>, - (did, param_did): (LocalDefId, DefId), -) -> &ty::TypeckResults<'tcx> { - let fallback = move || tcx.type_of(param_did).subst_identity(); - typeck_with_fallback(tcx, did, fallback) -} - fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> { - if let Some(param_did) = tcx.opt_const_param_of(def_id) { - tcx.typeck_const_arg((def_id, param_did)) - } else { - let fallback = move || tcx.type_of(def_id.to_def_id()).subst_identity(); - typeck_with_fallback(tcx, def_id, fallback) - } + let fallback = move || tcx.type_of(def_id.to_def_id()).subst_identity(); + typeck_with_fallback(tcx, def_id, fallback) } /// Used only to get `TypeckResults` for type inference during error recovery. @@ -492,7 +480,6 @@ pub fn provide(providers: &mut Providers) { method::provide(providers); *providers = Providers { typeck_item_bodies, - typeck_const_arg, typeck, diagnostic_only_typeck, has_typeck_results, diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs index 6c861b5930a..f5fca14eca8 100644 --- a/compiler/rustc_hir_typeck/src/mem_categorization.rs +++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs @@ -381,6 +381,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { | hir::ExprKind::Struct(..) | hir::ExprKind::Repeat(..) | hir::ExprKind::InlineAsm(..) + | hir::ExprKind::OffsetOf(..) | hir::ExprKind::Err(_) => Ok(self.cat_rvalue(expr.hir_id, expr.span, expr_ty)), } } diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 900a6fa0d8d..db1f10f645f 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1530,7 +1530,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); if pick.is_ok() { let range_span = parent_expr.span.with_hi(expr.span.hi()); - tcx.sess.emit_err(errors::MissingParentheseInRange { + tcx.sess.emit_err(errors::MissingParenthesesInRange { span, ty_str: ty_str.to_string(), method_name: item_name.as_str().to_string(), diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index af0bd26dec5..7160d1c67b2 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -1659,7 +1659,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if tcx.sess.teach(&err.get_code().unwrap()) { err.note( "This error indicates that a struct pattern attempted to \ - extract a non-existent field from a struct. Struct fields \ + extract a nonexistent field from a struct. Struct fields \ are identified by the name used before the colon : so struct \ patterns should resemble the declaration of the struct type \ being matched.\n\n\ diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 41a6ad80b65..147b3e74d0f 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -223,7 +223,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let closure_hir_id = self.tcx.hir().local_def_id_to_hir_id(closure_def_id); if should_do_rust_2021_incompatible_closure_captures_analysis(self.tcx, closure_hir_id) { - self.perform_2229_migration_anaysis(closure_def_id, body_id, capture_clause, span); + self.perform_2229_migration_analysis(closure_def_id, body_id, capture_clause, span); } let after_feature_tys = self.final_upvar_tys(closure_def_id); @@ -731,7 +731,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Perform the migration analysis for RFC 2229, and emit lint /// `disjoint_capture_drop_reorder` if needed. - fn perform_2229_migration_anaysis( + fn perform_2229_migration_analysis( &self, closure_def_id: LocalDefId, body_id: hir::BodyId, diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index e876fa27593..9432a5840b2 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -70,6 +70,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { wbcx.visit_user_provided_tys(); wbcx.visit_user_provided_sigs(); wbcx.visit_generator_interior_types(); + wbcx.visit_offset_of_container_types(); wbcx.typeck_results.rvalue_scopes = mem::take(&mut self.typeck_results.borrow_mut().rvalue_scopes); @@ -295,7 +296,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { self.visit_field_id(field.hir_id); } } - hir::ExprKind::Field(..) => { + hir::ExprKind::Field(..) | hir::ExprKind::OffsetOf(..) => { self.visit_field_id(e.hir_id); } hir::ExprKind::ConstBlock(anon_const) => { @@ -682,6 +683,28 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } + fn visit_offset_of_container_types(&mut self) { + let fcx_typeck_results = self.fcx.typeck_results.borrow(); + assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); + let common_hir_owner = fcx_typeck_results.hir_owner; + + for (local_id, &(container, ref indices)) in + fcx_typeck_results.offset_of_data().items_in_stable_order() + { + let hir_id = hir::HirId { owner: common_hir_owner, local_id }; + + if cfg!(debug_assertions) && container.needs_infer() { + span_bug!( + hir_id.to_span(self.fcx.tcx), + "writeback: `{:?}` has inference variables", + container + ); + }; + + self.typeck_results.offset_of_data_mut().insert(hir_id, (container, indices.clone())); + } + } + fn resolve<T>(&mut self, x: T, span: &dyn Locatable) -> T where T: TypeFoldable<TyCtxt<'tcx>>, diff --git a/compiler/rustc_incremental/Cargo.toml b/compiler/rustc_incremental/Cargo.toml index ad89393956e..59a0623c1e1 100644 --- a/compiler/rustc_incremental/Cargo.toml +++ b/compiler/rustc_incremental/Cargo.toml @@ -11,6 +11,7 @@ rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_fs_util = { path = "../rustc_fs_util" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_graphviz = { path = "../rustc_graphviz" } rustc_hir = { path = "../rustc_hir" } rustc_macros = { path = "../rustc_macros" } diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs index df958e4a61f..11710c368ce 100644 --- a/compiler/rustc_incremental/src/lib.rs +++ b/compiler/rustc_incremental/src/lib.rs @@ -33,6 +33,6 @@ pub use persist::LoadResult; pub use persist::{build_dep_graph, load_dep_graph, DepGraphFuture}; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; -use rustc_macros::fluent_messages; +use rustc_fluent_macro::fluent_messages; fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs index 1d88dfd20c8..43274091cb8 100644 --- a/compiler/rustc_incremental/src/persist/dirty_clean.rs +++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs @@ -139,7 +139,7 @@ pub fn check_dirty_clean_annotations(tcx: TyCtxt<'_>) { return; } - // can't add `#[rustc_clean]` etc without opting in to this feature + // can't add `#[rustc_clean]` etc without opting into this feature if !tcx.features().rustc_attrs { return; } diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index d6f83838a04..ec6d61f9e5f 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -601,7 +601,7 @@ fn string_to_timestamp(s: &str) -> Result<SystemTime, ()> { fn crate_path(sess: &Session, crate_name: Symbol, stable_crate_id: StableCrateId) -> PathBuf { let incr_dir = sess.opts.incremental.as_ref().unwrap().clone(); - let stable_crate_id = base_n::encode(stable_crate_id.to_u64() as u128, INT_ENCODE_BASE); + let stable_crate_id = base_n::encode(stable_crate_id.as_u64() as u128, INT_ENCODE_BASE); let crate_name = format!("{}-{}", crate_name, stable_crate_id); incr_dir.join(crate_name) diff --git a/compiler/rustc_index/src/interval.rs b/compiler/rustc_index/src/interval.rs index d809740c6ab..4605d42a15b 100644 --- a/compiler/rustc_index/src/interval.rs +++ b/compiler/rustc_index/src/interval.rs @@ -261,8 +261,7 @@ impl<R: Idx, C: Step + Idx> SparseIntervalMatrix<R, C> { } fn ensure_row(&mut self, row: R) -> &mut IntervalSet<C> { - self.rows.ensure_contains_elem(row, || IntervalSet::new(self.column_size)); - &mut self.rows[row] + self.rows.ensure_contains_elem(row, || IntervalSet::new(self.column_size)) } pub fn union_row(&mut self, row: R, from: &IntervalSet<C>) -> bool diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index ae2f52c513e..18e779f786e 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -236,12 +236,16 @@ impl<I: Idx, T> IndexVec<I, T> { /// `elem`; if that is already true, then has no /// effect. Otherwise, inserts new values as needed by invoking /// `fill_value`. + /// + /// Returns a reference to the `elem` entry. #[inline] - pub fn ensure_contains_elem(&mut self, elem: I, fill_value: impl FnMut() -> T) { + pub fn ensure_contains_elem(&mut self, elem: I, fill_value: impl FnMut() -> T) -> &mut T { let min_new_len = elem.index() + 1; if self.len() < min_new_len { self.raw.resize_with(min_new_len, fill_value); } + + &mut self[elem] } #[inline] @@ -446,20 +450,17 @@ impl<I: Idx, J: Idx> IndexSlice<I, J> { impl<I: Idx, T> IndexVec<I, Option<T>> { #[inline] pub fn insert(&mut self, index: I, value: T) -> Option<T> { - self.ensure_contains_elem(index, || None); - self[index].replace(value) + self.ensure_contains_elem(index, || None).replace(value) } #[inline] pub fn get_or_insert_with(&mut self, index: I, value: impl FnOnce() -> T) -> &mut T { - self.ensure_contains_elem(index, || None); - self[index].get_or_insert_with(value) + self.ensure_contains_elem(index, || None).get_or_insert_with(value) } #[inline] pub fn remove(&mut self, index: I) -> Option<T> { - self.ensure_contains_elem(index, || None); - self[index].take() + self.get_mut(index)?.take() } } diff --git a/compiler/rustc_infer/Cargo.toml b/compiler/rustc_infer/Cargo.toml index 02ac83a5e8b..9dd5868adc7 100644 --- a/compiler/rustc_infer/Cargo.toml +++ b/compiler/rustc_infer/Cargo.toml @@ -12,6 +12,7 @@ rustc_middle = { path = "../rustc_middle" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_hir = { path = "../rustc_hir" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_index = { path = "../rustc_index" } rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl index c8998ea91bf..fdc4ff0896f 100644 --- a/compiler/rustc_infer/messages.ftl +++ b/compiler/rustc_infer/messages.ftl @@ -80,7 +80,7 @@ infer_subtype = ...so that the {$requirement -> [no_else] `if` missing an `else` returns `()` [fn_main_correct_type] `main` function has the correct type [fn_start_correct_type] `#[start]` function has the correct type - [intristic_correct_type] intrinsic has the correct type + [intrinsic_correct_type] intrinsic has the correct type [method_correct_type] method receiver has the correct type *[other] types are compatible } @@ -93,7 +93,7 @@ infer_subtype_2 = ...so that {$requirement -> [no_else] `if` missing an `else` returns `()` [fn_main_correct_type] `main` function has the correct type [fn_start_correct_type] `#[start]` function has the correct type - [intristic_correct_type] intrinsic has the correct type + [intrinsic_correct_type] intrinsic has the correct type [method_correct_type] method receiver has the correct type *[other] types are compatible } @@ -341,8 +341,8 @@ infer_await_note = calling an async function returns a future infer_prlf_defined_with_sub = the lifetime `{$sub_symbol}` defined here... infer_prlf_defined_without_sub = the lifetime defined here... -infer_prlf_must_oultive_with_sup = ...must outlive the lifetime `{$sup_symbol}` defined here -infer_prlf_must_oultive_without_sup = ...must outlive the lifetime defined here +infer_prlf_must_outlive_with_sup = ...must outlive the lifetime `{$sup_symbol}` defined here +infer_prlf_must_outlive_without_sup = ...must outlive the lifetime defined here infer_prlf_known_limitation = this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information) infer_opaque_captures_lifetime = hidden type for `{$opaque_ty}` captures lifetime that does not appear in bounds @@ -380,7 +380,7 @@ infer_oc_no_else = `if` may be missing an `else` clause infer_oc_no_diverge = `else` clause of `let...else` does not diverge infer_oc_fn_main_correct_type = `main` function has wrong type infer_oc_fn_start_correct_type = `#[start]` function has wrong type -infer_oc_intristic_correct_type = intrinsic has wrong type +infer_oc_intrinsic_correct_type = intrinsic has wrong type infer_oc_method_correct_type = mismatched `self` parameter type infer_oc_closure_selfref = closure/generator type that references itself infer_oc_cant_coerce = cannot coerce intrinsics to function pointers diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 65b3dd1a892..b1e819e83f1 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -71,7 +71,7 @@ pub struct AmbiguousImpl<'a> { // Copy of `AnnotationRequired` for E0284 #[derive(Diagnostic)] #[diag(infer_type_annotations_needed, code = "E0284")] -pub struct AmbigousReturn<'a> { +pub struct AmbiguousReturn<'a> { #[primary_span] pub span: Span, pub source_kind: &'static str, @@ -1085,7 +1085,7 @@ pub enum PlaceholderRelationLfNotSatisfied { span: Span, #[note(infer_prlf_defined_with_sub)] sub_span: Span, - #[note(infer_prlf_must_oultive_with_sup)] + #[note(infer_prlf_must_outlive_with_sup)] sup_span: Span, sub_symbol: Symbol, sup_symbol: Symbol, @@ -1098,7 +1098,7 @@ pub enum PlaceholderRelationLfNotSatisfied { span: Span, #[note(infer_prlf_defined_with_sub)] sub_span: Span, - #[note(infer_prlf_must_oultive_without_sup)] + #[note(infer_prlf_must_outlive_without_sup)] sup_span: Span, sub_symbol: Symbol, #[note(infer_prlf_known_limitation)] @@ -1110,7 +1110,7 @@ pub enum PlaceholderRelationLfNotSatisfied { span: Span, #[note(infer_prlf_defined_without_sub)] sub_span: Span, - #[note(infer_prlf_must_oultive_with_sup)] + #[note(infer_prlf_must_outlive_with_sup)] sup_span: Span, sup_symbol: Symbol, #[note(infer_prlf_known_limitation)] @@ -1122,7 +1122,7 @@ pub enum PlaceholderRelationLfNotSatisfied { span: Span, #[note(infer_prlf_defined_without_sub)] sub_span: Span, - #[note(infer_prlf_must_oultive_without_sup)] + #[note(infer_prlf_must_outlive_without_sup)] sup_span: Span, #[note(infer_prlf_known_limitation)] note: (), @@ -1488,8 +1488,8 @@ pub enum ObligationCauseFailureCode { #[subdiagnostic] subdiags: Vec<TypeErrorAdditionalDiags>, }, - #[diag(infer_oc_intristic_correct_type, code = "E0308")] - IntristicCorrectType { + #[diag(infer_oc_intrinsic_correct_type, code = "E0308")] + IntrinsicCorrectType { #[primary_span] span: Span, #[subdiagnostic] diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index e98f68ae5a8..257d3625929 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -467,11 +467,11 @@ impl<'tcx> InferCtxt<'tcx> { } } GenericArgKind::Const(result_value) => { - if let ty::ConstKind::Bound(debrujin, b) = result_value.kind() { + if let ty::ConstKind::Bound(debruijn, b) = result_value.kind() { // ...in which case we would set `canonical_vars[0]` to `Some(const X)`. // We only allow a `ty::INNERMOST` index in substitutions. - assert_eq!(debrujin, ty::INNERMOST); + assert_eq!(debruijn, ty::INNERMOST); opt_values[b] = Some(*original_value); } } diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index fe45b5ebe61..9b670c76a18 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -832,7 +832,7 @@ pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> { /// Register predicates that must hold in order for this relation to hold. Uses /// a default obligation cause, [`ObligationEmittingRelation::register_obligations`] should - /// be used if control over the obligaton causes is required. + /// be used if control over the obligation causes is required. fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ToPredicate<'tcx>>); /// Register an obligation that both constants must be equal to each other. diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs index fe4a2dd3800..f90f7674b55 100644 --- a/compiler/rustc_infer/src/infer/equate.rs +++ b/compiler/rustc_infer/src/infer/equate.rs @@ -178,7 +178,7 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> { where T: Relate<'tcx>, { - // A binder is equal to itself if it's structually equal to itself + // A binder is equal to itself if it's structurally equal to itself if a == b { return Ok(a); } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 9e5f6d107d1..b0c376a26f6 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -74,7 +74,6 @@ use rustc_middle::ty::{ self, error::TypeError, List, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, }; -use rustc_span::DUMMY_SP; use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span}; use rustc_target::spec::abi; use std::ops::{ControlFlow, Deref}; @@ -138,7 +137,7 @@ impl Drop for TypeErrCtxt<'_, '_> { self.infcx .tcx .sess - .delay_span_bug(DUMMY_SP, "used a `TypeErrCtxt` without failing compilation"); + .delay_good_path_bug("used a `TypeErrCtxt` without raising an error or lint"); } } } @@ -1927,6 +1926,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { { let span = self.tcx.def_span(def_id); diag.span_note(span, "this closure does not fulfill the lifetime requirements"); + self.suggest_for_all_lifetime_closure(span, self.tcx.hir().get_by_def_id(def_id), &exp_found, diag); } // It reads better to have the error origin as the final @@ -2885,7 +2885,7 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { LetElse => ObligationCauseFailureCode::NoDiverge { span, subdiags }, MainFunctionType => ObligationCauseFailureCode::FnMainCorrectType { span }, StartFunctionType => ObligationCauseFailureCode::FnStartCorrectType { span, subdiags }, - IntrinsicType => ObligationCauseFailureCode::IntristicCorrectType { span, subdiags }, + IntrinsicType => ObligationCauseFailureCode::IntrinsicCorrectType { span, subdiags }, MethodReceiver => ObligationCauseFailureCode::MethodCorrectType { span, subdiags }, // In the case where we have no more specific thing to @@ -2942,7 +2942,7 @@ impl IntoDiagnosticArg for ObligationCauseAsDiagArg<'_> { IfExpressionWithNoElse => "no_else", MainFunctionType => "fn_main_correct_type", StartFunctionType => "fn_start_correct_type", - IntrinsicType => "intristic_correct_type", + IntrinsicType => "intrinsic_correct_type", MethodReceiver => "method_correct_type", _ => "other", } diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 75cc4e257bd..58e3159a4e2 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -1,5 +1,5 @@ use crate::errors::{ - AmbigousReturn, AmbiguousImpl, AnnotationRequired, InferenceBadError, NeedTypeInfoInGenerator, + AmbiguousImpl, AmbiguousReturn, AnnotationRequired, InferenceBadError, NeedTypeInfoInGenerator, SourceKindMultiSuggestion, SourceKindSubdiag, }; use crate::infer::error_reporting::TypeErrCtxt; @@ -368,7 +368,7 @@ impl<'tcx> InferCtxt<'tcx> { bad_label, } .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic), - TypeAnnotationNeeded::E0284 => AmbigousReturn { + TypeAnnotationNeeded::E0284 => AmbiguousReturn { span, source_kind, source_name, @@ -573,7 +573,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { bad_label: None, } .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic), - TypeAnnotationNeeded::E0284 => AmbigousReturn { + TypeAnnotationNeeded::E0284 => AmbiguousReturn { span, source_kind, source_name: &name, diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index 22c1e387117..27c3b796d14 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -312,13 +312,10 @@ pub fn suggest_new_region_bound( Applicability::MaybeIncorrect, ); } - } else if opaque.bounds.iter().any(|arg| match arg { - GenericBound::Outlives(Lifetime { ident, .. }) - if ident.name.to_string() == lifetime_name => - { - true - } - _ => false, + } else if opaque.bounds.iter().any(|arg| { + matches!(arg, + GenericBound::Outlives(Lifetime { ident, .. }) + if ident.name.to_string() == lifetime_name ) }) { } else { // get a lifetime name of existing named lifetimes if any diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 2875448ee15..ce70bcc5c85 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -13,7 +13,7 @@ use rustc_hir::intravisit::Visitor; use rustc_middle::hir::nested_filter; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::print::RegionHighlightMode; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor}; use rustc_span::Span; use std::ops::ControlFlow; @@ -81,7 +81,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { self.highlight.highlighting_region(r, self.counter); self.counter += 1; } - r.super_visit_with(self) + ControlFlow::Continue(()) } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs index b38bbdfe7bb..e410172c8c8 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs @@ -462,10 +462,7 @@ fn foo(&self) -> Self::T { String::new() } if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *proj_ty.self_ty().kind() { let opaque_local_def_id = def_id.as_local(); let opaque_hir_ty = if let Some(opaque_local_def_id) = opaque_local_def_id { - match &tcx.hir().expect_item(opaque_local_def_id).kind { - hir::ItemKind::OpaqueTy(opaque_hir_ty) => opaque_hir_ty, - _ => bug!("The HirId comes from a `ty::Opaque`"), - } + tcx.hir().expect_item(opaque_local_def_id).expect_opaque_ty() } else { return false; }; diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index b5aeca12a1f..d885d040707 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -1,16 +1,15 @@ use hir::def::CtorKind; use hir::intravisit::{walk_expr, walk_stmt, Visitor}; use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::Diagnostic; +use rustc_errors::{Applicability, Diagnostic}; use rustc_hir as hir; use rustc_middle::traits::{ IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, StatementAsExpression, }; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TypeVisitableExt}; +use rustc_middle::ty::{self as ty, GenericArgKind, IsSuggestable, Ty, TypeVisitableExt}; use rustc_span::{sym, BytePos, Span}; -use rustc_target::abi::FieldIdx; use crate::errors::{ ConsiderAddingAwait, FnConsiderCasting, FnItemsAreDistinct, FnUniqTypes, @@ -114,7 +113,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { variant.fields.len() == 1 && variant.ctor_kind() == Some(CtorKind::Fn) }) .filter_map(|variant| { - let sole_field = &variant.fields[FieldIdx::from_u32(0)]; + let sole_field = &variant.single_field(); let sole_field_ty = sole_field.ty(self.tcx, substs); if self.same_type_modulo_infer(sole_field_ty, exp_found.found) { let variant_path = @@ -536,6 +535,82 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } None } + + /// For "one type is more general than the other" errors on closures, suggest changing the lifetime + /// of the parameters to accept all lifetimes. + pub(super) fn suggest_for_all_lifetime_closure( + &self, + span: Span, + hir: hir::Node<'_>, + exp_found: &ty::error::ExpectedFound<ty::PolyTraitRef<'tcx>>, + diag: &mut Diagnostic, + ) { + // 0. Extract fn_decl from hir + let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(hir::Closure { body, fn_decl, .. }), .. }) = hir else { return; }; + let hir::Body { params, .. } = self.tcx.hir().body(*body); + + // 1. Get the substs of the closure. + // 2. Assume exp_found is FnOnce / FnMut / Fn, we can extract function parameters from [1]. + let Some(expected) = exp_found.expected.skip_binder().substs.get(1) else { return; }; + let Some(found) = exp_found.found.skip_binder().substs.get(1) else { return; }; + let expected = expected.unpack(); + let found = found.unpack(); + // 3. Extract the tuple type from Fn trait and suggest the change. + if let GenericArgKind::Type(expected) = expected && + let GenericArgKind::Type(found) = found && + let ty::Tuple(expected) = expected.kind() && + let ty::Tuple(found)= found.kind() && + expected.len() == found.len() { + let mut suggestion = "|".to_string(); + let mut is_first = true; + let mut has_suggestion = false; + + for (((expected, found), param_hir), arg_hir) in expected.iter() + .zip(found.iter()) + .zip(params.iter()) + .zip(fn_decl.inputs.iter()) { + if is_first { + is_first = false; + } else { + suggestion += ", "; + } + + if let ty::Ref(expected_region, _, _) = expected.kind() && + let ty::Ref(found_region, _, _) = found.kind() && + expected_region.is_late_bound() && + !found_region.is_late_bound() && + let hir::TyKind::Infer = arg_hir.kind { + // If the expected region is late bound, the found region is not, and users are asking compiler + // to infer the type, we can suggest adding `: &_`. + if param_hir.pat.span == param_hir.ty_span { + // for `|x|`, `|_|`, `|x: impl Foo|` + let Ok(pat) = self.tcx.sess.source_map().span_to_snippet(param_hir.pat.span) else { return; }; + suggestion += &format!("{}: &_", pat); + } else { + // for `|x: ty|`, `|_: ty|` + let Ok(pat) = self.tcx.sess.source_map().span_to_snippet(param_hir.pat.span) else { return; }; + let Ok(ty) = self.tcx.sess.source_map().span_to_snippet(param_hir.ty_span) else { return; }; + suggestion += &format!("{}: &{}", pat, ty); + } + has_suggestion = true; + } else { + let Ok(arg) = self.tcx.sess.source_map().span_to_snippet(param_hir.span) else { return; }; + // Otherwise, keep it as-is. + suggestion += &arg; + } + } + suggestion += "|"; + + if has_suggestion { + diag.span_suggestion_verbose( + span, + "consider specifying the type of the closure parameters", + suggestion, + Applicability::MaybeIncorrect, + ); + } + } + } } impl<'tcx> TypeErrCtxt<'_, 'tcx> { diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs index a63cfbc919c..c304cd25c9c 100644 --- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs +++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs @@ -42,7 +42,7 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> { // Next, we instantiate each bound region in the subtype // with a fresh region variable. These region variables -- - // but no other pre-existing region variables -- can name + // but no other preexisting region variables -- can name // the placeholders. let sub_prime = self.infcx.instantiate_binder_with_fresh_vars(span, HigherRankedType, sub); diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index f298b95ca35..df15cab00b4 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -131,10 +131,9 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { self.dump_constraints(); } - let graph = self.construct_graph(); self.expansion(&mut var_data); self.collect_errors(&mut var_data, errors); - self.collect_var_errors(&var_data, &graph, errors); + self.collect_var_errors(&var_data, errors); var_data } @@ -622,7 +621,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { fn collect_var_errors( &self, var_data: &LexicalRegionResolutions<'tcx>, - graph: &RegionGraph<'tcx>, errors: &mut Vec<RegionResolutionError<'tcx>>, ) { debug!("collect_var_errors, var_data = {:#?}", var_data.values); @@ -640,6 +638,10 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // overlapping locations. let mut dup_vec = IndexVec::from_elem_n(None, self.num_vars()); + // Only construct the graph when necessary, because it's moderately + // expensive. + let mut graph = None; + for (node_vid, value) in var_data.values.iter_enumerated() { match *value { VarValue::Empty(_) | VarValue::Value(_) => { /* Inference successful */ } @@ -672,7 +674,8 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // influence the constraints on this value for // richer diagnostics in `static_impl_trait`. - self.collect_error_for_expanding_node(graph, &mut dup_vec, node_vid, errors); + let g = graph.get_or_insert_with(|| self.construct_graph()); + self.collect_error_for_expanding_node(g, &mut dup_vec, node_vid, errors); } } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 66f51328bbe..3e80bb906e4 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1500,7 +1500,7 @@ impl<'tcx> InferCtxt<'tcx> { Ok(Some(val)) => Ok(self.tcx.mk_const(val, ty)), Ok(None) => { let tcx = self.tcx; - let def_id = unevaluated.def.did; + let def_id = unevaluated.def; span_bug!( tcx.def_span(def_id), "unable to construct a constant value for the unevaluated constant {:?}", @@ -1547,8 +1547,8 @@ impl<'tcx> InferCtxt<'tcx> { substs = replace_param_and_infer_substs_with_placeholder(tcx, substs); } } else { - substs = InternalSubsts::identity_for_item(tcx, unevaluated.def.did); - param_env = tcx.param_env(unevaluated.def.did); + substs = InternalSubsts::identity_for_item(tcx, unevaluated.def); + param_env = tcx.param_env(unevaluated.def); } } @@ -1577,10 +1577,10 @@ impl<'tcx> InferCtxt<'tcx> { (TyOrConstInferVar::Ty(ty_var), Ok(inner)) => { use self::type_variable::TypeVariableValue; - match inner.try_type_variables_probe_ref(ty_var) { - Some(TypeVariableValue::Unknown { .. }) => true, - _ => false, - } + matches!( + inner.try_type_variables_probe_ref(ty_var), + Some(TypeVariableValue::Unknown { .. }) + ) } _ => false, }; diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 3a0a0494a7e..680465bdab6 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -392,12 +392,7 @@ impl<'tcx> InferCtxt<'tcx> { /// defining scope. #[instrument(skip(self), level = "trace", ret)] fn opaque_type_origin_unchecked(&self, def_id: LocalDefId) -> OpaqueTyOrigin { - match self.tcx.hir().expect_item(def_id).kind { - hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => origin, - ref itemkind => { - bug!("weird opaque type: {:?}, {:#?}", def_id, itemkind) - } - } + self.tcx.hir().expect_item(def_id).expect_opaque_ty().origin } } diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs index ff23087fe8d..cb63d2f18b6 100644 --- a/compiler/rustc_infer/src/infer/outlives/components.rs +++ b/compiler/rustc_infer/src/infer/outlives/components.rs @@ -143,7 +143,7 @@ fn compute_components<'tcx>( // through and constrain Pi. let mut subcomponents = smallvec![]; let mut subvisited = SsoHashSet::new(); - compute_components_recursive(tcx, ty.into(), &mut subcomponents, &mut subvisited); + compute_alias_components_recursive(tcx, ty, &mut subcomponents, &mut subvisited); out.push(Component::EscapingAlias(subcomponents.into_iter().collect())); } } @@ -193,7 +193,43 @@ fn compute_components<'tcx>( /// /// This should not be used to get the components of `parent` itself. /// Use [push_outlives_components] instead. -pub(super) fn compute_components_recursive<'tcx>( +pub(super) fn compute_alias_components_recursive<'tcx>( + tcx: TyCtxt<'tcx>, + alias_ty: Ty<'tcx>, + out: &mut SmallVec<[Component<'tcx>; 4]>, + visited: &mut SsoHashSet<GenericArg<'tcx>>, +) { + let ty::Alias(kind, alias_ty) = alias_ty.kind() else { bug!() }; + let opt_variances = if *kind == ty::Opaque { tcx.variances_of(alias_ty.def_id) } else { &[] }; + for (index, child) in alias_ty.substs.iter().enumerate() { + if opt_variances.get(index) == Some(&ty::Bivariant) { + continue; + } + if !visited.insert(child) { + continue; + } + match child.unpack() { + GenericArgKind::Type(ty) => { + compute_components(tcx, ty, out, visited); + } + GenericArgKind::Lifetime(lt) => { + // Ignore late-bound regions. + if !lt.is_late_bound() { + out.push(Component::Region(lt)); + } + } + GenericArgKind::Const(_) => { + compute_components_recursive(tcx, child, out, visited); + } + } + } +} + +/// Collect [Component]s for *all* the substs of `parent`. +/// +/// This should not be used to get the components of `parent` itself. +/// Use [push_outlives_components] instead. +fn compute_components_recursive<'tcx>( tcx: TyCtxt<'tcx>, parent: GenericArg<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>, diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index ccf11c61b57..2f5e2e417a6 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -344,12 +344,14 @@ where // the problem is to add `T: 'r`, which isn't true. So, if there are no // inference variables, we use a verify constraint instead of adding // edges, which winds up enforcing the same condition. + let is_opaque = alias_ty.kind(self.tcx) == ty::Opaque; if approx_env_bounds.is_empty() && trait_bounds.is_empty() - && (alias_ty.needs_infer() || alias_ty.kind(self.tcx) == ty::Opaque) + && (alias_ty.needs_infer() || is_opaque) { debug!("no declared bounds"); - self.substs_must_outlive(alias_ty.substs, origin, region); + let opt_variances = is_opaque.then(|| self.tcx.variances_of(alias_ty.def_id)); + self.substs_must_outlive(alias_ty.substs, origin, region, opt_variances); return; } @@ -395,22 +397,31 @@ where self.delegate.push_verify(origin, GenericKind::Alias(alias_ty), region, verify_bound); } + #[instrument(level = "debug", skip(self))] fn substs_must_outlive( &mut self, substs: SubstsRef<'tcx>, origin: infer::SubregionOrigin<'tcx>, region: ty::Region<'tcx>, + opt_variances: Option<&[ty::Variance]>, ) { let constraint = origin.to_constraint_category(); - for k in substs { + for (index, k) in substs.iter().enumerate() { match k.unpack() { GenericArgKind::Lifetime(lt) => { - self.delegate.push_sub_region_constraint( - origin.clone(), - region, - lt, - constraint, - ); + let variance = if let Some(variances) = opt_variances { + variances[index] + } else { + ty::Invariant + }; + if variance == ty::Invariant { + self.delegate.push_sub_region_constraint( + origin.clone(), + region, + lt, + constraint, + ); + } } GenericArgKind::Type(ty) => { self.type_must_outlive(origin.clone(), ty, region, constraint); diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index bae246418b0..e1cb53bc71d 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -1,4 +1,4 @@ -use crate::infer::outlives::components::{compute_components_recursive, Component}; +use crate::infer::outlives::components::{compute_alias_components_recursive, Component}; use crate::infer::outlives::env::RegionBoundPairs; use crate::infer::region_constraints::VerifyIfEq; use crate::infer::VerifyBound; @@ -130,7 +130,12 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { // see the extensive comment in projection_must_outlive let recursive_bound = { let mut components = smallvec![]; - compute_components_recursive(self.tcx, alias_ty_as_ty.into(), &mut components, visited); + compute_alias_components_recursive( + self.tcx, + alias_ty_as_ty.into(), + &mut components, + visited, + ); self.bound_from_components(&components, visited) }; diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index 0dd73a6e999..3766c250a9c 100644 --- a/compiler/rustc_infer/src/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -210,7 +210,7 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { where T: Relate<'tcx>, { - // A binder is always a subtype of itself if it's structually equal to itself + // A binder is always a subtype of itself if it's structurally equal to itself if a == b { return Ok(a); } diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index 738a1237651..e92ba05aa67 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -35,7 +35,7 @@ extern crate tracing; extern crate rustc_middle; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; -use rustc_macros::fluent_messages; +use rustc_fluent_macro::fluent_messages; mod errors; pub mod infer; diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index e01b6caf430..9dd4f0a8e4c 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -89,10 +89,10 @@ impl<'tcx> PredicateObligation<'tcx> { impl<'tcx> TraitObligation<'tcx> { /// Returns `true` if the trait predicate is considered `const` in its ParamEnv. pub fn is_const(&self) -> bool { - match (self.predicate.skip_binder().constness, self.param_env.constness()) { - (ty::BoundConstness::ConstIfConst, hir::Constness::Const) => true, - _ => false, - } + matches!( + (self.predicate.skip_binder().constness, self.param_env.constness()), + (ty::BoundConstness::ConstIfConst, hir::Constness::Const) + ) } pub fn derived_cause( diff --git a/compiler/rustc_infer/src/traits/project.rs b/compiler/rustc_infer/src/traits/project.rs index ac455055b43..8d0af738dd1 100644 --- a/compiler/rustc_infer/src/traits/project.rs +++ b/compiler/rustc_infer/src/traits/project.rs @@ -103,7 +103,7 @@ pub enum ProjectionCacheEntry<'tcx> { /// if this field is set. Evaluation only /// cares about the final result, so we don't /// care about any region constraint side-effects - /// produced by evaluating the sub-boligations. + /// produced by evaluating the sub-obligations. /// /// Additionally, we will clear out the sub-obligations /// entirely if we ever evaluate the cache entry (along diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml index 98d3ab87f9c..4569c35e182 100644 --- a/compiler/rustc_interface/Cargo.toml +++ b/compiler/rustc_interface/Cargo.toml @@ -16,6 +16,7 @@ rustc_attr = { path = "../rustc_attr" } rustc_borrowck = { path = "../rustc_borrowck" } rustc_builtin_macros = { path = "../rustc_builtin_macros" } rustc_expand = { path = "../rustc_expand" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_fs_util = { path = "../rustc_fs_util" } rustc_macros = { path = "../rustc_macros" } rustc_parse = { path = "../rustc_parse" } diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index 9664ba8bd8a..51bd8381e93 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -13,7 +13,7 @@ extern crate tracing; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; -use rustc_macros::fluent_messages; +use rustc_fluent_macro::fluent_messages; mod callbacks; mod errors; diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 0e4e20c7cd1..de78f26eec6 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -794,9 +794,14 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { } tcx.ensure().has_ffi_unwind_calls(def_id); - if tcx.hir().body_const_context(def_id).is_some() { - tcx.ensure() - .mir_drops_elaborated_and_const_checked(ty::WithOptConstParam::unknown(def_id)); + // If we need to codegen, ensure that we emit all errors from + // `mir_drops_elaborated_and_const_checked` now, to avoid discovering + // them later during codegen. + if tcx.sess.opts.output_types.should_codegen() + || tcx.hir().body_const_context(def_id).is_some() + { + tcx.ensure().mir_drops_elaborated_and_const_checked(def_id); + tcx.ensure().unused_generic_params(ty::InstanceDef::Item(def_id.to_def_id())); } } }); diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 101967503c1..ce0f90bc1cc 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -747,7 +747,7 @@ fn test_unstable_options_tracking_hash() { tracked!(emit_thin_lto, false); tracked!(export_executable_symbols, true); tracked!(fewer_names, Some(true)); - tracked!(flatten_format_args, true); + tracked!(flatten_format_args, false); tracked!(force_unstable_if_unmarked, true); tracked!(fuel, Some(("abc".to_string(), 99))); tracked!(function_sections, Some(false)); @@ -768,6 +768,7 @@ fn test_unstable_options_tracking_hash() { tracked!(merge_functions, Some(MergeFunctions::Disabled)); tracked!(mir_emit_retag, true); tracked!(mir_enable_passes, vec![("DestProp".to_string(), false)]); + tracked!(mir_keep_place_mention, true); tracked!(mir_opt_level, Some(4)); tracked!(move_size_limit, Some(4096)); tracked!(mutable_noalias, false); diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml index abe61406c21..539eea3d816 100644 --- a/compiler/rustc_lint/Cargo.toml +++ b/compiler/rustc_lint/Cargo.toml @@ -11,6 +11,7 @@ rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_attr = { path = "../rustc_attr" } rustc_errors = { path = "../rustc_errors" } rustc_hir = { path = "../rustc_hir" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_target = { path = "../rustc_target" } rustc_ast = { path = "../rustc_ast" } rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index db15b176df0..3d1b8f8ed95 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -445,7 +445,7 @@ lint_builtin_incomplete_features = the feature `{$name}` is incomplete and may n .help = consider using `min_{$name}` instead, which is more stable and complete lint_builtin_unpermitted_type_init_zeroed = the type `{$ty}` does not permit zero-initialization -lint_builtin_unpermitted_type_init_unint = the type `{$ty}` does not permit being left uninitialized +lint_builtin_unpermitted_type_init_uninit = the type `{$ty}` does not permit being left uninitialized lint_builtin_unpermitted_type_init_label = this code causes undefined behavior when executed lint_builtin_unpermitted_type_init_label_suggestion = help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 6b387df785e..aeb791901bd 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -22,7 +22,7 @@ use crate::fluent_generated as fluent; use crate::{ - errors::BuiltinEllpisisInclusiveRangePatterns, + errors::BuiltinEllipsisInclusiveRangePatterns, lints::{ BuiltinAnonymousParams, BuiltinBoxPointers, BuiltinClashingExtern, BuiltinClashingExternSub, BuiltinConstNoMangle, BuiltinDeprecatedAttrLink, @@ -166,10 +166,8 @@ declare_lint_pass!(BoxPointers => [BOX_POINTERS]); impl BoxPointers { fn check_heap_type(&self, cx: &LateContext<'_>, span: Span, ty: Ty<'_>) { for leaf in ty.walk() { - if let GenericArgKind::Type(leaf_ty) = leaf.unpack() { - if leaf_ty.is_box() { - cx.emit_spanned_lint(BOX_POINTERS, span, BuiltinBoxPointers { ty }); - } + if let GenericArgKind::Type(leaf_ty) = leaf.unpack() && leaf_ty.is_box() { + cx.emit_spanned_lint(BOX_POINTERS, span, BuiltinBoxPointers { ty }); } } } @@ -1711,13 +1709,13 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns { } } - let (parenthesise, endpoints) = match &pat.kind { + let (parentheses, endpoints) = match &pat.kind { PatKind::Ref(subpat, _) => (true, matches_ellipsis_pat(&subpat)), _ => (false, matches_ellipsis_pat(pat)), }; if let Some((start, end, join)) = endpoints { - if parenthesise { + if parentheses { self.node_id = Some(pat.id); let end = expr_to_string(&end); let replace = match start { @@ -1725,7 +1723,7 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns { None => format!("&(..={})", end), }; if join.edition() >= Edition::Edition2021 { - cx.sess().emit_err(BuiltinEllpisisInclusiveRangePatterns { + cx.sess().emit_err(BuiltinEllipsisInclusiveRangePatterns { span: pat.span, suggestion: pat.span, replace, @@ -1743,7 +1741,7 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns { } else { let replace = "..="; if join.edition() >= Edition::Edition2021 { - cx.sess().emit_err(BuiltinEllpisisInclusiveRangePatterns { + cx.sess().emit_err(BuiltinEllipsisInclusiveRangePatterns { span: pat.span, suggestion: join, replace: replace.to_string(), @@ -2560,7 +2558,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { .subst(cx.tcx, substs) .apply_any_module(cx.tcx, cx.param_env) { - // Entirely skip uninhbaited variants. + // Entirely skip uninhabited variants. Some(false) => return None, // Forward the others, but remember which ones are definitely inhabited. Some(true) => true, @@ -2628,7 +2626,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { if let Some(err) = with_no_trimmed_paths!(ty_find_init_error(cx, conjured_ty, init)) { let msg = match init { InitKind::Zeroed => fluent::lint_builtin_unpermitted_type_init_zeroed, - InitKind::Uninit => fluent::lint_builtin_unpermitted_type_init_unint, + InitKind::Uninit => fluent::lint_builtin_unpermitted_type_init_uninit, }; let sub = BuiltinUnpermittedTypeInitSub { err }; cx.emit_spanned_lint( diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs index 9af5284df1e..bbae3d368f4 100644 --- a/compiler/rustc_lint/src/errors.rs +++ b/compiler/rustc_lint/src/errors.rs @@ -81,7 +81,7 @@ pub struct UnknownToolInScopedLint { #[derive(Diagnostic)] #[diag(lint_builtin_ellipsis_inclusive_range_patterns, code = "E0783")] -pub struct BuiltinEllpisisInclusiveRangePatterns { +pub struct BuiltinEllipsisInclusiveRangePatterns { #[primary_span] pub span: Span, #[suggestion(style = "short", code = "{replace}", applicability = "machine-applicable")] diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index b3578540516..76f07257907 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -82,9 +82,9 @@ pub use array_into_iter::ARRAY_INTO_ITER; use rustc_ast as ast; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; +use rustc_fluent_macro::fluent_messages; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; -use rustc_macros::fluent_messages; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::lint::builtin::{ diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 9efc14849c7..79253cbc8b4 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -33,6 +33,11 @@ pub fn method_context(cx: &LateContext<'_>, id: LocalDefId) -> MethodLateContext } } +fn assoc_item_in_trait_impl(cx: &LateContext<'_>, ii: &hir::ImplItem<'_>) -> bool { + let item = cx.tcx.associated_item(ii.owner_id); + item.trait_item_def_id.is_some() +} + declare_lint! { /// The `non_camel_case_types` lint detects types, variants, traits and /// type parameters that don't have camel case names. @@ -177,6 +182,7 @@ impl EarlyLintPass for NonCamelCaseTypes { // trait impls where we should have warned for the trait definition already. ast::ItemKind::Impl(box ast::Impl { of_trait: None, items, .. }) => { for it in items { + // FIXME: this doesn't respect `#[allow(..)]` on the item itself. if let ast::AssocItemKind::Type(..) = it.kind { self.check_case(cx, "associated type", &it.ident); } @@ -505,7 +511,7 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals { } fn check_impl_item(&mut self, cx: &LateContext<'_>, ii: &hir::ImplItem<'_>) { - if let hir::ImplItemKind::Const(..) = ii.kind { + if let hir::ImplItemKind::Const(..) = ii.kind && !assoc_item_in_trait_impl(cx, ii) { NonUpperCaseGlobals::check_upper_case(cx, "associated constant", &ii.ident); } } diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 1159d11e5c0..d677d51881e 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -569,36 +569,50 @@ trait UnusedDelimLint { } } - // Prevent false-positives in cases like `fn x() -> u8 { ({ 0 } + 1) }` - let lhs_needs_parens = { + // Check if LHS needs parens to prevent false-positives in cases like `fn x() -> u8 { ({ 0 } + 1) }`. + { let mut innermost = inner; loop { innermost = match &innermost.kind { - ExprKind::Binary(_, lhs, _rhs) => lhs, + ExprKind::Binary(_op, lhs, _rhs) => lhs, ExprKind::Call(fn_, _params) => fn_, ExprKind::Cast(expr, _ty) => expr, ExprKind::Type(expr, _ty) => expr, ExprKind::Index(base, _subscript) => base, - _ => break false, + _ => break, }; if !classify::expr_requires_semi_to_be_stmt(innermost) { - break true; + return true; } } - }; + } - lhs_needs_parens - || (followed_by_block - && match &inner.kind { - ExprKind::Ret(_) - | ExprKind::Break(..) - | ExprKind::Yield(..) - | ExprKind::Yeet(..) => true, - ExprKind::Range(_lhs, Some(rhs), _limits) => { - matches!(rhs.kind, ExprKind::Block(..)) - } - _ => parser::contains_exterior_struct_lit(&inner), - }) + // Check if RHS needs parens to prevent false-positives in cases like `if (() == return) {}`. + if !followed_by_block { + return false; + } + let mut innermost = inner; + loop { + innermost = match &innermost.kind { + ExprKind::Unary(_op, expr) => expr, + ExprKind::Binary(_op, _lhs, rhs) => rhs, + ExprKind::AssignOp(_op, _lhs, rhs) => rhs, + ExprKind::Assign(_lhs, rhs, _span) => rhs, + + ExprKind::Ret(_) | ExprKind::Yield(..) | ExprKind::Yeet(..) => return true, + + ExprKind::Break(_label, None) => return false, + ExprKind::Break(_label, Some(break_expr)) => { + return matches!(break_expr.kind, ExprKind::Block(..)); + } + + ExprKind::Range(_lhs, Some(rhs), _limits) => { + return matches!(rhs.kind, ExprKind::Block(..)); + } + + _ => return parser::contains_exterior_struct_lit(&inner), + } + } } fn emit_unused_delims_expr( @@ -636,20 +650,14 @@ trait UnusedDelimLint { return; } let spans = match value.kind { - ast::ExprKind::Block(ref block, None) if block.stmts.len() == 1 => { - if let Some(span) = block.stmts[0].span.find_ancestor_inside(value.span) { - Some((value.span.with_hi(span.lo()), value.span.with_lo(span.hi()))) - } else { - None - } - } + ast::ExprKind::Block(ref block, None) if block.stmts.len() == 1 => block.stmts[0] + .span + .find_ancestor_inside(value.span) + .map(|span| (value.span.with_hi(span.lo()), value.span.with_lo(span.hi()))), ast::ExprKind::Paren(ref expr) => { - let expr_span = expr.span.find_ancestor_inside(value.span); - if let Some(expr_span) = expr_span { - Some((value.span.with_hi(expr_span.lo()), value.span.with_lo(expr_span.hi()))) - } else { - None - } + expr.span.find_ancestor_inside(value.span).map(|expr_span| { + (value.span.with_hi(expr_span.lo()), value.span.with_lo(expr_span.hi())) + }) } _ => return, }; @@ -928,11 +936,10 @@ impl UnusedParens { // Otherwise proceed with linting. _ => {} } - let spans = if let Some(inner) = inner.span.find_ancestor_inside(value.span) { - Some((value.span.with_hi(inner.lo()), value.span.with_lo(inner.hi()))) - } else { - None - }; + let spans = inner + .span + .find_ancestor_inside(value.span) + .map(|inner| (value.span.with_hi(inner.lo()), value.span.with_lo(inner.hi()))); self.emit_unused_delims(cx, value.span, spans, "pattern", keep_space); } } @@ -1043,11 +1050,11 @@ impl EarlyLintPass for UnusedParens { if self.with_self_ty_parens && b.generic_params.len() > 0 => {} ast::TyKind::ImplTrait(_, bounds) if bounds.len() > 1 => {} _ => { - let spans = if let Some(r) = r.span.find_ancestor_inside(ty.span) { - Some((ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi()))) - } else { - None - }; + let spans = r + .span + .find_ancestor_inside(ty.span) + .map(|r| (ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi()))); + self.emit_unused_delims(cx, ty.span, spans, "type", (false, false)); } } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 9d6ab0b75df..b223b8c137a 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1021,7 +1021,7 @@ declare_lint! { declare_lint! { /// The `invalid_alignment` lint detects dereferences of misaligned pointers during - /// constant evluation. + /// constant evaluation. /// /// ### Example /// @@ -1854,7 +1854,7 @@ declare_lint! { /// When new methods are added to traits in the standard library, they are /// usually added in an "unstable" form which is only available on the /// [nightly channel] with a [`feature` attribute]. If there is any - /// pre-existing code which extends a trait to have a method with the same + /// preexisting code which extends a trait to have a method with the same /// name, then the names will collide. In the future, when the method is /// stabilized, this will cause an error due to the ambiguity. This lint /// is an early-warning to let you know that there may be a collision in diff --git a/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp index 448a1f62f69..35d6b9ed7a4 100644 --- a/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp @@ -39,6 +39,7 @@ enum class LLVMRustArchiveKind { BSD, DARWIN, COFF, + AIX_BIG, }; static Archive::Kind fromRust(LLVMRustArchiveKind Kind) { @@ -51,6 +52,8 @@ static Archive::Kind fromRust(LLVMRustArchiveKind Kind) { return Archive::K_DARWIN; case LLVMRustArchiveKind::COFF: return Archive::K_COFF; + case LLVMRustArchiveKind::AIX_BIG: + return Archive::K_AIXBIG; default: report_fatal_error("Bad ArchiveKind."); } diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 08e38b0c9d5..c9acbab253e 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -811,7 +811,7 @@ LLVMRustOptimize( ModulePassManager MPM; bool NeedThinLTOBufferPasses = UseThinLTOBuffers; if (!NoPrepopulatePasses) { - // The pre-link pipelines don't support O0 and require using budilO0DefaultPipeline() instead. + // The pre-link pipelines don't support O0 and require using buildO0DefaultPipeline() instead. // At the same time, the LTO pipelines do support O0 and using them is required. bool IsLTO = OptStage == LLVMRustOptStage::ThinLTO || OptStage == LLVMRustOptStage::FatLTO; if (OptLevel == OptimizationLevel::O0 && !IsLTO) { diff --git a/compiler/rustc_macros/Cargo.toml b/compiler/rustc_macros/Cargo.toml index 745983e7e86..1f1201b0035 100644 --- a/compiler/rustc_macros/Cargo.toml +++ b/compiler/rustc_macros/Cargo.toml @@ -7,11 +7,7 @@ edition = "2021" proc-macro = true [dependencies] -annotate-snippets = "0.9" -fluent-bundle = "0.15.2" -fluent-syntax = "0.11" synstructure = "0.13.0" syn = { version = "2", features = ["full"] } proc-macro2 = "1" quote = "1" -unic-langid = { version = "0.9.0", features = ["macros"] } diff --git a/compiler/rustc_macros/src/diagnostics/mod.rs b/compiler/rustc_macros/src/diagnostics/mod.rs index 78df0cd1d34..bd84681cbb4 100644 --- a/compiler/rustc_macros/src/diagnostics/mod.rs +++ b/compiler/rustc_macros/src/diagnostics/mod.rs @@ -1,12 +1,10 @@ mod diagnostic; mod diagnostic_builder; mod error; -mod fluent; mod subdiagnostic; mod utils; use diagnostic::{DiagnosticDerive, LintDiagnosticDerive}; -pub(crate) use fluent::fluent_messages; use proc_macro2::TokenStream; use quote::format_ident; use subdiagnostic::SubdiagnosticDeriveBuilder; diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index 737500cc257..904f8eb5731 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -54,60 +54,6 @@ pub fn newtype_index(input: TokenStream) -> TokenStream { newtype::newtype(input) } -/// Implements the `fluent_messages` macro, which performs compile-time validation of the -/// compiler's Fluent resources (i.e. that the resources parse and don't multiply define the same -/// messages) and generates constants that make using those messages in diagnostics more ergonomic. -/// -/// For example, given the following invocation of the macro.. -/// -/// ```ignore (rust) -/// fluent_messages! { "./typeck.ftl" } -/// ``` -/// ..where `typeck.ftl` has the following contents.. -/// -/// ```fluent -/// typeck_field_multiply_specified_in_initializer = -/// field `{$ident}` specified more than once -/// .label = used more than once -/// .label_previous_use = first use of `{$ident}` -/// ``` -/// ...then the macro parse the Fluent resource, emitting a diagnostic if it fails to do so, and -/// will generate the following code: -/// -/// ```ignore (rust) -/// pub static DEFAULT_LOCALE_RESOURCE: &'static [&'static str] = include_str!("./typeck.ftl"); -/// -/// mod fluent_generated { -/// mod typeck { -/// pub const field_multiply_specified_in_initializer: DiagnosticMessage = -/// DiagnosticMessage::fluent("typeck_field_multiply_specified_in_initializer"); -/// pub const field_multiply_specified_in_initializer_label_previous_use: DiagnosticMessage = -/// DiagnosticMessage::fluent_attr( -/// "typeck_field_multiply_specified_in_initializer", -/// "previous_use_label" -/// ); -/// } -/// } -/// ``` -/// When emitting a diagnostic, the generated constants can be used as follows: -/// -/// ```ignore (rust) -/// let mut err = sess.struct_span_err( -/// span, -/// fluent::typeck::field_multiply_specified_in_initializer -/// ); -/// err.span_default_label(span); -/// err.span_label( -/// previous_use_span, -/// fluent::typeck::field_multiply_specified_in_initializer_label_previous_use -/// ); -/// err.emit(); -/// ``` -#[proc_macro] -pub fn fluent_messages(input: TokenStream) -> TokenStream { - diagnostics::fluent_messages(input) -} - decl_derive!([HashStable, attributes(stable_hasher)] => hash_stable::hash_stable_derive); decl_derive!( [HashStable_Generic, attributes(stable_hasher)] => diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index f85ba38003c..a8b25ff66d7 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -112,9 +112,6 @@ struct QueryModifiers { /// Use a separate query provider for local and extern crates separate_provide_extern: Option<Ident>, - /// Always remap the ParamEnv's constness before hashing. - remap_env_constness: Option<Ident>, - /// Generate a `feed` method to set the query's value from another query. feedable: Option<Ident>, } @@ -130,7 +127,6 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> { let mut eval_always = None; let mut depth_limit = None; let mut separate_provide_extern = None; - let mut remap_env_constness = None; let mut feedable = None; while !input.is_empty() { @@ -189,8 +185,6 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> { try_insert!(depth_limit = modifier); } else if modifier == "separate_provide_extern" { try_insert!(separate_provide_extern = modifier); - } else if modifier == "remap_env_constness" { - try_insert!(remap_env_constness = modifier); } else if modifier == "feedable" { try_insert!(feedable = modifier); } else { @@ -211,7 +205,6 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> { eval_always, depth_limit, separate_provide_extern, - remap_env_constness, feedable, }) } @@ -332,7 +325,6 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { eval_always, depth_limit, separate_provide_extern, - remap_env_constness, ); if modifiers.cache.is_some() { diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml index 4d7c133e09b..0e54d6aa946 100644 --- a/compiler/rustc_metadata/Cargo.toml +++ b/compiler/rustc_metadata/Cargo.toml @@ -18,6 +18,7 @@ rustc_attr = { path = "../rustc_attr" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_fs_util = { path = "../rustc_fs_util" } rustc_hir = { path = "../rustc_hir" } rustc_hir_pretty = { path = "../rustc_hir_pretty" } diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 81e62eccb8a..9f664d0f0c8 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -28,7 +28,7 @@ extern crate tracing; pub use rmeta::{provide, provide_extern}; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; -use rustc_macros::fluent_messages; +use rustc_fluent_macro::fluent_messages; mod dependency_format; mod foreign_modules; diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index f7c9379e109..c9ab07f5f27 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -117,7 +117,7 @@ pub(crate) struct CrateMetadata { /// Additional data used for decoding `HygieneData` (e.g. `SyntaxContext` /// and `ExpnId`). - /// Note that we store a `HygieneDecodeContext` for each `CrateMetadat`. This is + /// Note that we store a `HygieneDecodeContext` for each `CrateMetadata`. This is /// because `SyntaxContext` ids are not globally unique, so we need /// to track which ids we've decoded on a per-crate basis. hygiene_context: HygieneDecodeContext, @@ -627,7 +627,7 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Symbol { let pos = d.read_usize(); let old_pos = d.opaque.position(); - // move to str ofset and read + // move to str offset and read d.opaque.set_position(pos); let s = d.read_str(); let sym = Symbol::intern(s); @@ -876,16 +876,11 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { variant_did, ctor, data.discr, - self.root - .tables - .children - .get(self, index) - .expect("fields are not encoded for a variant") - .decode(self) - .map(|index| ty::FieldDef { - did: self.local_def_id(index), - name: self.item_name(index), - vis: self.get_visibility(index), + self.get_associated_item_or_field_def_ids(index) + .map(|did| ty::FieldDef { + did, + name: self.item_name(did.index), + vis: self.get_visibility(did.index), }) .collect(), adt_kind, @@ -910,7 +905,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { let variants = if let ty::AdtKind::Enum = adt_kind { self.root .tables - .children + .module_children_non_reexports .get(self, item_id) .expect("variants are not encoded for an enum") .decode(self) @@ -998,9 +993,8 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { let ident = self.item_ident(id, sess); let res = Res::Def(self.def_kind(id), self.local_def_id(id)); let vis = self.get_visibility(id); - let span = self.get_span(id, sess); - ModChild { ident, res, vis, span, reexport_chain: Default::default() } + ModChild { ident, res, vis, reexport_chain: Default::default() } } /// Iterates over all named children of the given module, @@ -1023,11 +1017,9 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } else { // Iterate over all children. - for child_index in self.root.tables.children.get(self, id).unwrap().decode(self) { - // FIXME: Do not encode RPITITs as a part of this list. - if self.root.tables.opt_rpitit_info.get(self, child_index).is_none() { - yield self.get_mod_child(child_index, sess); - } + let non_reexports = self.root.tables.module_children_non_reexports.get(self, id); + for child_index in non_reexports.unwrap().decode(self) { + yield self.get_mod_child(child_index, sess); } let reexports = self.root.tables.module_children_reexports.get(self, id); @@ -1059,17 +1051,16 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .map_or(false, |ident| ident.name == kw::SelfLower) } - fn get_associated_item_def_ids( + fn get_associated_item_or_field_def_ids( self, id: DefIndex, - sess: &'a Session, ) -> impl Iterator<Item = DefId> + 'a { self.root .tables - .children + .associated_item_or_field_def_ids .get(self, id) - .expect("associated items not encoded for an item") - .decode((self, sess)) + .unwrap_or_else(|| self.missing("associated_item_or_field_def_ids", id)) + .decode(self) .map(move |child_index| self.local_def_id(child_index)) } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 6212597e1ac..4aa3768fc3b 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -276,7 +276,7 @@ provide! { tcx, def_id, other, cdata, tcx.calculate_dtor(def_id, |_,_| Ok(())) } associated_item_def_ids => { - tcx.arena.alloc_from_iter(cdata.get_associated_item_def_ids(def_id.index, tcx.sess)) + tcx.arena.alloc_from_iter(cdata.get_associated_item_or_field_def_ids(def_id.index)) } associated_item => { cdata.get_associated_item(def_id.index, tcx.sess) } inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) } @@ -513,14 +513,6 @@ impl CStore { self.get_crate_data(def.krate).get_ctor(def.index) } - pub fn module_children_untracked<'a>( - &'a self, - def_id: DefId, - sess: &'a Session, - ) -> impl Iterator<Item = ModChild> + 'a { - self.get_crate_data(def_id.krate).get_module_children(def_id.index, sess) - } - pub fn load_macro_untracked(&self, id: DefId, sess: &Session) -> LoadedMacro { let _prof_timer = sess.prof.generic_activity("metadata_load_macro"); diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index f9e42fdecdc..fd8e49efea0 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -7,7 +7,7 @@ use rustc_ast::Attribute; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::memmap::{Mmap, MmapMut}; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher}; use rustc_data_structures::sync::{join, par_iter, Lrc, ParallelIterator}; use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_hir as hir; @@ -531,7 +531,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { adapted.name_hash = { let mut hasher: StableHasher = StableHasher::new(); adapted.name.hash(&mut hasher); - hasher.finish::<u128>() + hasher.finish::<Hash128>() }; Lrc::new(adapted) } else { @@ -822,6 +822,8 @@ fn should_encode_span(def_kind: DefKind) -> bool { | DefKind::TraitAlias | DefKind::AssocTy | DefKind::TyParam + | DefKind::ConstParam + | DefKind::LifetimeParam | DefKind::Fn | DefKind::Const | DefKind::Static(_) @@ -829,6 +831,8 @@ fn should_encode_span(def_kind: DefKind) -> bool { | DefKind::AssocFn | DefKind::AssocConst | DefKind::Macro(_) + | DefKind::ExternCrate + | DefKind::Use | DefKind::AnonConst | DefKind::InlineConst | DefKind::OpaqueTy @@ -836,13 +840,7 @@ fn should_encode_span(def_kind: DefKind) -> bool { | DefKind::Impl { .. } | DefKind::Closure | DefKind::Generator => true, - DefKind::ConstParam - | DefKind::ExternCrate - | DefKind::Use - | DefKind::ForeignMod - | DefKind::ImplTraitPlaceholder - | DefKind::LifetimeParam - | DefKind::GlobalAsm => false, + DefKind::ForeignMod | DefKind::ImplTraitPlaceholder | DefKind::GlobalAsm => false, } } @@ -1366,7 +1364,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if adt_def.is_enum() { let module_children = tcx.module_children_non_reexports(local_def_id); - record_array!(self.tables.children[def_id] <- + record_array!(self.tables.module_children_non_reexports[def_id] <- module_children.iter().map(|def_id| def_id.local_def_index)); } else { // For non-enum, there is only one variant, and its def_id is the adt's. @@ -1384,7 +1382,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.variant_data[variant.def_id] <- data); self.tables.constness.set_some(variant.def_id.index, hir::Constness::Const); - record_array!(self.tables.children[variant.def_id] <- variant.fields.iter().map(|f| { + record_array!(self.tables.associated_item_or_field_def_ids[variant.def_id] <- variant.fields.iter().map(|f| { assert!(f.did.is_local()); f.did.index })); @@ -1414,7 +1412,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.expn_that_defined[def_id] <- tcx.expn_that_defined(local_def_id)); } else { let non_reexports = tcx.module_children_non_reexports(local_def_id); - record_array!(self.tables.children[def_id] <- + record_array!(self.tables.module_children_non_reexports[def_id] <- non_reexports.iter().map(|def_id| def_id.local_def_index)); record_defaulted_array!(self.tables.module_children_reexports[def_id] <- @@ -1468,8 +1466,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { match impl_item.kind { ty::AssocKind::Fn => { - let ast_item = self.tcx.hir().expect_impl_item(def_id.expect_local()); - let hir::ImplItemKind::Fn(ref sig, body) = ast_item.kind else { bug!() }; + let (sig, body) = + self.tcx.hir().expect_impl_item(def_id.expect_local()).expect_fn(); self.tables.asyncness.set_some(def_id.index, sig.header.asyncness); record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body)); // Can be inside `impl const Trait`, so using sig.header.constness is not reliable @@ -1538,8 +1536,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } record!(self.tables.promoted_mir[def_id.to_def_id()] <- tcx.promoted_mir(def_id)); - let instance = - ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id.to_def_id())); + let instance = ty::InstanceDef::Item(def_id.to_def_id()); let unused = tcx.unused_generic_params(instance); self.tables.unused_generic_params.set(def_id.local_def_index, unused); } @@ -1617,7 +1614,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { debug!("EncodeContext::encode_info_for_item({:?})", def_id); let record_associated_item_def_ids = |this: &mut Self, def_ids: &[DefId]| { - record_array!(this.tables.children[def_id] <- def_ids.iter().map(|&def_id| { + record_array!(this.tables.associated_item_or_field_def_ids[def_id] <- def_ids.iter().map(|&def_id| { assert!(def_id.is_local()); def_id.index })) @@ -1678,6 +1675,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { hir::ItemKind::Trait(..) => { record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id)); + let module_children = tcx.module_children_non_reexports(item.owner_id.def_id); + record_array!(self.tables.module_children_non_reexports[def_id] <- + module_children.iter().map(|def_id| def_id.local_def_index)); + let associated_item_def_ids = self.tcx.associated_item_def_ids(def_id); record_associated_item_def_ids(self, associated_item_def_ids); for &item_def_id in associated_item_def_ids { diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 68dc22e31e9..ee1c495ed1e 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -360,7 +360,8 @@ define_tables! { - optional: attributes: Table<DefIndex, LazyArray<ast::Attribute>>, - children: Table<DefIndex, LazyArray<DefIndex>>, + module_children_non_reexports: Table<DefIndex, LazyArray<DefIndex>>, + associated_item_or_field_def_ids: Table<DefIndex, LazyArray<DefIndex>>, opt_def_kind: Table<DefIndex, DefKind>, visibility: Table<DefIndex, LazyValue<ty::Visibility<DefIndex>>>, def_span: Table<DefIndex, LazyValue<Span>>, @@ -415,7 +416,7 @@ define_tables! { macro_definition: Table<DefIndex, LazyValue<ast::DelimArgs>>, proc_macro: Table<DefIndex, MacroKind>, deduced_param_attrs: Table<DefIndex, LazyArray<DeducedParamAttrs>>, - trait_impl_trait_tys: Table<DefIndex, LazyValue<FxHashMap<DefId, Ty<'static>>>>, + trait_impl_trait_tys: Table<DefIndex, LazyValue<FxHashMap<DefId, ty::EarlyBinder<Ty<'static>>>>>, doc_link_resolutions: Table<DefIndex, LazyValue<DocLinkResMap>>, doc_link_traits_in_scope: Table<DefIndex, LazyArray<DefId>>, } diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 364fa74ab7b..66e2518fa56 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -413,8 +413,8 @@ impl<I: Idx, const N: usize, T: FixedSizeEncoding<ByteArray = [u8; N]>> TableBui // > Space requirements could perhaps be optimized by using the HAMT `popcnt` // > trick (i.e. divide things into buckets of 32 or 64 items and then // > store bit-masks of which item in each bucket is actually serialized). - self.blocks.ensure_contains_elem(i, || [0; N]); - value.write_to_bytes(&mut self.blocks[i]); + let block = self.blocks.ensure_contains_elem(i, || [0; N]); + value.write_to_bytes(block); } } diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index 5b2ec9029b1..dfbe8ac0ba3 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -21,6 +21,7 @@ rustc_errors = { path = "../rustc_errors" } # Used for intra-doc links rustc_error_messages = { path = "../rustc_error_messages" } rustc_feature = { path = "../rustc_feature" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_graphviz = { path = "../rustc_graphviz" } rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index dd1e254f405..60d7cf59d04 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -114,7 +114,11 @@ macro_rules! arena_types { [] dep_kind: rustc_middle::dep_graph::DepKindStruct<'tcx>, - [decode] trait_impl_trait_tys: rustc_data_structures::fx::FxHashMap<rustc_hir::def_id::DefId, rustc_middle::ty::Ty<'tcx>>, + [decode] trait_impl_trait_tys: + rustc_data_structures::fx::FxHashMap< + rustc_hir::def_id::DefId, + rustc_middle::ty::EarlyBinder<rustc_middle::ty::Ty<'tcx>> + >, [] bit_set_u32: rustc_index::bit_set::BitSet<u32>, [] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData<'tcx>, [decode] doc_link_resolutions: rustc_hir::def::DocLinkResMap, diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index 865bb70afb5..82e396a9dd3 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -357,7 +357,7 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for HirId { Fingerprint::new( // `owner` is local, so is completely defined by the local hash def_path_hash.local_hash(), - local_id.as_u32().into(), + local_id.as_u32() as u64, ) } @@ -370,7 +370,7 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for HirId { #[inline(always)] fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> { if tcx.fingerprint_style(dep_node.kind) == FingerprintStyle::HirId { - let (local_hash, local_id) = Fingerprint::from(dep_node.hash).as_value(); + let (local_hash, local_id) = Fingerprint::from(dep_node.hash).split(); let def_path_hash = DefPathHash::new(tcx.sess.local_stable_crate_id(), local_hash); let def_id = tcx .def_path_hash_to_def_id(def_path_hash, &mut || { @@ -378,6 +378,7 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for HirId { }) .expect_local(); let local_id = local_id + .as_u64() .try_into() .unwrap_or_else(|_| panic!("local id should be u32, found {:?}", local_id)); Some(HirId { owner: OwnerId { def_id }, local_id: ItemLocalId::from_u32(local_id) }) diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index e551c76f8db..64aff27744f 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -1199,7 +1199,7 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh { stable_hasher.finish() }); - Svh::new(crate_hash.to_smaller_hash()) + Svh::new(crate_hash) } fn upstream_crates(tcx: TyCtxt<'_>) -> Vec<(StableCrateId, Svh)> { diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index b5b712c367d..c4e41e00520 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -348,14 +348,6 @@ impl<'tcx, R> Canonical<'tcx, QueryResponse<'tcx, R>> { } } -impl<'tcx, R> Canonical<'tcx, ty::ParamEnvAnd<'tcx, R>> { - #[inline] - pub fn without_const(mut self) -> Self { - self.value = self.value.without_const(); - self - } -} - impl<'tcx, V> Canonical<'tcx, V> { /// Allows you to map the `value` of a canonical while keeping the /// same set of bound variables. @@ -400,10 +392,8 @@ pub type QueryOutlivesConstraint<'tcx> = (ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>, ConstraintCategory<'tcx>); TrivialTypeTraversalAndLiftImpls! { - for <'tcx> { - crate::infer::canonical::Certainty, - crate::infer::canonical::CanonicalTyVarKind, - } + crate::infer::canonical::Certainty, + crate::infer::canonical::CanonicalTyVarKind, } impl<'tcx> CanonicalVarValues<'tcx> { diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index b4edb02f6c4..76a8367b2c4 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -59,6 +59,7 @@ #![feature(result_option_inspect)] #![feature(const_option)] #![feature(trait_alias)] +#![feature(ptr_alignment_type)] #![recursion_limit = "512"] #![allow(rustc::potential_query_instability)] @@ -74,7 +75,7 @@ extern crate tracing; extern crate smallvec; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; -use rustc_macros::fluent_messages; +use rustc_fluent_macro::fluent_messages; #[cfg(test)] mod tests; @@ -99,13 +100,9 @@ pub mod mir; pub mod thir; pub mod traits; pub mod ty; +pub mod util; mod values; -pub mod util { - pub mod bug; - pub mod common; -} - // Allows macros to refer to this crate as `::rustc_middle` extern crate self as rustc_middle; diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs index 89014f62d4d..cd1c6c330bc 100644 --- a/compiler/rustc_middle/src/macros.rs +++ b/compiler/rustc_middle/src/macros.rs @@ -43,34 +43,26 @@ macro_rules! span_bug { #[macro_export] macro_rules! CloneLiftImpls { - (for <$tcx:lifetime> { $($ty:ty,)+ }) => { + ($($ty:ty,)+) => { $( - impl<$tcx> $crate::ty::Lift<$tcx> for $ty { + impl<'tcx> $crate::ty::Lift<'tcx> for $ty { type Lifted = Self; - fn lift_to_tcx(self, _: $crate::ty::TyCtxt<$tcx>) -> Option<Self> { + fn lift_to_tcx(self, _: $crate::ty::TyCtxt<'tcx>) -> Option<Self> { Some(self) } } )+ }; - - ($($ty:ty,)+) => { - CloneLiftImpls! { - for <'tcx> { - $($ty,)+ - } - } - }; } /// Used for types that are `Copy` and which **do not care arena /// allocated data** (i.e., don't need to be folded). #[macro_export] macro_rules! TrivialTypeTraversalImpls { - (for <$tcx:lifetime> { $($ty:ty,)+ }) => { + ($($ty:ty,)+) => { $( - impl<$tcx> $crate::ty::fold::TypeFoldable<$crate::ty::TyCtxt<$tcx>> for $ty { - fn try_fold_with<F: $crate::ty::fold::FallibleTypeFolder<$crate::ty::TyCtxt<$tcx>>>( + impl<'tcx> $crate::ty::fold::TypeFoldable<$crate::ty::TyCtxt<'tcx>> for $ty { + fn try_fold_with<F: $crate::ty::fold::FallibleTypeFolder<$crate::ty::TyCtxt<'tcx>>>( self, _: &mut F, ) -> ::std::result::Result<Self, F::Error> { @@ -78,7 +70,7 @@ macro_rules! TrivialTypeTraversalImpls { } #[inline] - fn fold_with<F: $crate::ty::fold::TypeFolder<$crate::ty::TyCtxt<$tcx>>>( + fn fold_with<F: $crate::ty::fold::TypeFolder<$crate::ty::TyCtxt<'tcx>>>( self, _: &mut F, ) -> Self { @@ -86,9 +78,9 @@ macro_rules! TrivialTypeTraversalImpls { } } - impl<$tcx> $crate::ty::visit::TypeVisitable<$crate::ty::TyCtxt<$tcx>> for $ty { + impl<'tcx> $crate::ty::visit::TypeVisitable<$crate::ty::TyCtxt<'tcx>> for $ty { #[inline] - fn visit_with<F: $crate::ty::visit::TypeVisitor<$crate::ty::TyCtxt<$tcx>>>( + fn visit_with<F: $crate::ty::visit::TypeVisitor<$crate::ty::TyCtxt<'tcx>>>( &self, _: &mut F) -> ::std::ops::ControlFlow<F::BreakTy> @@ -98,14 +90,6 @@ macro_rules! TrivialTypeTraversalImpls { } )+ }; - - ($($ty:ty,)+) => { - TrivialTypeTraversalImpls! { - for<'tcx> { - $($ty,)+ - } - } - }; } #[macro_export] diff --git a/compiler/rustc_middle/src/metadata.rs b/compiler/rustc_middle/src/metadata.rs index f3170e0ec0e..674402cb4bf 100644 --- a/compiler/rustc_middle/src/metadata.rs +++ b/compiler/rustc_middle/src/metadata.rs @@ -4,7 +4,6 @@ use rustc_hir::def::Res; use rustc_macros::HashStable; use rustc_span::def_id::DefId; use rustc_span::symbol::Ident; -use rustc_span::Span; use smallvec::SmallVec; /// A simplified version of `ImportKind` from resolve. @@ -41,8 +40,6 @@ pub struct ModChild { pub res: Res<!>, /// Visibility of the item. pub vis: ty::Visibility<DefId>, - /// Span of the item. - pub span: Span, /// Reexport chain linking this module child to its original reexported item. /// Empty if the module child is a proper item. pub reexport_chain: SmallVec<[Reexport; 2]>, diff --git a/compiler/rustc_middle/src/middle/exported_symbols.rs b/compiler/rustc_middle/src/middle/exported_symbols.rs index c0c0fd07b6e..9041da9a060 100644 --- a/compiler/rustc_middle/src/middle/exported_symbols.rs +++ b/compiler/rustc_middle/src/middle/exported_symbols.rs @@ -72,6 +72,6 @@ pub fn metadata_symbol_name(tcx: TyCtxt<'_>) -> String { format!( "rust_metadata_{}_{:08x}", tcx.crate_name(LOCAL_CRATE), - tcx.sess.local_stable_crate_id().to_u64(), + tcx.sess.local_stable_crate_id(), ) } diff --git a/compiler/rustc_middle/src/mir/graphviz.rs b/compiler/rustc_middle/src/mir/graphviz.rs index cf6d46e1e2c..2de73db3a3c 100644 --- a/compiler/rustc_middle/src/mir/graphviz.rs +++ b/compiler/rustc_middle/src/mir/graphviz.rs @@ -16,19 +16,16 @@ where { let def_ids = dump_mir_def_ids(tcx, single); - let mirs = - def_ids - .iter() - .flat_map(|def_id| { - if tcx.is_const_fn_raw(*def_id) { - vec![tcx.optimized_mir(*def_id), tcx.mir_for_ctfe(*def_id)] - } else { - vec![tcx.instance_mir(ty::InstanceDef::Item(ty::WithOptConstParam::unknown( - *def_id, - )))] - } - }) - .collect::<Vec<_>>(); + let mirs = def_ids + .iter() + .flat_map(|def_id| { + if tcx.is_const_fn_raw(*def_id) { + vec![tcx.optimized_mir(*def_id), tcx.mir_for_ctfe(*def_id)] + } else { + vec![tcx.instance_mir(ty::InstanceDef::Item(*def_id))] + } + }) + .collect::<Vec<_>>(); let use_subgraphs = mirs.len() > 1; if use_subgraphs { diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs b/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs index dcb56a1755e..d4dd56a42c1 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs @@ -5,7 +5,9 @@ use std::hash; use std::iter; use std::ops::Range; +use rustc_serialize::{Decodable, Encodable}; use rustc_target::abi::Size; +use rustc_type_ir::{TyDecoder, TyEncoder}; use super::AllocRange; @@ -182,11 +184,39 @@ impl InitMask { /// The actual materialized blocks of the bitmask, when we can't keep the `InitMask` lazy. // Note: for performance reasons when interning, some of the fields can be partially // hashed. (see the `Hash` impl below for more details), so the impl is not derived. -#[derive(Clone, Debug, Eq, PartialEq, TyEncodable, TyDecodable, HashStable)] +#[derive(Clone, Debug, Eq, PartialEq, HashStable)] struct InitMaskMaterialized { blocks: Vec<Block>, } +// `Block` is a `u64`, but it is a bitmask not a numeric value. If we were to just derive +// Encodable and Decodable we would apply varint encoding to the bitmasks, which is slower +// and also produces more output when the high bits of each `u64` are occupied. +// Note: There is probably a remaining optimization for masks that do not use an entire +// `Block`. +impl<E: TyEncoder> Encodable<E> for InitMaskMaterialized { + fn encode(&self, encoder: &mut E) { + encoder.emit_usize(self.blocks.len()); + for block in &self.blocks { + encoder.emit_raw_bytes(&block.to_le_bytes()); + } + } +} + +// This implementation is deliberately not derived, see the matching `Encodable` impl. +impl<D: TyDecoder> Decodable<D> for InitMaskMaterialized { + fn decode(decoder: &mut D) -> Self { + let num_blocks = decoder.read_usize(); + let mut blocks = Vec::with_capacity(num_blocks); + for _ in 0..num_blocks { + let bytes = decoder.read_raw_bytes(8); + let block = u64::from_le_bytes(bytes.try_into().unwrap()); + blocks.push(block); + } + InitMaskMaterialized { blocks } + } +} + // Const allocations are only hashed for interning. However, they can be large, making the hashing // expensive especially since it uses `FxHash`: it's better suited to short keys, not potentially // big buffers like the allocation's init mask. We can partially hash some fields when they're diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs index 60927eed85d..65d04919357 100644 --- a/compiler/rustc_middle/src/mir/interpret/pointer.rs +++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs @@ -102,7 +102,7 @@ impl<T: HasDataLayout> PointerArithmetic for T {} /// This trait abstracts over the kind of provenance that is associated with a `Pointer`. It is /// mostly opaque; the `Machine` trait extends it with some more operations that also have access to /// some global state. -/// The `Debug` rendering is used to distplay bare provenance, and for the default impl of `fmt`. +/// The `Debug` rendering is used to display bare provenance, and for the default impl of `fmt`. pub trait Provenance: Copy + fmt::Debug { /// Says whether the `offset` field of `Pointer`s with this provenance is the actual physical address. /// - If `false`, the offset *must* be relative. This means the bytes representing a pointer are diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index 856d821a5cf..ed4ee93e97d 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -42,7 +42,7 @@ impl<'tcx> TyCtxt<'tcx> { span: Option<Span>, ) -> EvalToConstValueResult<'tcx> { // Cannot resolve `Unevaluated` constants that contain inference - // variables. We reject those here since `resolve_opt_const_arg` + // variables. We reject those here since `resolve` // would fail otherwise. // // When trying to evaluate constants containing inference variables, @@ -51,7 +51,7 @@ impl<'tcx> TyCtxt<'tcx> { bug!("did not expect inference variables here"); } - match ty::Instance::resolve_opt_const_arg( + match ty::Instance::resolve( self, param_env, // FIXME: maybe have a separate version for resolving mir::UnevaluatedConst? ct.def, ct.substs, @@ -73,7 +73,7 @@ impl<'tcx> TyCtxt<'tcx> { span: Option<Span>, ) -> EvalToValTreeResult<'tcx> { // Cannot resolve `Unevaluated` constants that contain inference - // variables. We reject those here since `resolve_opt_const_arg` + // variables. We reject those here since `resolve` // would fail otherwise. // // When trying to evaluate constants containing inference variables, @@ -82,7 +82,7 @@ impl<'tcx> TyCtxt<'tcx> { bug!("did not expect inference variables here"); } - match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs) { + match ty::Instance::resolve(self, param_env, ct.def, ct.substs) { Ok(Some(instance)) => { let cid = GlobalId { instance, promoted: None }; self.const_eval_global_id_for_typeck(param_env, cid, span).inspect(|_| { @@ -94,14 +94,14 @@ impl<'tcx> TyCtxt<'tcx> { // used generic parameters is a bug of evaluation, so checking for it // here does feel somewhat sensible. if !self.features().generic_const_exprs && ct.substs.has_non_region_param() { - assert!(matches!(self.def_kind(ct.def.did), DefKind::AnonConst)); - let mir_body = self.mir_for_ctfe_opt_const_arg(ct.def); + assert!(matches!(self.def_kind(ct.def), DefKind::AnonConst)); + let mir_body = self.mir_for_ctfe(ct.def); if mir_body.is_polymorphic { - let Some(local_def_id) = ct.def.did.as_local() else { return }; + let Some(local_def_id) = ct.def.as_local() else { return }; self.struct_span_lint_hir( lint::builtin::CONST_EVALUATABLE_UNCHECKED, self.hir().local_def_id_to_hir_id(local_def_id), - self.def_span(ct.def.did), + self.def_span(ct.def), "cannot use constants which depend on generic parameters in types", |err| err, ) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 2ea8602af12..6b6a2e561f5 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -191,20 +191,13 @@ pub struct MirSource<'tcx> { impl<'tcx> MirSource<'tcx> { pub fn item(def_id: DefId) -> Self { - MirSource { - instance: InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)), - promoted: None, - } + MirSource { instance: InstanceDef::Item(def_id), promoted: None } } pub fn from_instance(instance: InstanceDef<'tcx>) -> Self { MirSource { instance, promoted: None } } - pub fn with_opt_param(self) -> ty::WithOptConstParam<DefId> { - self.instance.with_opt_param() - } - #[inline] pub fn def_id(&self) -> DefId { self.instance.def_id() @@ -714,9 +707,7 @@ pub enum BindingForm<'tcx> { } TrivialTypeTraversalAndLiftImpls! { - for<'tcx> { - BindingForm<'tcx>, - } + BindingForm<'tcx>, } mod binding_form_impl { @@ -2050,7 +2041,11 @@ impl<'tcx> Debug for Rvalue<'tcx> { } UnaryOp(ref op, ref a) => write!(fmt, "{:?}({:?})", op, a), Discriminant(ref place) => write!(fmt, "discriminant({:?})", place), - NullaryOp(ref op, ref t) => write!(fmt, "{:?}({:?})", op, t), + NullaryOp(ref op, ref t) => match op { + NullOp::SizeOf => write!(fmt, "SizeOf({:?})", t), + NullOp::AlignOf => write!(fmt, "AlignOf({:?})", t), + NullOp::OffsetOf(fields) => write!(fmt, "OffsetOf({:?}, {:?})", t, fields), + }, ThreadLocalRef(did) => ty::tls::with(|tcx| { let muta = tcx.static_mutability(did).unwrap().prefix_str(); write!(fmt, "&/*tls*/ {}{}", muta, tcx.def_path_str(did)) @@ -2438,16 +2433,6 @@ impl<'tcx> ConstantKind<'tcx> { Self::Val(val, ty) } - /// Literals are converted to `ConstantKindVal`, const generic parameters are eagerly - /// converted to a constant, everything else becomes `Unevaluated`. - pub fn from_anon_const( - tcx: TyCtxt<'tcx>, - def_id: LocalDefId, - param_env: ty::ParamEnv<'tcx>, - ) -> Self { - Self::from_opt_const_arg_anon_const(tcx, ty::WithOptConstParam::unknown(def_id), param_env) - } - #[instrument(skip(tcx), level = "debug", ret)] pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self { let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); @@ -2487,28 +2472,25 @@ impl<'tcx> ConstantKind<'tcx> { ty::InlineConstSubsts::new(tcx, ty::InlineConstSubstsParts { parent_substs, ty }) .substs; - let uneval = UnevaluatedConst { - def: ty::WithOptConstParam::unknown(def_id).to_global(), - substs, - promoted: None, - }; + let uneval = UnevaluatedConst { def: def_id.to_def_id(), substs, promoted: None }; debug_assert!(!uneval.has_free_regions()); Self::Unevaluated(uneval, ty) } + /// Literals are converted to `ConstantKindVal`, const generic parameters are eagerly + /// converted to a constant, everything else becomes `Unevaluated`. #[instrument(skip(tcx), level = "debug", ret)] - fn from_opt_const_arg_anon_const( + pub fn from_anon_const( tcx: TyCtxt<'tcx>, - def: ty::WithOptConstParam<LocalDefId>, + def: LocalDefId, param_env: ty::ParamEnv<'tcx>, ) -> Self { - let body_id = match tcx.hir().get_by_def_id(def.did) { + let body_id = match tcx.hir().get_by_def_id(def) { hir::Node::AnonConst(ac) => ac.body, - _ => span_bug!( - tcx.def_span(def.did.to_def_id()), - "from_anon_const can only process anonymous constants" - ), + _ => { + span_bug!(tcx.def_span(def), "from_anon_const can only process anonymous constants") + } }; let expr = &tcx.hir().body(body_id).value; @@ -2524,7 +2506,7 @@ impl<'tcx> ConstantKind<'tcx> { }; debug!("expr.kind: {:?}", expr.kind); - let ty = tcx.type_of(def.def_id_for_type_of()).subst_identity(); + let ty = tcx.type_of(def).subst_identity(); debug!(?ty); // FIXME(const_generics): We currently have to special case parameters because `min_const_generics` @@ -2551,7 +2533,7 @@ impl<'tcx> ConstantKind<'tcx> { _ => {} } - let hir_id = tcx.hir().local_def_id_to_hir_id(def.did); + let hir_id = tcx.hir().local_def_id_to_hir_id(def); let parent_substs = if let Some(parent_hir_id) = tcx.hir().opt_parent_id(hir_id) && let Some(parent_did) = parent_hir_id.as_owner() { @@ -2561,15 +2543,14 @@ impl<'tcx> ConstantKind<'tcx> { }; debug!(?parent_substs); - let did = def.did.to_def_id(); + let did = def.to_def_id(); let child_substs = InternalSubsts::identity_for_item(tcx, did); let substs = tcx.mk_substs_from_iter(parent_substs.into_iter().chain(child_substs.into_iter())); debug!(?substs); - let hir_id = tcx.hir().local_def_id_to_hir_id(def.did); - let span = tcx.hir().span(hir_id); - let uneval = UnevaluatedConst::new(def.to_global(), substs); + let span = tcx.def_span(def); + let uneval = UnevaluatedConst::new(did, substs); debug!(?span, ?param_env); match tcx.const_eval_resolve(param_env, uneval, Some(span)) { @@ -2583,8 +2564,8 @@ impl<'tcx> ConstantKind<'tcx> { // new unevaluated const and error hard later in codegen Self::Unevaluated( UnevaluatedConst { - def: def.to_global(), - substs: InternalSubsts::identity_for_item(tcx, def.did), + def: did, + substs: InternalSubsts::identity_for_item(tcx, did), promoted: None, }, ty, @@ -2609,7 +2590,7 @@ impl<'tcx> ConstantKind<'tcx> { #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)] #[derive(Hash, HashStable, TypeFoldable, TypeVisitable)] pub struct UnevaluatedConst<'tcx> { - pub def: ty::WithOptConstParam<DefId>, + pub def: DefId, pub substs: SubstsRef<'tcx>, pub promoted: Option<Promoted>, } @@ -2625,10 +2606,7 @@ impl<'tcx> UnevaluatedConst<'tcx> { impl<'tcx> UnevaluatedConst<'tcx> { #[inline] - pub fn new( - def: ty::WithOptConstParam<DefId>, - substs: SubstsRef<'tcx>, - ) -> UnevaluatedConst<'tcx> { + pub fn new(def: DefId, substs: SubstsRef<'tcx>) -> UnevaluatedConst<'tcx> { UnevaluatedConst { def, substs, promoted: Default::default() } } } diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index f592f1515c1..67235f0f524 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -4,7 +4,7 @@ use rustc_attr::InlineAttr; use rustc_data_structures::base_n; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher}; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_hir::ItemId; use rustc_index::vec::Idx; @@ -313,8 +313,8 @@ impl<'tcx> CodegenUnit<'tcx> { // avoid collisions and is still reasonably short for filenames. let mut hasher = StableHasher::new(); human_readable_name.hash(&mut hasher); - let hash: u128 = hasher.finish(); - let hash = hash & ((1u128 << 80) - 1); + let hash: Hash128 = hasher.finish(); + let hash = hash.as_u128() & ((1u128 << 80) - 1); base_n::encode(hash, base_n::CASE_INSENSITIVE) } @@ -373,7 +373,7 @@ impl<'tcx> CodegenUnit<'tcx> { // instances into account. The others don't matter for // the codegen tests and can even make item order // unstable. - InstanceDef::Item(def) => def.did.as_local().map(Idx::index), + InstanceDef::Item(def) => def.as_local().map(Idx::index), InstanceDef::VTableShim(..) | InstanceDef::ReifyShim(..) | InstanceDef::Intrinsic(..) @@ -505,22 +505,13 @@ impl<'tcx> CodegenUnitNameBuilder<'tcx> { // instantiating stuff for upstream crates. let local_crate_id = if cnum != LOCAL_CRATE { let local_stable_crate_id = tcx.sess.local_stable_crate_id(); - format!( - "-in-{}.{:08x}", - tcx.crate_name(LOCAL_CRATE), - local_stable_crate_id.to_u64() as u32, - ) + format!("-in-{}.{:08x}", tcx.crate_name(LOCAL_CRATE), local_stable_crate_id) } else { String::new() }; let stable_crate_id = tcx.sess.local_stable_crate_id(); - format!( - "{}.{:08x}{}", - tcx.crate_name(cnum), - stable_crate_id.to_u64() as u32, - local_crate_id, - ) + format!("{}.{:08x}{}", tcx.crate_name(cnum), stable_crate_id, local_crate_id) }); write!(cgu_name, "{}", crate_prefix).unwrap(); diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 7e51953599d..89510bbb3aa 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -298,8 +298,7 @@ pub fn write_mir_pretty<'tcx>( // are shared between mir_for_ctfe and optimized_mir write_mir_fn(tcx, tcx.mir_for_ctfe(def_id), &mut |_, _| Ok(()), w)?; } else { - let instance_mir = - tcx.instance_mir(ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id))); + let instance_mir = tcx.instance_mir(ty::InstanceDef::Item(def_id)); render_body(w, instance_mir)?; } } @@ -464,11 +463,7 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> { ConstantKind::Ty(ct) => match ct.kind() { ty::ConstKind::Param(p) => format!("Param({})", p), ty::ConstKind::Unevaluated(uv) => { - format!( - "Unevaluated({}, {:?})", - self.tcx.def_path_str(uv.def.did), - uv.substs, - ) + format!("Unevaluated({}, {:?})", self.tcx.def_path_str(uv.def), uv.substs,) } ty::ConstKind::Value(val) => format!("Value({})", fmt_valtree(&val)), ty::ConstKind::Error(_) => "Error".to_string(), @@ -481,7 +476,7 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> { ConstantKind::Unevaluated(uv, _) => { format!( "Unevaluated({}, {:?}, {:?})", - self.tcx.def_path_str(uv.def.did), + self.tcx.def_path_str(uv.def), uv.substs, uv.promoted, ) diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index cfdf1dcf5c0..17eaf3e08d8 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -1,12 +1,12 @@ //! Values computed by queries that use MIR. -use crate::mir::{Body, ConstantKind, Promoted}; +use crate::mir::ConstantKind; use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::UnordSet; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::LocalDefId; use rustc_index::bit_set::BitMatrix; use rustc_index::vec::{Idx, IndexVec}; use rustc_span::Span; @@ -454,42 +454,3 @@ pub struct CoverageInfo { /// The total number of coverage region counter expressions added to the MIR `Body`. pub num_expressions: u32, } - -/// Shims which make dealing with `WithOptConstParam` easier. -/// -/// For more information on why this is needed, consider looking -/// at the docs for `WithOptConstParam` itself. -impl<'tcx> TyCtxt<'tcx> { - #[inline] - pub fn mir_const_qualif_opt_const_arg( - self, - def: ty::WithOptConstParam<LocalDefId>, - ) -> ConstQualifs { - if let Some(param_did) = def.const_param_did { - self.mir_const_qualif_const_arg((def.did, param_did)) - } else { - self.mir_const_qualif(def.did) - } - } - - #[inline] - pub fn promoted_mir_opt_const_arg( - self, - def: ty::WithOptConstParam<DefId>, - ) -> &'tcx IndexVec<Promoted, Body<'tcx>> { - if let Some((did, param_did)) = def.as_const_arg() { - self.promoted_mir_of_const_arg((did, param_did)) - } else { - self.promoted_mir(def.did) - } - } - - #[inline] - pub fn mir_for_ctfe_opt_const_arg(self, def: ty::WithOptConstParam<DefId>) -> &'tcx Body<'tcx> { - if let Some((did, param_did)) = def.as_const_arg() { - self.mir_for_ctfe_of_const_arg((did, param_did)) - } else { - self.mir_for_ctfe(def.did) - } - } -} diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 135889d0da8..69ce6835ba6 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -251,7 +251,7 @@ pub enum StatementKind<'tcx> { /// **Needs clarification**: The implication of the above idea would be that assignment implies /// that the resulting value is initialized. I believe we could commit to this separately from /// committing to whatever part of the memory model we would need to decide on to make the above - /// paragragh precise. Do we want to? + /// paragraph precise. Do we want to? /// /// Assignments in which the types of the place and rvalue differ are not well-formed. /// @@ -331,9 +331,8 @@ pub enum StatementKind<'tcx> { /// This is especially useful for `let _ = PLACE;` bindings that desugar to a single /// `PlaceMention(PLACE)`. /// - /// When executed at runtime this is a nop. - /// - /// Disallowed after drop elaboration. + /// When executed at runtime, this computes the given place, but then discards + /// it without doing a load. It is UB if the place is not pointing to live memory. PlaceMention(Box<Place<'tcx>>), /// Encodes a user's type ascription. These need to be preserved @@ -997,7 +996,7 @@ pub type PlaceElem<'tcx> = ProjectionElem<Local, Ty<'tcx>>; /// This is what is implemented in miri today. Are these the semantics we want for MIR? Is this /// something we can even decide without knowing more about Rust's memory model? /// -/// **Needs clarifiation:** Is loading a place that has its variant index set well-formed? Miri +/// **Needs clarification:** Is loading a place that has its variant index set well-formed? Miri /// currently implements it, but it seems like this may be something to check against in the /// validator. #[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)] @@ -1115,7 +1114,7 @@ pub enum Rvalue<'tcx> { CheckedBinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>), /// Computes a value as described by the operation. - NullaryOp(NullOp, Ty<'tcx>), + NullaryOp(NullOp<'tcx>, Ty<'tcx>), /// Exactly like `BinaryOp`, but less operands. /// @@ -1211,12 +1210,14 @@ pub enum AggregateKind<'tcx> { Generator(DefId, SubstsRef<'tcx>, hir::Movability), } -#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] -pub enum NullOp { +#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] +pub enum NullOp<'tcx> { /// Returns the size of a value of that type SizeOf, /// Returns the minimum alignment of a type AlignOf, + /// Returns the offset of a field + OffsetOf(&'tcx List<FieldIdx>), } #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index 4f00abf7fab..5ca82413448 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -188,7 +188,9 @@ impl<'tcx> Rvalue<'tcx> { } Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, ref operand) => operand.ty(local_decls, tcx), Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx), - Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => tcx.types.usize, + Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => { + tcx.types.usize + } Rvalue::Aggregate(ref ak, ref ops) => match **ak { AggregateKind::Array(ty) => tcx.mk_array(ty, ops.len() as u64), AggregateKind::Tuple => { diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs index 9881583214e..06874741bb0 100644 --- a/compiler/rustc_middle/src/mir/type_foldable.rs +++ b/compiler/rustc_middle/src/mir/type_foldable.rs @@ -16,7 +16,6 @@ TrivialTypeTraversalAndLiftImpls! { UserTypeAnnotationIndex, BorrowKind, CastKind, - NullOp, hir::Movability, BasicBlock, SwitchTargets, @@ -25,9 +24,8 @@ TrivialTypeTraversalAndLiftImpls! { } TrivialTypeTraversalImpls! { - for <'tcx> { - ConstValue<'tcx>, - } + ConstValue<'tcx>, + NullOp<'tcx>, } impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx [InlineAsmTemplatePiece] { diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index 23b28ac5ca9..fa62b7f32b1 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -174,14 +174,6 @@ impl AsLocalKey for DefId { } } -impl Key for ty::WithOptConstParam<LocalDefId> { - type CacheSelector = DefaultCacheSelector<Self>; - - fn default_span(&self, tcx: TyCtxt<'_>) -> Span { - self.did.default_span(tcx) - } -} - impl Key for SimplifiedType { type CacheSelector = DefaultCacheSelector<Self>; @@ -313,7 +305,7 @@ impl<'tcx> Key for (ty::UnevaluatedConst<'tcx>, ty::UnevaluatedConst<'tcx>) { type CacheSelector = DefaultCacheSelector<Self>; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { - (self.0).def.did.default_span(tcx) + (self.0).def.default_span(tcx) } } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 0cecf8db1af..292718b82aa 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -127,29 +127,6 @@ rustc_queries! { desc { |tcx| "getting HIR owner attributes in `{}`", tcx.def_path_str(key.to_def_id()) } } - /// Computes the `DefId` of the corresponding const parameter in case the `key` is a - /// const argument and returns `None` otherwise. - /// - /// ```ignore (incomplete) - /// let a = foo::<7>(); - /// // ^ Calling `opt_const_param_of` for this argument, - /// - /// fn foo<const N: usize>() - /// // ^ returns this `DefId`. - /// - /// fn bar() { - /// // ^ While calling `opt_const_param_of` for other bodies returns `None`. - /// } - /// ``` - // It looks like caching this query on disk actually slightly - // worsened performance in #74376. - // - // Once const generics are more prevalently used, we might want to - // consider only caching calls returning `Some`. - query opt_const_param_of(key: LocalDefId) -> Option<DefId> { - desc { |tcx| "computing the optional const parameter of `{}`", tcx.def_path_str(key.to_def_id()) } - } - /// Given the def_id of a const-generic parameter, computes the associated default const /// parameter. e.g. `fn example<const N: usize=3>` called on `N` would return `3`. query const_param_default(param: DefId) -> ty::EarlyBinder<ty::Const<'tcx>> { @@ -181,7 +158,7 @@ rustc_queries! { } query collect_return_position_impl_trait_in_trait_tys(key: DefId) - -> Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed> + -> Result<&'tcx FxHashMap<DefId, ty::EarlyBinder<Ty<'tcx>>>, ErrorGuaranteed> { desc { "comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process" } cache_on_disk_if { key.is_local() } @@ -369,26 +346,24 @@ rustc_queries! { } /// Fetch the THIR for a given body. If typeck for that body failed, returns an empty `Thir`. - query thir_body(key: ty::WithOptConstParam<LocalDefId>) - -> Result<(&'tcx Steal<thir::Thir<'tcx>>, thir::ExprId), ErrorGuaranteed> - { + query thir_body(key: LocalDefId) -> Result<(&'tcx Steal<thir::Thir<'tcx>>, thir::ExprId), ErrorGuaranteed> { // Perf tests revealed that hashing THIR is inefficient (see #85729). no_hash - desc { |tcx| "building THIR for `{}`", tcx.def_path_str(key.did.to_def_id()) } + desc { |tcx| "building THIR for `{}`", tcx.def_path_str(key.to_def_id()) } } /// Create a THIR tree for debugging. - query thir_tree(key: ty::WithOptConstParam<LocalDefId>) -> &'tcx String { + query thir_tree(key: LocalDefId) -> &'tcx String { no_hash arena_cache - desc { |tcx| "constructing THIR tree for `{}`", tcx.def_path_str(key.did.to_def_id()) } + desc { |tcx| "constructing THIR tree for `{}`", tcx.def_path_str(key.to_def_id()) } } /// Create a list-like THIR representation for debugging. - query thir_flat(key: ty::WithOptConstParam<LocalDefId>) -> &'tcx String { + query thir_flat(key: LocalDefId) -> &'tcx String { no_hash arena_cache - desc { |tcx| "constructing flat THIR representation for `{}`", tcx.def_path_str(key.did.to_def_id()) } + desc { |tcx| "constructing flat THIR representation for `{}`", tcx.def_path_str(key.to_def_id()) } } /// Set of all the `DefId`s in this crate that have MIR associated with @@ -407,31 +382,19 @@ rustc_queries! { cache_on_disk_if { key.is_local() } separate_provide_extern } - query mir_const_qualif_const_arg( - key: (LocalDefId, DefId) - ) -> mir::ConstQualifs { - desc { - |tcx| "const checking the const argument `{}`", - tcx.def_path_str(key.0.to_def_id()) - } - } /// Fetch the MIR for a given `DefId` right after it's built - this includes /// unreachable code. - query mir_built(key: ty::WithOptConstParam<LocalDefId>) -> &'tcx Steal<mir::Body<'tcx>> { - desc { |tcx| "building MIR for `{}`", tcx.def_path_str(key.did.to_def_id()) } + query mir_built(key: LocalDefId) -> &'tcx Steal<mir::Body<'tcx>> { + desc { |tcx| "building MIR for `{}`", tcx.def_path_str(key.to_def_id()) } } /// Fetch the MIR for a given `DefId` up till the point where it is /// ready for const qualification. /// /// See the README for the `mir` module for details. - query mir_const(key: ty::WithOptConstParam<LocalDefId>) -> &'tcx Steal<mir::Body<'tcx>> { - desc { - |tcx| "preparing {}`{}` for borrow checking", - if key.const_param_did.is_some() { "the const argument " } else { "" }, - tcx.def_path_str(key.did.to_def_id()), - } + query mir_const(key: LocalDefId) -> &'tcx Steal<mir::Body<'tcx>> { + desc { |tcx| "preparing `{}` for borrow checking", tcx.def_path_str(key.to_def_id()) } no_hash } @@ -444,22 +407,10 @@ rustc_queries! { } separate_provide_extern } - /// Try to build an abstract representation of the given constant. - query thir_abstract_const_of_const_arg( - key: (LocalDefId, DefId) - ) -> Result<Option<ty::Const<'tcx>>, ErrorGuaranteed> { - desc { - |tcx| - "building an abstract representation for the const argument `{}`", - tcx.def_path_str(key.0.to_def_id()), - } - } - query mir_drops_elaborated_and_const_checked( - key: ty::WithOptConstParam<LocalDefId> - ) -> &'tcx Steal<mir::Body<'tcx>> { + query mir_drops_elaborated_and_const_checked(key: LocalDefId) -> &'tcx Steal<mir::Body<'tcx>> { no_hash - desc { |tcx| "elaborating drops for `{}`", tcx.def_path_str(key.did.to_def_id()) } + desc { |tcx| "elaborating drops for `{}`", tcx.def_path_str(key.to_def_id()) } } query mir_for_ctfe( @@ -470,24 +421,12 @@ rustc_queries! { separate_provide_extern } - query mir_for_ctfe_of_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::Body<'tcx> { - desc { - |tcx| "caching MIR for CTFE of the const argument `{}`", - tcx.def_path_str(key.0.to_def_id()) - } - } - - query mir_promoted(key: ty::WithOptConstParam<LocalDefId>) -> - ( - &'tcx Steal<mir::Body<'tcx>>, - &'tcx Steal<IndexVec<mir::Promoted, mir::Body<'tcx>>> - ) { + query mir_promoted(key: LocalDefId) -> ( + &'tcx Steal<mir::Body<'tcx>>, + &'tcx Steal<IndexVec<mir::Promoted, mir::Body<'tcx>>> + ) { no_hash - desc { - |tcx| "processing MIR for {}`{}`", - if key.const_param_did.is_some() { "the const argument " } else { "" }, - tcx.def_path_str(key.did.to_def_id()), - } + desc { |tcx| "promoting constants in MIR for `{}`", tcx.def_path_str(key.to_def_id()) } } query closure_typeinfo(key: LocalDefId) -> ty::ClosureTypeInfo<'tcx> { @@ -544,14 +483,6 @@ rustc_queries! { cache_on_disk_if { key.is_local() } separate_provide_extern } - query promoted_mir_of_const_arg( - key: (LocalDefId, DefId) - ) -> &'tcx IndexVec<mir::Promoted, mir::Body<'tcx>> { - desc { - |tcx| "optimizing promoted MIR for the const argument `{}`", - tcx.def_path_str(key.0.to_def_id()), - } - } /// Erases regions from `ty` to yield a new type. /// Normally you would just use `tcx.erase_regions(value)`, @@ -739,9 +670,10 @@ rustc_queries! { desc { "computing the inferred outlives predicates for items in this crate" } } - /// Maps from an impl/trait `DefId` to a list of the `DefId`s of its items. + /// Maps from an impl/trait or struct/variant `DefId` + /// to a list of the `DefId`s of its associated items or fields. query associated_item_def_ids(key: DefId) -> &'tcx [DefId] { - desc { |tcx| "collecting associated items of `{}`", tcx.def_path_str(key) } + desc { |tcx| "collecting associated items or fields of `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern } @@ -840,12 +772,6 @@ rustc_queries! { desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key.to_def_id()) } cache_on_disk_if { true } } - query unsafety_check_result_for_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::UnsafetyCheckResult { - desc { - |tcx| "unsafety-checking the const argument `{}`", - tcx.def_path_str(key.0.to_def_id()) - } - } /// Unsafety-check this `LocalDefId` with THIR unsafeck. This should be /// used with `-Zthir-unsafeck`. @@ -853,12 +779,6 @@ rustc_queries! { desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key.to_def_id()) } cache_on_disk_if { true } } - query thir_check_unsafety_for_const_arg(key: (LocalDefId, DefId)) { - desc { - |tcx| "unsafety-checking the const argument `{}`", - tcx.def_path_str(key.0.to_def_id()) - } - } /// Returns the types assumed to be well formed while "inside" of the given item. /// @@ -960,14 +880,6 @@ rustc_queries! { desc { |tcx| "type-checking `{}`", tcx.def_path_str(key.to_def_id()) } cache_on_disk_if { true } } - query typeck_const_arg( - key: (LocalDefId, DefId) - ) -> &'tcx ty::TypeckResults<'tcx> { - desc { - |tcx| "type-checking the const argument `{}`", - tcx.def_path_str(key.0.to_def_id()), - } - } query diagnostic_only_typeck(key: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> { desc { |tcx| "type-checking `{}`", tcx.def_path_str(key.to_def_id()) } cache_on_disk_if { true } @@ -992,12 +904,6 @@ rustc_queries! { desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key.to_def_id()) } cache_on_disk_if(tcx) { tcx.is_typeck_child(key.to_def_id()) } } - query mir_borrowck_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::BorrowCheckResult<'tcx> { - desc { - |tcx| "borrow-checking the const argument`{}`", - tcx.def_path_str(key.0.to_def_id()) - } - } /// Gets a complete map from all types to their inherent impls. /// Not meant to be used directly outside of coherence. @@ -1094,7 +1000,6 @@ rustc_queries! { key: ty::ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>> ) -> Option<mir::DestructuredConstant<'tcx>> { desc { "destructuring MIR constant"} - remap_env_constness } /// Dereference a constant reference or raw pointer and turn the result into a constant @@ -1103,7 +1008,6 @@ rustc_queries! { key: ty::ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>> ) -> mir::ConstantKind<'tcx> { desc { "dereferencing MIR constant" } - remap_env_constness } query const_caller_location(key: (rustc_span::Symbol, u32, u32)) -> ConstValue<'tcx> { @@ -1346,32 +1250,26 @@ rustc_queries! { /// `ty.is_copy()`, etc, since that will prune the environment where possible. query is_copy_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` is `Copy`", env.value } - remap_env_constness } /// Query backing `Ty::is_sized`. query is_sized_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` is `Sized`", env.value } - remap_env_constness } /// Query backing `Ty::is_freeze`. query is_freeze_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` is freeze", env.value } - remap_env_constness } /// Query backing `Ty::is_unpin`. query is_unpin_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` is `Unpin`", env.value } - remap_env_constness } /// Query backing `Ty::needs_drop`. query needs_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` needs drop", env.value } - remap_env_constness } /// Query backing `Ty::has_significant_drop_raw`. query has_significant_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` has a significant drop", env.value } - remap_env_constness } /// Query backing `Ty::is_structural_eq_shallow`. @@ -1411,7 +1309,6 @@ rustc_queries! { ) -> Result<ty::layout::TyAndLayout<'tcx>, ty::layout::LayoutError<'tcx>> { depth_limit desc { "computing layout of `{}`", key.value } - remap_env_constness } /// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers. @@ -1422,7 +1319,6 @@ rustc_queries! { key: ty::ParamEnvAnd<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>)> ) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, ty::layout::FnAbiError<'tcx>> { desc { "computing call ABI of `{}` function pointers", key.value.0 } - remap_env_constness } /// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for @@ -1434,7 +1330,6 @@ rustc_queries! { key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>)> ) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, ty::layout::FnAbiError<'tcx>> { desc { "computing call ABI of `{}`", key.value.0 } - remap_env_constness } query dylib_dependency_formats(_: CrateNum) @@ -1926,7 +1821,6 @@ rustc_queries! { NoSolution, > { desc { "normalizing `{}`", goal.value.value } - remap_env_constness } /// Do not call this query directly: invoke `try_normalize_erasing_regions` instead. @@ -1934,7 +1828,6 @@ rustc_queries! { goal: ParamEnvAnd<'tcx, GenericArg<'tcx>> ) -> Result<GenericArg<'tcx>, NoSolution> { desc { "normalizing `{}`", goal.value } - remap_env_constness } query implied_outlives_bounds( @@ -1944,7 +1837,6 @@ rustc_queries! { NoSolution, > { desc { "computing implied outlives bounds for `{}`", goal.value.value } - remap_env_constness } /// Do not call this query directly: @@ -1956,7 +1848,6 @@ rustc_queries! { NoSolution, > { desc { "computing dropck types for `{}`", goal.value.value } - remap_env_constness } /// Do not call this query directly: invoke `infcx.predicate_may_hold()` or @@ -1984,7 +1875,6 @@ rustc_queries! { NoSolution, > { desc { "evaluating `type_op_ascribe_user_type` `{:?}`", goal.value.value } - remap_env_constness } /// Do not call this query directly: part of the `Eq` type-op @@ -1995,7 +1885,6 @@ rustc_queries! { NoSolution, > { desc { "evaluating `type_op_eq` `{:?}`", goal.value.value } - remap_env_constness } /// Do not call this query directly: part of the `Subtype` type-op @@ -2006,7 +1895,6 @@ rustc_queries! { NoSolution, > { desc { "evaluating `type_op_subtype` `{:?}`", goal.value.value } - remap_env_constness } /// Do not call this query directly: part of the `ProvePredicate` type-op @@ -2027,7 +1915,6 @@ rustc_queries! { NoSolution, > { desc { "normalizing `{}`", goal.value.value.value } - remap_env_constness } /// Do not call this query directly: part of the `Normalize` type-op @@ -2038,7 +1925,6 @@ rustc_queries! { NoSolution, > { desc { "normalizing `{:?}`", goal.value.value.value } - remap_env_constness } /// Do not call this query directly: part of the `Normalize` type-op @@ -2049,7 +1935,6 @@ rustc_queries! { NoSolution, > { desc { "normalizing `{:?}`", goal.value.value.value } - remap_env_constness } /// Do not call this query directly: part of the `Normalize` type-op @@ -2060,7 +1945,6 @@ rustc_queries! { NoSolution, > { desc { "normalizing `{:?}`", goal.value.value.value } - remap_env_constness } query subst_and_check_impossible_predicates(key: (DefId, SubstsRef<'tcx>)) -> bool { @@ -2082,7 +1966,6 @@ rustc_queries! { goal: CanonicalTyGoal<'tcx> ) -> MethodAutoderefStepsResult<'tcx> { desc { "computing autoderef types for `{}`", goal.value.value } - remap_env_constness } query supported_target_features(_: CrateNum) -> &'tcx FxHashMap<String, Option<Symbol>> { @@ -2127,17 +2010,6 @@ rustc_queries! { key: ty::ParamEnvAnd<'tcx, (DefId, SubstsRef<'tcx>)> ) -> Result<Option<ty::Instance<'tcx>>, ErrorGuaranteed> { desc { "resolving instance `{}`", ty::Instance::new(key.value.0, key.value.1) } - remap_env_constness - } - - query resolve_instance_of_const_arg( - key: ty::ParamEnvAnd<'tcx, (LocalDefId, DefId, SubstsRef<'tcx>)> - ) -> Result<Option<ty::Instance<'tcx>>, ErrorGuaranteed> { - desc { - "resolving instance of the const argument `{}`", - ty::Instance::new(key.value.0.to_def_id(), key.value.2), - } - remap_env_constness } query reveal_opaque_types_in_bounds(key: &'tcx ty::List<ty::Predicate<'tcx>>) -> &'tcx ty::List<ty::Predicate<'tcx>> { diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 7d79a13d3fd..8700a98b365 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -20,7 +20,7 @@ use rustc_middle::mir::interpret::AllocId; use rustc_middle::mir::{self, BinOp, BorrowKind, FakeReadCause, Mutability, UnOp}; use rustc_middle::ty::adjustment::PointerCast; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, AdtDef, FnSig, Ty, UpvarSubsts}; +use rustc_middle::ty::{self, AdtDef, FnSig, List, Ty, UpvarSubsts}; use rustc_middle::ty::{CanonicalUserType, CanonicalUserTypeAnnotation}; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span, Symbol, DUMMY_SP}; @@ -481,6 +481,11 @@ pub enum ExprKind<'tcx> { }, /// Inline assembly, i.e. `asm!()`. InlineAsm(Box<InlineAsmExpr<'tcx>>), + /// Field offset (`offset_of!`) + OffsetOf { + container: Ty<'tcx>, + fields: &'tcx List<FieldIdx>, + }, /// An expression taking a reference to a thread local. ThreadLocalRef(DefId), /// A `yield` expression. @@ -929,8 +934,8 @@ mod size_asserts { static_assert_size!(Block, 56); static_assert_size!(Expr<'_>, 64); static_assert_size!(ExprKind<'_>, 40); - static_assert_size!(Pat<'_>, 72); - static_assert_size!(PatKind<'_>, 56); + static_assert_size!(Pat<'_>, 64); + static_assert_size!(PatKind<'_>, 48); static_assert_size!(Stmt<'_>, 56); static_assert_size!(StmtKind<'_>, 48); // tidy-alphabetical-end diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 5614528c4cb..5c7ec31cf93 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -160,6 +160,7 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp } } } + OffsetOf { container: _, fields: _ } => {} ThreadLocalRef(_) => {} Yield { value } => visitor.visit_expr(&visitor.thir()[value]), } diff --git a/compiler/rustc_middle/src/ty/abstract_const.rs b/compiler/rustc_middle/src/ty/abstract_const.rs index f889ce82706..029cf793ad8 100644 --- a/compiler/rustc_middle/src/ty/abstract_const.rs +++ b/compiler/rustc_middle/src/ty/abstract_const.rs @@ -1,4 +1,4 @@ -//! A subset of a mir body used for const evaluatability checking. +//! A subset of a mir body used for const evaluability checking. use crate::ty::{ self, Const, EarlyBinder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, @@ -36,15 +36,8 @@ pub type BoundAbstractConst<'tcx> = Result<Option<EarlyBinder<ty::Const<'tcx>>>, impl<'tcx> TyCtxt<'tcx> { /// Returns a const without substs applied - pub fn bound_abstract_const( - self, - uv: ty::WithOptConstParam<DefId>, - ) -> BoundAbstractConst<'tcx> { - let ac = if let Some((did, param_did)) = uv.as_const_arg() { - self.thir_abstract_const_of_const_arg((did, param_did)) - } else { - self.thir_abstract_const(uv.did) - }; + pub fn bound_abstract_const(self, uv: DefId) -> BoundAbstractConst<'tcx> { + let ac = self.thir_abstract_const(uv); Ok(ac?.map(|ac| EarlyBinder(ac))) } diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 8ef4a46a733..5454d406dd1 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -19,6 +19,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty::TyCtxt; use rustc_serialize::{Decodable, Encodable}; use rustc_span::Span; +use rustc_target::abi::FieldIdx; pub use rustc_type_ir::{TyDecoder, TyEncoder}; use std::hash::Hash; use std::intrinsics; @@ -401,6 +402,15 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<ty } } +impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<FieldIdx> { + fn decode(decoder: &mut D) -> &'tcx Self { + let len = decoder.read_usize(); + decoder + .interner() + .mk_fields_from_iter((0..len).map::<FieldIdx, _>(|_| Decodable::decode(decoder))) + } +} + impl_decodable_via_ref! { &'tcx ty::TypeckResults<'tcx>, &'tcx ty::List<Ty<'tcx>>, @@ -412,6 +422,7 @@ impl_decodable_via_ref! { &'tcx mir::coverage::CodeRegion, &'tcx ty::List<ty::BoundVariableKind>, &'tcx ty::List<ty::Predicate<'tcx>>, + &'tcx ty::List<FieldIdx>, } #[macro_export] diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index bcedae233d9..0a191ff7626 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -53,19 +53,12 @@ impl<'tcx> Const<'tcx> { /// Literals and const generic parameters are eagerly converted to a constant, everything else /// becomes `Unevaluated`. - pub fn from_anon_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self { - Self::from_opt_const_arg_anon_const(tcx, ty::WithOptConstParam::unknown(def_id)) - } - #[instrument(skip(tcx), level = "debug")] - pub fn from_opt_const_arg_anon_const( - tcx: TyCtxt<'tcx>, - def: ty::WithOptConstParam<LocalDefId>, - ) -> Self { - let body_id = match tcx.hir().get_by_def_id(def.did) { + pub fn from_anon_const(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Self { + let body_id = match tcx.hir().get_by_def_id(def) { hir::Node::AnonConst(ac) => ac.body, _ => span_bug!( - tcx.def_span(def.did.to_def_id()), + tcx.def_span(def.to_def_id()), "from_anon_const can only process anonymous constants" ), }; @@ -73,17 +66,14 @@ impl<'tcx> Const<'tcx> { let expr = &tcx.hir().body(body_id).value; debug!(?expr); - let ty = tcx - .type_of(def.def_id_for_type_of()) - .no_bound_vars() - .expect("const parameter types cannot be generic"); + let ty = tcx.type_of(def).no_bound_vars().expect("const parameter types cannot be generic"); match Self::try_eval_lit_or_param(tcx, ty, expr) { Some(v) => v, None => tcx.mk_const( ty::UnevaluatedConst { - def: def.to_global(), - substs: InternalSubsts::identity_for_item(tcx, def.did), + def: def.to_def_id(), + substs: InternalSubsts::identity_for_item(tcx, def.to_def_id()), }, ty, ), diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index c0e557d480d..d1dbc531edf 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -141,14 +141,18 @@ impl<CTX> crate::ty::HashStable<CTX> for ScalarInt { impl<S: Encoder> Encodable<S> for ScalarInt { fn encode(&self, s: &mut S) { - s.emit_u128(self.data); - s.emit_u8(self.size.get()); + let size = self.size.get(); + s.emit_u8(size); + s.emit_raw_bytes(&self.data.to_le_bytes()[..size as usize]); } } impl<D: Decoder> Decodable<D> for ScalarInt { fn decode(d: &mut D) -> ScalarInt { - ScalarInt { data: d.read_u128(), size: NonZeroU8::new(d.read_u8()).unwrap() } + let mut data = [0u8; 16]; + let size = d.read_u8(); + data[..size as usize].copy_from_slice(d.read_raw_bytes(size as usize)); + ScalarInt { data: u128::from_le_bytes(data), size: NonZeroU8::new(size).unwrap() } } } diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index 560caa041a7..1ac2cd13982 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -17,7 +17,7 @@ use super::ScalarInt; #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)] #[derive(Hash, HashStable, TypeFoldable, TypeVisitable)] pub struct UnevaluatedConst<'tcx> { - pub def: ty::WithOptConstParam<DefId>, + pub def: DefId, pub substs: SubstsRef<'tcx>, } @@ -36,10 +36,7 @@ impl<'tcx> UnevaluatedConst<'tcx> { impl<'tcx> UnevaluatedConst<'tcx> { #[inline] - pub fn new( - def: ty::WithOptConstParam<DefId>, - substs: SubstsRef<'tcx>, - ) -> UnevaluatedConst<'tcx> { + pub fn new(def: DefId, substs: SubstsRef<'tcx>) -> UnevaluatedConst<'tcx> { UnevaluatedConst { def, substs } } } @@ -224,9 +221,9 @@ impl<'tcx> ConstKind<'tcx> { // FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that // we can call `infcx.const_eval_resolve` which handles inference variables. let param_env_and = if (param_env, unevaluated).has_non_region_infer() { - tcx.param_env(unevaluated.def.did).and(ty::UnevaluatedConst { + tcx.param_env(unevaluated.def).and(ty::UnevaluatedConst { def: unevaluated.def, - substs: InternalSubsts::identity_for_item(tcx, unevaluated.def.did), + substs: InternalSubsts::identity_for_item(tcx, unevaluated.def), }) } else { tcx.erase_regions(param_env) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 63f7cc2ee73..6f122d97a39 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -13,7 +13,7 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrs; use crate::middle::resolve_bound_vars; use crate::middle::stability; use crate::mir::interpret::{self, Allocation, ConstAllocation}; -use crate::mir::{Body, BorrowCheckResult, Local, Place, PlaceElem, ProjectionKind, Promoted}; +use crate::mir::{Body, Local, Place, PlaceElem, ProjectionKind, Promoted}; use crate::query::LocalCrate; use crate::thir::Thir; use crate::traits; @@ -24,7 +24,7 @@ use crate::ty::{ self, AdtDef, AdtDefData, AdtKind, Binder, Const, ConstData, FloatTy, FloatVar, FloatVid, GenericParamDefKind, ImplPolarity, InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, Region, RegionKind, ReprOptions, - TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, TypeckResults, UintTy, Visibility, + TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, UintTy, Visibility, }; use crate::ty::{GenericArg, InternalSubsts, SubstsRef}; use rustc_ast::{self as ast, attr}; @@ -141,6 +141,7 @@ pub struct CtxtInterners<'tcx> { type_: InternedSet<'tcx, WithCachedTypeInfo<TyKind<'tcx>>>, const_lists: InternedSet<'tcx, List<ty::Const<'tcx>>>, substs: InternedSet<'tcx, InternalSubsts<'tcx>>, + type_lists: InternedSet<'tcx, List<Ty<'tcx>>>, canonical_var_infos: InternedSet<'tcx, List<CanonicalVarInfo<'tcx>>>, region: InternedSet<'tcx, RegionKind<'tcx>>, poly_existential_predicates: InternedSet<'tcx, List<PolyExistentialPredicate<'tcx>>>, @@ -154,6 +155,7 @@ pub struct CtxtInterners<'tcx> { layout: InternedSet<'tcx, LayoutS>, adt_def: InternedSet<'tcx, AdtDefData>, external_constraints: InternedSet<'tcx, ExternalConstraintsData<'tcx>>, + fields: InternedSet<'tcx, List<FieldIdx>>, } impl<'tcx> CtxtInterners<'tcx> { @@ -163,6 +165,7 @@ impl<'tcx> CtxtInterners<'tcx> { type_: Default::default(), const_lists: Default::default(), substs: Default::default(), + type_lists: Default::default(), region: Default::default(), poly_existential_predicates: Default::default(), canonical_var_infos: Default::default(), @@ -176,6 +179,7 @@ impl<'tcx> CtxtInterners<'tcx> { layout: Default::default(), adt_def: Default::default(), external_constraints: Default::default(), + fields: Default::default(), } } @@ -447,6 +451,14 @@ impl<'tcx> TyCtxt<'tcx> { pub fn feed_local_crate(self) -> TyCtxtFeed<'tcx, CrateNum> { TyCtxtFeed { tcx: self, key: LOCAL_CRATE } } + + /// In order to break cycles involving `AnonConst`, we need to set the expected type by side + /// effect. However, we do not want this as a general capability, so this interface restricts + /// to the only allowed case. + pub fn feed_anon_const_type(self, key: LocalDefId, value: ty::EarlyBinder<Ty<'tcx>>) { + debug_assert_eq!(self.def_kind(key), DefKind::AnonConst); + TyCtxtFeed { tcx: self, key }.type_of(value) + } } impl<'tcx, KEY: Copy> TyCtxtFeed<'tcx, KEY> { @@ -581,28 +593,6 @@ impl<'tcx> TyCtxt<'tcx> { } } - pub fn typeck_opt_const_arg( - self, - def: ty::WithOptConstParam<LocalDefId>, - ) -> &'tcx TypeckResults<'tcx> { - if let Some(param_did) = def.const_param_did { - self.typeck_const_arg((def.did, param_did)) - } else { - self.typeck(def.did) - } - } - - pub fn mir_borrowck_opt_const_arg( - self, - def: ty::WithOptConstParam<LocalDefId>, - ) -> &'tcx BorrowCheckResult<'tcx> { - if let Some(param_did) = def.const_param_did { - self.mir_borrowck_const_arg((def.did, param_did)) - } else { - self.mir_borrowck(def.did) - } - } - pub fn alloc_steal_thir(self, thir: Thir<'tcx>) -> &'tcx Steal<Thir<'tcx>> { self.arena.alloc(Steal::new(thir)) } @@ -925,7 +915,7 @@ impl<'tcx> TyCtxt<'tcx> { crate_name, // Don't print the whole stable crate id. That's just // annoying in debug output. - stable_crate_id.to_u64() >> (8 * 6), + stable_crate_id.as_u64() >> (8 * 6), self.def_path(def_id).to_string_no_crate_verbose() ) } @@ -1278,25 +1268,6 @@ macro_rules! nop_lift { }; } -// Can't use the macros as we have reuse the `substs` here. -// -// See `mk_type_list` for more info. -impl<'a, 'tcx> Lift<'tcx> for &'a List<Ty<'a>> { - type Lifted = &'tcx List<Ty<'tcx>>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - if self.is_empty() { - return Some(List::empty()); - } - - tcx.interners - .substs - .contains_pointer_to(&InternedInSet(self.as_substs())) - // SAFETY: `self` is interned and therefore valid - // for the entire lifetime of the `TyCtxt`. - .then(|| unsafe { mem::transmute::<&'a List<Ty<'a>>, &'tcx List<Ty<'tcx>>>(self) }) - } -} - macro_rules! nop_list_lift { ($set:ident; $ty:ty => $lifted:ty) => { impl<'a, 'tcx> Lift<'tcx> for &'a List<$ty> { @@ -1320,6 +1291,7 @@ nop_lift! {const_; Const<'a> => Const<'tcx>} nop_lift! {const_allocation; ConstAllocation<'a> => ConstAllocation<'tcx>} nop_lift! {predicate; Predicate<'a> => Predicate<'tcx>} +nop_list_lift! {type_lists; Ty<'a> => Ty<'tcx>} nop_list_lift! {poly_existential_predicates; PolyExistentialPredicate<'a> => PolyExistentialPredicate<'tcx>} nop_list_lift! {predicates; Predicate<'a> => Predicate<'tcx>} nop_list_lift! {canonical_var_infos; CanonicalVarInfo<'a> => CanonicalVarInfo<'tcx>} @@ -1329,9 +1301,12 @@ nop_list_lift! {bound_variable_kinds; ty::BoundVariableKind => ty::BoundVariable // This is the impl for `&'a InternalSubsts<'a>`. nop_list_lift! {substs; GenericArg<'a> => GenericArg<'tcx>} -CloneLiftImpls! { for<'tcx> { - Constness, traits::WellFormedLoc, ImplPolarity, crate::mir::ReturnConstraint, -} } +CloneLiftImpls! { + Constness, + traits::WellFormedLoc, + ImplPolarity, + crate::mir::ReturnConstraint, +} macro_rules! sty_debug_print { ($fmt: expr, $ctxt: expr, $($variant: ident),*) => {{ @@ -1591,12 +1566,14 @@ macro_rules! slice_interners { slice_interners!( const_lists: pub mk_const_list(Const<'tcx>), substs: pub mk_substs(GenericArg<'tcx>), + type_lists: pub mk_type_list(Ty<'tcx>), canonical_var_infos: pub mk_canonical_var_infos(CanonicalVarInfo<'tcx>), poly_existential_predicates: intern_poly_existential_predicates(PolyExistentialPredicate<'tcx>), predicates: intern_predicates(Predicate<'tcx>), projs: pub mk_projs(ProjectionKind), place_elems: pub mk_place_elems(PlaceElem<'tcx>), bound_variable_kinds: pub mk_bound_variable_kinds(ty::BoundVariableKind), + fields: pub mk_fields(FieldIdx), ); impl<'tcx> TyCtxt<'tcx> { @@ -2190,18 +2167,6 @@ impl<'tcx> TyCtxt<'tcx> { T::collect_and_apply(iter, |xs| self.mk_const_list(xs)) } - pub fn mk_type_list(self, ts: &[Ty<'tcx>]) -> &'tcx List<Ty<'tcx>> { - // Actually intern type lists as lists of `GenericArg`s. - // - // Transmuting from `Ty<'tcx>` to `GenericArg<'tcx>` is sound - // as explained in `ty_slice_as_generic_arg`. With this, - // we guarantee that even when transmuting between `List<Ty<'tcx>>` - // and `List<GenericArg<'tcx>>`, the uniqueness requirement for - // lists is upheld. - let substs = self.mk_substs(ty::subst::ty_slice_as_generic_args(ts)); - substs.try_as_type_list().unwrap() - } - // Unlike various other `mk_*_from_iter` functions, this one uses `I: // IntoIterator` instead of `I: Iterator`, and it doesn't have a slice // variant, because of the need to combine `inputs` and `output`. This @@ -2277,6 +2242,14 @@ impl<'tcx> TyCtxt<'tcx> { T::collect_and_apply(iter, |xs| self.mk_place_elems(xs)) } + pub fn mk_fields_from_iter<I, T>(self, iter: I) -> T::Output + where + I: Iterator<Item = T>, + T: CollectAndApply<FieldIdx, &'tcx List<FieldIdx>>, + { + T::collect_and_apply(iter, |xs| self.mk_fields(xs)) + } + pub fn mk_substs_trait( self, self_ty: Ty<'tcx>, diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs index 31d00b65e98..76f61d9ac9c 100644 --- a/compiler/rustc_middle/src/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -68,7 +68,7 @@ pub enum TreatParams { } /// During fast-rejection, we have the choice of treating projection types -/// as either simplifyable or not, depending on whether we expect the projection +/// as either simplifiable or not, depending on whether we expect the projection /// to be normalized/rigid. #[derive(PartialEq, Eq, Debug, Clone, Copy)] pub enum TreatProjections { diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 5a6ee123811..68002bfcfbd 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -178,7 +178,7 @@ impl FlagComputation { &ty::Alias(ty::Projection, data) => { self.add_flags(TypeFlags::HAS_TY_PROJECTION); - self.add_projection_ty(data); + self.add_alias_ty(data); } &ty::Alias(ty::Opaque, ty::AliasTy { substs, .. }) => { @@ -267,7 +267,7 @@ impl FlagComputation { projection_ty, term, })) => { - self.add_projection_ty(projection_ty); + self.add_alias_ty(projection_ty); self.add_term(term); } ty::PredicateKind::WellFormed(arg) => { @@ -372,8 +372,8 @@ impl FlagComputation { } } - fn add_projection_ty(&mut self, projection_ty: ty::AliasTy<'_>) { - self.add_substs(projection_ty.substs); + fn add_alias_ty(&mut self, alias_ty: ty::AliasTy<'_>) { + self.add_substs(alias_ty.substs); } fn add_substs(&mut self, substs: &[GenericArg<'_>]) { diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 203e16bea27..25890eb15cd 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -37,7 +37,8 @@ where } fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - let r = r.super_fold_with(self); + // This one is a little different, because `super_fold_with` is not + // implemented on non-recursive `Region`. (self.lt_op)(r) } diff --git a/compiler/rustc_middle/src/ty/impls_ty.rs b/compiler/rustc_middle/src/ty/impls_ty.rs index 4c7822acdf7..02baa395c3c 100644 --- a/compiler/rustc_middle/src/ty/impls_ty.rs +++ b/compiler/rustc_middle/src/ty/impls_ty.rs @@ -73,34 +73,6 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ty::subst::GenericArg<'t } } -impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ty::subst::GenericArgKind<'tcx> { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - match self { - // WARNING: We dedup cache the `HashStable` results for `List` - // while ignoring types and freely transmute - // between `List<Ty<'tcx>>` and `List<GenericArg<'tcx>>`. - // See `fn mk_type_list` for more details. - // - // We therefore hash types without adding a hash for their discriminant. - // - // In order to make it very unlikely for the sequence of bytes being hashed for - // a `GenericArgKind::Type` to be the same as the sequence of bytes being - // hashed for one of the other variants, we hash some very high number instead - // of their actual discriminant since `TyKind` should never start with anything - // that high. - ty::subst::GenericArgKind::Type(ty) => ty.hash_stable(hcx, hasher), - ty::subst::GenericArgKind::Const(ct) => { - 0xF3u8.hash_stable(hcx, hasher); - ct.hash_stable(hcx, hasher); - } - ty::subst::GenericArgKind::Lifetime(lt) => { - 0xF5u8.hash_stable(hcx, hasher); - lt.hash_stable(hcx, hasher); - } - } - } -} - // AllocIds get resolved to whatever they point to (to be stable) impl<'a> HashStable<StableHashingContext<'a>> for mir::interpret::AllocId { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index e73225f70cc..cc86cba6fda 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -34,7 +34,7 @@ pub enum InstanceDef<'tcx> { /// - `fn` items /// - closures /// - generators - Item(ty::WithOptConstParam<DefId>), + Item(DefId), /// An intrinsic `fn` item (with `"rust-intrinsic"` or `"platform-intrinsic"` ABI). /// @@ -143,7 +143,7 @@ impl<'tcx> Instance<'tcx> { match self.def { InstanceDef::Item(def) => tcx - .upstream_monomorphizations_for(def.did) + .upstream_monomorphizations_for(def) .and_then(|monos| monos.get(&self.substs).cloned()), InstanceDef::DropGlue(_, Some(_)) => tcx.upstream_drop_glue_for(self.substs), _ => None, @@ -155,8 +155,8 @@ impl<'tcx> InstanceDef<'tcx> { #[inline] pub fn def_id(self) -> DefId { match self { - InstanceDef::Item(def) => def.did, - InstanceDef::VTableShim(def_id) + InstanceDef::Item(def_id) + | InstanceDef::VTableShim(def_id) | InstanceDef::ReifyShim(def_id) | InstanceDef::FnPtrShim(def_id, _) | InstanceDef::Virtual(def_id, _) @@ -172,7 +172,7 @@ impl<'tcx> InstanceDef<'tcx> { /// Returns the `DefId` of instances which might not require codegen locally. pub fn def_id_if_not_guaranteed_local_codegen(self) -> Option<DefId> { match self { - ty::InstanceDef::Item(def) => Some(def.did), + ty::InstanceDef::Item(def) => Some(def), ty::InstanceDef::DropGlue(def_id, Some(_)) | InstanceDef::ThreadLocalShim(def_id) => { Some(def_id) } @@ -189,23 +189,6 @@ impl<'tcx> InstanceDef<'tcx> { } #[inline] - pub fn with_opt_param(self) -> ty::WithOptConstParam<DefId> { - match self { - InstanceDef::Item(def) => def, - InstanceDef::VTableShim(def_id) - | InstanceDef::ReifyShim(def_id) - | InstanceDef::FnPtrShim(def_id, _) - | InstanceDef::Virtual(def_id, _) - | InstanceDef::Intrinsic(def_id) - | InstanceDef::ClosureOnceShim { call_once: def_id, track_caller: _ } - | InstanceDef::DropGlue(def_id, _) - | InstanceDef::CloneShim(def_id, _) - | InstanceDef::ThreadLocalShim(def_id) - | InstanceDef::FnPtrAddrShim(def_id, _) => ty::WithOptConstParam::unknown(def_id), - } - } - - #[inline] pub fn get_attrs( &self, tcx: TyCtxt<'tcx>, @@ -222,7 +205,7 @@ impl<'tcx> InstanceDef<'tcx> { pub fn requires_inline(&self, tcx: TyCtxt<'tcx>) -> bool { use rustc_hir::definitions::DefPathData; let def_id = match *self { - ty::InstanceDef::Item(def) => def.did, + ty::InstanceDef::Item(def) => def, ty::InstanceDef::DropGlue(_, Some(_)) => return false, ty::InstanceDef::ThreadLocalShim(_) => return false, _ => return true, @@ -273,8 +256,7 @@ impl<'tcx> InstanceDef<'tcx> { pub fn requires_caller_location(&self, tcx: TyCtxt<'_>) -> bool { match *self { - InstanceDef::Item(ty::WithOptConstParam { did: def_id, .. }) - | InstanceDef::Virtual(def_id, _) => { + InstanceDef::Item(def_id) | InstanceDef::Virtual(def_id, _) => { tcx.body_codegen_attrs(def_id).flags.contains(CodegenFnAttrFlags::TRACK_CALLER) } InstanceDef::ClosureOnceShim { call_once: _, track_caller } => track_caller, @@ -358,7 +340,7 @@ impl<'tcx> Instance<'tcx> { def_id, substs ); - Instance { def: InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)), substs } + Instance { def: InstanceDef::Item(def_id), substs } } pub fn mono(tcx: TyCtxt<'tcx>, def_id: DefId) -> Instance<'tcx> { @@ -403,18 +385,21 @@ impl<'tcx> Instance<'tcx> { /// couldn't complete due to errors elsewhere - this is distinct /// from `Ok(None)` to avoid misleading diagnostics when an error /// has already been/will be emitted, for the original cause + #[instrument(level = "debug", skip(tcx))] pub fn resolve( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, def_id: DefId, substs: SubstsRef<'tcx>, ) -> Result<Option<Instance<'tcx>>, ErrorGuaranteed> { - Instance::resolve_opt_const_arg( - tcx, - param_env, - ty::WithOptConstParam::unknown(def_id), - substs, - ) + // All regions in the result of this query are erased, so it's + // fine to erase all of the input regions. + + // HACK(eddyb) erase regions in `substs` first, so that `param_env.and(...)` + // below is more likely to ignore the bounds in scope (e.g. if the only + // generic parameters mentioned by `substs` were lifetime ones). + let substs = tcx.erase_regions(substs); + tcx.resolve_instance(tcx.erase_regions(param_env.and((def_id, substs)))) } pub fn expect_resolve( @@ -432,31 +417,6 @@ impl<'tcx> Instance<'tcx> { } } - // This should be kept up to date with `resolve`. - pub fn resolve_opt_const_arg( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - def: ty::WithOptConstParam<DefId>, - substs: SubstsRef<'tcx>, - ) -> Result<Option<Instance<'tcx>>, ErrorGuaranteed> { - // All regions in the result of this query are erased, so it's - // fine to erase all of the input regions. - - // HACK(eddyb) erase regions in `substs` first, so that `param_env.and(...)` - // below is more likely to ignore the bounds in scope (e.g. if the only - // generic parameters mentioned by `substs` were lifetime ones). - let substs = tcx.erase_regions(substs); - - // FIXME(eddyb) should this always use `param_env.with_reveal_all()`? - if let Some((did, param_did)) = def.as_const_arg() { - tcx.resolve_instance_of_const_arg( - tcx.erase_regions(param_env.and((did, param_did, substs))), - ) - } else { - tcx.resolve_instance(tcx.erase_regions(param_env.and((def.did, substs)))) - } - } - pub fn resolve_for_fn_ptr( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -470,7 +430,7 @@ impl<'tcx> Instance<'tcx> { match resolved.def { InstanceDef::Item(def) if resolved.def.requires_caller_location(tcx) => { debug!(" => fn pointer created for function with #[track_caller]"); - resolved.def = InstanceDef::ReifyShim(def.did); + resolved.def = InstanceDef::ReifyShim(def); } InstanceDef::Virtual(def_id, _) => { debug!(" => fn pointer created for virtual call"); @@ -513,23 +473,23 @@ impl<'tcx> Instance<'tcx> { if resolved.def.requires_caller_location(tcx) // 2) The caller location parameter comes from having `#[track_caller]` // on the implementation, and *not* on the trait method. - && !tcx.should_inherit_track_caller(def.did) + && !tcx.should_inherit_track_caller(def) // If the method implementation comes from the trait definition itself // (e.g. `trait Foo { #[track_caller] my_fn() { /* impl */ } }`), // then we don't need to generate a shim. This check is needed because // `should_inherit_track_caller` returns `false` if our method // implementation comes from the trait block, and not an impl block && !matches!( - tcx.opt_associated_item(def.did), + tcx.opt_associated_item(def), Some(ty::AssocItem { container: ty::AssocItemContainer::TraitContainer, .. }) ) { - if tcx.is_closure(def.did) { + if tcx.is_closure(def) { debug!(" => vtable fn pointer created for closure with #[track_caller]: {:?} for method {:?} {:?}", - def.did, def_id, substs); + def, def_id, substs); // Create a shim for the `FnOnce/FnMut/Fn` method we are calling // - unlike functions, invoking a closure always goes through a @@ -537,9 +497,9 @@ impl<'tcx> Instance<'tcx> { resolved = Instance { def: InstanceDef::ReifyShim(def_id), substs }; } else { debug!( - " => vtable fn pointer created for function with #[track_caller]: {:?}", def.did + " => vtable fn pointer created for function with #[track_caller]: {:?}", def ); - resolved.def = InstanceDef::ReifyShim(def.did); + resolved.def = InstanceDef::ReifyShim(def); } } } @@ -714,11 +674,8 @@ fn polymorphize<'tcx>( debug!("fold_ty: ty={:?}", ty); match *ty.kind() { ty::Closure(def_id, substs) => { - let polymorphized_substs = polymorphize( - self.tcx, - ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)), - substs, - ); + let polymorphized_substs = + polymorphize(self.tcx, ty::InstanceDef::Item(def_id), substs); if substs == polymorphized_substs { ty } else { @@ -726,11 +683,8 @@ fn polymorphize<'tcx>( } } ty::Generator(def_id, substs, movability) => { - let polymorphized_substs = polymorphize( - self.tcx, - ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)), - substs, - ); + let polymorphized_substs = + polymorphize(self.tcx, ty::InstanceDef::Item(def_id), substs); if substs == polymorphized_substs { ty } else { diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 195d951f9f3..1e2fd86e13d 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -235,7 +235,7 @@ impl IntoDiagnostic<'_, !> for LayoutError<'_> { } } -// FIXME: Once the other errors that embed this error have been converted to translateable +// FIXME: Once the other errors that embed this error have been converted to translatable // diagnostics, this Display impl should be removed. impl<'tcx> fmt::Display for LayoutError<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -458,10 +458,10 @@ impl<'tcx> SizeSkeleton<'tcx> { } } -/// When creating the layout for types with abstract conts in their size (i.e. [usize; 4 * N]), +/// When creating the layout for types with abstract consts in their size (i.e. [usize; 4 * N]), /// to ensure that they have a canonical order and can be compared directly we combine all /// constants, and sort the other terms. This allows comparison of expressions of sizes, -/// allowing for things like transmutating between types that depend on generic consts. +/// allowing for things like transmuting between types that depend on generic consts. /// This returns `None` if multiplication of constants overflows. fn mul_sorted_consts<'tcx>( tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs index 79365ef281b..30f036e471c 100644 --- a/compiler/rustc_middle/src/ty/list.rs +++ b/compiler/rustc_middle/src/ty/list.rs @@ -1,4 +1,5 @@ use crate::arena::Arena; +use rustc_data_structures::aligned::{align_of, Aligned}; use rustc_serialize::{Encodable, Encoder}; use std::alloc::Layout; use std::cmp::Ordering; @@ -198,22 +199,17 @@ impl<'a, T: Copy> IntoIterator for &'a List<T> { unsafe impl<T: Sync> Sync for List<T> {} -unsafe impl<'a, T: 'a> rustc_data_structures::tagged_ptr::Pointer for &'a List<T> { - const BITS: usize = std::mem::align_of::<usize>().trailing_zeros() as usize; - - #[inline] - fn into_usize(self) -> usize { - self as *const List<T> as usize - } - - #[inline] - unsafe fn from_usize(ptr: usize) -> &'a List<T> { - &*(ptr as *const List<T>) - } +// Safety: +// Layouts of `Equivalent<T>` and `List<T>` are the same, modulo opaque tail, +// thus aligns of `Equivalent<T>` and `List<T>` must be the same. +unsafe impl<T> Aligned for List<T> { + const ALIGN: ptr::Alignment = { + #[repr(C)] + struct Equivalent<T> { + _len: usize, + _data: [T; 0], + } - unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R { - // `Self` is `&'a List<T>` which impls `Copy`, so this is fine. - let ptr = Self::from_usize(ptr); - f(&ptr) - } + align_of::<Equivalent<T>>() + }; } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 2e516f291bc..42b98540ac7 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1007,7 +1007,7 @@ impl<'tcx> Term<'tcx> { _ => None, }, TermKind::Const(ct) => match ct.kind() { - ConstKind::Unevaluated(uv) => Some(tcx.mk_alias_ty(uv.def.did, uv.substs)), + ConstKind::Unevaluated(uv) => Some(tcx.mk_alias_ty(uv.def, uv.substs)), _ => None, }, } @@ -1471,135 +1471,6 @@ pub struct BoundConst<'tcx> { pub type PlaceholderConst<'tcx> = Placeholder<BoundVar>; -/// A `DefId` which, in case it is a const argument, is potentially bundled with -/// the `DefId` of the generic parameter it instantiates. -/// -/// This is used to avoid calls to `type_of` for const arguments during typeck -/// which cause cycle errors. -/// -/// ```rust -/// struct A; -/// impl A { -/// fn foo<const N: usize>(&self) -> [u8; N] { [0; N] } -/// // ^ const parameter -/// } -/// struct B; -/// impl B { -/// fn foo<const M: u8>(&self) -> usize { 42 } -/// // ^ const parameter -/// } -/// -/// fn main() { -/// let a = A; -/// let _b = a.foo::<{ 3 + 7 }>(); -/// // ^^^^^^^^^ const argument -/// } -/// ``` -/// -/// Let's look at the call `a.foo::<{ 3 + 7 }>()` here. We do not know -/// which `foo` is used until we know the type of `a`. -/// -/// We only know the type of `a` once we are inside of `typeck(main)`. -/// We also end up normalizing the type of `_b` during `typeck(main)` which -/// requires us to evaluate the const argument. -/// -/// To evaluate that const argument we need to know its type, -/// which we would get using `type_of(const_arg)`. This requires us to -/// resolve `foo` as it can be either `usize` or `u8` in this example. -/// However, resolving `foo` once again requires `typeck(main)` to get the type of `a`, -/// which results in a cycle. -/// -/// In short we must not call `type_of(const_arg)` during `typeck(main)`. -/// -/// When first creating the `ty::Const` of the const argument inside of `typeck` we have -/// already resolved `foo` so we know which const parameter this argument instantiates. -/// This means that we also know the expected result of `type_of(const_arg)` even if we -/// aren't allowed to call that query: it is equal to `type_of(const_param)` which is -/// trivial to compute. -/// -/// If we now want to use that constant in a place which potentially needs its type -/// we also pass the type of its `const_param`. This is the point of `WithOptConstParam`, -/// except that instead of a `Ty` we bundle the `DefId` of the const parameter. -/// Meaning that we need to use `type_of(const_param_did)` if `const_param_did` is `Some` -/// to get the type of `did`. -#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, Lift, TyEncodable, TyDecodable)] -#[derive(PartialEq, Eq, PartialOrd, Ord)] -#[derive(Hash, HashStable)] -pub struct WithOptConstParam<T> { - pub did: T, - /// The `DefId` of the corresponding generic parameter in case `did` is - /// a const argument. - /// - /// Note that even if `did` is a const argument, this may still be `None`. - /// All queries taking `WithOptConstParam` start by calling `tcx.opt_const_param_of(def.did)` - /// to potentially update `param_did` in the case it is `None`. - pub const_param_did: Option<DefId>, -} - -impl<T> WithOptConstParam<T> { - /// Creates a new `WithOptConstParam` setting `const_param_did` to `None`. - #[inline(always)] - pub fn unknown(did: T) -> WithOptConstParam<T> { - WithOptConstParam { did, const_param_did: None } - } -} - -impl WithOptConstParam<LocalDefId> { - /// Returns `Some((did, param_did))` if `def_id` is a const argument, - /// `None` otherwise. - #[inline(always)] - pub fn try_lookup(did: LocalDefId, tcx: TyCtxt<'_>) -> Option<(LocalDefId, DefId)> { - tcx.opt_const_param_of(did).map(|param_did| (did, param_did)) - } - - /// In case `self` is unknown but `self.did` is a const argument, this returns - /// a `WithOptConstParam` with the correct `const_param_did`. - #[inline(always)] - pub fn try_upgrade(self, tcx: TyCtxt<'_>) -> Option<WithOptConstParam<LocalDefId>> { - if self.const_param_did.is_none() { - if let const_param_did @ Some(_) = tcx.opt_const_param_of(self.did) { - return Some(WithOptConstParam { did: self.did, const_param_did }); - } - } - - None - } - - pub fn to_global(self) -> WithOptConstParam<DefId> { - WithOptConstParam { did: self.did.to_def_id(), const_param_did: self.const_param_did } - } - - pub fn def_id_for_type_of(self) -> DefId { - if let Some(did) = self.const_param_did { did } else { self.did.to_def_id() } - } -} - -impl WithOptConstParam<DefId> { - pub fn as_local(self) -> Option<WithOptConstParam<LocalDefId>> { - self.did - .as_local() - .map(|did| WithOptConstParam { did, const_param_did: self.const_param_did }) - } - - pub fn as_const_arg(self) -> Option<(LocalDefId, DefId)> { - if let Some(param_did) = self.const_param_did { - if let Some(did) = self.did.as_local() { - return Some((did, param_did)); - } - } - - None - } - - pub fn is_local(self) -> bool { - self.did.is_local() - } - - pub fn def_id_for_type_of(self) -> DefId { - self.const_param_did.unwrap_or(self.did) - } -} - /// When type checking, we use the `ParamEnv` to track /// details about the set of where-clauses that are in scope at this /// particular point. @@ -1627,7 +1498,8 @@ struct ParamTag { } unsafe impl rustc_data_structures::tagged_ptr::Tag for ParamTag { - const BITS: usize = 2; + const BITS: u32 = 2; + #[inline] fn into_usize(self) -> usize { match self { @@ -1637,6 +1509,7 @@ unsafe impl rustc_data_structures::tagged_ptr::Tag for ParamTag { Self { reveal: traits::Reveal::All, constness: hir::Constness::Const } => 3, } } + #[inline] unsafe fn from_usize(ptr: usize) -> Self { match ptr { @@ -1850,12 +1723,6 @@ impl<'tcx, T> ParamEnvAnd<'tcx, T> { pub fn into_parts(self) -> (ParamEnv<'tcx>, T) { (self.param_env, self.value) } - - #[inline] - pub fn without_const(mut self) -> Self { - self.param_env = self.param_env.without_const(); - self - } } #[derive(Copy, Clone, Debug, HashStable, Encodable, Decodable)] @@ -1969,6 +1836,16 @@ impl VariantDef { pub fn ctor_def_id(&self) -> Option<DefId> { self.ctor.map(|(_, def_id)| def_id) } + + /// Returns the one field in this variant. + /// + /// `panic!`s if there are no fields or multiple fields. + #[inline] + pub fn single_field(&self) -> &FieldDef { + assert!(self.fields.len() == 1); + + &self.fields[FieldIdx::from_u32(0)] + } } impl PartialEq for VariantDef { @@ -2361,7 +2238,7 @@ impl<'tcx> TyCtxt<'tcx> { match instance { ty::InstanceDef::Item(def) => { debug!("calling def_kind on def: {:?}", def); - let def_kind = self.def_kind(def.did); + let def_kind = self.def_kind(def); debug!("returned from def_kind: {:?}", def_kind); match def_kind { DefKind::Const @@ -2369,13 +2246,10 @@ impl<'tcx> TyCtxt<'tcx> { | DefKind::AssocConst | DefKind::Ctor(..) | DefKind::AnonConst - | DefKind::InlineConst => self.mir_for_ctfe_opt_const_arg(def), + | DefKind::InlineConst => self.mir_for_ctfe(def), // If the caller wants `mir_for_ctfe` of a function they should not be using // `instance_mir`, so we'll assume const fn also wants the optimized version. - _ => { - assert_eq!(def.const_param_did, None); - self.optimized_mir(def.did) - } + _ => self.optimized_mir(def), } } ty::InstanceDef::VTableShim(..) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 72caadaf661..888b3a50b77 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -738,7 +738,9 @@ pub trait PrettyPrinter<'tcx>: } } ty::Placeholder(placeholder) => match placeholder.bound.kind { - ty::BoundTyKind::Anon => p!(write("Placeholder({:?})", placeholder)), + ty::BoundTyKind::Anon => { + self.pretty_print_placeholder_var(placeholder.universe, placeholder.bound.var)? + } ty::BoundTyKind::Param(_, name) => p!(write("{}", name)), }, ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { @@ -1172,6 +1174,18 @@ pub trait PrettyPrinter<'tcx>: } } + fn pretty_print_placeholder_var( + &mut self, + ui: ty::UniverseIndex, + var: ty::BoundVar, + ) -> Result<(), Self::Error> { + if ui == ty::UniverseIndex::ROOT { + write!(self, "!{}", var.index()) + } else { + write!(self, "!{}_{}", ui.index(), var.index()) + } + } + fn ty_infer_name(&self, _: ty::TyVid) -> Option<Symbol> { None } @@ -1328,13 +1342,13 @@ pub trait PrettyPrinter<'tcx>: match ct.kind() { ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) => { - match self.tcx().def_kind(def.did) { + match self.tcx().def_kind(def) { DefKind::Const | DefKind::AssocConst => { - p!(print_value_path(def.did, substs)) + p!(print_value_path(def, substs)) } DefKind::AnonConst => { if def.is_local() - && let span = self.tcx().def_span(def.did) + && let span = self.tcx().def_span(def) && let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) { p!(write("{}", snip)) @@ -1344,7 +1358,7 @@ pub trait PrettyPrinter<'tcx>: // cause printing to enter an infinite recursion if the anon const is in the self type i.e. // `impl<T: Default> Default for [T; 32 - 1 - 1 - 1] {` // where we would try to print `<[T; /* print `constant#0` again */] as Default>::{constant#0}` - p!(write("{}::{}", self.tcx().crate_name(def.did.krate), self.tcx().def_path(def.did).to_string_no_crate_verbose())) + p!(write("{}::{}", self.tcx().crate_name(def.krate), self.tcx().def_path(def).to_string_no_crate_verbose())) } } defkind => bug!("`{:?}` has unexpected defkind {:?}", ct, defkind), @@ -2518,7 +2532,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { self.used_region_names.insert(name); } - r.super_visit_with(self) + ControlFlow::Continue(()) } // We collect types in order to prevent really large types from compiling for diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index fa9fea72344..e46cfb8dd16 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -76,6 +76,9 @@ use std::ops::Deref; use std::path::PathBuf; use std::sync::Arc; +use rustc_data_structures::fingerprint::Fingerprint; +use rustc_query_system::ich::StableHashingContext; + #[derive(Default)] pub struct QuerySystem<'tcx> { pub arenas: QueryArenas<'tcx>, @@ -202,16 +205,6 @@ macro_rules! separate_provide_extern_default { }; } -macro_rules! opt_remap_env_constness { - ([][$name:ident]) => {}; - ([(remap_env_constness) $($rest:tt)*][$name:ident]) => { - let $name = $name.without_const(); - }; - ([$other:tt $($modifiers:tt)*][$name:ident]) => { - opt_remap_env_constness!([$($modifiers)*][$name]) - }; -} - macro_rules! define_callbacks { ( $($(#[$attr:meta])* @@ -353,7 +346,6 @@ macro_rules! define_callbacks { #[inline(always)] pub fn $name(self, key: query_helper_param_ty!($($K)*)) { let key = key.into_query_param(); - opt_remap_env_constness!([$($modifiers)*][key]); match try_get_cached(self.tcx, &self.tcx.query_system.caches.$name, &key) { Some(_) => return, @@ -372,7 +364,6 @@ macro_rules! define_callbacks { #[inline(always)] pub fn $name(self, key: query_helper_param_ty!($($K)*)) { let key = key.into_query_param(); - opt_remap_env_constness!([$($modifiers)*][key]); match try_get_cached(self.tcx, &self.tcx.query_system.caches.$name, &key) { Some(_) => return, @@ -402,7 +393,6 @@ macro_rules! define_callbacks { pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> $V { let key = key.into_query_param(); - opt_remap_env_constness!([$($modifiers)*][key]); restore::<$V>(match try_get_cached(self.tcx, &self.tcx.query_system.caches.$name, &key) { Some(value) => value, @@ -490,22 +480,33 @@ macro_rules! define_feedable { $(impl<'tcx, K: IntoQueryParam<$($K)*> + Copy> TyCtxtFeed<'tcx, K> { $(#[$attr])* #[inline(always)] - pub fn $name(self, value: query_provided::$name<'tcx>) -> $V { + pub fn $name(self, value: query_provided::$name<'tcx>) { let key = self.key().into_query_param(); - opt_remap_env_constness!([$($modifiers)*][key]); let tcx = self.tcx; let erased = query_provided_to_value::$name(tcx, value); let value = restore::<$V>(erased); let cache = &tcx.query_system.caches.$name; + let hasher: Option<fn(&mut StableHashingContext<'_>, &_) -> _> = hash_result!([$($modifiers)*]); match try_get_cached(tcx, cache, &key) { Some(old) => { let old = restore::<$V>(old); - bug!( - "Trying to feed an already recorded value for query {} key={key:?}:\nold value: {old:?}\nnew value: {value:?}", - stringify!($name), - ) + if let Some(hasher) = hasher { + let (value_hash, old_hash): (Fingerprint, Fingerprint) = tcx.with_stable_hashing_context(|mut hcx| + (hasher(&mut hcx, &value), hasher(&mut hcx, &old)) + ); + assert_eq!( + old_hash, value_hash, + "Trying to feed an already recorded value for query {} key={key:?}:\nold value: {old:?}\nnew value: {value:?}", + stringify!($name), + ) + } else { + bug!( + "Trying to feed an already recorded value for query {} key={key:?}:\nold value: {old:?}\nnew value: {value:?}", + stringify!($name), + ) + } } None => { let dep_node = dep_graph::DepNode::construct(tcx, dep_graph::DepKind::$name, &key); @@ -517,7 +518,6 @@ macro_rules! define_feedable { hash_result!([$($modifiers)*]), ); cache.complete(key, erased, dep_node_index); - value } } } diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 46c931d61dc..c6d10f4741a 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -7,7 +7,7 @@ use crate::ty::error::{ExpectedFound, TypeError}; use crate::ty::{self, Expr, ImplSubject, Term, TermKind, Ty, TyCtxt, TypeFoldable}; use crate::ty::{GenericArg, GenericArgKind, SubstsRef}; -use rustc_hir as ast; +use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_target::spec::abi; use std::iter; @@ -123,8 +123,8 @@ pub fn relate_type_and_mut<'tcx, R: TypeRelation<'tcx>>( } else { let mutbl = a.mutbl; let (variance, info) = match mutbl { - ast::Mutability::Not => (ty::Covariant, ty::VarianceDiagInfo::None), - ast::Mutability::Mut => { + hir::Mutability::Not => (ty::Covariant, ty::VarianceDiagInfo::None), + hir::Mutability::Mut => { (ty::Invariant, ty::VarianceDiagInfo::Invariant { ty: base_ty, param_index: 0 }) } }; @@ -239,12 +239,12 @@ impl<'tcx> Relate<'tcx> for ty::BoundConstness { } } -impl<'tcx> Relate<'tcx> for ast::Unsafety { +impl<'tcx> Relate<'tcx> for hir::Unsafety { fn relate<R: TypeRelation<'tcx>>( relation: &mut R, - a: ast::Unsafety, - b: ast::Unsafety, - ) -> RelateResult<'tcx, ast::Unsafety> { + a: hir::Unsafety, + b: hir::Unsafety, + ) -> RelateResult<'tcx, hir::Unsafety> { if a != b { Err(TypeError::UnsafetyMismatch(expected_found(relation, a, b))) } else { diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 5c604bb6db2..8a2258375ab 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -197,7 +197,7 @@ impl<'tcx> fmt::Debug for AliasTy<'tcx> { // Atomic structs // // For things that don't carry any arena-allocated data (and are -// copy...), just add them to one of these lists as appropriat. +// copy...), just add them to one of these lists as appropriate. // For things for which the type library provides traversal implementations // for all Interners, we only need to provide a Lift implementation: @@ -276,9 +276,7 @@ TrivialTypeTraversalAndLiftImpls! { } TrivialTypeTraversalAndLiftImpls! { - for<'tcx> { - ty::ValTree<'tcx>, - } + ty::ValTree<'tcx>, } /////////////////////////////////////////////////////////////////////////// @@ -583,24 +581,6 @@ impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for ty::Region<'tcx> { } } -impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for ty::Region<'tcx> { - fn try_super_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( - self, - _folder: &mut F, - ) -> Result<Self, F::Error> { - Ok(self) - } -} - -impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Region<'tcx> { - fn super_visit_with<V: TypeVisitor<TyCtxt<'tcx>>>( - &self, - _visitor: &mut V, - ) -> ControlFlow<V::BreakTy> { - ControlFlow::Continue(()) - } -} - impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ty::Predicate<'tcx> { fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( self, diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index f05b873432d..a439211ca33 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -21,7 +21,6 @@ use std::marker::PhantomData; use std::mem; use std::num::NonZeroUsize; use std::ops::{ControlFlow, Deref}; -use std::slice; /// An entity in the Rust type system, which can be one of /// several kinds (types, lifetimes, and consts). @@ -48,38 +47,13 @@ const TYPE_TAG: usize = 0b00; const REGION_TAG: usize = 0b01; const CONST_TAG: usize = 0b10; -#[derive(Debug, TyEncodable, TyDecodable, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, TyEncodable, TyDecodable, PartialEq, Eq, PartialOrd, Ord, HashStable)] pub enum GenericArgKind<'tcx> { Lifetime(ty::Region<'tcx>), Type(Ty<'tcx>), Const(ty::Const<'tcx>), } -/// This function goes from `&'a [Ty<'tcx>]` to `&'a [GenericArg<'tcx>]` -/// -/// This is sound as, for types, `GenericArg` is just -/// `NonZeroUsize::new_unchecked(ty as *const _ as usize)` as -/// long as we use `0` for the `TYPE_TAG`. -pub fn ty_slice_as_generic_args<'a, 'tcx>(ts: &'a [Ty<'tcx>]) -> &'a [GenericArg<'tcx>] { - assert_eq!(TYPE_TAG, 0); - // SAFETY: the whole slice is valid and immutable. - // `Ty` and `GenericArg` is explained above. - unsafe { slice::from_raw_parts(ts.as_ptr().cast(), ts.len()) } -} - -impl<'tcx> List<Ty<'tcx>> { - /// Allows to freely switch between `List<Ty<'tcx>>` and `List<GenericArg<'tcx>>`. - /// - /// As lists are interned, `List<Ty<'tcx>>` and `List<GenericArg<'tcx>>` have - /// be interned together, see `mk_type_list` for more details. - #[inline] - pub fn as_substs(&'tcx self) -> SubstsRef<'tcx> { - assert_eq!(TYPE_TAG, 0); - // SAFETY: `List<T>` is `#[repr(C)]`. `Ty` and `GenericArg` is explained above. - unsafe { &*(self as *const List<Ty<'tcx>> as *const List<GenericArg<'tcx>>) } - } -} - impl<'tcx> GenericArgKind<'tcx> { #[inline] fn pack(self) -> GenericArg<'tcx> { @@ -180,30 +154,45 @@ impl<'tcx> GenericArg<'tcx> { } } - /// Unpack the `GenericArg` as a region when it is known certainly to be a region. - pub fn expect_region(self) -> ty::Region<'tcx> { + #[inline] + pub fn as_type(self) -> Option<Ty<'tcx>> { + match self.unpack() { + GenericArgKind::Type(ty) => Some(ty), + _ => None, + } + } + + #[inline] + pub fn as_region(self) -> Option<ty::Region<'tcx>> { + match self.unpack() { + GenericArgKind::Lifetime(re) => Some(re), + _ => None, + } + } + + #[inline] + pub fn as_const(self) -> Option<ty::Const<'tcx>> { match self.unpack() { - GenericArgKind::Lifetime(lt) => lt, - _ => bug!("expected a region, but found another kind"), + GenericArgKind::Const(ct) => Some(ct), + _ => None, } } + /// Unpack the `GenericArg` as a region when it is known certainly to be a region. + pub fn expect_region(self) -> ty::Region<'tcx> { + self.as_region().unwrap_or_else(|| bug!("expected a region, but found another kind")) + } + /// Unpack the `GenericArg` as a type when it is known certainly to be a type. /// This is true in cases where `Substs` is used in places where the kinds are known /// to be limited (e.g. in tuples, where the only parameters are type parameters). pub fn expect_ty(self) -> Ty<'tcx> { - match self.unpack() { - GenericArgKind::Type(ty) => ty, - _ => bug!("expected a type, but found another kind"), - } + self.as_type().unwrap_or_else(|| bug!("expected a type, but found another kind")) } /// Unpack the `GenericArg` as a const when it is known certainly to be a const. pub fn expect_const(self) -> ty::Const<'tcx> { - match self.unpack() { - GenericArgKind::Const(c) => c, - _ => bug!("expected a const, but found another kind"), - } + self.as_const().unwrap_or_else(|| bug!("expected a const, but found another kind")) } pub fn is_non_region_infer(self) -> bool { @@ -268,13 +257,16 @@ pub type InternalSubsts<'tcx> = List<GenericArg<'tcx>>; pub type SubstsRef<'tcx> = &'tcx InternalSubsts<'tcx>; impl<'tcx> InternalSubsts<'tcx> { - /// Checks whether all elements of this list are types, if so, transmute. - pub fn try_as_type_list(&'tcx self) -> Option<&'tcx List<Ty<'tcx>>> { - self.iter().all(|arg| matches!(arg.unpack(), GenericArgKind::Type(_))).then(|| { - assert_eq!(TYPE_TAG, 0); - // SAFETY: All elements are types, see `List<Ty<'tcx>>::as_substs`. - unsafe { &*(self as *const List<GenericArg<'tcx>> as *const List<Ty<'tcx>>) } - }) + /// Converts substs to a type list. + /// + /// # Panics + /// + /// If any of the generic arguments are not types. + pub fn into_type_list(&self, tcx: TyCtxt<'tcx>) -> &'tcx List<Ty<'tcx>> { + tcx.mk_type_list_from_iter(self.iter().map(|arg| match arg.unpack() { + GenericArgKind::Type(ty) => ty, + _ => bug!("`into_type_list` called on substs with non-types"), + })) } /// Interpret these substitutions as the substitutions of a closure type. @@ -379,22 +371,17 @@ impl<'tcx> InternalSubsts<'tcx> { #[inline] pub fn types(&'tcx self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> + 'tcx { - self.iter() - .filter_map(|k| if let GenericArgKind::Type(ty) = k.unpack() { Some(ty) } else { None }) + self.iter().filter_map(|k| k.as_type()) } #[inline] pub fn regions(&'tcx self) -> impl DoubleEndedIterator<Item = ty::Region<'tcx>> + 'tcx { - self.iter().filter_map(|k| { - if let GenericArgKind::Lifetime(lt) = k.unpack() { Some(lt) } else { None } - }) + self.iter().filter_map(|k| k.as_region()) } #[inline] pub fn consts(&'tcx self) -> impl DoubleEndedIterator<Item = ty::Const<'tcx>> + 'tcx { - self.iter().filter_map(|k| { - if let GenericArgKind::Const(ct) = k.unpack() { Some(ct) } else { None } - }) + self.iter().filter_map(|k| k.as_const()) } #[inline] @@ -410,31 +397,21 @@ impl<'tcx> InternalSubsts<'tcx> { #[inline] #[track_caller] pub fn type_at(&self, i: usize) -> Ty<'tcx> { - if let GenericArgKind::Type(ty) = self[i].unpack() { - ty - } else { - bug!("expected type for param #{} in {:?}", i, self); - } + self[i].as_type().unwrap_or_else(|| bug!("expected type for param #{} in {:?}", i, self)) } #[inline] #[track_caller] pub fn region_at(&self, i: usize) -> ty::Region<'tcx> { - if let GenericArgKind::Lifetime(lt) = self[i].unpack() { - lt - } else { - bug!("expected region for param #{} in {:?}", i, self); - } + self[i] + .as_region() + .unwrap_or_else(|| bug!("expected region for param #{} in {:?}", i, self)) } #[inline] #[track_caller] pub fn const_at(&self, i: usize) -> ty::Const<'tcx> { - if let GenericArgKind::Const(ct) = self[i].unpack() { - ct - } else { - bug!("expected const for param #{} in {:?}", i, self); - } + self[i].as_const().unwrap_or_else(|| bug!("expected const for param #{} in {:?}", i, self)) } #[inline] diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 47943b94c3b..ef8955b1d3a 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -208,6 +208,9 @@ pub struct TypeckResults<'tcx> { /// Contains the data for evaluating the effect of feature `capture_disjoint_fields` /// on closure size. pub closure_size_eval: FxHashMap<LocalDefId, ClosureSizeProfileData<'tcx>>, + + /// Container types and field indices of `offset_of!` expressions + offset_of_data: ItemLocalMap<(Ty<'tcx>, Vec<FieldIdx>)>, } /// Whenever a value may be live across a generator yield, the type of that value winds up in the @@ -280,6 +283,7 @@ impl<'tcx> TypeckResults<'tcx> { generator_interior_predicates: Default::default(), treat_byte_string_as_slice: Default::default(), closure_size_eval: Default::default(), + offset_of_data: Default::default(), } } @@ -530,6 +534,14 @@ impl<'tcx> TypeckResults<'tcx> { pub fn coercion_casts(&self) -> &ItemLocalSet { &self.coercion_casts } + + pub fn offset_of_data(&self) -> LocalTableInContext<'_, (Ty<'tcx>, Vec<FieldIdx>)> { + LocalTableInContext { hir_owner: self.hir_owner, data: &self.offset_of_data } + } + + pub fn offset_of_data_mut(&mut self) -> LocalTableInContextMut<'_, (Ty<'tcx>, Vec<FieldIdx>)> { + LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.offset_of_data } + } } /// Validate that the given HirId (respectively its `local_id` part) can be diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index c8a78ec03d9..dbe2eebe336 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -11,7 +11,7 @@ use crate::ty::{ use crate::ty::{GenericArgKind, SubstsRef}; use rustc_apfloat::Float as _; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher}; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; @@ -124,7 +124,7 @@ impl IntTypeExt for IntegerType { impl<'tcx> TyCtxt<'tcx> { /// Creates a hash of the type `Ty` which will be the same no matter what crate /// context it's calculated within. This is used by the `type_id` intrinsic. - pub fn type_id_hash(self, ty: Ty<'tcx>) -> u64 { + pub fn type_id_hash(self, ty: Ty<'tcx>) -> Hash64 { // We want the type_id be independent of the types free regions, so we // erase them. The erase_regions() call will also anonymize bound // regions, which is desirable too. @@ -642,7 +642,7 @@ impl<'tcx> TyCtxt<'tcx> { } } - /// Return the set of types that should be taken into accound when checking + /// Return the set of types that should be taken into account when checking /// trait bounds on a generator's internal state. pub fn generator_hidden_types( self, @@ -694,13 +694,6 @@ impl<'tcx> TyCtxt<'tcx> { if visitor.found_recursion { Err(expanded_type) } else { Ok(expanded_type) } } - pub fn bound_return_position_impl_trait_in_trait_tys( - self, - def_id: DefId, - ) -> ty::EarlyBinder<Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed>> { - ty::EarlyBinder(self.collect_return_position_impl_trait_in_trait_tys(def_id)) - } - pub fn bound_explicit_item_bounds( self, def_id: DefId, @@ -1402,7 +1395,7 @@ pub fn is_trivially_const_drop(ty: Ty<'_>) -> bool { } /// Does the equivalent of -/// ```ignore (ilustrative) +/// ```ignore (illustrative) /// let v = self.iter().map(|p| p.fold_with(folder)).collect::<SmallVec<[_; 8]>>(); /// folder.tcx().intern_*(&v) /// ``` diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index 08a62c900f9..1b07f52afca 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -33,6 +33,14 @@ pub trait TypeVisitableExt<'tcx>: TypeVisitable<TyCtxt<'tcx>> { } fn has_type_flags(&self, flags: TypeFlags) -> bool { + // N.B. Even though this uses a visitor, the visitor does not actually + // recurse through the whole `TypeVisitable` implementor type. + // + // Instead it stops on the first "level", visiting types, regions, + // consts and predicates just fetches their type flags. + // + // Thus this is a lot faster than it might seem and should be + // optimized to a simple field access. let res = self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags); trace!(?self, ?flags, ?res, "has_type_flags"); @@ -364,7 +372,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ValidateBoundVars<'tcx> { _ => (), }; - r.super_visit_with(self) + ControlFlow::Continue(()) } } diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index 182945b9c3d..04a635a6803 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -194,7 +194,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) | ty::FnDef(_, substs) => { stack.extend(substs.iter().rev()); } - ty::Tuple(ts) => stack.extend(ts.as_substs().iter().rev()), + ty::Tuple(ts) => stack.extend(ts.iter().rev().map(GenericArg::from)), ty::GeneratorWitness(ts) => { stack.extend(ts.skip_binder().iter().rev().map(|ty| ty.into())); } diff --git a/compiler/rustc_const_eval/src/util/call_kind.rs b/compiler/rustc_middle/src/util/call_kind.rs index 995363c0edd..627c84c388c 100644 --- a/compiler/rustc_const_eval/src/util/call_kind.rs +++ b/compiler/rustc_middle/src/util/call_kind.rs @@ -2,10 +2,10 @@ //! as well as errors when attempting to call a non-const function in a const //! context. +use crate::ty::subst::SubstsRef; +use crate::ty::{AssocItemContainer, Instance, ParamEnv, Ty, TyCtxt}; use rustc_hir::def_id::DefId; use rustc_hir::{lang_items, LangItem}; -use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{AssocItemContainer, Instance, ParamEnv, Ty, TyCtxt}; use rustc_span::symbol::Ident; use rustc_span::{sym, DesugaringKind, Span}; diff --git a/compiler/rustc_const_eval/src/util/find_self_call.rs b/compiler/rustc_middle/src/util/find_self_call.rs index 33ad128eeeb..0eab0adf07e 100644 --- a/compiler/rustc_const_eval/src/util/find_self_call.rs +++ b/compiler/rustc_middle/src/util/find_self_call.rs @@ -1,6 +1,6 @@ -use rustc_middle::mir::*; -use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, TyCtxt}; +use crate::mir::*; +use crate::ty::subst::SubstsRef; +use crate::ty::{self, TyCtxt}; use rustc_span::def_id::DefId; /// Checks if the specified `local` is used as the `self` parameter of a method call diff --git a/compiler/rustc_middle/src/util/mod.rs b/compiler/rustc_middle/src/util/mod.rs new file mode 100644 index 00000000000..53b4257899b --- /dev/null +++ b/compiler/rustc_middle/src/util/mod.rs @@ -0,0 +1,7 @@ +pub mod bug; +pub mod call_kind; +pub mod common; +pub mod find_self_call; + +pub use call_kind::{call_kind, CallDesugaringKind, CallKind}; +pub use find_self_call::find_self_call; diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml index f24b165d7c2..58449ee9eb4 100644 --- a/compiler/rustc_mir_build/Cargo.toml +++ b/compiler/rustc_mir_build/Cargo.toml @@ -14,6 +14,7 @@ rustc_apfloat = { path = "../rustc_apfloat" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_index = { path = "../rustc_index" } rustc_errors = { path = "../rustc_errors" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_hir = { path = "../rustc_hir" } rustc_infer = { path = "../rustc_infer" } rustc_macros = { path = "../rustc_macros" } diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index 99291740ac8..fbcfd433724 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -78,7 +78,7 @@ pub fn as_constant_inner<'tcx>( ExprKind::NamedConst { def_id, substs, ref user_ty } => { let user_ty = user_ty.as_ref().and_then(push_cuta); - let uneval = mir::UnevaluatedConst::new(ty::WithOptConstParam::unknown(def_id), substs); + let uneval = mir::UnevaluatedConst::new(def_id, substs); let literal = ConstantKind::Unevaluated(uneval, ty); Constant { user_ty, span, literal } @@ -90,7 +90,7 @@ pub fn as_constant_inner<'tcx>( Constant { user_ty: None, span, literal } } ExprKind::ConstBlock { did: def_id, substs } => { - let uneval = mir::UnevaluatedConst::new(ty::WithOptConstParam::unknown(def_id), substs); + let uneval = mir::UnevaluatedConst::new(def_id, substs); let literal = ConstantKind::Unevaluated(uneval, ty); Constant { user_ty: None, span, literal } diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index fb775766c65..7ec57add66b 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -557,6 +557,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | ExprKind::ConstBlock { .. } | ExprKind::StaticRef { .. } | ExprKind::InlineAsm { .. } + | ExprKind::OffsetOf { .. } | ExprKind::Yield { .. } | ExprKind::ThreadLocalRef(_) | ExprKind::Call { .. } => { diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 8631749a524..fbde0b28f54 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -481,6 +481,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { })))) } + ExprKind::OffsetOf { container, fields } => { + block.and(Rvalue::NullaryOp(NullOp::OffsetOf(fields), container)) + } + ExprKind::Literal { .. } | ExprKind::NamedConst { .. } | ExprKind::NonHirLiteral { .. } diff --git a/compiler/rustc_mir_build/src/build/expr/category.rs b/compiler/rustc_mir_build/src/build/expr/category.rs index d33401f0764..d9aa461c19d 100644 --- a/compiler/rustc_mir_build/src/build/expr/category.rs +++ b/compiler/rustc_mir_build/src/build/expr/category.rs @@ -67,7 +67,8 @@ impl Category { | ExprKind::Repeat { .. } | ExprKind::Assign { .. } | ExprKind::AssignOp { .. } - | ExprKind::ThreadLocalRef(_) => Some(Category::Rvalue(RvalueFunc::AsRvalue)), + | ExprKind::ThreadLocalRef(_) + | ExprKind::OffsetOf { .. } => Some(Category::Rvalue(RvalueFunc::AsRvalue)), ExprKind::ConstBlock { .. } | ExprKind::Literal { .. } diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 05a723a6b67..29ff916d2cc 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -163,13 +163,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // // [block: If(lhs)] -true-> [else_block: dest = (rhs)] // | (false) - // [shortcurcuit_block: dest = false] + // [shortcircuit_block: dest = false] // // Or: // // [block: If(lhs)] -false-> [else_block: dest = (rhs)] // | (true) - // [shortcurcuit_block: dest = true] + // [shortcircuit_block: dest = true] let (shortcircuit_block, mut else_block, join_block) = ( this.cfg.start_new_block(), @@ -561,7 +561,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | ExprKind::ZstLiteral { .. } | ExprKind::ConstParam { .. } | ExprKind::ThreadLocalRef(_) - | ExprKind::StaticRef { .. } => { + | ExprKind::StaticRef { .. } + | ExprKind::OffsetOf { .. } => { debug_assert!(match Category::of(&expr.kind).unwrap() { // should be handled above Category::Rvalue(RvalueFunc::Into) => false, diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 8a03ea7e2cc..4536ecf17b8 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -77,7 +77,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | PatKind::Wild | PatKind::Binding { .. } | PatKind::Leaf { .. } - | PatKind::Deref { .. } => self.error_simplifyable(match_pair), + | PatKind::Deref { .. } => self.error_simplifiable(match_pair), } } @@ -173,7 +173,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { debug_assert_ne!( target_blocks[idx.index()], otherwise_block, - "no canididates for tested discriminant: {:?}", + "no candidates for tested discriminant: {:?}", discr, ); Some((discr.val, target_blocks[idx.index()])) @@ -181,7 +181,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { debug_assert_eq!( target_blocks[idx.index()], otherwise_block, - "found canididates for untested discriminant: {:?}", + "found candidates for untested discriminant: {:?}", discr, ); None @@ -499,7 +499,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// However, in some cases, the test may just not be relevant to candidate. /// For example, suppose we are testing whether `foo.x == 22`, but in one /// match arm we have `Foo { x: _, ... }`... in that case, the test for - /// what value `x` has has no particular relevance to this candidate. In + /// the value of `x` has no particular relevance to this candidate. In /// such cases, this function just returns None without doing anything. /// This is used by the overall `match_candidates` algorithm to structure /// the match as a whole. See `match_candidates` for more details. @@ -763,8 +763,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { candidate.match_pairs.extend(consequent_match_pairs); } - fn error_simplifyable<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> ! { - span_bug!(match_pair.pattern.span, "simplifyable pattern found: {:?}", match_pair.pattern) + fn error_simplifiable<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> ! { + span_bug!(match_pair.pattern.span, "simplifiable pattern found: {:?}", match_pair.pattern) } fn const_range_contains( diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index bc50bcbc3d0..b05c3056cba 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -32,38 +32,20 @@ use super::lints; pub(crate) fn mir_built( tcx: TyCtxt<'_>, - def: ty::WithOptConstParam<LocalDefId>, + def: LocalDefId, ) -> &rustc_data_structures::steal::Steal<Body<'_>> { - if let Some(def) = def.try_upgrade(tcx) { - return tcx.mir_built(def); - } - - let mut body = mir_build(tcx, def); - if def.const_param_did.is_some() { - assert!(matches!(body.source.instance, ty::InstanceDef::Item(_))); - body.source = MirSource::from_instance(ty::InstanceDef::Item(def.to_global())); - } - - tcx.alloc_steal_mir(body) + tcx.alloc_steal_mir(mir_build(tcx, def)) } /// Construct the MIR for a given `DefId`. -fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_> { +fn mir_build(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> { // Ensure unsafeck and abstract const building is ran before we steal the THIR. - match def { - ty::WithOptConstParam { did, const_param_did: Some(const_param_did) } => { - tcx.ensure_with_value().thir_check_unsafety_for_const_arg((did, const_param_did)); - tcx.ensure_with_value().thir_abstract_const_of_const_arg((did, const_param_did)); - } - ty::WithOptConstParam { did, const_param_did: None } => { - tcx.ensure_with_value().thir_check_unsafety(did); - tcx.ensure_with_value().thir_abstract_const(did); - tcx.ensure_with_value().check_match(did); - } - } + tcx.ensure_with_value().thir_check_unsafety(def); + tcx.ensure_with_value().thir_abstract_const(def); + tcx.ensure_with_value().check_match(def); let body = match tcx.thir_body(def) { - Err(error_reported) => construct_error(tcx, def.did, error_reported), + Err(error_reported) => construct_error(tcx, def, error_reported), Ok((thir, expr)) => { // We ran all queries that depended on THIR at the beginning // of `mir_build`, so now we can steal it @@ -161,8 +143,7 @@ struct Builder<'a, 'tcx> { thir: &'a Thir<'tcx>, cfg: CFG<'tcx>, - def: ty::WithOptConstParam<LocalDefId>, - def_id: DefId, + def_id: LocalDefId, hir_id: hir::HirId, parent_module: DefId, check_overflow: bool, @@ -428,26 +409,26 @@ macro_rules! unpack { fn construct_fn<'tcx>( tcx: TyCtxt<'tcx>, - fn_def: ty::WithOptConstParam<LocalDefId>, + fn_def: LocalDefId, thir: &Thir<'tcx>, expr: ExprId, fn_sig: ty::FnSig<'tcx>, ) -> Body<'tcx> { - let span = tcx.def_span(fn_def.did); - let fn_id = tcx.hir().local_def_id_to_hir_id(fn_def.did); - let generator_kind = tcx.generator_kind(fn_def.did); + let span = tcx.def_span(fn_def); + let fn_id = tcx.hir().local_def_id_to_hir_id(fn_def); + let generator_kind = tcx.generator_kind(fn_def); // The representation of thir for `-Zunpretty=thir-tree` relies on // the entry expression being the last element of `thir.exprs`. assert_eq!(expr.as_usize(), thir.exprs.len() - 1); // Figure out what primary body this item has. - let body_id = tcx.hir().body_owned_by(fn_def.did); + let body_id = tcx.hir().body_owned_by(fn_def); let span_with_body = tcx.hir().span_with_body(fn_id); let return_ty_span = tcx .hir() .fn_decl_by_hir_id(fn_id) - .unwrap_or_else(|| span_bug!(span, "can't build MIR for {:?}", fn_def.did)) + .unwrap_or_else(|| span_bug!(span, "can't build MIR for {:?}", fn_def)) .output .span(); @@ -457,7 +438,7 @@ fn construct_fn<'tcx>( }; let mut abi = fn_sig.abi; - if let DefKind::Closure = tcx.def_kind(fn_def.did) { + if let DefKind::Closure = tcx.def_kind(fn_def) { // HACK(eddyb) Avoid having RustCall on closures, // as it adds unnecessary (and wrong) auto-tupling. abi = Abi::Rust; @@ -483,7 +464,7 @@ fn construct_fn<'tcx>( { return custom::build_custom_mir( tcx, - fn_def.did.to_def_id(), + fn_def.to_def_id(), fn_id, thir, expr, @@ -547,12 +528,12 @@ fn construct_fn<'tcx>( fn construct_const<'a, 'tcx>( tcx: TyCtxt<'tcx>, - def: ty::WithOptConstParam<LocalDefId>, + def: LocalDefId, thir: &'a Thir<'tcx>, expr: ExprId, const_ty: Ty<'tcx>, ) -> Body<'tcx> { - let hir_id = tcx.hir().local_def_id_to_hir_id(def.did); + let hir_id = tcx.hir().local_def_id_to_hir_id(def); // Figure out what primary body this item has. let (span, const_ty_span) = match tcx.hir().get(hir_id) { @@ -568,10 +549,10 @@ fn construct_const<'a, 'tcx>( .. }) => (*span, ty.span), Node::AnonConst(_) => { - let span = tcx.def_span(def.did); + let span = tcx.def_span(def); (span, span) } - _ => span_bug!(tcx.def_span(def.did), "can't build MIR for {:?}", def.did), + _ => span_bug!(tcx.def_span(def), "can't build MIR for {:?}", def), }; let infcx = tcx.infer_ctxt().build(); @@ -669,7 +650,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn new( thir: &'a Thir<'tcx>, infcx: InferCtxt<'tcx>, - def: ty::WithOptConstParam<LocalDefId>, + def: LocalDefId, hir_id: hir::HirId, span: Span, arg_count: usize, @@ -688,20 +669,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { check_overflow |= tcx.sess.overflow_checks(); // Constants always need overflow checks. check_overflow |= matches!( - tcx.hir().body_owner_kind(def.did), + tcx.hir().body_owner_kind(def), hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) ); let lint_level = LintLevel::Explicit(hir_id); - let param_env = tcx.param_env(def.did); + let param_env = tcx.param_env(def); let mut builder = Builder { thir, tcx, infcx, - region_scope_tree: tcx.region_scope_tree(def.did), + region_scope_tree: tcx.region_scope_tree(def), param_env, - def, - def_id: def.did.to_def_id(), + def_id: def, hir_id, parent_module: tcx.parent_module(hir_id).to_def_id(), check_overflow, @@ -741,7 +721,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } Body::new( - MirSource::item(self.def_id), + MirSource::item(self.def_id.to_def_id()), self.cfg.basic_blocks, self.source_scopes, self.local_decls, @@ -779,7 +759,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let tcx = self.tcx; self.upvars = tcx - .closure_captures(self.def.did) + .closure_captures(self.def_id) .iter() .zip(capture_tys) .enumerate() diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 03a7f2d70fa..0506f2bf238 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -117,10 +117,10 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { } /// Handle closures/generators/inline-consts, which is unsafecked with their parent body. - fn visit_inner_body(&mut self, def: ty::WithOptConstParam<LocalDefId>) { + fn visit_inner_body(&mut self, def: LocalDefId) { if let Ok((inner_thir, expr)) = self.tcx.thir_body(def) { let inner_thir = &inner_thir.borrow(); - let hir_context = self.tcx.hir().local_def_id_to_hir_id(def.did); + let hir_context = self.tcx.hir().local_def_id_to_hir_id(def); let mut inner_visitor = UnsafetyVisitor { thir: inner_thir, hir_context, ..*self }; inner_visitor.visit_expr(&inner_thir[expr]); // Unsafe blocks can be used in the inner body, make sure to take it into account @@ -323,6 +323,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { | ExprKind::Box { .. } | ExprKind::If { .. } | ExprKind::InlineAsm { .. } + | ExprKind::OffsetOf { .. } | ExprKind::LogicalOp { .. } | ExprKind::Use { .. } => { // We don't need to save the old value and restore it @@ -396,18 +397,11 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { movability: _, fake_reads: _, }) => { - let closure_def = if let Some((did, const_param_id)) = - ty::WithOptConstParam::try_lookup(closure_id, self.tcx) - { - ty::WithOptConstParam { did, const_param_did: Some(const_param_id) } - } else { - ty::WithOptConstParam::unknown(closure_id) - }; - self.visit_inner_body(closure_def); + self.visit_inner_body(closure_id); } ExprKind::ConstBlock { did, substs: _ } => { let def_id = did.expect_local(); - self.visit_inner_body(ty::WithOptConstParam::unknown(def_id)); + self.visit_inner_body(def_id); } ExprKind::Field { lhs, .. } => { let lhs = &self.thir[lhs]; @@ -706,14 +700,14 @@ impl UnsafeOpKind { } } -pub fn check_unsafety(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) { +pub fn thir_check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) { // THIR unsafeck is gated under `-Z thir-unsafeck` if !tcx.sess.opts.unstable_opts.thir_unsafeck { return; } // Closures and inline consts are handled by their owner, if it has a body - if tcx.is_typeck_child(def.did.to_def_id()) { + if tcx.is_typeck_child(def.to_def_id()) { return; } @@ -726,7 +720,7 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) { return; } - let hir_id = tcx.hir().local_def_id_to_hir_id(def.did); + let hir_id = tcx.hir().local_def_id_to_hir_id(def); let body_unsafety = tcx.hir().fn_sig_by_hir_id(hir_id).map_or(BodyUnsafety::Safe, |fn_sig| { if fn_sig.header.unsafety == hir::Unsafety::Unsafe { BodyUnsafety::Unsafe(fn_sig.span) @@ -734,7 +728,7 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) { BodyUnsafety::Safe } }); - let body_target_features = &tcx.body_codegen_attrs(def.did.to_def_id()).target_features; + let body_target_features = &tcx.body_codegen_attrs(def.to_def_id()).target_features; let safety_context = if body_unsafety.is_unsafe() { SafetyContext::UnsafeFn } else { SafetyContext::Safe }; let mut visitor = UnsafetyVisitor { @@ -746,23 +740,8 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) { body_target_features, assignment_info: None, in_union_destructure: false, - param_env: tcx.param_env(def.did), + param_env: tcx.param_env(def), inside_adt: false, }; visitor.visit_expr(&thir[expr]); } - -pub(crate) fn thir_check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) { - if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) { - tcx.thir_check_unsafety_for_const_arg(def) - } else { - check_unsafety(tcx, ty::WithOptConstParam::unknown(def_id)) - } -} - -pub(crate) fn thir_check_unsafety_for_const_arg( - tcx: TyCtxt<'_>, - (did, param_did): (LocalDefId, DefId), -) { - check_unsafety(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) }) -} diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 43e787db41a..dcdeaf008d6 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -384,13 +384,8 @@ impl<'a> IntoDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> { diag.span_note(span, fluent::mir_build_def_note); } - let is_variant_list_non_exhaustive = match self.ty.kind() { - ty::Adt(def, _) if def.is_variant_list_non_exhaustive() && !def.did().is_local() => { - true - } - _ => false, - }; - + let is_variant_list_non_exhaustive = matches!(self.ty.kind(), + ty::Adt(def, _) if def.is_variant_list_non_exhaustive() && !def.did().is_local()); if is_variant_list_non_exhaustive { diag.note(fluent::mir_build_non_exhaustive_type_note); } else { diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index 3f9236c9dd9..2765a107cf0 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -25,7 +25,7 @@ pub mod thir; use rustc_middle::ty::query::Providers; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; -use rustc_macros::fluent_messages; +use rustc_fluent_macro::fluent_messages; fluent_messages! { "../messages.ftl" } @@ -35,7 +35,6 @@ pub fn provide(providers: &mut Providers) { providers.lit_to_mir_constant = build::lit_to_mir_constant; providers.mir_built = build::mir_built; providers.thir_check_unsafety = check_unsafety::thir_check_unsafety; - providers.thir_check_unsafety_for_const_arg = check_unsafety::thir_check_unsafety_for_const_arg; providers.thir_body = thir::cx::thir_body; providers.thir_tree = thir::print::thir_tree; providers.thir_flat = thir::print::thir_flat; diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 8e2e92e6f6a..ce13d522aae 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -664,6 +664,14 @@ impl<'tcx> Cx<'tcx> { line_spans: asm.line_spans, })), + hir::ExprKind::OffsetOf(_, _) => { + let data = self.typeck_results.offset_of_data(); + let &(container, ref indices) = data.get(expr.hir_id).unwrap(); + let fields = tcx.mk_fields_from_iter(indices.iter().copied()); + + ExprKind::OffsetOf { container, fields } + } + hir::ExprKind::ConstBlock(ref anon_const) => { let ty = self.typeck_results().node_type(anon_const.hir_id); let did = anon_const.def_id.to_def_id(); diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index 070544446e3..463f639defe 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -20,25 +20,25 @@ use rustc_span::Span; pub(crate) fn thir_body( tcx: TyCtxt<'_>, - owner_def: ty::WithOptConstParam<LocalDefId>, + owner_def: LocalDefId, ) -> Result<(&Steal<Thir<'_>>, ExprId), ErrorGuaranteed> { let hir = tcx.hir(); - let body = hir.body(hir.body_owned_by(owner_def.did)); + let body = hir.body(hir.body_owned_by(owner_def)); let mut cx = Cx::new(tcx, owner_def); if let Some(reported) = cx.typeck_results.tainted_by_errors { return Err(reported); } let expr = cx.mirror_expr(&body.value); - let owner_id = hir.local_def_id_to_hir_id(owner_def.did); + let owner_id = hir.local_def_id_to_hir_id(owner_def); if let Some(ref fn_decl) = hir.fn_decl_by_hir_id(owner_id) { - let closure_env_param = cx.closure_env_param(owner_def.did, owner_id); + let closure_env_param = cx.closure_env_param(owner_def, owner_id); let explicit_params = cx.explicit_params(owner_id, fn_decl, body); cx.thir.params = closure_env_param.into_iter().chain(explicit_params).collect(); // The resume argument may be missing, in that case we need to provide it here. // It will always be `()` in this case. - if tcx.def_kind(owner_def.did) == DefKind::Generator && body.params.is_empty() { + if tcx.def_kind(owner_def) == DefKind::Generator && body.params.is_empty() { cx.thir.params.push(Param { ty: tcx.mk_unit(), pat: None, @@ -78,13 +78,12 @@ struct Cx<'tcx> { } impl<'tcx> Cx<'tcx> { - fn new(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalDefId>) -> Cx<'tcx> { - let typeck_results = tcx.typeck_opt_const_arg(def); - let did = def.did; + fn new(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Cx<'tcx> { + let typeck_results = tcx.typeck(def); let hir = tcx.hir(); - let hir_id = hir.local_def_id_to_hir_id(did); + let hir_id = hir.local_def_id_to_hir_id(def); - let body_type = if hir.body_owner_kind(did).is_fn_or_closure() { + let body_type = if hir.body_owner_kind(def).is_fn_or_closure() { // fetch the fully liberated fn signature (that is, all bound // types/lifetimes replaced) BodyTy::Fn(typeck_results.liberated_fn_sigs()[hir_id]) @@ -106,11 +105,11 @@ impl<'tcx> Cx<'tcx> { Cx { tcx, thir: Thir::new(body_type), - param_env: tcx.param_env(def.did), - region_scope_tree: tcx.region_scope_tree(def.did), + param_env: tcx.param_env(def), + region_scope_tree: tcx.region_scope_tree(def), typeck_results, rvalue_scopes: &typeck_results.rvalue_scopes, - body_owner: did.to_def_id(), + body_owner: def.to_def_id(), adjustment_span: None, apply_adjustments: hir .attrs(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 bac46db2b1e..2b52d70af2a 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -27,7 +27,7 @@ use rustc_span::hygiene::DesugaringKind; use rustc_span::Span; pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) { - let Ok((thir, expr)) = tcx.thir_body(ty::WithOptConstParam::unknown(def_id)) else { return }; + let Ok((thir, expr)) = tcx.thir_body(def_id) else { return }; let thir = thir.borrow(); let pattern_arena = TypedArena::default(); let mut visitor = MatchVisitor { @@ -671,10 +671,8 @@ fn non_exhaustive_match<'p, 'tcx>( }; }; - let is_variant_list_non_exhaustive = match scrut_ty.kind() { - ty::Adt(def, _) if def.is_variant_list_non_exhaustive() && !def.did().is_local() => true, - _ => false, - }; + let is_variant_list_non_exhaustive = matches!(scrut_ty.kind(), + ty::Adt(def, _) if def.is_variant_list_non_exhaustive() && !def.did().is_local()); adt_defined_here(cx, &mut err, scrut_ty, &witnesses); err.note(&format!( 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 32d0404bd07..c99fc73fe8a 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 @@ -156,7 +156,7 @@ impl<'tcx> ConstToPat<'tcx> { if let Some(non_sm_ty) = structural { if !self.type_may_have_partial_eq_impl(cv.ty()) { - // fatal avoids ICE from resolution of non-existent method (rare case). + // fatal avoids ICE from resolution of nonexistent method (rare case). self.tcx() .sess .emit_fatal(TypeNotStructural { span: self.span, non_sm_ty: non_sm_ty }); diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index ed61d6ee78b..b2f2a64e29c 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -3,7 +3,7 @@ use rustc_middle::ty::{self, TyCtxt}; use rustc_span::def_id::LocalDefId; use std::fmt::{self, Write}; -pub(crate) fn thir_tree(tcx: TyCtxt<'_>, owner_def: ty::WithOptConstParam<LocalDefId>) -> String { +pub(crate) fn thir_tree(tcx: TyCtxt<'_>, owner_def: LocalDefId) -> String { match super::cx::thir_body(tcx, owner_def) { Ok((thir, _)) => { let thir = thir.steal(); @@ -15,7 +15,7 @@ pub(crate) fn thir_tree(tcx: TyCtxt<'_>, owner_def: ty::WithOptConstParam<LocalD } } -pub(crate) fn thir_flat(tcx: TyCtxt<'_>, owner_def: ty::WithOptConstParam<LocalDefId>) -> String { +pub(crate) fn thir_flat(tcx: TyCtxt<'_>, owner_def: LocalDefId) -> String { match super::cx::thir_body(tcx, owner_def) { Ok((thir, _)) => format!("{:#?}", thir.steal()), Err(_) => "error".into(), @@ -519,6 +519,19 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { self.print_inline_asm_expr(&**expr, depth_lvl + 2); print_indented!(self, "}", depth_lvl); } + OffsetOf { container, fields } => { + print_indented!(self, "OffsetOf {", depth_lvl); + print_indented!(self, format!("container: {:?}", container), depth_lvl + 1); + print_indented!(self, "fields: [", depth_lvl + 1); + + for field in fields.iter() { + print_indented!(self, format!("{:?}", field), depth_lvl + 2); + print_indented!(self, ",", depth_lvl + 1); + } + + print_indented!(self, "]", depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } ThreadLocalRef(def_id) => { print_indented!(self, "ThreadLocalRef {", depth_lvl); print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1); diff --git a/compiler/rustc_mir_dataflow/Cargo.toml b/compiler/rustc_mir_dataflow/Cargo.toml index 68c61a18d72..4a296bb3367 100644 --- a/compiler/rustc_mir_dataflow/Cargo.toml +++ b/compiler/rustc_mir_dataflow/Cargo.toml @@ -13,6 +13,7 @@ tracing = "0.1" rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_graphviz = { path = "../rustc_graphviz" } rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index 43caa2ea973..fc4efb943e6 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -16,8 +16,8 @@ extern crate rustc_middle; use rustc_ast::MetaItem; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; +use rustc_fluent_macro::fluent_messages; use rustc_hir::def_id::DefId; -use rustc_macros::fluent_messages; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::symbol::{sym, Symbol}; diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index 64ed7a29f6f..736ca62cacc 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -360,7 +360,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { | Rvalue::AddressOf(..) | Rvalue::Discriminant(..) | Rvalue::Len(..) - | Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {} + | Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {} } } diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 98bebc9b13b..d8fd06eab86 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -366,7 +366,7 @@ where rustc_index::newtype_index!( /// This index uniquely identifies a place. /// - /// Not every place has a `PlaceIndex`, and not every `PlaceIndex` correspondends to a tracked + /// Not every place has a `PlaceIndex`, and not every `PlaceIndex` corresponds to a tracked /// place. However, every tracked place and all places along its projection have a `PlaceIndex`. pub struct PlaceIndex {} ); 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 896fcd9cdd6..b29ffcc70f9 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 @@ -10,7 +10,7 @@ use rustc_middle::mir::patch::MirPatch; /// they are dropped from an aligned address. /// /// For example, if we have something like -/// ```ignore (ilustrative) +/// ```ignore (illustrative) /// #[repr(packed)] /// struct Foo { /// dealign: u8, @@ -25,7 +25,7 @@ use rustc_middle::mir::patch::MirPatch; /// its address is not aligned. /// /// Instead, we move `foo.data` to a local and drop that: -/// ```ignore (ilustrative) +/// ```ignore (illustrative) /// storage.live(drop_temp) /// drop_temp = foo.data; /// drop(drop_temp) -> next diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs index 916f2904dda..187d38b385b 100644 --- a/compiler/rustc_mir_transform/src/add_retag.rs +++ b/compiler/rustc_mir_transform/src/add_retag.rs @@ -59,7 +59,7 @@ impl<'tcx> MirPass<'tcx> for AddRetag { let basic_blocks = body.basic_blocks.as_mut(); let local_decls = &body.local_decls; let needs_retag = |place: &Place<'tcx>| { - !place.has_deref() // we're not eally interested in stores to "outside" locations, they are hard to keep track of anyway + !place.has_deref() // we're not really interested in stores to "outside" locations, they are hard to keep track of anyway && may_contain_reference(place.ty(&*local_decls, tcx).ty, /*depth*/ 3, tcx) && !local_decls[place.local].is_deref_temp() }; diff --git a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs index 3d32c586554..57b24c9c552 100644 --- a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs +++ b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs @@ -134,7 +134,12 @@ impl<'tcx> Visitor<'tcx> for ConstMutationChecker<'_, 'tcx> { // the `self` parameter of a method call (as the terminator of our current // BasicBlock). If so, we emit a more specific lint. let method_did = self.target_local.and_then(|target_local| { - crate::util::find_self_call(self.tcx, &self.body, target_local, loc.block) + rustc_middle::util::find_self_call( + self.tcx, + &self.body, + target_local, + loc.block, + ) }); let lint_loc = if method_did.is_some() { self.body.terminator_loc(loc.block) } else { loc }; diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index d908f6b3a9b..ce6d865a7dc 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -148,7 +148,7 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> { if let Some(uv) = maybe_uneval { if uv.promoted.is_none() { - let def_id = uv.def.def_id_for_type_of(); + let def_id = uv.def; if self.tcx.def_kind(def_id) == DefKind::InlineConst { let local_def_id = def_id.expect_local(); let UnsafetyCheckResult { violations, used_unsafe_blocks, .. } = @@ -375,22 +375,7 @@ impl<'tcx> UnsafetyChecker<'_, 'tcx> { } pub(crate) fn provide(providers: &mut Providers) { - *providers = Providers { - unsafety_check_result: |tcx, def_id| { - if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) { - tcx.unsafety_check_result_for_const_arg(def) - } else { - unsafety_check_result(tcx, ty::WithOptConstParam::unknown(def_id)) - } - }, - unsafety_check_result_for_const_arg: |tcx, (did, param_did)| { - unsafety_check_result( - tcx, - ty::WithOptConstParam { did, const_param_did: Some(param_did) }, - ) - }, - ..*providers - }; + *providers = Providers { unsafety_check_result, ..*providers }; } /// Context information for [`UnusedUnsafeVisitor`] traversal, @@ -492,10 +477,7 @@ fn check_unused_unsafe( unused_unsafes } -fn unsafety_check_result( - tcx: TyCtxt<'_>, - def: ty::WithOptConstParam<LocalDefId>, -) -> &UnsafetyCheckResult { +fn unsafety_check_result(tcx: TyCtxt<'_>, def: LocalDefId) -> &UnsafetyCheckResult { debug!("unsafety_violations({:?})", def); // N.B., this borrow is valid because all the consumers of @@ -510,13 +492,13 @@ fn unsafety_check_result( }); } - let param_env = tcx.param_env(def.did); + let param_env = tcx.param_env(def); - let mut checker = UnsafetyChecker::new(body, def.did, tcx, param_env); + let mut checker = UnsafetyChecker::new(body, def, tcx, param_env); checker.visit_body(&body); - let unused_unsafes = (!tcx.is_typeck_child(def.did.to_def_id())) - .then(|| check_unused_unsafe(tcx, def.did, &checker.used_unsafe_blocks)); + let unused_unsafes = (!tcx.is_typeck_child(def.to_def_id())) + .then(|| check_unused_unsafe(tcx, def, &checker.used_unsafe_blocks)); tcx.arena.alloc(UnsafetyCheckResult { violations: checker.violations, diff --git a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs index 0923824db48..d435d3ee69b 100644 --- a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs +++ b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs @@ -24,7 +24,6 @@ impl<'tcx> MirPass<'tcx> for CleanupPostBorrowck { for statement in basic_block.statements.iter_mut() { match statement.kind { StatementKind::AscribeUserType(..) - | StatementKind::PlaceMention(..) | StatementKind::Assign(box (_, Rvalue::Ref(_, BorrowKind::Shallow, _))) | StatementKind::FakeRead(..) => statement.make_nop(), _ => (), diff --git a/compiler/rustc_mir_transform/src/const_debuginfo.rs b/compiler/rustc_mir_transform/src/const_debuginfo.rs index 6f0ae4f07ab..692b3182f7d 100644 --- a/compiler/rustc_mir_transform/src/const_debuginfo.rs +++ b/compiler/rustc_mir_transform/src/const_debuginfo.rs @@ -22,7 +22,7 @@ impl<'tcx> MirPass<'tcx> for ConstDebugInfo { fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { trace!("running ConstDebugInfo on {:?}", body.source); - for (local, constant) in find_optimization_oportunities(body) { + for (local, constant) in find_optimization_opportunities(body) { for debuginfo in &mut body.var_debug_info { if let VarDebugInfoContents::Place(p) = debuginfo.value { if p.local == local && p.projection.is_empty() { @@ -45,7 +45,7 @@ struct LocalUseVisitor { local_assignment_locations: IndexVec<Local, Option<Location>>, } -fn find_optimization_oportunities<'tcx>(body: &Body<'tcx>) -> Vec<(Local, Constant<'tcx>)> { +fn find_optimization_opportunities<'tcx>(body: &Body<'tcx>) -> Vec<(Local, Constant<'tcx>)> { let mut visitor = LocalUseVisitor { local_mutating_uses: IndexVec::from_elem(0, &body.local_decls), local_assignment_locations: IndexVec::from_elem(None, &body.local_decls), diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index c0146e3efb0..c9537f9a61c 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -826,7 +826,7 @@ impl Visitor<'_> for CanConstProp { | NonMutatingUse(NonMutatingUseContext::AddressOf) | MutatingUse(MutatingUseContext::Borrow) | MutatingUse(MutatingUseContext::AddressOf) => { - trace!("local {:?} can't be propagaged because it's used: {:?}", local, context); + trace!("local {:?} can't be propagated because it's used: {:?}", local, context); self.can_const_prop[local] = ConstPropMode::NoPropagation; } } diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index 699fe44892b..3a105a2abae 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -493,7 +493,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { cond: &Operand<'tcx>, location: Location, ) -> Option<!> { - let ref value = self.eval_operand(&cond, location)?; + let value = &self.eval_operand(&cond, location)?; trace!("assertion on {:?} should be {:?}", value, expected); let expected = Scalar::from_bool(expected); diff --git a/compiler/rustc_mir_transform/src/coverage/debug.rs b/compiler/rustc_mir_transform/src/coverage/debug.rs index 725883b83fa..e554c470646 100644 --- a/compiler/rustc_mir_transform/src/coverage/debug.rs +++ b/compiler/rustc_mir_transform/src/coverage/debug.rs @@ -292,10 +292,8 @@ impl DebugCounters { } pub fn some_block_label(&self, operand: ExpressionOperandId) -> Option<&String> { - self.some_counters.as_ref().map_or(None, |counters| { - counters - .get(&operand) - .map_or(None, |debug_counter| debug_counter.some_block_label.as_ref()) + self.some_counters.as_ref().and_then(|counters| { + counters.get(&operand).and_then(|debug_counter| debug_counter.some_block_label.as_ref()) }) } diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index 7391a77b0a6..8ff67b5f8d3 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -111,7 +111,7 @@ impl CoverageGraph { if predecessors.len() > 1 { "predecessors.len() > 1".to_owned() } else { - format!("bb {} is not in precessors: {:?}", bb.index(), predecessors) + format!("bb {} is not in predecessors: {:?}", bb.index(), predecessors) } ); } diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 5ecb2d6a631..444b1565d36 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -577,5 +577,10 @@ fn get_body_span<'tcx>( fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx rustc_hir::Body<'tcx>) -> u64 { // FIXME(cjgillot) Stop hashing HIR manually here. let owner = hir_body.id().hir_id.owner; - tcx.hir_owner_nodes(owner).unwrap().opt_hash_including_bodies.unwrap().to_smaller_hash() + tcx.hir_owner_nodes(owner) + .unwrap() + .opt_hash_including_bodies + .unwrap() + .to_smaller_hash() + .as_u64() } diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs index 3bd7f31b45d..bf01b45eb40 100644 --- a/compiler/rustc_mir_transform/src/coverage/query.rs +++ b/compiler/rustc_mir_transform/src/coverage/query.rs @@ -164,7 +164,6 @@ fn is_inlined(body: &Body<'_>, statement: &Statement<'_>) -> bool { /// whether that means const mir or runtime mir. For `const fn` this opts for runtime /// mir. fn mir_body(tcx: TyCtxt<'_>, def_id: DefId) -> &mir::Body<'_> { - let id = ty::WithOptConstParam::unknown(def_id); - let def = ty::InstanceDef::Item(id); + let def = ty::InstanceDef::Item(def_id); tcx.instance_mir(def) } diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index d4db7e2de40..a56c5cc5c12 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -351,7 +351,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { } (FlatSet::Bottom, _) | (_, FlatSet::Bottom) => (FlatSet::Bottom, FlatSet::Bottom), (_, _) => { - // Could attempt some algebraic simplifcations here. + // Could attempt some algebraic simplifications here. (FlatSet::Top, FlatSet::Top) } } diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs index 18c407b42d3..7bc5183a00a 100644 --- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs +++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs @@ -54,11 +54,10 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS | StatementKind::Coverage(_) | StatementKind::Intrinsic(_) | StatementKind::ConstEvalCounter + | StatementKind::PlaceMention(_) | StatementKind::Nop => (), - StatementKind::FakeRead(_) - | StatementKind::PlaceMention(_) - | StatementKind::AscribeUserType(_, _) => { + StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => { bug!("{:?} not found in this MIR phase!", &statement.kind) } } diff --git a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs index e5c3fa5646a..8ee08c5be34 100644 --- a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs +++ b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs @@ -9,7 +9,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_index::bit_set::BitSet; use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::{Body, Local, Location, Operand, Terminator, TerminatorKind, RETURN_PLACE}; -use rustc_middle::ty::{self, DeducedParamAttrs, ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::{self, DeducedParamAttrs, Ty, TyCtxt}; use rustc_session::config::OptLevel; /// A visitor that determines which arguments have been mutated. We can't use the mutability field @@ -198,11 +198,12 @@ pub fn deduced_param_attrs<'tcx>( // see [1]. // // [1]: https://github.com/rust-lang/rust/pull/103172#discussion_r999139997 + let param_env = tcx.param_env_reveal_all_normalized(def_id); let mut deduced_param_attrs = tcx.arena.alloc_from_iter( body.local_decls.iter().skip(1).take(body.arg_count).enumerate().map( |(arg_index, local_decl)| DeducedParamAttrs { read_only: !deduce_read_only.mutable_args.contains(arg_index) - && local_decl.ty.is_freeze(tcx, ParamEnv::reveal_all()), + && local_decl.ty.is_freeze(tcx, param_env), }, ), ); diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index 39164917770..78758e2db28 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -69,7 +69,7 @@ //! of this is that such liveness analysis can report more accurate results about whole locals at //! a time. For example, consider: //! -//! ```ignore (syntax-highliting-only) +//! ```ignore (syntax-highlighting-only) //! _1 = u; //! // unrelated code //! _1.f1 = v; @@ -360,7 +360,7 @@ struct FilterInformation<'a, 'body, 'alloc, 'tcx> { } // We first implement some utility functions which we will expose removing candidates according to -// different needs. Throughout the livenss filtering, the `candidates` are only ever accessed +// different needs. Throughout the liveness filtering, the `candidates` are only ever accessed // through these methods, and not directly. impl<'alloc> Candidates<'alloc> { /// Just `Vec::retain`, but the condition is inverted and we add debugging output @@ -582,10 +582,9 @@ impl WriteInfo { | StatementKind::Nop | StatementKind::Coverage(_) | StatementKind::StorageLive(_) - | StatementKind::StorageDead(_) => (), - StatementKind::FakeRead(_) - | StatementKind::AscribeUserType(_, _) - | StatementKind::PlaceMention(_) => { + | StatementKind::StorageDead(_) + | StatementKind::PlaceMention(_) => (), + StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => { bug!("{:?} not found in this MIR phase", statement) } } diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index a702113bd99..1e115be2c2a 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -24,7 +24,7 @@ use std::fmt; /// In general, the compiler cannot determine at compile time whether a destructor will run or not. /// /// At a high level, this pass refines Drop to only run the destructor if the -/// target is initialized. The way this is achievied is by inserting drop flags for every variable +/// target is initialized. The way this is achieved is by inserting drop flags for every variable /// that may be dropped, and then using those flags to determine whether a destructor should run. /// Once this is complete, Drop terminators in the MIR correspond to a call to the "drop glue" or /// "drop shim" for the type of the dropped place. diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs index c9b24adba0c..db68adc8bc9 100644 --- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs +++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs @@ -48,7 +48,7 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool { return false; } - let body = &*tcx.mir_built(ty::WithOptConstParam::unknown(local_def_id)).borrow(); + let body = &*tcx.mir_built(local_def_id).borrow(); let body_ty = tcx.type_of(def_id).skip_binder(); let body_abi = match body_ty.kind() { diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs index 8601c1b2d71..f26c6de9648 100644 --- a/compiler/rustc_mir_transform/src/function_item_references.rs +++ b/compiler/rustc_mir_transform/src/function_item_references.rs @@ -3,7 +3,7 @@ use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; -use rustc_middle::ty::{self, EarlyBinder, GenericArgKind, PredicateKind, SubstsRef, Ty, TyCtxt}; +use rustc_middle::ty::{self, EarlyBinder, PredicateKind, SubstsRef, Ty, TyCtxt}; use rustc_session::lint::builtin::FUNCTION_ITEM_REFERENCES; use rustc_span::{symbol::sym, Span}; use rustc_target::spec::abi::Abi; @@ -45,14 +45,12 @@ impl<'tcx> Visitor<'tcx> for FunctionItemRefChecker<'_, 'tcx> { // Handle calls to `transmute` if self.tcx.is_diagnostic_item(sym::transmute, def_id) { let arg_ty = args[0].ty(self.body, self.tcx); - for generic_inner_ty in arg_ty.walk() { - if let GenericArgKind::Type(inner_ty) = generic_inner_ty.unpack() { - if let Some((fn_id, fn_substs)) = - FunctionItemRefChecker::is_fn_ref(inner_ty) - { - let span = self.nth_arg_span(&args, 0); - self.emit_lint(fn_id, fn_substs, source_info, span); - } + for inner_ty in arg_ty.walk().filter_map(|arg| arg.as_type()) { + if let Some((fn_id, fn_substs)) = + FunctionItemRefChecker::is_fn_ref(inner_ty) + { + let span = self.nth_arg_span(&args, 0); + self.emit_lint(fn_id, fn_substs, source_info, span); } } } else { @@ -82,24 +80,22 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> { let arg_defs = self.tcx.fn_sig(def_id).subst_identity().skip_binder().inputs(); for (arg_num, arg_def) in arg_defs.iter().enumerate() { // For all types reachable from the argument type in the fn sig - for generic_inner_ty in arg_def.walk() { - if let GenericArgKind::Type(inner_ty) = generic_inner_ty.unpack() { - // If the inner type matches the type bound by `Pointer` - if inner_ty == bound_ty { - // Do a substitution using the parameters from the callsite - let subst_ty = EarlyBinder(inner_ty).subst(self.tcx, substs_ref); - if let Some((fn_id, fn_substs)) = - FunctionItemRefChecker::is_fn_ref(subst_ty) - { - let mut span = self.nth_arg_span(args, arg_num); - if span.from_expansion() { - // The operand's ctxt wouldn't display the lint since it's inside a macro so - // we have to use the callsite's ctxt. - let callsite_ctxt = span.source_callsite().ctxt(); - span = span.with_ctxt(callsite_ctxt); - } - self.emit_lint(fn_id, fn_substs, source_info, span); + for inner_ty in arg_def.walk().filter_map(|arg| arg.as_type()) { + // If the inner type matches the type bound by `Pointer` + if inner_ty == bound_ty { + // Do a substitution using the parameters from the callsite + let subst_ty = EarlyBinder(inner_ty).subst(self.tcx, substs_ref); + if let Some((fn_id, fn_substs)) = + FunctionItemRefChecker::is_fn_ref(subst_ty) + { + let mut span = self.nth_arg_span(args, arg_num); + if span.from_expansion() { + // The operand's ctxt wouldn't display the lint since it's inside a macro so + // we have to use the callsite's ctxt. + let callsite_ctxt = span.source_callsite().ctxt(); + span = span.with_ctxt(callsite_ctxt); } + self.emit_lint(fn_id, fn_substs, source_info, span); } } } diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index 4c4423721fb..5b3a66bc3d2 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -1399,7 +1399,7 @@ pub(crate) fn mir_generator_witnesses<'tcx>( ) -> GeneratorLayout<'tcx> { assert!(tcx.sess.opts.unstable_opts.drop_tracking_mir); - let (body, _) = tcx.mir_promoted(ty::WithOptConstParam::unknown(def_id)); + let (body, _) = tcx.mir_promoted(def_id); let body = body.borrow(); let body = &*body; @@ -1869,7 +1869,7 @@ fn check_must_not_suspend_ty<'tcx>( }, ) } - // If drop tracking is enabled, we want to look through references, since the referrent + // If drop tracking is enabled, we want to look through references, since the referent // may not be considered live across the await point. ty::Ref(_region, ty, _mutability) => { let descr_pre = &format!("{}reference{} to ", data.descr_pre, plural_suffix); diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index f0cb317f449..1525933aee3 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -350,14 +350,8 @@ impl<'tcx> Inliner<'tcx> { callsite: &CallSite<'tcx>, callee_attrs: &CodegenFnAttrs, ) -> Result<(), &'static str> { - match callee_attrs.inline { - InlineAttr::Never => return Err("never inline hint"), - InlineAttr::Always | InlineAttr::Hint => {} - InlineAttr::None => { - if self.tcx.sess.mir_opt_level() <= 2 { - return Err("at mir-opt-level=2, only #[inline] is inlined"); - } - } + if let InlineAttr::Never = callee_attrs.inline { + return Err("never inline hint"); } // Only inline local functions if they would be eligible for cross-crate diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index 8aa3c23d019..8b811d7e870 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -148,8 +148,7 @@ pub(crate) fn mir_inliner_callees<'tcx>( let guard; let body = match (instance, instance.def_id().as_local()) { (InstanceDef::Item(_), Some(def_id)) => { - let def = ty::WithOptConstParam::unknown(def_id); - steal = tcx.mir_promoted(def).0; + steal = tcx.mir_promoted(def_id).0; guard = steal.borrow(); &*guard } diff --git a/compiler/rustc_mir_transform/src/instcombine.rs b/compiler/rustc_mir_transform/src/instcombine.rs index 3d06a0a495f..432852a1fdd 100644 --- a/compiler/rustc_mir_transform/src/instcombine.rs +++ b/compiler/rustc_mir_transform/src/instcombine.rs @@ -1,11 +1,9 @@ //! Performs various peephole optimizations. +use crate::simplify::combine_duplicate_switch_targets; use crate::MirPass; use rustc_hir::Mutability; -use rustc_middle::mir::{ - BinOp, Body, CastKind, Constant, ConstantKind, LocalDecls, Operand, Place, ProjectionElem, - Rvalue, SourceInfo, Statement, StatementKind, SwitchTargets, Terminator, TerminatorKind, UnOp, -}; +use rustc_middle::mir::*; use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, ParamEnv, SubstsRef, Ty, TyCtxt}; @@ -46,7 +44,7 @@ impl<'tcx> MirPass<'tcx> for InstCombine { &mut block.terminator.as_mut().unwrap(), &mut block.statements, ); - ctx.combine_duplicate_switch_targets(&mut block.terminator.as_mut().unwrap()); + combine_duplicate_switch_targets(block.terminator.as_mut().unwrap()); } } } @@ -264,19 +262,6 @@ impl<'tcx> InstCombineContext<'tcx, '_> { terminator.kind = TerminatorKind::Goto { target: destination_block }; } - fn combine_duplicate_switch_targets(&self, terminator: &mut Terminator<'tcx>) { - let TerminatorKind::SwitchInt { targets, .. } = &mut terminator.kind - else { return }; - - let otherwise = targets.otherwise(); - if targets.iter().any(|t| t.1 == otherwise) { - *targets = SwitchTargets::new( - targets.iter().filter(|t| t.1 != otherwise), - targets.otherwise(), - ); - } - } - fn combine_intrinsic_assert( &self, terminator: &mut Terminator<'tcx>, diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index fc12d423cb0..6d8b4dc91f4 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -23,7 +23,7 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::steal::Steal; use rustc_hir as hir; use rustc_hir::def::DefKind; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_index::vec::IndexVec; use rustc_middle::mir::visit::Visitor as _; @@ -48,6 +48,7 @@ mod add_retag; mod check_const_item_mutation; mod check_packed_ref; pub mod check_unsafety; +mod remove_place_mention; // This pass is public to allow external drivers to perform MIR cleanup pub mod cleanup_post_borrowck; mod const_debuginfo; @@ -111,36 +112,17 @@ pub fn provide(providers: &mut Providers) { *providers = Providers { mir_keys, mir_const, - mir_const_qualif: |tcx, def_id| { - if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) { - tcx.mir_const_qualif_const_arg(def) - } else { - mir_const_qualif(tcx, ty::WithOptConstParam::unknown(def_id)) - } - }, - mir_const_qualif_const_arg: |tcx, (did, param_did)| { - mir_const_qualif(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) }) - }, + mir_const_qualif, mir_promoted, mir_drops_elaborated_and_const_checked, mir_for_ctfe, - mir_for_ctfe_of_const_arg, mir_generator_witnesses: generator::mir_generator_witnesses, optimized_mir, is_mir_available, is_ctfe_mir_available: |tcx, did| is_mir_available(tcx, did), mir_callgraph_reachable: inline::cycle::mir_callgraph_reachable, mir_inliner_callees: inline::cycle::mir_inliner_callees, - promoted_mir: |tcx, def_id| { - if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) { - tcx.promoted_mir_of_const_arg(def) - } else { - promoted_mir(tcx, ty::WithOptConstParam::unknown(def_id)) - } - }, - promoted_mir_of_const_arg: |tcx, (did, param_did)| { - promoted_mir(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) }) - }, + promoted_mir, deduced_param_attrs: deduce_param_attrs::deduced_param_attrs, ..*providers }; @@ -234,8 +216,8 @@ fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LocalDefId> { set } -fn mir_const_qualif(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> ConstQualifs { - let const_kind = tcx.hir().body_const_context(def.did); +fn mir_const_qualif(tcx: TyCtxt<'_>, def: LocalDefId) -> ConstQualifs { + let const_kind = tcx.hir().body_const_context(def); // No need to const-check a non-const `fn`. if const_kind.is_none() { @@ -253,7 +235,7 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> return Default::default(); } - let ccx = check_consts::ConstCx { body, tcx, const_kind, param_env: tcx.param_env(def.did) }; + let ccx = check_consts::ConstCx { body, tcx, const_kind, param_env: tcx.param_env(def) }; let mut validator = check_consts::check::Checker::new(&ccx); validator.check_body(); @@ -266,22 +248,14 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> /// Make MIR ready for const evaluation. This is run on all MIR, not just on consts! /// FIXME(oli-obk): it's unclear whether we still need this phase (and its corresponding query). /// We used to have this for pre-miri MIR based const eval. -fn mir_const(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> &Steal<Body<'_>> { - if let Some(def) = def.try_upgrade(tcx) { - return tcx.mir_const(def); - } - +fn mir_const(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> { // Unsafety check uses the raw mir, so make sure it is run. if !tcx.sess.opts.unstable_opts.thir_unsafeck { - if let Some(param_did) = def.const_param_did { - tcx.ensure_with_value().unsafety_check_result_for_const_arg((def.did, param_did)); - } else { - tcx.ensure_with_value().unsafety_check_result(def.did); - } + tcx.ensure_with_value().unsafety_check_result(def); } // has_ffi_unwind_calls query uses the raw mir, so make sure it is run. - tcx.ensure_with_value().has_ffi_unwind_calls(def.did); + tcx.ensure_with_value().has_ffi_unwind_calls(def); let mut body = tcx.mir_built(def).steal(); @@ -296,7 +270,7 @@ fn mir_const(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> &Steal< &Lint(check_const_item_mutation::CheckConstItemMutation), &Lint(function_item_references::FunctionItemReferences), // What we need to do constant evaluation. - &simplify::SimplifyCfg::new("initial"), + &simplify::SimplifyCfg::Initial, &rustc_peek::SanityCheck, // Just a lint ], None, @@ -307,16 +281,12 @@ fn mir_const(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> &Steal< /// Compute the main MIR body and the list of MIR bodies of the promoteds. fn mir_promoted( tcx: TyCtxt<'_>, - def: ty::WithOptConstParam<LocalDefId>, + def: LocalDefId, ) -> (&Steal<Body<'_>>, &Steal<IndexVec<Promoted, Body<'_>>>) { - if let Some(def) = def.try_upgrade(tcx) { - return tcx.mir_promoted(def); - } - // Ensure that we compute the `mir_const_qualif` for constants at // this point, before we steal the mir-const result. // Also this means promotion can rely on all const checks having been done. - let const_qualifs = tcx.mir_const_qualif_opt_const_arg(def); + let const_qualifs = tcx.mir_const_qualif(def); let mut body = tcx.mir_const(def).steal(); if let Some(error_reported) = const_qualifs.tainted_by_errors { body.tainted_by_errors = Some(error_reported); @@ -334,11 +304,7 @@ fn mir_promoted( pm::run_passes( tcx, &mut body, - &[ - &promote_pass, - &simplify::SimplifyCfg::new("promote-consts"), - &coverage::InstrumentCoverage, - ], + &[&promote_pass, &simplify::SimplifyCfg::PromoteConsts, &coverage::InstrumentCoverage], Some(MirPhase::Analysis(AnalysisPhase::Initial)), ); @@ -348,38 +314,22 @@ fn mir_promoted( /// Compute the MIR that is used during CTFE (and thus has no optimizations run on it) fn mir_for_ctfe(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &Body<'_> { - if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) { - tcx.mir_for_ctfe_of_const_arg(def) - } else { - tcx.arena.alloc(inner_mir_for_ctfe(tcx, ty::WithOptConstParam::unknown(def_id))) - } + tcx.arena.alloc(inner_mir_for_ctfe(tcx, def_id)) } -/// Same as `mir_for_ctfe`, but used to get the MIR of a const generic parameter. -/// The docs on `WithOptConstParam` explain this a bit more, but the TLDR is that -/// we'd get cycle errors with `mir_for_ctfe`, because typeck would need to typeck -/// the const parameter while type checking the main body, which in turn would try -/// to type check the main body again. -fn mir_for_ctfe_of_const_arg(tcx: TyCtxt<'_>, (did, param_did): (LocalDefId, DefId)) -> &Body<'_> { - tcx.arena.alloc(inner_mir_for_ctfe( - tcx, - ty::WithOptConstParam { did, const_param_did: Some(param_did) }, - )) -} - -fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_> { +fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> { // FIXME: don't duplicate this between the optimized_mir/mir_for_ctfe queries - if tcx.is_constructor(def.did.to_def_id()) { + if tcx.is_constructor(def.to_def_id()) { // There's no reason to run all of the MIR passes on constructors when // we can just output the MIR we want directly. This also saves const // qualification and borrow checking the trouble of special casing // constructors. - return shim::build_adt_ctor(tcx, def.did.to_def_id()); + return shim::build_adt_ctor(tcx, def.to_def_id()); } let context = tcx .hir() - .body_const_context(def.did) + .body_const_context(def) .expect("mir_for_ctfe should not be used for runtime functions"); let body = tcx.mir_drops_elaborated_and_const_checked(def).borrow().clone(); @@ -417,29 +367,19 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) - /// Obtain just the main MIR (no promoteds) and run some cleanups on it. This also runs /// mir borrowck *before* doing so in order to ensure that borrowck can be run and doesn't /// end up missing the source MIR due to stealing happening. -fn mir_drops_elaborated_and_const_checked( - tcx: TyCtxt<'_>, - def: ty::WithOptConstParam<LocalDefId>, -) -> &Steal<Body<'_>> { - if let Some(def) = def.try_upgrade(tcx) { - return tcx.mir_drops_elaborated_and_const_checked(def); - } - +fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> { if tcx.sess.opts.unstable_opts.drop_tracking_mir - && let DefKind::Generator = tcx.def_kind(def.did) + && let DefKind::Generator = tcx.def_kind(def) { - tcx.ensure_with_value().mir_generator_witnesses(def.did); + tcx.ensure_with_value().mir_generator_witnesses(def); } - let mir_borrowck = tcx.mir_borrowck_opt_const_arg(def); + let mir_borrowck = tcx.mir_borrowck(def); - let is_fn_like = tcx.def_kind(def.did).is_fn_like(); + let is_fn_like = tcx.def_kind(def).is_fn_like(); if is_fn_like { - let did = def.did.to_def_id(); - let def = ty::WithOptConstParam::unknown(did); - // Do not compute the mir call graph without said call graph actually being used. if inline::Inline.is_enabled(&tcx.sess) { - tcx.ensure_with_value().mir_inliner_callees(ty::InstanceDef::Item(def)); + tcx.ensure_with_value().mir_inliner_callees(ty::InstanceDef::Item(def.to_def_id())); } } @@ -467,10 +407,7 @@ fn run_analysis_to_runtime_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx> pm::run_passes( tcx, body, - &[ - &remove_uninit_drops::RemoveUninitDrops, - &simplify::SimplifyCfg::new("remove-false-edges"), - ], + &[&remove_uninit_drops::RemoveUninitDrops, &simplify::SimplifyCfg::RemoveFalseEdges], None, ); check_consts::post_drop_elaboration::check_live_drops(tcx, &body); // FIXME: make this a MIR lint @@ -492,7 +429,7 @@ fn run_analysis_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let passes: &[&dyn MirPass<'tcx>] = &[ &cleanup_post_borrowck::CleanupPostBorrowck, &remove_noop_landing_pads::RemoveNoopLandingPads, - &simplify::SimplifyCfg::new("early-opt"), + &simplify::SimplifyCfg::EarlyOpt, &deref_separator::Derefer, ]; @@ -524,8 +461,11 @@ fn run_runtime_lowering_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { /// Returns the sequence of passes that do the initial cleanup of runtime MIR. fn run_runtime_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let passes: &[&dyn MirPass<'tcx>] = - &[&lower_intrinsics::LowerIntrinsics, &simplify::SimplifyCfg::new("elaborate-drops")]; + let passes: &[&dyn MirPass<'tcx>] = &[ + &lower_intrinsics::LowerIntrinsics, + &remove_place_mention::RemovePlaceMention, + &simplify::SimplifyCfg::ElaborateDrops, + ]; pm::run_passes(tcx, body, passes, Some(MirPhase::Runtime(RuntimePhase::PostCleanup))); @@ -551,7 +491,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &lower_slice_len::LowerSliceLenCalls, // has to be done before inlining, otherwise actual call will be almost always inlined. Also simple, so can just do first &unreachable_prop::UnreachablePropagation, &uninhabited_enum_branching::UninhabitedEnumBranching, - &o1(simplify::SimplifyCfg::new("after-uninhabited-enum-branching")), + &o1(simplify::SimplifyCfg::AfterUninhabitedEnumBranching), &inline::Inline, &remove_storage_markers::RemoveStorageMarkers, &remove_zsts::RemoveZsts, @@ -564,23 +504,23 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &multiple_return_terminators::MultipleReturnTerminators, &instcombine::InstCombine, &separate_const_switch::SeparateConstSwitch, - &simplify::SimplifyLocals::new("before-const-prop"), + &simplify::SimplifyLocals::BeforeConstProp, ©_prop::CopyProp, &const_prop::ConstProp, &dataflow_const_prop::DataflowConstProp, // // Const-prop runs unconditionally, but doesn't mutate the MIR at mir-opt-level=0. &const_debuginfo::ConstDebugInfo, - &o1(simplify_branches::SimplifyConstCondition::new("after-const-prop")), + &o1(simplify_branches::SimplifyConstCondition::AfterConstProp), &early_otherwise_branch::EarlyOtherwiseBranch, &simplify_comparison_integral::SimplifyComparisonIntegral, &dead_store_elimination::DeadStoreElimination, &dest_prop::DestinationPropagation, - &o1(simplify_branches::SimplifyConstCondition::new("final")), + &o1(simplify_branches::SimplifyConstCondition::Final), &o1(remove_noop_landing_pads::RemoveNoopLandingPads), - &o1(simplify::SimplifyCfg::new("final")), + &o1(simplify::SimplifyCfg::Final), &nrvo::RenameReturnPlace, - &simplify::SimplifyLocals::new("final"), + &simplify::SimplifyLocals::Final, &multiple_return_terminators::MultipleReturnTerminators, &deduplicate_blocks::DeduplicateBlocks, &large_enums::EnumSizeOpt { discrepancy: 128 }, @@ -595,7 +535,6 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { /// Optimize the MIR and prepare it for codegen. fn optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> &Body<'_> { - assert_eq!(ty::WithOptConstParam::try_lookup(did, tcx), None); tcx.arena.alloc(inner_optimized_mir(tcx, did)) } @@ -617,8 +556,7 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> { Some(other) => panic!("do not use `optimized_mir` for constants: {:?}", other), } debug!("about to call mir_drops_elaborated..."); - let body = - tcx.mir_drops_elaborated_and_const_checked(ty::WithOptConstParam::unknown(did)).steal(); + let body = tcx.mir_drops_elaborated_and_const_checked(did).steal(); let mut body = remap_mir_for_const_eval_select(tcx, body, hir::Constness::NotConst); debug!("body: {:#?}", body); run_optimization_passes(tcx, &mut body); @@ -628,15 +566,12 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> { /// Fetch all the promoteds of an item and prepare their MIR bodies to be ready for /// constant evaluation once all substitutions become known. -fn promoted_mir( - tcx: TyCtxt<'_>, - def: ty::WithOptConstParam<LocalDefId>, -) -> &IndexVec<Promoted, Body<'_>> { - if tcx.is_constructor(def.did.to_def_id()) { +fn promoted_mir(tcx: TyCtxt<'_>, def: LocalDefId) -> &IndexVec<Promoted, Body<'_>> { + if tcx.is_constructor(def.to_def_id()) { return tcx.arena.alloc(IndexVec::new()); } - let tainted_by_errors = tcx.mir_borrowck_opt_const_arg(def).tainted_by_errors; + let tainted_by_errors = tcx.mir_borrowck(def).tainted_by_errors; let mut promoted = tcx.mir_promoted(def).1.steal(); for body in &mut promoted { diff --git a/compiler/rustc_mir_transform/src/remove_place_mention.rs b/compiler/rustc_mir_transform/src/remove_place_mention.rs new file mode 100644 index 00000000000..8be1c37572d --- /dev/null +++ b/compiler/rustc_mir_transform/src/remove_place_mention.rs @@ -0,0 +1,23 @@ +//! This pass removes `PlaceMention` statement, which has no effect at codegen. + +use crate::MirPass; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; + +pub struct RemovePlaceMention; + +impl<'tcx> MirPass<'tcx> for RemovePlaceMention { + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + !sess.opts.unstable_opts.mir_keep_place_mention + } + + fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + trace!("Running RemovePlaceMention on {:?}", body.source); + for data in body.basic_blocks.as_mut_preserves_cfg() { + data.statements.retain(|statement| match statement.kind { + StatementKind::PlaceMention(..) | StatementKind::Nop => false, + _ => true, + }) + } + } +} diff --git a/compiler/rustc_mir_transform/src/separate_const_switch.rs b/compiler/rustc_mir_transform/src/separate_const_switch.rs index ef367faf6a7..2479856b727 100644 --- a/compiler/rustc_mir_transform/src/separate_const_switch.rs +++ b/compiler/rustc_mir_transform/src/separate_const_switch.rs @@ -303,8 +303,7 @@ fn find_determining_place<'tcx>( | Rvalue::NullaryOp(_, _) | Rvalue::ShallowInitBox(_, _) | Rvalue::UnaryOp(_, Operand::Constant(_)) - | Rvalue::Cast(_, Operand::Constant(_), _) - => return None, + | Rvalue::Cast(_, Operand::Constant(_), _) => return None, } } diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 2787fe2ce42..4396a83e8b8 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -95,7 +95,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' &add_moves_for_packed_drops::AddMovesForPackedDrops, &deref_separator::Derefer, &remove_noop_landing_pads::RemoveNoopLandingPads, - &simplify::SimplifyCfg::new("make_shim"), + &simplify::SimplifyCfg::MakeShim, &add_call_guards::CriticalCallEdges, &abort_unwinding_calls::AbortUnwindingCalls, ], diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index c79e1cf0805..e1ca7c107b9 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -36,13 +36,31 @@ use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; use smallvec::SmallVec; -pub struct SimplifyCfg { - label: String, +pub enum SimplifyCfg { + Initial, + PromoteConsts, + RemoveFalseEdges, + EarlyOpt, + ElaborateDrops, + Final, + MakeShim, + AfterUninhabitedEnumBranching, } impl SimplifyCfg { - pub fn new(label: &str) -> Self { - SimplifyCfg { label: format!("SimplifyCfg-{}", label) } + pub fn name(&self) -> &'static str { + match self { + SimplifyCfg::Initial => "SimplifyCfg-initial", + SimplifyCfg::PromoteConsts => "SimplifyCfg-promote-consts", + SimplifyCfg::RemoveFalseEdges => "SimplifyCfg-remove-false-edges", + SimplifyCfg::EarlyOpt => "SimplifyCfg-early-opt", + SimplifyCfg::ElaborateDrops => "SimplifyCfg-elaborate-drops", + SimplifyCfg::Final => "SimplifyCfg-final", + SimplifyCfg::MakeShim => "SimplifyCfg-make_shim", + SimplifyCfg::AfterUninhabitedEnumBranching => { + "SimplifyCfg-after-uninhabited-enum-branching" + } + } } } @@ -57,11 +75,11 @@ pub fn simplify_cfg<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { impl<'tcx> MirPass<'tcx> for SimplifyCfg { fn name(&self) -> &str { - &self.label + &self.name() } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, body.source); + debug!("SimplifyCfg({:?}) - simplifying {:?}", self.name(), body.source); simplify_cfg(tcx, body); } } @@ -260,6 +278,18 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { } } +pub fn combine_duplicate_switch_targets(terminator: &mut Terminator<'_>) { + if let TerminatorKind::SwitchInt { targets, .. } = &mut terminator.kind { + let otherwise = targets.otherwise(); + if targets.iter().any(|t| t.1 == otherwise) { + *targets = SwitchTargets::new( + targets.iter().filter(|t| t.1 != otherwise), + targets.otherwise(), + ); + } + } +} + pub fn remove_duplicate_unreachable_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { struct OptApplier<'tcx> { tcx: TyCtxt<'tcx>, @@ -280,6 +310,8 @@ pub fn remove_duplicate_unreachable_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut B } } + combine_duplicate_switch_targets(terminator); + self.super_terminator(terminator, location); } } @@ -423,19 +455,17 @@ fn save_unreachable_coverage( )); } -pub struct SimplifyLocals { - label: String, -} - -impl SimplifyLocals { - pub fn new(label: &str) -> SimplifyLocals { - SimplifyLocals { label: format!("SimplifyLocals-{}", label) } - } +pub enum SimplifyLocals { + BeforeConstProp, + Final, } impl<'tcx> MirPass<'tcx> for SimplifyLocals { - fn name(&self) -> &str { - &self.label + fn name(&self) -> &'static str { + match &self { + SimplifyLocals::BeforeConstProp => "SimplifyLocals-before-const-prop", + SimplifyLocals::Final => "SimplifyLocals-final", + } } fn is_enabled(&self, sess: &rustc_session::Session) -> bool { diff --git a/compiler/rustc_mir_transform/src/simplify_branches.rs b/compiler/rustc_mir_transform/src/simplify_branches.rs index 8164b305278..c65a7ec6783 100644 --- a/compiler/rustc_mir_transform/src/simplify_branches.rs +++ b/compiler/rustc_mir_transform/src/simplify_branches.rs @@ -2,20 +2,17 @@ use crate::MirPass; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; -/// A pass that replaces a branch with a goto when its condition is known. -pub struct SimplifyConstCondition { - label: String, -} - -impl SimplifyConstCondition { - pub fn new(label: &str) -> Self { - SimplifyConstCondition { label: format!("SimplifyConstCondition-{}", label) } - } +pub enum SimplifyConstCondition { + AfterConstProp, + Final, } - +/// A pass that replaces a branch with a goto when its condition is known. impl<'tcx> MirPass<'tcx> for SimplifyConstCondition { - fn name(&self) -> &str { - &self.label + fn name(&self) -> &'static str { + match self { + SimplifyConstCondition::AfterConstProp => "SimplifyConstCondition-after-const-prop", + SimplifyConstCondition::Final => "SimplifyConstCondition-final", + } } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { diff --git a/compiler/rustc_mir_transform/src/ssa.rs b/compiler/rustc_mir_transform/src/ssa.rs index be026402dd5..9d9c5d54038 100644 --- a/compiler/rustc_mir_transform/src/ssa.rs +++ b/compiler/rustc_mir_transform/src/ssa.rs @@ -21,7 +21,7 @@ pub struct SsaLocals { /// We often encounter MIR bodies with 1 or 2 basic blocks. In those cases, it's unnecessary to /// actually compute dominators, we can just compare block indices because bb0 is always the first -/// block, and in any body all other blocks are always always dominated by bb0. +/// block, and in any body all other blocks are always dominated by bb0. struct SmallDominators { inner: Option<Dominators<BasicBlock>>, } diff --git a/compiler/rustc_monomorphize/Cargo.toml b/compiler/rustc_monomorphize/Cargo.toml index c8af10576b4..5ecd68c79bb 100644 --- a/compiler/rustc_monomorphize/Cargo.toml +++ b/compiler/rustc_monomorphize/Cargo.toml @@ -13,6 +13,7 @@ tracing = "0.1" rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_hir = { path = "../rustc_hir" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_index = { path = "../rustc_index" } rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 7bcff7e07fb..2ed628871d2 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -402,7 +402,7 @@ fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionMode) -> Vec<MonoItem< } /// Collect all monomorphized items reachable from `starting_point`, and emit a note diagnostic if a -/// post-monorphization error is encountered during a collection step. +/// post-monomorphization error is encountered during a collection step. #[instrument(skip(tcx, visited, recursion_depths, recursion_limit, inlining_map), level = "debug")] fn collect_items_rec<'tcx>( tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index 5000fb71937..aea9f719027 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -10,8 +10,8 @@ extern crate tracing; extern crate rustc_middle; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; +use rustc_fluent_macro::fluent_messages; use rustc_hir::lang_items::LangItem; -use rustc_macros::fluent_messages; use rustc_middle::traits; use rustc_middle::ty::adjustment::CustomCoerceUnsized; use rustc_middle::ty::query::{Providers, TyCtxtAt}; diff --git a/compiler/rustc_monomorphize/src/partitioning/default.rs b/compiler/rustc_monomorphize/src/partitioning/default.rs index 482b78d42e3..bd24deb590a 100644 --- a/compiler/rustc_monomorphize/src/partitioning/default.rs +++ b/compiler/rustc_monomorphize/src/partitioning/default.rs @@ -16,17 +16,20 @@ use super::PartitioningCx; use crate::collector::InliningMap; use crate::partitioning::merging; use crate::partitioning::{ - MonoItemPlacement, Partitioner, PostInliningPartitioning, PreInliningPartitioning, + MonoItemPlacement, Partition, PostInliningPartitioning, PreInliningPartitioning, }; pub struct DefaultPartitioning; -impl<'tcx> Partitioner<'tcx> for DefaultPartitioning { - fn place_root_mono_items( +impl<'tcx> Partition<'tcx> for DefaultPartitioning { + fn place_root_mono_items<I>( &mut self, cx: &PartitioningCx<'_, 'tcx>, - mono_items: &mut dyn Iterator<Item = MonoItem<'tcx>>, - ) -> PreInliningPartitioning<'tcx> { + mono_items: &mut I, + ) -> PreInliningPartitioning<'tcx> + where + I: Iterator<Item = MonoItem<'tcx>>, + { let mut roots = FxHashSet::default(); let mut codegen_units = FxHashMap::default(); let is_incremental_build = cx.tcx.sess.opts.incremental.is_some(); @@ -89,7 +92,7 @@ impl<'tcx> Partitioner<'tcx> for DefaultPartitioning { } PreInliningPartitioning { - codegen_units: codegen_units.into_values().map(|codegen_unit| codegen_unit).collect(), + codegen_units: codegen_units.into_values().collect(), roots, internalization_candidates, } @@ -267,7 +270,7 @@ fn characteristic_def_id_of_mono_item<'tcx>( match mono_item { MonoItem::Fn(instance) => { let def_id = match instance.def { - ty::InstanceDef::Item(def) => def.did, + ty::InstanceDef::Item(def) => def, ty::InstanceDef::VTableShim(..) | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::FnPtrShim(..) @@ -421,10 +424,9 @@ fn mono_item_visibility<'tcx>( }; let def_id = match instance.def { - InstanceDef::Item(def) => def.did, - InstanceDef::DropGlue(def_id, Some(_)) => def_id, + InstanceDef::Item(def_id) | InstanceDef::DropGlue(def_id, Some(_)) => def_id, - // We match the visiblity of statics here + // We match the visibility of statics here InstanceDef::ThreadLocalShim(def_id) => { return static_visibility(tcx, can_be_internalized, def_id); } diff --git a/compiler/rustc_monomorphize/src/partitioning/mod.rs b/compiler/rustc_monomorphize/src/partitioning/mod.rs index 18aa0742c09..993e35c7fd2 100644 --- a/compiler/rustc_monomorphize/src/partitioning/mod.rs +++ b/compiler/rustc_monomorphize/src/partitioning/mod.rs @@ -118,18 +118,81 @@ use crate::errors::{ CouldntDumpMonoStats, SymbolAlreadyDefined, UnknownCguCollectionMode, UnknownPartitionStrategy, }; +enum Partitioner { + Default(default::DefaultPartitioning), + // Other partitioning strategies can go here. + Unknown, +} + +impl<'tcx> Partition<'tcx> for Partitioner { + fn place_root_mono_items<I>( + &mut self, + cx: &PartitioningCx<'_, 'tcx>, + mono_items: &mut I, + ) -> PreInliningPartitioning<'tcx> + where + I: Iterator<Item = MonoItem<'tcx>>, + { + match self { + Partitioner::Default(partitioner) => partitioner.place_root_mono_items(cx, mono_items), + Partitioner::Unknown => cx.tcx.sess.emit_fatal(UnknownPartitionStrategy), + } + } + + fn merge_codegen_units( + &mut self, + cx: &PartitioningCx<'_, 'tcx>, + initial_partitioning: &mut PreInliningPartitioning<'tcx>, + ) { + match self { + Partitioner::Default(partitioner) => { + partitioner.merge_codegen_units(cx, initial_partitioning) + } + Partitioner::Unknown => cx.tcx.sess.emit_fatal(UnknownPartitionStrategy), + } + } + + fn place_inlined_mono_items( + &mut self, + cx: &PartitioningCx<'_, 'tcx>, + initial_partitioning: PreInliningPartitioning<'tcx>, + ) -> PostInliningPartitioning<'tcx> { + match self { + Partitioner::Default(partitioner) => { + partitioner.place_inlined_mono_items(cx, initial_partitioning) + } + Partitioner::Unknown => cx.tcx.sess.emit_fatal(UnknownPartitionStrategy), + } + } + + fn internalize_symbols( + &mut self, + cx: &PartitioningCx<'_, 'tcx>, + post_inlining_partitioning: &mut PostInliningPartitioning<'tcx>, + ) { + match self { + Partitioner::Default(partitioner) => { + partitioner.internalize_symbols(cx, post_inlining_partitioning) + } + Partitioner::Unknown => cx.tcx.sess.emit_fatal(UnknownPartitionStrategy), + } + } +} + pub struct PartitioningCx<'a, 'tcx> { tcx: TyCtxt<'tcx>, target_cgu_count: usize, inlining_map: &'a InliningMap<'tcx>, } -trait Partitioner<'tcx> { - fn place_root_mono_items( +trait Partition<'tcx> { + fn place_root_mono_items<I>( &mut self, cx: &PartitioningCx<'_, 'tcx>, - mono_items: &mut dyn Iterator<Item = MonoItem<'tcx>>, - ) -> PreInliningPartitioning<'tcx>; + mono_items: &mut I, + ) -> PreInliningPartitioning<'tcx> + where + I: Iterator<Item = MonoItem<'tcx>>; fn merge_codegen_units( &mut self, @@ -150,26 +213,27 @@ trait Partitioner<'tcx> { ); } -fn get_partitioner<'tcx>(tcx: TyCtxt<'tcx>) -> Box<dyn Partitioner<'tcx>> { +fn get_partitioner(tcx: TyCtxt<'_>) -> Partitioner { let strategy = match &tcx.sess.opts.unstable_opts.cgu_partitioning_strategy { None => "default", Some(s) => &s[..], }; match strategy { - "default" => Box::new(default::DefaultPartitioning), - _ => { - tcx.sess.emit_fatal(UnknownPartitionStrategy); - } + "default" => Partitioner::Default(default::DefaultPartitioning), + _ => Partitioner::Unknown, } } -pub fn partition<'tcx>( +pub fn partition<'tcx, I>( tcx: TyCtxt<'tcx>, - mono_items: &mut dyn Iterator<Item = MonoItem<'tcx>>, + mono_items: &mut I, max_cgu_count: usize, inlining_map: &InliningMap<'tcx>, -) -> Vec<CodegenUnit<'tcx>> { +) -> Vec<CodegenUnit<'tcx>> +where + I: Iterator<Item = MonoItem<'tcx>>, +{ let _prof_timer = tcx.prof.generic_activity("cgu_partitioning"); let mut partitioner = get_partitioner(tcx); @@ -182,7 +246,9 @@ pub fn partition<'tcx>( partitioner.place_root_mono_items(cx, mono_items) }; - initial_partitioning.codegen_units.iter_mut().for_each(|cgu| cgu.create_size_estimate(tcx)); + for cgu in &mut initial_partitioning.codegen_units { + cgu.create_size_estimate(tcx); + } debug_dump(tcx, "INITIAL PARTITIONING:", initial_partitioning.codegen_units.iter()); @@ -202,7 +268,9 @@ pub fn partition<'tcx>( partitioner.place_inlined_mono_items(cx, initial_partitioning) }; - post_inlining.codegen_units.iter_mut().for_each(|cgu| cgu.create_size_estimate(tcx)); + for cgu in &mut post_inlining.codegen_units { + cgu.create_size_estimate(tcx); + } debug_dump(tcx, "POST INLINING:", post_inlining.codegen_units.iter()); @@ -380,7 +448,7 @@ fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> (&DefIdSet, &[Co || { let mut codegen_units = partition( tcx, - &mut items.iter().cloned(), + &mut items.iter().copied(), tcx.sess.codegen_units(), &inlining_map, ); diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index 63263a642ac..ddc62d9c390 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -232,7 +232,7 @@ impl<'a, 'tcx> MarkUsedGenericParams<'a, 'tcx> { /// a closure, generator or constant). #[instrument(level = "debug", skip(self, def_id, substs))] fn visit_child_body(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) { - let instance = ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)); + let instance = ty::InstanceDef::Item(def_id); let unused = self.tcx.unused_generic_params(instance); debug!(?self.unused_parameters, ?unused); for (i, arg) in substs.iter().enumerate() { @@ -272,10 +272,10 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { // Avoid considering `T` unused when constants are of the form: // `<Self as Foo<T>>::foo::promoted[p]` if let Some(p) = promoted { - if self.def_id == def.did && !self.tcx.generics_of(def.did).has_self { + if self.def_id == def && !self.tcx.generics_of(def).has_self { // If there is a promoted, don't look at the substs - since it will always contain // the generic parameters, instead, traverse the promoted MIR. - let promoted = self.tcx.promoted_mir(def.did); + let promoted = self.tcx.promoted_mir(def); self.visit_body(&promoted[p]); } } @@ -305,9 +305,9 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for MarkUsedGenericParams<'a, 'tcx> { ControlFlow::Continue(()) } ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) - if matches!(self.tcx.def_kind(def.did), DefKind::AnonConst) => + if matches!(self.tcx.def_kind(def), DefKind::AnonConst) => { - self.visit_child_body(def.did, substs); + self.visit_child_body(def, substs); ControlFlow::Continue(()) } _ => c.super_visit_with(self), diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml index 3eb158c817c..1bd9f66290d 100644 --- a/compiler/rustc_parse/Cargo.toml +++ b/compiler/rustc_parse/Cargo.toml @@ -12,6 +12,7 @@ rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_lexer = { path = "../rustc_lexer" } rustc_macros = { path = "../rustc_macros" } rustc_session = { path = "../rustc_session" } diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 9e856c9f212..ad9b20f9c76 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -67,7 +67,7 @@ pub(crate) fn parse_token_trees<'a>( match token_trees { Ok(stream) if unmatched_delims.is_empty() => Ok(stream), _ => { - // Return error if there are unmatched delimiters or unclosng delimiters. + // Return error if there are unmatched delimiters or unclosed delimiters. // We emit delimiter mismatch errors first, then emit the unclosing delimiter mismatch // because the delimiter mismatch is more likely to be the root cause of error diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 17466cd0e6d..507f6e4182e 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -20,7 +20,7 @@ use rustc_ast_pretty::pprust; use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, Diagnostic, FatalError, Level, PResult}; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; -use rustc_macros::fluent_messages; +use rustc_fluent_macro::fluent_messages; use rustc_session::parse::ParseSess; use rustc_span::{FileName, SourceFile, Span}; diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index e3e7c63e344..e1db19557cf 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -45,10 +45,10 @@ impl<'a> Parser<'a> { Some(InnerAttrForbiddenReason::AfterOuterDocComment { prev_doc_comment_span: prev_outer_attr_sp.unwrap(), }) - } else if let Some(prev_outer_attr_sp) = prev_outer_attr_sp { - Some(InnerAttrForbiddenReason::AfterOuterAttribute { prev_outer_attr_sp }) } else { - None + prev_outer_attr_sp.map(|prev_outer_attr_sp| { + InnerAttrForbiddenReason::AfterOuterAttribute { prev_outer_attr_sp } + }) }; let inner_parse_policy = InnerAttrPolicy::Forbidden(inner_error_reason); just_parsed_doc_comment = false; diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index e03ce5d7120..c14c7f2fa0d 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -570,15 +570,13 @@ impl<'a> Parser<'a> { let expect = tokens_to_string(&expected); let actual = super::token_descr(&self.token); let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 { + let fmt = format!("expected one of {expect}, found {actual}"); let short_expect = if expected.len() > 6 { format!("{} possible tokens", expected.len()) } else { - expect.clone() + expect }; - ( - format!("expected one of {expect}, found {actual}"), - (self.prev_token.span.shrink_to_hi(), format!("expected one of {short_expect}")), - ) + (fmt, (self.prev_token.span.shrink_to_hi(), format!("expected one of {short_expect}"))) } else if expected.is_empty() { ( format!("unexpected token: {actual}"), diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 6422b8ac1ba..f5fef6ad019 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -2577,14 +2577,12 @@ impl<'a> Parser<'a> { } fn recover_self_param(&mut self) -> bool { - match self - .parse_outer_attributes() - .and_then(|_| self.parse_self_param()) - .map_err(|e| e.cancel()) - { - Ok(Some(_)) => true, - _ => false, - } + matches!( + self.parse_outer_attributes() + .and_then(|_| self.parse_self_param()) + .map_err(|e| e.cancel()), + Ok(Some(_)) + ) } } diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 7a4d53ed8bb..adb0d372a40 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -20,12 +20,10 @@ impl<'a> Parser<'a> { pub fn nonterminal_may_begin_with(kind: NonterminalKind, token: &Token) -> bool { /// Checks whether the non-terminal may contain a single (non-keyword) identifier. fn may_be_ident(nt: &token::Nonterminal) -> bool { - match *nt { - token::NtItem(_) | token::NtBlock(_) | token::NtVis(_) | token::NtLifetime(_) => { - false - } - _ => true, - } + !matches!( + *nt, + token::NtItem(_) | token::NtBlock(_) | token::NtVis(_) | token::NtLifetime(_) + ) } match kind { diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 72402a20090..2f397e303e5 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -68,7 +68,7 @@ pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Meta } } else { // The non-error case can happen with e.g. `#[foo = 1+1]`. The error case can - // happen with e.g. `#[foo = include_str!("non-existent-file.rs")]`; in that + // happen with e.g. `#[foo = include_str!("nonexistent-file.rs")]`; in that // case we delay the error because an earlier error will have already been // reported. let msg = format!("unexpected expression: `{}`", pprust::expr_to_string(expr)); diff --git a/compiler/rustc_passes/Cargo.toml b/compiler/rustc_passes/Cargo.toml index 44f991f8c15..0413b5b4fb9 100644 --- a/compiler/rustc_passes/Cargo.toml +++ b/compiler/rustc_passes/Cargo.toml @@ -12,6 +12,7 @@ rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_expand = { path = "../rustc_expand" } rustc_hir = { path = "../rustc_hir" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_index = { path = "../rustc_index" } rustc_session = { path = "../rustc_session" } rustc_target = { path = "../rustc_target" } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index b354dca7cc4..055682a1509 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -627,9 +627,9 @@ passes_attr_application_struct_enum_union = attribute should be applied to a struct, enum, or union .label = not a struct, enum, or union -passes_attr_application_struct_enum_function_union = - attribute should be applied to a struct, enum, function, or union - .label = not a struct, enum, function, or union +passes_attr_application_struct_enum_function_method_union = + attribute should be applied to a struct, enum, function, associated function, or union + .label = not a struct, enum, function, associated function, or union passes_transparent_incompatible = transparent {$target} cannot have other repr hints diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 80a93da2b45..085a28626ea 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1728,7 +1728,9 @@ impl CheckAttrVisitor<'_> { } } sym::align => { - if let (Target::Fn, false) = (target, self.tcx.features().fn_align) { + if let (Target::Fn | Target::Method(MethodKind::Inherent), false) = + (target, self.tcx.features().fn_align) + { feature_err( &self.tcx.sess.parse_sess, sym::fn_align, @@ -1739,10 +1741,14 @@ impl CheckAttrVisitor<'_> { } match target { - Target::Struct | Target::Union | Target::Enum | Target::Fn => continue, + Target::Struct + | Target::Union + | Target::Enum + | Target::Fn + | Target::Method(_) => continue, _ => { self.tcx.sess.emit_err( - errors::AttrApplication::StructEnumFunctionUnion { + errors::AttrApplication::StructEnumFunctionMethodUnion { hint_span: hint.span(), span, }, diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 5cfe691df17..3ae5b45d330 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -237,6 +237,37 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { } } + fn handle_offset_of(&mut self, expr: &'tcx hir::Expr<'tcx>) { + let data = self.typeck_results().offset_of_data(); + let &(container, ref indices) = + data.get(expr.hir_id).expect("no offset_of_data for offset_of"); + + let body_did = self.typeck_results().hir_owner.to_def_id(); + let param_env = self.tcx.param_env(body_did); + + let mut current_ty = container; + + for &index in indices { + match current_ty.kind() { + ty::Adt(def, subst) => { + let field = &def.non_enum_variant().fields[index]; + + self.insert_def_id(field.did); + let field_ty = field.ty(self.tcx, subst); + + current_ty = self.tcx.normalize_erasing_regions(param_env, field_ty); + } + // we don't need to mark tuple fields as live, + // but we may need to mark subfields + ty::Tuple(tys) => { + current_ty = + self.tcx.normalize_erasing_regions(param_env, tys[index.as_usize()]); + } + _ => span_bug!(expr.span, "named field access on non-ADT"), + } + } + } + fn mark_live_symbols(&mut self) { let mut scanned = LocalDefIdSet::default(); while let Some(id) = self.worklist.pop() { @@ -405,6 +436,9 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { hir::ExprKind::Closure(cls) => { self.insert_def_id(cls.def_id.to_def_id()); } + hir::ExprKind::OffsetOf(..) => { + self.handle_offset_of(expr); + } _ => (), } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 139ba8c9677..e8603b3a2f1 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1355,8 +1355,8 @@ pub enum AttrApplication { #[label] span: Span, }, - #[diag(passes_attr_application_struct_enum_function_union, code = "E0517")] - StructEnumFunctionUnion { + #[diag(passes_attr_application_struct_enum_function_method_union, code = "E0517")] + StructEnumFunctionMethodUnion { #[primary_span] hint_span: Span, #[label] diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index 47e032758f2..dc5e454074d 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -302,7 +302,8 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { [ ConstBlock, Array, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, DropTemps, Let, If, Loop, Match, Closure, Block, Assign, AssignOp, Field, Index, - Path, AddrOf, Break, Continue, Ret, InlineAsm, Struct, Repeat, Yield, Err + Path, AddrOf, Break, Continue, Ret, InlineAsm, OffsetOf, Struct, Repeat, Yield, + Err ] ); hir_visit::walk_expr(self, e) @@ -568,7 +569,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { Array, ConstBlock, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, Let, If, While, ForLoop, Loop, Match, Closure, Block, Async, Await, TryBlock, Assign, AssignOp, Field, Index, Range, Underscore, Path, AddrOf, Break, Continue, Ret, - InlineAsm, FormatArgs, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet, IncludedBytes, Err + InlineAsm, FormatArgs, OffsetOf, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet, IncludedBytes, Err ] ); ast_visit::walk_expr(self, e) diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index b7e07aff42b..eca3bae9a1c 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -19,7 +19,7 @@ extern crate rustc_middle; extern crate tracing; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; -use rustc_macros::fluent_messages; +use rustc_fluent_macro::fluent_messages; use rustc_middle::ty::query::Providers; mod check_attr; diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index a8471ce3b6f..b39a8c5598f 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -473,6 +473,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { | hir::ExprKind::Struct(..) | hir::ExprKind::Repeat(..) | hir::ExprKind::InlineAsm(..) + | hir::ExprKind::OffsetOf(..) | hir::ExprKind::Type(..) | hir::ExprKind::Err(_) | hir::ExprKind::Path(hir::QPath::TypeRelative(..)) @@ -1129,7 +1130,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { | hir::ExprKind::ConstBlock(..) | hir::ExprKind::Err(_) | hir::ExprKind::Path(hir::QPath::TypeRelative(..)) - | hir::ExprKind::Path(hir::QPath::LangItem(..)) => succ, + | hir::ExprKind::Path(hir::QPath::LangItem(..)) + | hir::ExprKind::OffsetOf(..) => succ, // Note that labels have been resolved, so we don't need to look // at the label ident @@ -1418,6 +1420,7 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) { | hir::ExprKind::ConstBlock(..) | hir::ExprKind::Block(..) | hir::ExprKind::AddrOf(..) + | hir::ExprKind::OffsetOf(..) | hir::ExprKind::Struct(..) | hir::ExprKind::Repeat(..) | hir::ExprKind::Closure { .. } diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index c398467f03e..cf8d9300a11 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -203,6 +203,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> { | ExprKind::Break(..) | ExprKind::Continue(..) | ExprKind::Ret(..) + | ExprKind::OffsetOf(..) | ExprKind::Struct(..) | ExprKind::Repeat(..) | ExprKind::Yield(..) => { diff --git a/compiler/rustc_plugin_impl/Cargo.toml b/compiler/rustc_plugin_impl/Cargo.toml index fa27bfc61d1..c930b3365fd 100644 --- a/compiler/rustc_plugin_impl/Cargo.toml +++ b/compiler/rustc_plugin_impl/Cargo.toml @@ -12,6 +12,7 @@ rustc_errors = { path = "../rustc_errors" } rustc_lint = { path = "../rustc_lint" } rustc_macros = { path = "../rustc_macros" } rustc_metadata = { path = "../rustc_metadata" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_ast = { path = "../rustc_ast" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_plugin_impl/src/lib.rs b/compiler/rustc_plugin_impl/src/lib.rs index 672189e22cf..faa7495ef9f 100644 --- a/compiler/rustc_plugin_impl/src/lib.rs +++ b/compiler/rustc_plugin_impl/src/lib.rs @@ -12,8 +12,8 @@ #![deny(rustc::diagnostic_outside_of_impl)] use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; +use rustc_fluent_macro::fluent_messages; use rustc_lint::LintStore; -use rustc_macros::fluent_messages; mod errors; pub mod load; diff --git a/compiler/rustc_privacy/Cargo.toml b/compiler/rustc_privacy/Cargo.toml index 744cb77dd00..08c4067705c 100644 --- a/compiler/rustc_privacy/Cargo.toml +++ b/compiler/rustc_privacy/Cargo.toml @@ -9,6 +9,7 @@ rustc_attr = { path = "../rustc_attr" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_hir = { path = "../rustc_hir" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } rustc_session = { path = "../rustc_session" } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index dcebfca08fa..9567329192d 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -17,12 +17,12 @@ use rustc_attr as attr; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::intern::Interned; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; +use rustc_fluent_macro::fluent_messages; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{AssocItemKind, HirIdSet, ItemId, Node, PatKind}; -use rustc_macros::fluent_messages; use rustc_middle::bug; use rustc_middle::hir::nested_filter; use rustc_middle::middle::privacy::{EffectiveVisibilities, Level}; diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs index 30477c7bd44..c05323c2d6c 100644 --- a/compiler/rustc_query_impl/src/on_disk_cache.rs +++ b/compiler/rustc_query_impl/src/on_disk_cache.rs @@ -1,6 +1,7 @@ use crate::QueryCtxt; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::memmap::Mmap; +use rustc_data_structures::stable_hasher::Hash64; use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, RwLock}; use rustc_data_structures::unhash::UnhashMap; use rustc_data_structures::unord::UnordSet; @@ -138,7 +139,7 @@ impl AbsoluteBytePos { /// is the only thing available when decoding the cache's [Footer]. #[derive(Encodable, Decodable, Clone, Debug)] struct EncodedSourceFileId { - file_name_hash: u64, + file_name_hash: Hash64, stable_crate_id: StableCrateId, } @@ -299,7 +300,7 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> { interpret_alloc_index.reserve(new_n - n); for idx in n..new_n { let id = encoder.interpret_allocs[idx]; - let pos = encoder.position() as u32; + let pos: u32 = encoder.position().try_into().unwrap(); interpret_alloc_index.push(pos); interpret::specialized_encode_alloc_id(&mut encoder, tcx, id); } @@ -667,7 +668,7 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for ExpnId { #[cfg(debug_assertions)] { use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; - let local_hash: u64 = decoder.tcx.with_stable_hashing_context(|mut hcx| { + let local_hash = decoder.tcx.with_stable_hashing_context(|mut hcx| { let mut hasher = StableHasher::new(); expn_id.expn_data().hash_stable(&mut hcx, &mut hasher); hasher.finish() @@ -744,7 +745,7 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Symbol { let pos = d.read_usize(); let old_pos = d.opaque.position(); - // move to str ofset and read + // move to str offset and read d.opaque.set_position(pos); let s = d.read_str(); let sym = Symbol::intern(s); @@ -806,7 +807,9 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx UnordSet<LocalDefId> } } -impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx FxHashMap<DefId, Ty<'tcx>> { +impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> + for &'tcx FxHashMap<DefId, ty::EarlyBinder<Ty<'tcx>>> +{ fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { RefDecodable::decode(d) } diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index afbead7d1ae..32222df25d4 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -5,7 +5,7 @@ use crate::on_disk_cache::{CacheDecoder, CacheEncoder, EncodedDepNodeIndex}; use crate::profiling_support::QueryKeyStringCache; use crate::{on_disk_cache, Queries}; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher}; use rustc_data_structures::sync::{AtomicU64, Lock}; use rustc_errors::{Diagnostic, Handler}; use rustc_middle::dep_graph::{ @@ -342,7 +342,7 @@ pub(crate) fn create_query_frame< let mut hasher = StableHasher::new(); std::mem::discriminant(&kind).hash_stable(&mut hcx, &mut hasher); key.hash_stable(&mut hcx, &mut hasher); - hasher.finish::<u64>() + hasher.finish::<Hash64>() }) }; let ty_adt_id = key.ty_adt_id(); diff --git a/compiler/rustc_query_impl/src/profiling_support.rs b/compiler/rustc_query_impl/src/profiling_support.rs index 4743170e9bf..08b588a8c94 100644 --- a/compiler/rustc_query_impl/src/profiling_support.rs +++ b/compiler/rustc_query_impl/src/profiling_support.rs @@ -4,7 +4,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::profiling::SelfProfiler; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE}; use rustc_hir::definitions::DefPathData; -use rustc_middle::ty::{TyCtxt, WithOptConstParam}; +use rustc_middle::ty::TyCtxt; use rustc_query_system::query::QueryCache; use std::fmt::Debug; use std::io::Write; @@ -151,37 +151,6 @@ impl SpecIntoSelfProfilingString for LocalDefId { } } -impl<T: SpecIntoSelfProfilingString> SpecIntoSelfProfilingString for WithOptConstParam<T> { - fn spec_to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId { - // We print `WithOptConstParam` values as tuples to make them shorter - // and more readable, without losing information: - // - // "WithOptConstParam { did: foo::bar, const_param_did: Some(foo::baz) }" - // becomes "(foo::bar, foo::baz)" and - // "WithOptConstParam { did: foo::bar, const_param_did: None }" - // becomes "(foo::bar, _)". - - let did = StringComponent::Ref(self.did.to_self_profile_string(builder)); - - let const_param_did = if let Some(const_param_did) = self.const_param_did { - let const_param_did = builder.def_id_to_string_id(const_param_did); - StringComponent::Ref(const_param_did) - } else { - StringComponent::Value("_") - }; - - let components = [ - StringComponent::Value("("), - did, - StringComponent::Value(", "), - const_param_did, - StringComponent::Value(")"), - ]; - - builder.profiler.alloc_string(&components[..]) - } -} - impl<T0, T1> SpecIntoSelfProfilingString for (T0, T1) where T0: SpecIntoSelfProfilingString, @@ -231,7 +200,7 @@ pub(crate) fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>( // locked while doing so. Instead we copy out the // `(query_key, dep_node_index)` pairs and release the lock again. let mut query_keys_and_indices = Vec::new(); - query_cache.iter(&mut |k, _, i| query_keys_and_indices.push((k.clone(), i))); + query_cache.iter(&mut |k, _, i| query_keys_and_indices.push((*k, i))); // Now actually allocate the strings. If allocating the strings // generates new entries in the query cache, we'll miss them but diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml index 12b4a114313..34e57637976 100644 --- a/compiler/rustc_query_system/Cargo.toml +++ b/compiler/rustc_query_system/Cargo.toml @@ -12,6 +12,7 @@ rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_macros = { path = "../rustc_macros" } diff --git a/compiler/rustc_query_system/messages.ftl b/compiler/rustc_query_system/messages.ftl index 870e824039c..0d01123ad88 100644 --- a/compiler/rustc_query_system/messages.ftl +++ b/compiler/rustc_query_system/messages.ftl @@ -1,4 +1,4 @@ -query_system_reentrant = internal compiler error: re-entrant incremental verify failure, suppressing message +query_system_reentrant = internal compiler error: reentrant incremental verify failure, suppressing message query_system_increment_compilation = internal compiler error: encountered incremental compilation error with {$dep_node} .help = This is a known issue with the compiler. Run {$run_cmd} to allow your project to compile diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index a9a2e6dd04c..fd9e685ab80 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -249,7 +249,7 @@ impl<K: DepKind> DepGraph<K> { /// get an ICE. Normally, we would have tried (and failed) to mark /// some other query green (e.g. `item_children`) which was used /// to obtain `C`, which would prevent us from ever trying to force - /// a non-existent `D`. + /// a nonexistent `D`. /// /// It might be possible to enforce that all `DepNode`s read during /// deserialization already exist in the previous `DepGraph`. In diff --git a/compiler/rustc_query_system/src/dep_graph/query.rs b/compiler/rustc_query_system/src/dep_graph/query.rs index 27b3b5e1366..9dcc41e2726 100644 --- a/compiler/rustc_query_system/src/dep_graph/query.rs +++ b/compiler/rustc_query_system/src/dep_graph/query.rs @@ -24,10 +24,7 @@ impl<K: DepKind> DepGraphQuery<K> { pub fn push(&mut self, index: DepNodeIndex, node: DepNode<K>, edges: &[DepNodeIndex]) { let source = self.graph.add_node(node); - if index.index() >= self.dep_index_to_index.len() { - self.dep_index_to_index.resize(index.index() + 1, None); - } - self.dep_index_to_index[index] = Some(source); + self.dep_index_to_index.insert(index, source); self.indices.insert(node, source); for &target in edges.iter() { diff --git a/compiler/rustc_query_system/src/ich/impls_syntax.rs b/compiler/rustc_query_system/src/ich/impls_syntax.rs index 0bc811eb044..8865ecf3e05 100644 --- a/compiler/rustc_query_system/src/ich/impls_syntax.rs +++ b/compiler/rustc_query_system/src/ich/impls_syntax.rs @@ -75,7 +75,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for SourceFile { ref normalized_pos, } = *self; - (name_hash as u64).hash_stable(hcx, hasher); + name_hash.hash_stable(hcx, hasher); src_hash.hash_stable(hcx, hasher); diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs index bb812b006e9..8c9e9cfad60 100644 --- a/compiler/rustc_query_system/src/lib.rs +++ b/compiler/rustc_query_system/src/lib.rs @@ -16,7 +16,7 @@ extern crate rustc_data_structures; extern crate rustc_macros; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; -use rustc_macros::fluent_messages; +use rustc_fluent_macro::fluent_messages; pub mod cache; pub mod dep_graph; diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs index c8d77938510..bb9ea50a1ea 100644 --- a/compiler/rustc_query_system/src/query/config.rs +++ b/compiler/rustc_query_system/src/query/config.rs @@ -63,7 +63,7 @@ pub trait QueryConfig<Qcx: QueryContext>: Copy { fn handle_cycle_error(self) -> HandleCycleError; fn hash_result(self) -> HashResult<Self::Value>; - // Just here for convernience and checking that the key matches the kind, don't override this. + // Just here for convenience and checking that the key matches the kind, don't override this. fn construct_dep_node(self, tcx: Qcx::DepContext, key: &Self::Key) -> DepNode<Qcx::DepKind> { DepNode::construct(tcx, self.dep_kind(), key) } diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index 312b0e1688d..fa1f51b04da 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -16,6 +16,7 @@ pub use self::config::{HashResult, QueryConfig, TryLoadFromDisk}; use crate::dep_graph::DepKind; use crate::dep_graph::{DepNodeIndex, HasDepContext, SerializedDepNodeIndex}; +use rustc_data_structures::stable_hasher::Hash64; use rustc_data_structures::sync::Lock; use rustc_errors::Diagnostic; use rustc_hir::def::DefKind; @@ -37,7 +38,7 @@ pub struct QueryStackFrame<D: DepKind> { /// This hash is used to deterministically pick /// a query to remove cycles in the parallel compiler. #[cfg(parallel_compiler)] - hash: u64, + hash: Hash64, } impl<D: DepKind> QueryStackFrame<D> { @@ -49,7 +50,7 @@ impl<D: DepKind> QueryStackFrame<D> { def_kind: Option<DefKind>, dep_kind: D, ty_adt_id: Option<DefId>, - _hash: impl FnOnce() -> u64, + _hash: impl FnOnce() -> Hash64, ) -> Self { Self { description, diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 20310483d7e..bce01debc53 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -410,9 +410,28 @@ where // as its feeding query had. So if the fed query is red, so is its feeder, which will // get evaluated first, and re-feed the query. if let Some((cached_result, _)) = cache.lookup(&key) { - panic!( - "fed query later has its value computed. The already cached value: {}", - (query.format_value())(&cached_result) + let Some(hasher) = query.hash_result() else { + panic!( + "no_hash fed query later has its value computed.\n\ + Remove `no_hash` modifier to allow recomputation.\n\ + The already cached value: {}", + (query.format_value())(&cached_result) + ); + }; + + let (old_hash, new_hash) = qcx.dep_context().with_stable_hashing_context(|mut hcx| { + (hasher(&mut hcx, &cached_result), hasher(&mut hcx, &result)) + }); + let formatter = query.format_value(); + debug_assert_eq!( + old_hash, + new_hash, + "Computed query value for {:?}({:?}) is inconsistent with fed value,\n\ + computed={:#?}\nfed={:#?}", + query.dep_kind(), + key, + formatter(&result), + formatter(&cached_result), ); } } @@ -573,7 +592,7 @@ where // from disk. Re-hashing results is fairly expensive, so we can't // currently afford to verify every hash. This subset should still // give us some coverage of potential bugs though. - let try_verify = prev_fingerprint.as_value().1 % 32 == 0; + let try_verify = prev_fingerprint.split().1.as_u64() % 32 == 0; if std::intrinsics::unlikely( try_verify || qcx.dep_context().sess().opts.unstable_opts.incremental_verify_ich, ) { @@ -691,7 +710,7 @@ fn incremental_verify_ich_failed<Tcx>( // which may result in another fingerprint mismatch while we're in the middle // of processing this one. To avoid a double-panic (which kills the process // before we can print out the query static), we print out a terse - // but 'safe' message if we detect a re-entrant call to this method. + // but 'safe' message if we detect a reentrant call to this method. thread_local! { static INSIDE_VERIFY_PANIC: Cell<bool> = const { Cell::new(false) }; }; diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml index 5c4ec44d2b8..1c16d85f1b9 100644 --- a/compiler/rustc_resolve/Cargo.toml +++ b/compiler/rustc_resolve/Cargo.toml @@ -16,6 +16,7 @@ rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_expand = { path = "../rustc_expand" } rustc_feature = { path = "../rustc_feature" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_macros = { path = "../rustc_macros" } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index ff0f1f55975..967c9e22fb2 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -197,10 +197,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } pub(crate) fn build_reduced_graph_external(&mut self, module: Module<'a>) { - // Query `module_children` is not used because hashing spans in its result is expensive. - let children = - Vec::from_iter(self.cstore().module_children_untracked(module.def_id(), self.tcx.sess)); - for child in children { + for child in self.tcx.module_children(module.def_id()) { let parent_scope = ParentScope::module(module, self); BuildReducedGraphVisitor { r: self, parent_scope } .build_reduced_graph_for_external_crate_res(child); @@ -929,9 +926,15 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { } /// Builds the reduced graph for a single item in an external crate. - fn build_reduced_graph_for_external_crate_res(&mut self, child: ModChild) { + fn build_reduced_graph_for_external_crate_res(&mut self, child: &ModChild) { let parent = self.parent_scope.module; - let ModChild { ident, res, vis, span, .. } = child; + let ModChild { ident, res, vis, ref reexport_chain } = *child; + let span = self.r.def_span( + reexport_chain + .first() + .and_then(|reexport| reexport.id()) + .unwrap_or_else(|| res.def_id()), + ); let res = res.expect_non_local(); let expansion = self.parent_scope.expansion; // Record primary definitions. diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 0c9d306081e..4b7048eac04 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -663,15 +663,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { Ident::with_dummy_span(name), Namespace::ValueNS, &parent_scope, - &|res: Res| match res { - Res::Def( - DefKind::Ctor(CtorOf::Variant, CtorKind::Const) - | DefKind::Ctor(CtorOf::Struct, CtorKind::Const) - | DefKind::Const - | DefKind::AssocConst, - _, - ) => true, - _ => false, + &|res: Res| { + matches!( + res, + Res::Def( + DefKind::Ctor(CtorOf::Variant, CtorKind::Const) + | DefKind::Ctor(CtorOf::Struct, CtorKind::Const) + | DefKind::Const + | DefKind::AssocConst, + _, + ) + ) }, ); @@ -1867,15 +1869,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { Some(LexicalScopeBinding::Item(name_binding)) => Some(name_binding.span), _ => None, }; - let suggestion = if let Some(span) = match_span { - Some(( + let suggestion = match_span.map(|span| { + ( vec![(span, String::from(""))], format!("`{}` is defined here, but is not a type", ident), Applicability::MaybeIncorrect, - )) - } else { - None - }; + ) + }); (format!("use of undeclared type `{}`", ident), suggestion) } else { diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index bed579f6b92..87067189a77 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -175,7 +175,7 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> { /// to not update anything and we can skip it. /// /// We are checking this condition only if the correct value of private visibility is - /// cheaply available, otherwise it does't make sense performance-wise. + /// cheaply available, otherwise it doesn't make sense performance-wise. /// /// `None` is returned if the update can be skipped, /// and cheap private visibility is returned otherwise. diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index afa796cb645..af0ec236df0 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -22,7 +22,7 @@ pub(crate) struct UnderscoreLifetimeNameCannotBeUsedHere(#[primary_span] pub(cra #[derive(Diagnostic)] #[diag(resolve_crate_may_not_be_imported)] -pub(crate) struct CrateMayNotBeImprted(#[primary_span] pub(crate) Span); +pub(crate) struct CrateMayNotBeImported(#[primary_span] pub(crate) Span); #[derive(Diagnostic)] #[diag(resolve_crate_root_imports_must_be_named_explicitly)] diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 3c22d51c3d4..d7c518fbdd0 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -1276,13 +1276,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { next_binding = binding; } - reexports.push(ModChild { - ident, - res, - vis: binding.vis, - span: binding.span, - reexport_chain, - }); + reexports.push(ModChild { ident, res, vis: binding.vis, reexport_chain }); } }); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 90a2fa89cd2..a97857e05e2 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1079,7 +1079,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, for rib in self.lifetime_ribs.iter().rev() { match rib.kind { // We are inside a `PolyTraitRef`. The lifetimes are - // to be intoduced in that (maybe implicit) `for<>` binder. + // to be introduced in that (maybe implicit) `for<>` binder. LifetimeRibKind::Generics { binder, kind: LifetimeBinderKind::PolyTrait, @@ -3803,7 +3803,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // use std::u8; // bring module u8 in scope // fn f() -> u8 { // OK, resolves to primitive u8, not to std::u8 // u8::max_value() // OK, resolves to associated function <u8>::max_value, - // // not to non-existent std::u8::max_value + // // not to nonexistent std::u8::max_value // } // // Such behavior is required for backward compatibility. diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 37fbfad2de6..e824a6ddc07 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -91,7 +91,7 @@ fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, Str /// Description of an elided lifetime. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] pub(super) struct MissingLifetime { - /// Used to overwrite the resolution with the suggestion, to avoid cascasing errors. + /// Used to overwrite the resolution with the suggestion, to avoid cascading errors. pub id: NodeId, /// Where to suggest adding the lifetime. pub span: Span, @@ -408,7 +408,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } let Some(path_last_segment) = path.last() else { return }; let item_str = path_last_segment.ident; - // Emit help message for fake-self from other languages (e.g., `this` in Javascript). + // Emit help message for fake-self from other languages (e.g., `this` in JavaScript). if ["this", "my"].contains(&item_str.as_str()) { err.span_suggestion_short( span, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index b820d56b8af..282f12bd3c0 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -33,6 +33,7 @@ use rustc_errors::{ Applicability, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, SubdiagnosticMessage, }; use rustc_expand::base::{DeriveResolutions, SyntaxExtension, SyntaxExtensionKind}; +use rustc_fluent_macro::fluent_messages; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorOf, DefKind, DocLinkResMap, LifetimeRes, PartialRes, PerNS}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap, LocalDefIdSet}; @@ -40,7 +41,6 @@ use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::definitions::DefPathData; use rustc_hir::TraitCandidate; use rustc_index::vec::IndexVec; -use rustc_macros::fluent_messages; use rustc_metadata::creader::{CStore, CrateLoader}; use rustc_middle::metadata::ModChild; use rustc_middle::middle::privacy::EffectiveVisibilities; diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index 9eae99be2e9..d433391f272 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -367,6 +367,7 @@ fn preprocess_link(link: &str) -> Box<str> { let link = link.strip_suffix("{}").unwrap_or(link); let link = link.strip_suffix("[]").unwrap_or(link); let link = if link != "!" { link.strip_suffix('!').unwrap_or(link) } else { link }; + let link = link.trim(); strip_generics_from_path(link).unwrap_or_else(|_| link.into()) } diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml index 9e337dde995..15dbfbfd387 100644 --- a/compiler/rustc_session/Cargo.toml +++ b/compiler/rustc_session/Cargo.toml @@ -10,6 +10,7 @@ tracing = "0.1" rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } rustc_hir = { path = "../rustc_hir" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_target = { path = "../rustc_target" } rustc_serialize = { path = "../rustc_serialize" } rustc_data_structures = { path = "../rustc_data_structures" } diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index 968728905e7..590a68c6600 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -19,7 +19,7 @@ pub mod errors; extern crate tracing; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; -use rustc_macros::fluent_messages; +use rustc_fluent_macro::fluent_messages; pub mod cgu_reuse_tracker; pub mod utils; diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 46c992dfefd..98bcacbe7ff 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1452,9 +1452,9 @@ options! { fewer_names: Option<bool> = (None, parse_opt_bool, [TRACKED], "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \ (default: no)"), - flatten_format_args: bool = (false, parse_bool, [TRACKED], + flatten_format_args: bool = (true, parse_bool, [TRACKED], "flatten nested format_args!() and literals into a simplified format_args!() call \ - (default: no)"), + (default: yes)"), force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED], "force all crates to be `rustc_private` unstable (default: no)"), fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED], @@ -1558,6 +1558,9 @@ options! { "use like `-Zmir-enable-passes=+DestProp,-InstCombine`. Forces the specified passes to be \ enabled, overriding all other checks. Passes that are not specified are enabled or \ disabled by other flags as usual."), + mir_keep_place_mention: bool = (false, parse_bool, [TRACKED], + "keep place mention MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \ + (default: no)"), #[rustc_lint_opt_deny_field_access("use `Session::mir_opt_level` instead of this field")] mir_opt_level: Option<usize> = (None, parse_opt_number, [TRACKED], "MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)"), diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 340bb158e17..14a8e8ff727 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -811,7 +811,7 @@ impl Session { } pub fn generate_proc_macro_decls_symbol(&self, stable_crate_id: StableCrateId) -> String { - format!("__rustc_proc_macro_decls_{:08x}__", stable_crate_id.to_u64()) + format!("__rustc_proc_macro_decls_{:08x}__", stable_crate_id.as_u64()) } pub fn target_filesearch(&self, kind: PathKind) -> filesearch::FileSearch<'_> { diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 4dad3c6bce7..09cb6fd22d5 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -128,6 +128,18 @@ fn rustc_place_to_place(place: &rustc_middle::mir::Place<'_>) -> stable_mir::mir stable_mir::mir::Place { local: place.local.as_usize() } } +fn rustc_unwind_to_unwind( + unwind: &rustc_middle::mir::UnwindAction, +) -> stable_mir::mir::UnwindAction { + use rustc_middle::mir::UnwindAction; + match unwind { + UnwindAction::Continue => stable_mir::mir::UnwindAction::Continue, + UnwindAction::Unreachable => stable_mir::mir::UnwindAction::Unreachable, + UnwindAction::Terminate => stable_mir::mir::UnwindAction::Terminate, + UnwindAction::Cleanup(bb) => stable_mir::mir::UnwindAction::Cleanup(bb.as_usize()), + } +} + fn rustc_terminator_to_terminator( terminator: &rustc_middle::mir::Terminator<'_>, ) -> stable_mir::mir::Terminator { @@ -151,7 +163,15 @@ fn rustc_terminator_to_terminator( Return => Terminator::Return, Unreachable => Terminator::Unreachable, Drop { .. } => todo!(), - Call { .. } => todo!(), + Call { func, args, destination, target, unwind, from_hir_call: _, fn_span: _ } => { + Terminator::Call { + func: rustc_op_to_op(func), + args: args.iter().map(|arg| rustc_op_to_op(arg)).collect(), + destination: rustc_place_to_place(destination), + target: target.map(|t| t.as_usize()), + unwind: rustc_unwind_to_unwind(unwind), + } + } Assert { .. } => todo!(), Yield { .. } => todo!(), GeneratorDrop => todo!(), diff --git a/compiler/rustc_smir/src/stable_mir/mir/body.rs b/compiler/rustc_smir/src/stable_mir/mir/body.rs index c504065c993..bd5e6b68a12 100644 --- a/compiler/rustc_smir/src/stable_mir/mir/body.rs +++ b/compiler/rustc_smir/src/stable_mir/mir/body.rs @@ -33,7 +33,7 @@ pub enum Terminator { args: Vec<Operand>, destination: Place, target: Option<usize>, - cleanup: Option<usize>, + unwind: UnwindAction, }, Assert { cond: Operand, @@ -45,6 +45,14 @@ pub enum Terminator { } #[derive(Clone, Debug)] +pub enum UnwindAction { + Continue, + Unreachable, + Terminate, + Cleanup(usize), +} + +#[derive(Clone, Debug)] pub enum Statement { Assign(Place, Operand), Nop, diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index b2c58caff2e..6004009c6ff 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -1,12 +1,11 @@ use crate::{HashStableContext, Symbol}; use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; +use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher, ToStableHashKey}; use rustc_data_structures::unhash::Unhasher; use rustc_data_structures::AtomicRef; use rustc_index::vec::Idx; use rustc_macros::HashStable_Generic; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; -use std::borrow::Borrow; use std::fmt; use std::hash::{BuildHasherDefault, Hash, Hasher}; @@ -105,20 +104,20 @@ impl DefPathHash { /// originates from. #[inline] pub fn stable_crate_id(&self) -> StableCrateId { - StableCrateId(self.0.as_value().0) + StableCrateId(self.0.split().0) } /// Returns the crate-local part of the [DefPathHash]. /// /// Used for tests. #[inline] - pub fn local_hash(&self) -> u64 { - self.0.as_value().1 + pub fn local_hash(&self) -> Hash64 { + self.0.split().1 } /// Builds a new [DefPathHash] with the given [StableCrateId] and /// `local_hash`, where `local_hash` must be unique within its crate. - pub fn new(stable_crate_id: StableCrateId, local_hash: u64) -> DefPathHash { + pub fn new(stable_crate_id: StableCrateId, local_hash: Hash64) -> DefPathHash { DefPathHash(Fingerprint::new(stable_crate_id.0, local_hash)) } } @@ -129,13 +128,6 @@ impl Default for DefPathHash { } } -impl Borrow<Fingerprint> for DefPathHash { - #[inline] - fn borrow(&self) -> &Fingerprint { - &self.0 - } -} - /// A [`StableCrateId`] is a 64-bit hash of a crate name, together with all /// `-Cmetadata` arguments, and some other data. It is to [`CrateNum`] what [`DefPathHash`] is to /// [`DefId`]. It is stable across compilation sessions. @@ -147,15 +139,11 @@ impl Borrow<Fingerprint> for DefPathHash { /// /// For more information on the possibility of hash collisions in rustc, /// see the discussion in [`DefId`]. -#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] -#[derive(HashStable_Generic, Encodable, Decodable)] -pub struct StableCrateId(pub(crate) u64); +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] +#[derive(Hash, HashStable_Generic, Encodable, Decodable)] +pub struct StableCrateId(pub(crate) Hash64); impl StableCrateId { - pub fn to_u64(self) -> u64 { - self.0 - } - /// Computes the stable ID for a crate with the given name and /// `-Cmetadata` arguments. pub fn new(crate_name: Symbol, is_exe: bool, mut metadata: Vec<String>) -> StableCrateId { @@ -197,6 +185,17 @@ impl StableCrateId { StableCrateId(hasher.finish()) } + + #[inline] + pub fn as_u64(self) -> u64 { + self.0.as_u64() + } +} + +impl fmt::LowerHex for StableCrateId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::LowerHex::fmt(&self.0, f) + } } rustc_index::newtype_index! { diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 08c4414034a..f8741d85934 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -33,7 +33,7 @@ use crate::def_id::{CrateNum, DefId, StableCrateId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stable_hasher::HashingControls; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher}; use rustc_data_structures::sync::{Lock, Lrc}; use rustc_data_structures::unhash::UnhashMap; use rustc_index::vec::IndexVec; @@ -123,15 +123,15 @@ impl ExpnHash { /// originates from. #[inline] pub fn stable_crate_id(self) -> StableCrateId { - StableCrateId(self.0.as_value().0) + StableCrateId(self.0.split().0) } /// Returns the crate-local part of the [ExpnHash]. /// /// Used for tests. #[inline] - pub fn local_hash(self) -> u64 { - self.0.as_value().1 + pub fn local_hash(self) -> Hash64 { + self.0.split().1 } #[inline] @@ -141,7 +141,7 @@ impl ExpnHash { /// Builds a new [ExpnHash] with the given [StableCrateId] and /// `local_hash`, where `local_hash` must be unique within its crate. - fn new(stable_crate_id: StableCrateId, local_hash: u64) -> ExpnHash { + fn new(stable_crate_id: StableCrateId, local_hash: Hash64) -> ExpnHash { ExpnHash(Fingerprint::new(stable_crate_id.0, local_hash)) } } @@ -350,7 +350,7 @@ pub struct HygieneData { /// would have collisions without a disambiguator. /// The keys of this map are always computed with `ExpnData.disambiguator` /// set to 0. - expn_data_disambiguators: FxHashMap<u64, u32>, + expn_data_disambiguators: FxHashMap<Hash64, u32>, } impl HygieneData { @@ -1040,7 +1040,7 @@ impl ExpnData { } #[inline] - fn hash_expn(&self, ctx: &mut impl HashStableContext) -> u64 { + fn hash_expn(&self, ctx: &mut impl HashStableContext) -> Hash64 { let mut hasher = StableHasher::new(); self.hash_stable(ctx, &mut hasher); hasher.finish() diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index aa8859ed1a3..8a900ca427e 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -59,7 +59,7 @@ pub mod fatal_error; pub mod profiling; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::stable_hasher::{Hash128, Hash64, HashStable, StableHasher}; use rustc_data_structures::sync::{Lock, Lrc}; use std::borrow::Cow; @@ -282,22 +282,22 @@ impl RealFileName { pub enum FileName { Real(RealFileName), /// Call to `quote!`. - QuoteExpansion(u64), + QuoteExpansion(Hash64), /// Command line. - Anon(u64), + Anon(Hash64), /// Hack in `src/librustc_ast/parse.rs`. // FIXME(jseyfried) - MacroExpansion(u64), - ProcMacroSourceCode(u64), + MacroExpansion(Hash64), + ProcMacroSourceCode(Hash64), /// Strings provided as `--cfg [cfgspec]` stored in a `crate_cfg`. - CfgSpec(u64), + CfgSpec(Hash64), /// Strings provided as crate attributes in the CLI. - CliCrateAttr(u64), + CliCrateAttr(Hash64), /// Custom sources for explicit parser calls from plugins and drivers. Custom(String), DocTest(PathBuf, isize), /// Post-substitution inline assembly from LLVM. - InlineAsm(u64), + InlineAsm(Hash64), } impl From<PathBuf> for FileName { @@ -1044,17 +1044,26 @@ impl fmt::Debug for Span { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Use the global `SourceMap` to print the span. If that's not // available, fall back to printing the raw values. - with_session_globals(|session_globals| { - if let Some(source_map) = &*session_globals.source_map.borrow() { - write!(f, "{} ({:?})", source_map.span_to_diagnostic_string(*self), self.ctxt()) - } else { - f.debug_struct("Span") - .field("lo", &self.lo()) - .field("hi", &self.hi()) - .field("ctxt", &self.ctxt()) - .finish() - } - }) + + fn fallback(span: Span, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Span") + .field("lo", &span.lo()) + .field("hi", &span.hi()) + .field("ctxt", &span.ctxt()) + .finish() + } + + if SESSION_GLOBALS.is_set() { + with_session_globals(|session_globals| { + if let Some(source_map) = &*session_globals.source_map.borrow() { + write!(f, "{} ({:?})", source_map.span_to_diagnostic_string(*self), self.ctxt()) + } else { + fallback(*self, f) + } + }) + } else { + fallback(*self, f) + } } } @@ -1343,7 +1352,7 @@ pub struct SourceFile { /// Locations of characters removed during normalization. pub normalized_pos: Vec<NormalizedPos>, /// A hash of the filename, used for speeding up hashing in incremental compilation. - pub name_hash: u128, + pub name_hash: Hash128, /// Indicates which crate this `SourceFile` was imported from. pub cnum: CrateNum, } @@ -1472,7 +1481,7 @@ impl<D: Decoder> Decodable<D> for SourceFile { }; let multibyte_chars: Vec<MultiByteChar> = Decodable::decode(d); let non_narrow_chars: Vec<NonNarrowChar> = Decodable::decode(d); - let name_hash: u128 = Decodable::decode(d); + let name_hash = Decodable::decode(d); let normalized_pos: Vec<NormalizedPos> = Decodable::decode(d); let cnum: CrateNum = Decodable::decode(d); SourceFile { @@ -1514,7 +1523,7 @@ impl SourceFile { let name_hash = { let mut hasher: StableHasher = StableHasher::new(); name.hash(&mut hasher); - hasher.finish::<u128>() + hasher.finish() }; let end_pos = start_pos.to_usize() + src.len(); assert!(end_pos <= u32::MAX as usize); @@ -1663,10 +1672,11 @@ impl SourceFile { if let Some(ref src) = self.src { Some(Cow::from(get_until_newline(src, begin))) - } else if let Some(src) = self.external_src.borrow().get_source() { - Some(Cow::Owned(String::from(get_until_newline(src, begin)))) } else { - None + self.external_src + .borrow() + .get_source() + .map(|src| Cow::Owned(String::from(get_until_newline(src, begin)))) } } @@ -2159,9 +2169,7 @@ where }; Hash::hash(&TAG_VALID_SPAN, hasher); - // We truncate the stable ID hash and line and column numbers. The chances - // of causing a collision this way should be minimal. - Hash::hash(&(file.name_hash as u64), hasher); + Hash::hash(&file.name_hash, hasher); // Hash both the length and the end location (line/column) of a span. If we // hash only the length, for example, then two otherwise equal spans with diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 88e3674f899..1294a8b8e6b 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -13,7 +13,7 @@ pub use crate::hygiene::{ExpnData, ExpnKind}; pub use crate::*; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::stable_hasher::StableHasher; +use rustc_data_structures::stable_hasher::{Hash128, Hash64, StableHasher}; use rustc_data_structures::sync::{AtomicU32, Lrc, MappedReadGuard, ReadGuard, RwLock}; use std::cmp; use std::hash::Hash; @@ -138,7 +138,7 @@ impl FileLoader for RealFileLoader { pub struct StableSourceFileId { /// A hash of the source file's [`FileName`]. This is hash so that it's size /// is more predictable than if we included the actual [`FileName`] value. - pub file_name_hash: u64, + pub file_name_hash: Hash64, /// The [`CrateNum`] of the crate this source file was originally parsed for. /// We cannot include this information in the hash because at the time @@ -331,7 +331,7 @@ impl SourceMap { &self, filename: FileName, src_hash: SourceFileHash, - name_hash: u128, + name_hash: Hash128, source_len: usize, cnum: CrateNum, file_local_lines: Lock<SourceFileLines>, @@ -483,7 +483,7 @@ impl SourceMap { self.span_to_string(sp, FileNameDisplayPreference::Remapped) } - /// Format the span location suitable for pretty printing anotations with relative line numbers + /// Format the span location suitable for pretty printing annotations with relative line numbers pub fn span_to_relative_line_string(&self, sp: Span, relative_to: Span) -> String { if self.files.borrow().source_files.is_empty() || sp.is_dummy() || relative_to.is_dummy() { return "no-location".to_string(); @@ -777,7 +777,7 @@ impl SourceMap { /// Given a 'Span', tries to tell if it's wrapped by "<>" or "()" /// the algorithm searches if the next character is '>' or ')' after skipping white space - /// then searches the previous charactoer to match '<' or '(' after skipping white space + /// then searches the previous character to match '<' or '(' after skipping white space /// return true if wrapped by '<>' or '()' pub fn span_wrapped_by_angle_or_parentheses(&self, span: Span) -> bool { self.span_to_source(span, |src, start_index, end_index| { @@ -906,10 +906,8 @@ impl SourceMap { let snippet = if let Some(ref src) = local_begin.sf.src { Some(&src[start_index..]) - } else if let Some(src) = src.get_source() { - Some(&src[start_index..]) } else { - None + src.get_source().map(|src| &src[start_index..]) }; match snippet { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 6bfae377152..9891915d076 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -204,6 +204,7 @@ symbols! { HashSet, Hasher, Implied, + IndexOutput, Input, Into, IntoDiagnostic, @@ -1036,6 +1037,7 @@ symbols! { object_safe_for_dispatch, of, offset, + offset_of, omit_gdb_pretty_printer_section, on, on_unimplemented, @@ -1986,8 +1988,9 @@ impl Interner { name } - // Get the symbol as a string. `Symbol::as_str()` should be used in - // preference to this function. + /// 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[symbol.0.as_usize()] } diff --git a/compiler/rustc_span/src/tests.rs b/compiler/rustc_span/src/tests.rs index 5b3915c3338..a242ad6d1d7 100644 --- a/compiler/rustc_span/src/tests.rs +++ b/compiler/rustc_span/src/tests.rs @@ -3,8 +3,12 @@ use super::*; #[test] fn test_lookup_line() { let source = "abcdefghijklm\nabcdefghij\n...".to_owned(); - let sf = - SourceFile::new(FileName::Anon(0), source, BytePos(3), SourceFileHashAlgorithm::Sha256); + let sf = SourceFile::new( + FileName::Anon(Hash64::ZERO), + source, + BytePos(3), + SourceFileHashAlgorithm::Sha256, + ); sf.lines(|lines| assert_eq!(lines, &[BytePos(3), BytePos(17), BytePos(28)])); assert_eq!(sf.lookup_line(BytePos(0)), None); diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml index 4e447eab02e..052ef8bb94c 100644 --- a/compiler/rustc_symbol_mangling/Cargo.toml +++ b/compiler/rustc_symbol_mangling/Cargo.toml @@ -15,6 +15,7 @@ twox-hash = "1.6.3" rustc_span = { path = "../rustc_span" } rustc_middle = { path = "../rustc_middle" } rustc_hir = { path = "../rustc_hir" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_target = { path = "../rustc_target" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_session = { path = "../rustc_session" } diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 5cbca81926b..6a0ca06f69c 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -1,4 +1,4 @@ -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher}; use rustc_hir::def_id::CrateNum; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; use rustc_middle::ty::print::{PrettyPrinter, Print, Printer}; @@ -93,7 +93,7 @@ fn get_symbol_hash<'tcx>( item_type: Ty<'tcx>, instantiating_crate: Option<CrateNum>, -) -> u64 { +) -> Hash64 { let def_id = instance.def_id(); let substs = instance.substs; debug!("get_symbol_hash(def_id={:?}, parameters={:?})", def_id, substs); @@ -138,7 +138,7 @@ fn get_symbol_hash<'tcx>( }); // 64 bits should be enough to avoid collisions. - hasher.finish::<u64>() + hasher.finish::<Hash64>() }) } @@ -176,7 +176,7 @@ impl SymbolPath { } } - fn finish(mut self, hash: u64) -> String { + fn finish(mut self, hash: Hash64) -> String { self.finalize_pending_component(); // E = end name-sequence let _ = write!(self.result, "17h{hash:016x}E"); diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index c2fd3304f2b..c97406868b6 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -101,9 +101,9 @@ extern crate rustc_middle; extern crate tracing; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; +use rustc_fluent_macro::fluent_messages; use rustc_hir::def::DefKind; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; -use rustc_macros::fluent_messages; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::mir::mono::{InstantiationMode, MonoItem}; diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs index 1a679f32ca5..a9152b8113f 100644 --- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs +++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs @@ -406,7 +406,7 @@ fn encode_ty_name(tcx: TyCtxt<'_>, def_id: DefId) -> String { // Crate disambiguator and name s.push('C'); - s.push_str(&to_disambiguator(tcx.stable_crate_id(def_path.krate).to_u64())); + s.push_str(&to_disambiguator(tcx.stable_crate_id(def_path.krate).as_u64())); let crate_name = tcx.crate_name(def_path.krate).to_string(); let _ = write!(s, "{}{}", crate_name.len(), &crate_name); @@ -814,16 +814,10 @@ fn transform_substs<'tcx>( substs: SubstsRef<'tcx>, options: TransformTyOptions, ) -> SubstsRef<'tcx> { - let substs = substs.iter().map(|subst| { - if let GenericArgKind::Type(ty) = subst.unpack() { - if is_c_void_ty(tcx, ty) { - tcx.mk_unit().into() - } else { - transform_ty(tcx, ty, options).into() - } - } else { - subst - } + let substs = substs.iter().map(|subst| match subst.unpack() { + GenericArgKind::Type(ty) if is_c_void_ty(tcx, ty) => tcx.mk_unit().into(), + GenericArgKind::Type(ty) => transform_ty(tcx, ty, options).into(), + _ => subst, }); tcx.mk_substs_from_iter(substs) } diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index ee883285531..2235524129e 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -731,7 +731,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> { self.push("C"); let stable_crate_id = self.tcx.def_path_hash(cnum.as_def_id()).stable_crate_id(); - self.push_disambiguator(stable_crate_id.to_u64()); + self.push_disambiguator(stable_crate_id.as_u64()); let name = self.tcx.crate_name(cnum); self.push_ident(name.as_str()); Ok(self) diff --git a/compiler/rustc_target/src/abi/call/avr.rs b/compiler/rustc_target/src/abi/call/avr.rs index e20f01355a4..b01dac8c70d 100644 --- a/compiler/rustc_target/src/abi/call/avr.rs +++ b/compiler/rustc_target/src/abi/call/avr.rs @@ -10,7 +10,7 @@ //! > self-consistent and sensible LLVM IR generation, but does not //! > conform to any particular ABI. //! > -//! > - Doxygen Doxumentation of `clang::DefaultABIInfo` +//! > - Doxygen Documentation of `clang::DefaultABIInfo` //! //! This calling convention may not match AVR-GCC in all cases. //! diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index 8d2e92cc76c..589cd3cf96b 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -124,6 +124,21 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { { Ty::is_unit(self) } + + pub fn offset_of_subfield<C>(self, cx: &C, indices: impl Iterator<Item = usize>) -> Size + where + Ty: TyAbiInterface<'a, C>, + { + let mut layout = self; + let mut offset = Size::ZERO; + + for index in indices { + offset += layout.fields.offset(index); + layout = layout.field(cx, index); + } + + offset + } } impl<'a, Ty> TyAndLayout<'a, Ty> { diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs index 5c6dcc0aba9..4c7f64b2078 100644 --- a/compiler/rustc_target/src/spec/apple_base.rs +++ b/compiler/rustc_target/src/spec/apple_base.rs @@ -19,6 +19,7 @@ pub enum Arch { I386, I686, X86_64, + X86_64h, X86_64_sim, X86_64_macabi, Arm64_macabi, @@ -36,6 +37,7 @@ impl Arch { I386 => "i386", I686 => "i686", X86_64 | X86_64_sim | X86_64_macabi => "x86_64", + X86_64h => "x86_64h", } } @@ -44,13 +46,13 @@ impl Arch { Armv7 | Armv7k | Armv7s => "arm", Arm64 | Arm64_32 | Arm64_macabi | Arm64_sim => "aarch64", I386 | I686 => "x86", - X86_64 | X86_64_sim | X86_64_macabi => "x86_64", + X86_64 | X86_64_sim | X86_64_macabi | X86_64h => "x86_64", }) } fn target_abi(self) -> &'static str { match self { - Armv7 | Armv7k | Armv7s | Arm64 | Arm64_32 | I386 | I686 | X86_64 => "", + Armv7 | Armv7k | Armv7s | Arm64 | Arm64_32 | I386 | I686 | X86_64 | X86_64h => "", X86_64_macabi | Arm64_macabi => "macabi", // x86_64-apple-ios is a simulator target, even though it isn't // declared that way in the target like the other ones... @@ -67,6 +69,10 @@ impl Arch { Arm64_32 => "apple-s4", I386 | I686 => "yonah", X86_64 | X86_64_sim => "core2", + // Note: `core-avx2` is slightly more advanced than `x86_64h`, see + // comments (and disabled features) in `x86_64h_apple_darwin` for + // details. + X86_64h => "core-avx2", X86_64_macabi => "core2", Arm64_macabi => "apple-a12", Arm64_sim => "apple-a12", @@ -182,8 +188,13 @@ fn deployment_target(var_name: &str) -> Option<(u32, u32)> { } fn macos_default_deployment_target(arch: Arch) -> (u32, u32) { - // Note: Arm64_sim is not included since macOS has no simulator. - if matches!(arch, Arm64 | Arm64_macabi) { (11, 0) } else { (10, 7) } + match arch { + // Note: Arm64_sim is not included since macOS has no simulator. + Arm64 | Arm64_macabi => (11, 0), + // x86_64h-apple-darwin only supports macOS 10.8 and later + X86_64h => (10, 8), + _ => (10, 7), + } } fn macos_deployment_target(arch: Arch) -> (u32, u32) { @@ -227,7 +238,7 @@ fn link_env_remove(arch: Arch, os: &'static str) -> StaticCow<[StaticCow<str>]> // of the linking environment that's wrong and reversed. match arch { Armv7 | Armv7k | Armv7s | Arm64 | Arm64_32 | I386 | I686 | X86_64 | X86_64_sim - | Arm64_sim => { + | X86_64h | Arm64_sim => { cvs!["MACOSX_DEPLOYMENT_TARGET"] } X86_64_macabi | Arm64_macabi => cvs!["IPHONEOS_DEPLOYMENT_TARGET"], diff --git a/compiler/rustc_target/src/spec/m68k_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/m68k_unknown_linux_gnu.rs index ebd74012dcd..9bcd56bed00 100644 --- a/compiler/rustc_target/src/spec/m68k_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/m68k_unknown_linux_gnu.rs @@ -3,6 +3,7 @@ use crate::spec::{Target, TargetOptions}; pub fn target() -> Target { let mut base = super::linux_gnu_base::opts(); + base.cpu = "M68020".into(); base.max_atomic_width = Some(32); Target { diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 4e5a821f0f6..10d38c34919 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1112,6 +1112,7 @@ supported_targets! { ("aarch64-apple-darwin", aarch64_apple_darwin), ("x86_64-apple-darwin", x86_64_apple_darwin), + ("x86_64h-apple-darwin", x86_64h_apple_darwin), ("i686-apple-darwin", i686_apple_darwin), // FIXME(#106649): Remove aarch64-fuchsia in favor of aarch64-unknown-fuchsia @@ -2285,13 +2286,13 @@ impl Target { } } } ); - ($key_name:ident, falliable_list) => ( { + ($key_name:ident, fallible_list) => ( { let name = (stringify!($key_name)).replace("_", "-"); obj.remove(&name).and_then(|j| { if let Some(v) = j.as_array() { match v.iter().map(|a| FromStr::from_str(a.as_str().unwrap())).collect() { Ok(l) => { base.$key_name = l }, - // FIXME: `falliable_list` can't re-use the `key!` macro for list + // FIXME: `fallible_list` can't re-use the `key!` macro for list // elements and the error messages from that macro, so it has a bad // generic message instead Err(_) => return Some(Err( @@ -2610,7 +2611,7 @@ impl Target { key!(has_thumb_interworking, bool); key!(debuginfo_kind, DebuginfoKind)?; key!(split_debuginfo, SplitDebuginfo)?; - key!(supported_split_debuginfo, falliable_list)?; + key!(supported_split_debuginfo, fallible_list)?; key!(supported_sanitizers, SanitizerSet)?; key!(default_adjusted_cabi, Option<Abi>)?; key!(generate_arange_section, bool); diff --git a/compiler/rustc_target/src/spec/thumb_base.rs b/compiler/rustc_target/src/spec/thumb_base.rs index 4dcf47fe465..2220b9326c9 100644 --- a/compiler/rustc_target/src/spec/thumb_base.rs +++ b/compiler/rustc_target/src/spec/thumb_base.rs @@ -12,7 +12,7 @@ // // We have opted for these instead of one target per processor (e.g., `cortex-m0`, `cortex-m3`, // etc) because the differences between some processors like the cortex-m0 and cortex-m1 are almost -// non-existent from the POV of codegen so it doesn't make sense to have separate targets for them. +// nonexistent from the POV of codegen so it doesn't make sense to have separate targets for them. // And if differences exist between two processors under the same target, rustc flags can be used to // optimize for one processor or the other. // diff --git a/compiler/rustc_target/src/spec/x86_64h_apple_darwin.rs b/compiler/rustc_target/src/spec/x86_64h_apple_darwin.rs new file mode 100644 index 00000000000..54f7490b2c0 --- /dev/null +++ b/compiler/rustc_target/src/spec/x86_64h_apple_darwin.rs @@ -0,0 +1,44 @@ +use super::apple_base::{macos_llvm_target, opts, Arch}; +use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, SanitizerSet}; +use crate::spec::{StackProbeType, Target, TargetOptions}; + +pub fn target() -> Target { + let arch = Arch::X86_64h; + let mut base = opts("macos", arch); + base.max_atomic_width = Some(128); + base.frame_pointer = FramePointer::Always; + base.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-m64"]); + base.stack_probes = StackProbeType::X86; + base.supported_sanitizers = + SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::LEAK | SanitizerSet::THREAD; + + // x86_64h is core2-avx without a few of the features which would otherwise + // be guaranteed, so we need to disable those. This imitates clang's logic: + // - https://github.com/llvm/llvm-project/blob/bd1f7c417/clang/lib/Driver/ToolChains/Arch/X86.cpp#L77-L78 + // - https://github.com/llvm/llvm-project/blob/bd1f7c417/clang/lib/Driver/ToolChains/Arch/X86.cpp#L133-L141 + // + // FIXME: Sadly, turning these off here disables them in such a way that they + // aren't re-enabled by `-Ctarget-cpu=native` (on a machine that has them). + // It would be nice if this were not the case, but fixing it seems tricky + // (and given that the main use-case for this target is for use in universal + // binaries, probably not that important). + base.features = "-rdrnd,-aes,-pclmul,-rtm,-fsgsbase".into(); + // Double-check that the `cpu` is what we expect (if it's not the list above + // may need updating). + assert_eq!( + base.cpu, "core-avx2", + "you need to adjust the feature list in x86_64h-apple-darwin if you change this", + ); + + Target { + // Clang automatically chooses a more specific target based on + // MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work + // correctly, we do too. + llvm_target: macos_llvm_target(arch).into(), + pointer_width: 64, + data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + .into(), + arch: arch.target_arch(), + options: TargetOptions { mcount: "\u{1}mcount".into(), ..base }, + } +} diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index d3eba43b47e..a81459317be 100644 --- a/compiler/rustc_trait_selection/Cargo.toml +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -14,6 +14,7 @@ rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_hir = { path = "../rustc_hir" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_index = { path = "../rustc_index" } rustc_infer = { path = "../rustc_infer" } rustc_macros = { path = "../rustc_macros" } diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index f866cb016e2..ed3994be987 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -37,7 +37,7 @@ extern crate rustc_middle; extern crate smallvec; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; -use rustc_macros::fluent_messages; +use rustc_fluent_macro::fluent_messages; pub mod errors; pub mod infer; diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 10d817f75ac..bacb0e32efc 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -51,7 +51,7 @@ pub(super) enum CandidateSource { BuiltinImpl, /// An assumption from the environment. /// - /// More precicely we've used the `n-th` assumption in the `param_env`. + /// More precisely we've used the `n-th` assumption in the `param_env`. /// /// ## Examples /// @@ -241,7 +241,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // HACK: `_: Trait` is ambiguous, because it may be satisfied via a builtin rule, // object bound, alias bound, etc. We are unable to determine this until we can at - // least structually resolve the type one layer. + // least structurally resolve the type one layer. if goal.predicate.self_ty().is_ty_var() { return vec![Candidate { source: CandidateSource::BuiltinImpl, diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index c29b5b04e00..bd52957d162 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -57,6 +57,14 @@ pub struct EvalCtxt<'a, 'tcx> { pub(super) search_graph: &'a mut SearchGraph<'tcx>, pub(super) nested_goals: NestedGoals<'tcx>, + + // Has this `EvalCtxt` errored out with `NoSolution` in `try_evaluate_added_goals`? + // + // If so, then it can no longer be used to make a canonical query response, + // since subsequent calls to `try_evaluate_added_goals` have possibly dropped + // ambiguous goals. Instead, a probe needs to be introduced somewhere in the + // evaluation code. + tainted: Result<(), NoSolution>, } #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -121,6 +129,7 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { max_input_universe: ty::UniverseIndex::ROOT, var_values: CanonicalVarValues::dummy(), nested_goals: NestedGoals::new(), + tainted: Ok(()), }; let result = ecx.evaluate_goal(IsNormalizesToHack::No, goal); @@ -172,6 +181,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { max_input_universe: canonical_goal.max_universe, search_graph, nested_goals: NestedGoals::new(), + tainted: Ok(()), }; ecx.compute_goal(goal) }) @@ -391,6 +401,10 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { }, ); + if response.is_err() { + self.tainted = Err(NoSolution); + } + self.nested_goals = goals; response } @@ -404,6 +418,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { max_input_universe: self.max_input_universe, search_graph: self.search_graph, nested_goals: self.nested_goals.clone(), + tainted: self.tainted, }; self.infcx.probe(|_| f(&mut ecx)) } @@ -649,7 +664,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // FIXME(transmutability): This really should be returning nested goals for `Answer::If*` match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable( ObligationCause::dummy(), - ty::Binder::dummy(src_and_dst), + src_and_dst, scope, assume, ) { diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs index ada868705c7..2dea36811d8 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -11,12 +11,13 @@ use super::{CanonicalGoal, Certainty, EvalCtxt, Goal}; use crate::solve::canonicalize::{CanonicalizeMode, Canonicalizer}; use crate::solve::{CanonicalResponse, QueryResult, Response}; +use rustc_index::vec::IndexVec; use rustc_infer::infer::canonical::query_response::make_query_region_constraints; use rustc_infer::infer::canonical::CanonicalVarValues; use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints}; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::{ExternalConstraints, ExternalConstraintsData}; -use rustc_middle::ty::{self, GenericArgKind}; +use rustc_middle::ty::{self, BoundVar, GenericArgKind}; use rustc_span::DUMMY_SP; use std::iter; use std::ops::Deref; @@ -50,6 +51,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { certainty: Certainty, ) -> QueryResult<'tcx> { let goals_certainty = self.try_evaluate_added_goals()?; + assert_eq!( + self.tainted, + Ok(()), + "EvalCtxt is tainted -- nested goals may have been dropped in a \ + previous call to `try_evaluate_added_goals!`" + ); + let certainty = certainty.unify_with(goals_certainty); let external_constraints = self.compute_external_query_constraints()?; @@ -139,25 +147,25 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // // We therefore instantiate the existential variable in the canonical response with the // inference variable of the input right away, which is more performant. - let mut opt_values = vec![None; response.variables.len()]; + let mut opt_values = IndexVec::from_elem_n(None, response.variables.len()); for (original_value, result_value) in iter::zip(original_values, var_values.var_values) { match result_value.unpack() { GenericArgKind::Type(t) => { if let &ty::Bound(debruijn, b) = t.kind() { assert_eq!(debruijn, ty::INNERMOST); - opt_values[b.var.index()] = Some(*original_value); + opt_values[b.var] = Some(*original_value); } } GenericArgKind::Lifetime(r) => { if let ty::ReLateBound(debruijn, br) = *r { assert_eq!(debruijn, ty::INNERMOST); - opt_values[br.var.index()] = Some(*original_value); + opt_values[br.var] = Some(*original_value); } } GenericArgKind::Const(c) => { - if let ty::ConstKind::Bound(debrujin, b) = c.kind() { - assert_eq!(debrujin, ty::INNERMOST); - opt_values[b.index()] = Some(*original_value); + if let ty::ConstKind::Bound(debruijn, b) = c.kind() { + assert_eq!(debruijn, ty::INNERMOST); + opt_values[b] = Some(*original_value); } } } @@ -176,11 +184,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // As an optimization we sometimes avoid creating a new inference variable here. // // All new inference variables we create start out in the current universe of the caller. - // This is conceptionally wrong as these inference variables would be able to name + // This is conceptually wrong as these inference variables would be able to name // more placeholders then they should be able to. However the inference variables have // to "come from somewhere", so by equating them with the original values of the caller // later on, we pull them down into their correct universe again. - if let Some(v) = opt_values[index] { + if let Some(v) = opt_values[BoundVar::from_usize(index)] { v } else { self.infcx.instantiate_canonical_var(DUMMY_SP, info, |_| prev_universe) diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 14cb43b89c3..3a2acbeb32e 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -198,7 +198,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { let term: ty::EarlyBinder<ty::Term<'tcx>> = if is_const { let identity_substs = ty::InternalSubsts::identity_for_item(tcx, assoc_def.item.def_id); - let did = ty::WithOptConstParam::unknown(assoc_def.item.def_id); + let did = assoc_def.item.def_id; let kind = ty::ConstKind::Unevaluated(ty::UnevaluatedConst::new(did, identity_substs)); ty.map_bound(|ty| tcx.mk_const(kind, ty).into()) diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index abd11a15ac2..1abcc80d01a 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -591,7 +591,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { Some(self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)) } - // These types cannot be structurally decomposed into constitutent + // These types cannot be structurally decomposed into constituent // types, and therefore have no built-in auto impl. ty::Dynamic(..) | ty::Param(..) diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 182d995c4eb..222af4c2ace 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -796,10 +796,9 @@ impl<'tcx> AutoTraitFinder<'tcx> { Ok(Some(valtree)) => Ok(selcx.tcx().mk_const(valtree, c.ty())), Ok(None) => { let tcx = self.tcx; - let def_id = unevaluated.def.did; let reported = tcx.sess.emit_err(UnableToConstructConstantValue { - span: tcx.def_span(def_id), + span: tcx.def_span(unevaluated.def), unevaluated: unevaluated, }); Err(ErrorHandled::Reported(reported)) diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 345e84990ed..9d99d30d45c 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -44,7 +44,7 @@ pub fn is_const_evaluatable<'tcx>( let ct = tcx.expand_abstract_consts(unexpanded_ct); let is_anon_ct = if let ty::ConstKind::Unevaluated(uv) = ct.kind() { - tcx.def_kind(uv.def.did) == DefKind::AnonConst + tcx.def_kind(uv.def) == DefKind::AnonConst } else { false }; @@ -119,7 +119,7 @@ pub fn is_const_evaluatable<'tcx>( tcx.sess .struct_span_fatal( // Slightly better span than just using `span` alone - if span == rustc_span::DUMMY_SP { tcx.def_span(uv.def.did) } else { span }, + if span == rustc_span::DUMMY_SP { tcx.def_span(uv.def) } else { span }, "failed to evaluate generic const expression", ) .note("the crate this constant originates from uses `#![feature(generic_const_exprs)]`") diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 1b741b7302b..ae21dcd2a36 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -467,7 +467,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } - self.tcx.sess.delay_span_bug(DUMMY_SP, "expected fullfillment errors") + self.tcx.sess.delay_span_bug(DUMMY_SP, "expected fulfillment errors") } /// Reports that an overflow has occurred and halts compilation. We @@ -742,7 +742,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { { // Recompute the safe transmute reason and use that for the error reporting self.get_safe_transmute_error_and_reason( - trait_predicate, obligation.clone(), trait_ref, span, @@ -1477,7 +1476,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { }; let mut err = self.tcx.sess.struct_span_err(span, "unconstrained generic constant"); - let const_span = self.tcx.def_span(uv.def.did); + let const_span = self.tcx.def_span(uv.def); match self.tcx.sess.source_map().span_to_snippet(const_span) { Ok(snippet) => err.help(&format!( "try adding a `where` bound using this expression: `where [(); {}]:`", @@ -1629,7 +1628,6 @@ trait InferCtxtPrivExt<'tcx> { fn get_safe_transmute_error_and_reason( &self, - trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>, obligation: Obligation<'tcx, ty::Predicate<'tcx>>, trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, span: Span, @@ -1773,7 +1771,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { .tcx .mk_const( ty::UnevaluatedConst { - def: ty::WithOptConstParam::unknown(data.projection_ty.def_id), + def: data.projection_ty.def_id, substs: data.projection_ty.substs, }, ct.ty(), @@ -2058,7 +2056,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if candidates.iter().any(|c| matches!(c.similarity, CandidateSimilarity::Exact { .. })) { // If any of the candidates is a perfect match, we don't want to show all of them. // This is particularly relevant for the case of numeric types (as they all have the - // same cathegory). + // same category). candidates.retain(|c| matches!(c.similarity, CandidateSimilarity::Exact { .. })); } candidates @@ -2921,18 +2919,20 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn get_safe_transmute_error_and_reason( &self, - trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>, obligation: Obligation<'tcx, ty::Predicate<'tcx>>, trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, span: Span, ) -> (String, Option<String>) { - let src_and_dst = trait_predicate.map_bound(|p| rustc_transmute::Types { - dst: p.trait_ref.substs.type_at(0), - src: p.trait_ref.substs.type_at(1), - }); - let scope = trait_ref.skip_binder().substs.type_at(2); + // Erase regions because layout code doesn't particularly care about regions. + let trait_ref = self.tcx.erase_regions(self.tcx.erase_late_bound_regions(trait_ref)); + + let src_and_dst = rustc_transmute::Types { + dst: trait_ref.substs.type_at(0), + src: trait_ref.substs.type_at(1), + }; + let scope = trait_ref.substs.type_at(2); let Some(assume) = - rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, trait_ref.skip_binder().substs.const_at(3)) else { + rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, trait_ref.substs.const_at(3)) else { span_bug!(span, "Unable to construct rustc_transmute::Assume where it was previously possible"); }; match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable( @@ -2942,24 +2942,27 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { assume, ) { rustc_transmute::Answer::No(reason) => { - let dst = trait_ref.skip_binder().substs.type_at(0); - let src = trait_ref.skip_binder().substs.type_at(1); - let custom_err_msg = format!("`{src}` cannot be safely transmuted into `{dst}` in the defining scope of `{scope}`").to_string(); + let dst = trait_ref.substs.type_at(0); + let src = trait_ref.substs.type_at(1); + let custom_err_msg = format!( + "`{src}` cannot be safely transmuted into `{dst}` in the defining scope of `{scope}`" + ); let reason_msg = match reason { rustc_transmute::Reason::SrcIsUnspecified => { - format!("`{src}` does not have a well-specified layout").to_string() + format!("`{src}` does not have a well-specified layout") } + rustc_transmute::Reason::DstIsUnspecified => { - format!("`{dst}` does not have a well-specified layout").to_string() + format!("`{dst}` does not have a well-specified layout") } + rustc_transmute::Reason::DstIsBitIncompatible => { format!("At least one value of `{src}` isn't a bit-valid value of `{dst}`") - .to_string() } + rustc_transmute::Reason::DstIsPrivate => format!( "`{dst}` is or contains a type or field that is not visible in that scope" - ) - .to_string(), + ), // FIXME(bryangarza): Include the number of bytes of src and dst rustc_transmute::Reason::DstIsTooBig => { format!("The size of `{src}` is smaller than the size of `{dst}`") diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index fb75ec76729..73207f183a1 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1381,7 +1381,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } - // Issue #104961, we need to add parentheses properly for compond expressions + // Issue #104961, we need to add parentheses properly for compound expressions // for example, `x.starts_with("hi".to_string() + "you")` // should be `x.starts_with(&("hi".to_string() + "you"))` let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) else { return false; }; diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 26cadab3e9f..43196d1e629 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -540,8 +540,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { use ty::ConstKind::Unevaluated; match (c1.kind(), c2.kind()) { (Unevaluated(a), Unevaluated(b)) - if a.def.did == b.def.did - && tcx.def_kind(a.def.did) == DefKind::AssocConst => + if a.def == b.def && tcx.def_kind(a.def) == DefKind::AssocConst => { if let Ok(new_obligations) = infcx .at(&obligation.cause, obligation.param_env) diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index af567c07438..63949843aed 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -14,7 +14,7 @@ use rustc_span::DUMMY_SP; use super::outlives_bounds::InferCtxtExt; pub enum CopyImplementationError<'tcx> { - InfrigingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>), + InfringingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>), NotAnAdt, HasDestructor, } @@ -125,7 +125,7 @@ pub fn type_allowed_to_implement_copy<'tcx>( } if !infringing.is_empty() { - return Err(CopyImplementationError::InfrigingFields(infringing)); + return Err(CopyImplementationError::InfringingFields(infringing)); } if adt.has_dtor(tcx) { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 8a203dec86b..4c9df5d9d0a 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -203,7 +203,7 @@ fn do_normalize_predicates<'tcx>( } }; - debug!("do_normalize_predictes: normalized predicates = {:?}", predicates); + debug!("do_normalize_predicates: normalized predicates = {:?}", predicates); // We can use the `elaborated_env` here; the region code only // cares about declarations like `'a: 'b`. @@ -450,7 +450,7 @@ fn is_impossible_method(tcx: TyCtxt<'_>, (impl_def_id, trait_item_def_id): (DefI { return ControlFlow::Break(()); } - r.super_visit_with(self) + ControlFlow::Continue(()) } fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { if let ty::ConstKind::Param(param) = ct.kind() diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index cff3d277a78..e01a57ea4fe 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -55,7 +55,18 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> { ) -> Vec<OutlivesBound<'tcx>> { let ty = self.resolve_vars_if_possible(ty); let ty = OpportunisticRegionResolver::new(self).fold_ty(ty); - assert!(!ty.needs_infer()); + + // We do not expect existential variables in implied bounds. + // We may however encounter unconstrained lifetime variables in invalid + // code. See #110161 for context. + assert!(!ty.has_non_region_infer()); + if ty.needs_infer() { + self.tcx.sess.delay_span_bug( + self.tcx.def_span(body_id), + "skipped implied_outlives_bounds due to unconstrained lifetimes", + ); + return vec![]; + } let span = self.tcx.def_span(body_id); let result = param_env diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 826fc63ca06..6ba05387173 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -2131,9 +2131,8 @@ fn confirm_impl_candidate<'cx, 'tcx>( let ty = tcx.type_of(assoc_ty.item.def_id); let is_const = matches!(tcx.def_kind(assoc_ty.item.def_id), DefKind::AssocConst); let term: ty::EarlyBinder<ty::Term<'tcx>> = if is_const { - let identity_substs = - crate::traits::InternalSubsts::identity_for_item(tcx, assoc_ty.item.def_id); - let did = ty::WithOptConstParam::unknown(assoc_ty.item.def_id); + let did = assoc_ty.item.def_id; + let identity_substs = crate::traits::InternalSubsts::identity_for_item(tcx, did); let kind = ty::ConstKind::Unevaluated(ty::UnevaluatedConst::new(did, identity_substs)); ty.map_bound(|ty| tcx.mk_const(kind, ty).into()) } else { @@ -2277,11 +2276,10 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>( obligation.param_env, cause.clone(), obligation.recursion_depth + 1, - tcx.bound_return_position_impl_trait_in_trait_tys(impl_fn_def_id) - .map_bound(|tys| { - tys.map_or_else(|guar| tcx.ty_error(guar), |tys| tys[&obligation.predicate.def_id]) - }) - .subst(tcx, impl_fn_substs), + tcx.collect_return_position_impl_trait_in_trait_tys(impl_fn_def_id).map_or_else( + |guar| tcx.ty_error(guar), + |tys| tys[&obligation.predicate.def_id].subst(tcx, impl_fn_substs), + ), &mut obligations, ); diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs index b63da28e274..baa2fbb6751 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs @@ -32,14 +32,8 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> { fn perform_query( tcx: TyCtxt<'tcx>, - mut canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>, + canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>, ) -> Fallible<CanonicalQueryResponse<'tcx, ()>> { - match canonicalized.value.value.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => { - canonicalized.value.param_env.remap_constness_with(pred.constness); - } - _ => canonicalized.value.param_env = canonicalized.value.param_env.without_const(), - } tcx.type_op_prove_predicate(canonicalized) } } diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 1f5bbc178f7..a019d00461b 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -775,7 +775,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, ) { - if obligation.has_non_region_param() { + if obligation.predicate.has_non_region_param() { return; } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 5e60bc01bb6..3bba11262f5 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -275,33 +275,35 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> Result<ImplSourceBuiltinData<PredicateObligation<'tcx>>, SelectionError<'tcx>> { debug!(?obligation, "confirm_transmutability_candidate"); - let predicate = obligation.predicate; - - let type_at = |i| predicate.map_bound(|p| p.trait_ref.substs.type_at(i)); - let const_at = |i| predicate.skip_binder().trait_ref.substs.const_at(i); - - let src_and_dst = predicate.map_bound(|p| rustc_transmute::Types { - dst: p.trait_ref.substs.type_at(0), - src: p.trait_ref.substs.type_at(1), - }); - - let scope = type_at(2).skip_binder(); - - let Some(assume) = - rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, const_at(3)) else { - return Err(Unimplemented); - }; - - let cause = obligation.cause.clone(); + // We erase regions here because transmutability calls layout queries, + // which does not handle inference regions and doesn't particularly + // care about other regions. Erasing late-bound regions is equivalent + // to instantiating the binder with placeholders then erasing those + // placeholder regions. + let predicate = + self.tcx().erase_regions(self.tcx().erase_late_bound_regions(obligation.predicate)); + + let Some(assume) = rustc_transmute::Assume::from_const( + self.infcx.tcx, + obligation.param_env, + predicate.trait_ref.substs.const_at(3) + ) else { + return Err(Unimplemented); + }; let mut transmute_env = rustc_transmute::TransmuteTypeEnv::new(self.infcx); - - let maybe_transmutable = transmute_env.is_transmutable(cause, src_and_dst, scope, assume); - - use rustc_transmute::Answer; + let maybe_transmutable = transmute_env.is_transmutable( + obligation.cause.clone(), + rustc_transmute::Types { + dst: predicate.trait_ref.substs.type_at(0), + src: predicate.trait_ref.substs.type_at(1), + }, + predicate.trait_ref.substs.type_at(2), + assume, + ); match maybe_transmutable { - Answer::Yes => Ok(ImplSourceBuiltinData { nested: vec![] }), + rustc_transmute::Answer::Yes => Ok(ImplSourceBuiltinData { nested: vec![] }), _ => Err(Unimplemented), } } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 6bb53418bea..081e4d7cfa4 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -888,7 +888,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let c1 = tcx.expand_abstract_consts(c1); let c2 = tcx.expand_abstract_consts(c2); debug!( - "evalaute_predicate_recursively: equating consts:\nc1= {:?}\nc2= {:?}", + "evaluate_predicate_recursively: equating consts:\nc1= {:?}\nc2= {:?}", c1, c2 ); @@ -896,8 +896,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { use ty::ConstKind::Unevaluated; match (c1.kind(), c2.kind()) { (Unevaluated(a), Unevaluated(b)) - if a.def.did == b.def.did - && tcx.def_kind(a.def.did) == DefKind::AssocConst => + if a.def == b.def && tcx.def_kind(a.def) == DefKind::AssocConst => { if let Ok(InferOk { obligations, value: () }) = self .infcx diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 20357d4d250..7792ceabe7e 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -243,16 +243,11 @@ pub fn get_vtable_index_of_object_method<'tcx, N>( ) -> Option<usize> { // Count number of methods preceding the one we are selecting and // add them to the total offset. - if let Some(index) = tcx - .own_existential_vtable_entries(object.upcast_trait_ref.def_id()) + tcx.own_existential_vtable_entries(object.upcast_trait_ref.def_id()) .iter() .copied() .position(|def_id| def_id == method_def_id) - { - Some(object.vtable_base + index) - } else { - None - } + .map(|index| object.vtable_base + index) } pub fn closure_trait_ref_and_return_type<'tcx>( diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 3d026506a5a..40e19abc0d0 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -170,29 +170,20 @@ pub fn predicate_obligations<'tcx>( ty::PredicateKind::WellFormed(arg) => { wf.compute(arg); } - ty::PredicateKind::ObjectSafe(_) => {} - ty::PredicateKind::ClosureKind(..) => {} - ty::PredicateKind::Subtype(ty::SubtypePredicate { a, b, a_is_expected: _ }) => { - wf.compute(a.into()); - wf.compute(b.into()); - } - ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => { - wf.compute(a.into()); - wf.compute(b.into()); - } + ty::PredicateKind::ConstEvaluatable(ct) => { wf.compute(ct.into()); } - ty::PredicateKind::ConstEquate(c1, c2) => { - wf.compute(c1.into()); - wf.compute(c2.into()); - } - ty::PredicateKind::Ambiguous => {} - ty::PredicateKind::TypeWellFormedFromEnv(..) => { - bug!("TypeWellFormedFromEnv is only used for Chalk") - } - ty::PredicateKind::AliasRelate(..) => { - bug!("We should only wf check where clauses and `AliasRelate` is not a `Clause`") + + ty::PredicateKind::ObjectSafe(_) + | ty::PredicateKind::ClosureKind(..) + | ty::PredicateKind::Subtype(..) + | ty::PredicateKind::Coerce(..) + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::Ambiguous + | ty::PredicateKind::AliasRelate(..) + | ty::PredicateKind::TypeWellFormedFromEnv(..) => { + bug!("We should only wf check where clauses, unexpected predicate: {predicate:?}") } } @@ -487,7 +478,7 @@ impl<'tcx> WfPredicates<'tcx> { match ct.kind() { ty::ConstKind::Unevaluated(uv) => { if !ct.has_escaping_bound_vars() { - let obligations = self.nominal_obligations(uv.def.did, uv.substs); + let obligations = self.nominal_obligations(uv.def, uv.substs); self.out.extend(obligations); let predicate = diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 2be72879b7b..4d225e36b22 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -60,6 +60,20 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Substitution<RustInterner<'tcx>>> for Subst } } +impl<'tcx> LowerInto<'tcx, chalk_ir::Substitution<RustInterner<'tcx>>> + for &'tcx ty::List<Ty<'tcx>> +{ + fn lower_into( + self, + interner: RustInterner<'tcx>, + ) -> chalk_ir::Substitution<RustInterner<'tcx>> { + chalk_ir::Substitution::from_iter( + interner, + self.iter().map(|ty| GenericArg::from(ty).lower_into(interner)), + ) + } +} + impl<'tcx> LowerInto<'tcx, SubstsRef<'tcx>> for &chalk_ir::Substitution<RustInterner<'tcx>> { fn lower_into(self, interner: RustInterner<'tcx>) -> SubstsRef<'tcx> { interner @@ -351,9 +365,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> for Ty<'tcx> { ty::GeneratorWitness(_) => unimplemented!(), ty::GeneratorWitnessMIR(..) => unimplemented!(), ty::Never => chalk_ir::TyKind::Never, - ty::Tuple(types) => { - chalk_ir::TyKind::Tuple(types.len(), types.as_substs().lower_into(interner)) - } + ty::Tuple(types) => chalk_ir::TyKind::Tuple(types.len(), types.lower_into(interner)), ty::Alias(ty::Projection, ty::AliasTy { def_id, substs, .. }) => { chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy { associated_ty_id: chalk_ir::AssocTypeId(def_id), @@ -435,7 +447,7 @@ impl<'tcx> LowerInto<'tcx, Ty<'tcx>> for &chalk_ir::Ty<RustInterner<'tcx>> { TyKind::GeneratorWitness(..) => unimplemented!(), TyKind::Never => ty::Never, TyKind::Tuple(_len, substitution) => { - ty::Tuple(substitution.lower_into(interner).try_as_type_list().unwrap()) + ty::Tuple(substitution.lower_into(interner).into_type_list(interner.tcx)) } TyKind::Slice(ty) => ty::Slice(ty.lower_into(interner)), TyKind::Raw(mutbl, ty) => ty::RawPtr(ty::TypeAndMut { @@ -998,7 +1010,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for BoundVarsCollector<'tcx> { _ => (), }; - r.super_visit_with(self) + ControlFlow::Continue(()) } } @@ -1048,7 +1060,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for NamedBoundVarSubstitutor<'a, 'tcx> { _ => (), }; - r.super_fold_with(self) + r } } @@ -1142,7 +1154,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ParamsSubstitutor<'tcx> { } }, - _ => r.super_fold_with(self), + _ => r, } } } @@ -1223,6 +1235,6 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for PlaceholdersCollector { _ => (), }; - r.super_visit_with(self) + ControlFlow::Continue(()) } } diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs index e0fd487b3d3..19622112f2a 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -89,6 +89,7 @@ fn relate_mir_and_user_substs<'tcx>( def_id: hir::def_id::DefId, user_substs: UserSubsts<'tcx>, ) -> Result<(), NoSolution> { + let param_env = param_env.without_const(); let UserSubsts { user_self_ty, substs } = user_substs; let tcx = ocx.infcx.tcx; let cause = ObligationCause::dummy_with_span(span); diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index 2a89494c80b..a6d88b1342a 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -196,7 +196,7 @@ pub(crate) mod rustc { fn from(err: LayoutError<'tcx>) -> Self { match err { LayoutError::Unknown(..) => Self::Unknown, - err @ _ => unimplemented!("{:?}", err), + err => unimplemented!("{:?}", err), } } } diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index a93a42987ed..8be02c1d988 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -64,7 +64,6 @@ mod rustc { use rustc_infer::infer::InferCtxt; use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::traits::ObligationCause; - use rustc_middle::ty::Binder; use rustc_middle::ty::Const; use rustc_middle::ty::ParamEnv; use rustc_middle::ty::Ty; @@ -92,15 +91,13 @@ mod rustc { pub fn is_transmutable( &mut self, cause: ObligationCause<'tcx>, - src_and_dst: Binder<'tcx, Types<'tcx>>, + types: Types<'tcx>, scope: Ty<'tcx>, assume: crate::Assume, ) -> crate::Answer<crate::layout::rustc::Ref<'tcx>> { - let src = src_and_dst.map_bound(|types| types.src).skip_binder(); - let dst = src_and_dst.map_bound(|types| types.dst).skip_binder(); crate::maybe_transmutable::MaybeTransmutableQuery::new( - src, - dst, + types.src, + types.dst, scope, assume, self.infcx.tcx, diff --git a/compiler/rustc_ty_utils/Cargo.toml b/compiler/rustc_ty_utils/Cargo.toml index 52fbd3ae047..51885c9b47e 100644 --- a/compiler/rustc_ty_utils/Cargo.toml +++ b/compiler/rustc_ty_utils/Cargo.toml @@ -9,6 +9,7 @@ rustc_middle = { path = "../rustc_middle" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_hir = { path = "../rustc_hir" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_infer = { path = "../rustc_infer" } rustc_macros = { path = "../rustc_macros" } rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index b67607a4db6..b08a92570ed 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -132,7 +132,7 @@ fn recurse_build<'tcx>( tcx.mk_const(val, node.ty) } &ExprKind::NamedConst { def_id, substs, user_ty: _ } => { - let uneval = ty::UnevaluatedConst::new(ty::WithOptConstParam::unknown(def_id), substs); + let uneval = ty::UnevaluatedConst::new(def_id, substs); tcx.mk_const(uneval, node.ty) } ExprKind::ConstParam { param, .. } => tcx.mk_const(*param, node.ty), @@ -256,6 +256,7 @@ fn recurse_build<'tcx>( ExprKind::VarRef { .. } | ExprKind::UpvarRef { .. } | ExprKind::StaticRef { .. } + | ExprKind::OffsetOf { .. } | ExprKind::ThreadLocalRef(_) => { error(GenericConstantTooComplexSub::OperationNotSupported(node.span))? } @@ -347,6 +348,7 @@ impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> { | thir::ExprKind::ZstLiteral { .. } | thir::ExprKind::StaticRef { .. } | thir::ExprKind::InlineAsm(_) + | thir::ExprKind::OffsetOf { .. } | thir::ExprKind::ThreadLocalRef(_) | thir::ExprKind::Yield { .. } => false, } @@ -391,52 +393,36 @@ impl<'a, 'tcx> visit::Visitor<'a, 'tcx> for IsThirPolymorphic<'a, 'tcx> { /// Builds an abstract const, do not use this directly, but use `AbstractConst::new` instead. pub fn thir_abstract_const( tcx: TyCtxt<'_>, - def: ty::WithOptConstParam<LocalDefId>, + def: LocalDefId, ) -> Result<Option<ty::Const<'_>>, ErrorGuaranteed> { - if tcx.features().generic_const_exprs { - match tcx.def_kind(def.did) { - // FIXME(generic_const_exprs): We currently only do this for anonymous constants, - // meaning that we do not look into associated constants. I(@lcnr) am not yet sure whether - // we want to look into them or treat them as opaque projections. - // - // Right now we do neither of that and simply always fail to unify them. - DefKind::AnonConst | DefKind::InlineConst => (), - _ => return Ok(None), - } - - let body = tcx.thir_body(def)?; - let (body, body_id) = (&*body.0.borrow(), body.1); + if !tcx.features().generic_const_exprs { + return Ok(None); + } - let mut is_poly_vis = IsThirPolymorphic { is_poly: false, thir: body }; - visit::walk_expr(&mut is_poly_vis, &body[body_id]); - if !is_poly_vis.is_poly { - return Ok(None); - } + match tcx.def_kind(def) { + // FIXME(generic_const_exprs): We currently only do this for anonymous constants, + // meaning that we do not look into associated constants. I(@lcnr) am not yet sure whether + // we want to look into them or treat them as opaque projections. + // + // Right now we do neither of that and simply always fail to unify them. + DefKind::AnonConst | DefKind::InlineConst => (), + _ => return Ok(None), + } - let root_span = body.exprs[body_id].span; + let body = tcx.thir_body(def)?; + let (body, body_id) = (&*body.0.borrow(), body.1); - Some(recurse_build(tcx, body, body_id, root_span)).transpose() - } else { - Ok(None) + let mut is_poly_vis = IsThirPolymorphic { is_poly: false, thir: body }; + visit::walk_expr(&mut is_poly_vis, &body[body_id]); + if !is_poly_vis.is_poly { + return Ok(None); } + + let root_span = body.exprs[body_id].span; + + Some(recurse_build(tcx, body, body_id, root_span)).transpose() } pub fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { - destructure_const, - thir_abstract_const: |tcx, def_id| { - if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) { - tcx.thir_abstract_const_of_const_arg(def) - } else { - thir_abstract_const(tcx, ty::WithOptConstParam::unknown(def_id)) - } - }, - thir_abstract_const_of_const_arg: |tcx, (did, param_did)| { - thir_abstract_const( - tcx, - ty::WithOptConstParam { did, const_param_did: Some(param_did) }, - ) - }, - ..*providers - }; + *providers = ty::query::Providers { destructure_const, thir_abstract_const, ..*providers }; } diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 0a6c118093e..21cc3c9517e 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -1,5 +1,5 @@ use rustc_errors::ErrorGuaranteed; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::DefId; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::traits::CodegenObligationError; use rustc_middle::ty::subst::SubstsRef; @@ -14,54 +14,26 @@ fn resolve_instance<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, (DefId, SubstsRef<'tcx>)>, ) -> Result<Option<Instance<'tcx>>, ErrorGuaranteed> { - let (param_env, (did, substs)) = key.into_parts(); - if let Some(did) = did.as_local() { - if let Some(param_did) = tcx.opt_const_param_of(did) { - return tcx.resolve_instance_of_const_arg(param_env.and((did, param_did, substs))); - } - } - - inner_resolve_instance(tcx, param_env.and((ty::WithOptConstParam::unknown(did), substs))) -} - -fn resolve_instance_of_const_arg<'tcx>( - tcx: TyCtxt<'tcx>, - key: ty::ParamEnvAnd<'tcx, (LocalDefId, DefId, SubstsRef<'tcx>)>, -) -> Result<Option<Instance<'tcx>>, ErrorGuaranteed> { - let (param_env, (did, const_param_did, substs)) = key.into_parts(); - inner_resolve_instance( - tcx, - param_env.and(( - ty::WithOptConstParam { did: did.to_def_id(), const_param_did: Some(const_param_did) }, - substs, - )), - ) -} - -fn inner_resolve_instance<'tcx>( - tcx: TyCtxt<'tcx>, - key: ty::ParamEnvAnd<'tcx, (ty::WithOptConstParam<DefId>, SubstsRef<'tcx>)>, -) -> Result<Option<Instance<'tcx>>, ErrorGuaranteed> { let (param_env, (def, substs)) = key.into_parts(); - let result = if let Some(trait_def_id) = tcx.trait_of_item(def.did) { + let result = if let Some(trait_def_id) = tcx.trait_of_item(def) { debug!(" => associated item, attempting to find impl in param_env {:#?}", param_env); resolve_associated_item( tcx, - def.did, + def, param_env, trait_def_id, tcx.normalize_erasing_regions(param_env, substs), ) } else { - let ty = tcx.type_of(def.def_id_for_type_of()); + let ty = tcx.type_of(def); let item_type = tcx.subst_and_normalize_erasing_regions(substs, param_env, ty.skip_binder()); let def = match *item_type.kind() { ty::FnDef(def_id, ..) if tcx.is_intrinsic(def_id) => { debug!(" => intrinsic"); - ty::InstanceDef::Intrinsic(def.did) + ty::InstanceDef::Intrinsic(def) } ty::FnDef(def_id, substs) if Some(def_id) == tcx.lang_items().drop_in_place_fn() => { let ty = substs.type_at(0); @@ -206,15 +178,11 @@ fn resolve_associated_item<'tcx>( Some(ty::Instance::new(leaf_def.item.def_id, substs)) } traits::ImplSource::Generator(generator_data) => Some(Instance { - def: ty::InstanceDef::Item(ty::WithOptConstParam::unknown( - generator_data.generator_def_id, - )), + def: ty::InstanceDef::Item(generator_data.generator_def_id), substs: generator_data.substs, }), traits::ImplSource::Future(future_data) => Some(Instance { - def: ty::InstanceDef::Item(ty::WithOptConstParam::unknown( - future_data.generator_def_id, - )), + def: ty::InstanceDef::Item(future_data.generator_def_id), substs: future_data.substs, }), traits::ImplSource::Closure(closure_data) => { @@ -234,15 +202,12 @@ fn resolve_associated_item<'tcx>( _ => None, }, traits::ImplSource::Object(ref data) => { - if let Some(index) = traits::get_vtable_index_of_object_method(tcx, data, trait_item_id) - { - Some(Instance { + traits::get_vtable_index_of_object_method(tcx, data, trait_item_id).map(|index| { + Instance { def: ty::InstanceDef::Virtual(trait_item_id, index), substs: rcvr_substs, - }) - } else { - None - } + } + }) } traits::ImplSource::Builtin(..) => { let lang_items = tcx.lang_items(); @@ -301,6 +266,5 @@ fn resolve_associated_item<'tcx>( } pub fn provide(providers: &mut ty::query::Providers) { - *providers = - ty::query::Providers { resolve_instance, resolve_instance_of_const_arg, ..*providers }; + *providers = ty::query::Providers { resolve_instance, ..*providers }; } diff --git a/compiler/rustc_ty_utils/src/layout_sanity_check.rs b/compiler/rustc_ty_utils/src/layout_sanity_check.rs index a5311dbd1b7..ed513cb3c7f 100644 --- a/compiler/rustc_ty_utils/src/layout_sanity_check.rs +++ b/compiler/rustc_ty_utils/src/layout_sanity_check.rs @@ -285,7 +285,7 @@ pub(super) fn sanity_check_layout<'tcx>( { // These are never actually accessed anyway, so we can skip the coherence check // for them. They also fail that check, since they have - // `Aggregate`/`Uninhbaited` ABI even when the main type is + // `Aggregate`/`Uninhabited` ABI even when the main type is // `Scalar`/`ScalarPair`. (Note that sometimes, variants with fields have size // 0, and sometimes, variants without fields have non-0 size.) continue; diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index 2613445f39b..9d5a72a73cd 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -19,7 +19,7 @@ extern crate rustc_middle; extern crate tracing; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; -use rustc_macros::fluent_messages; +use rustc_fluent_macro::fluent_messages; use rustc_middle::ty::query::Providers; mod abi; diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index de7fd003176..5f436f7c9fd 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -243,7 +243,7 @@ fn drop_tys_helper<'tcx>( } else { let field_tys = adt_def.all_fields().map(|field| { let r = tcx.type_of(field.did).subst(tcx, substs); - debug!("drop_tys_helper: Subst into {:?} with {:?} gettng {:?}", field, substs, r); + debug!("drop_tys_helper: Subst into {:?} with {:?} getting {:?}", field, substs, r); r }); if only_significant { diff --git a/compiler/rustc_ty_utils/src/structural_match.rs b/compiler/rustc_ty_utils/src/structural_match.rs index a55bb7e7e90..9cb0fc10594 100644 --- a/compiler/rustc_ty_utils/src/structural_match.rs +++ b/compiler/rustc_ty_utils/src/structural_match.rs @@ -13,7 +13,7 @@ use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt}; /// Note that this does *not* recursively check if the substructure of `adt_ty` /// implements the traits. fn has_structural_eq_impls<'tcx>(tcx: TyCtxt<'tcx>, adt_ty: Ty<'tcx>) -> bool { - let ref infcx = tcx.infer_ctxt().build(); + let infcx = &tcx.infer_ctxt().build(); let cause = ObligationCause::dummy(); let ocx = ObligationCtxt::new(infcx); diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs index 3a053d4c6a9..371c6119122 100644 --- a/compiler/rustc_type_ir/src/fold.rs +++ b/compiler/rustc_type_ir/src/fold.rs @@ -16,8 +16,10 @@ //! - Types of interest, for which the methods delegate to the folder. //! - All other types, including generic containers like `Vec` and `Option`. //! It defines a "skeleton" of how they should be folded. -//! - `TypeSuperFoldable`. This is implemented only for each type of interest, -//! and defines the folding "skeleton" for these types. +//! - `TypeSuperFoldable`. This is implemented only for recursive types of +//! interest, and defines the folding "skeleton" for these types. (This +//! excludes `Region` because it is non-recursive, i.e. it never contains +//! other types of interest.) //! - `TypeFolder`/`FallibleTypeFolder`. One of these is implemented for each //! folder. This defines how types of interest are folded. //! @@ -72,9 +74,9 @@ pub trait TypeFoldable<I: Interner>: TypeVisitable<I> { // This trait is implemented for types of interest. pub trait TypeSuperFoldable<I: Interner>: TypeFoldable<I> { - /// Provides a default fold for a type of interest. This should only be - /// called within `TypeFolder` methods, when a non-custom traversal is - /// desired for the value of the type of interest passed to that method. + /// Provides a default fold for a recursive type of interest. This should + /// only be called within `TypeFolder` methods, when a non-custom traversal + /// is desired for the value of the type of interest passed to that method. /// For example, in `MyFolder::try_fold_ty(ty)`, it is valid to call /// `ty.try_super_fold_with(self)`, but any other folding should be done /// with `xyz.try_fold_with(self)`. @@ -118,11 +120,11 @@ pub trait TypeFolder<I: Interner>: FallibleTypeFolder<I, Error = !> { t.super_fold_with(self) } - fn fold_region(&mut self, r: I::Region) -> I::Region - where - I::Region: TypeSuperFoldable<I>, - { - r.super_fold_with(self) + // The default region folder is a no-op because `Region` is non-recursive + // and has no `super_visit_with` method to call. That also explains the + // lack of `I::Region: TypeSuperFoldable<I>` bound on this method. + fn fold_region(&mut self, r: I::Region) -> I::Region { + r } fn fold_const(&mut self, c: I::Const) -> I::Const @@ -167,11 +169,11 @@ pub trait FallibleTypeFolder<I: Interner>: Sized { t.try_super_fold_with(self) } - fn try_fold_region(&mut self, r: I::Region) -> Result<I::Region, Self::Error> - where - I::Region: TypeSuperFoldable<I>, - { - r.try_super_fold_with(self) + // The default region folder is a no-op because `Region` is non-recursive + // and has no `super_visit_with` method to call. That also explains the + // lack of `I::Region: TypeSuperFoldable<I>` bound on this method. + fn try_fold_region(&mut self, r: I::Region) -> Result<I::Region, Self::Error> { + Ok(r) } fn try_fold_const(&mut self, c: I::Const) -> Result<I::Const, Self::Error> @@ -216,10 +218,7 @@ where Ok(self.fold_ty(t)) } - fn try_fold_region(&mut self, r: I::Region) -> Result<I::Region, !> - where - I::Region: TypeSuperFoldable<I>, - { + fn try_fold_region(&mut self, r: I::Region) -> Result<I::Region, !> { Ok(self.fold_region(r)) } diff --git a/compiler/rustc_type_ir/src/macros.rs b/compiler/rustc_type_ir/src/macros.rs index 6c181039730..8c3cb228322 100644 --- a/compiler/rustc_type_ir/src/macros.rs +++ b/compiler/rustc_type_ir/src/macros.rs @@ -33,144 +33,3 @@ macro_rules! TrivialTypeTraversalImpls { )+ }; } - -macro_rules! EnumTypeTraversalImpl { - (impl<$($p:tt),*> TypeFoldable<$tcx:tt> for $s:path { - $($variants:tt)* - } $(where $($wc:tt)*)*) => { - impl<$($p),*> $crate::fold::TypeFoldable<$tcx> for $s - $(where $($wc)*)* - { - fn try_fold_with<V: $crate::fold::FallibleTypeFolder<$tcx>>( - self, - folder: &mut V, - ) -> ::std::result::Result<Self, V::Error> { - EnumTypeTraversalImpl!(@FoldVariants(self, folder) input($($variants)*) output()) - } - } - }; - - (impl<$($p:tt),*> TypeVisitable<$tcx:tt> for $s:path { - $($variants:tt)* - } $(where $($wc:tt)*)*) => { - impl<$($p),*> $crate::visit::TypeVisitable<$tcx> for $s - $(where $($wc)*)* - { - fn visit_with<V: $crate::visit::TypeVisitor<$tcx>>( - &self, - visitor: &mut V, - ) -> ::std::ops::ControlFlow<V::BreakTy> { - EnumTypeTraversalImpl!(@VisitVariants(self, visitor) input($($variants)*) output()) - } - } - }; - - (@FoldVariants($this:expr, $folder:expr) input() output($($output:tt)*)) => { - Ok(match $this { - $($output)* - }) - }; - - (@FoldVariants($this:expr, $folder:expr) - input( ($variant:path) ( $($variant_arg:ident),* ) , $($input:tt)*) - output( $($output:tt)*) ) => { - EnumTypeTraversalImpl!( - @FoldVariants($this, $folder) - input($($input)*) - output( - $variant ( $($variant_arg),* ) => { - $variant ( - $($crate::fold::TypeFoldable::try_fold_with($variant_arg, $folder)?),* - ) - } - $($output)* - ) - ) - }; - - (@FoldVariants($this:expr, $folder:expr) - input( ($variant:path) { $($variant_arg:ident),* $(,)? } , $($input:tt)*) - output( $($output:tt)*) ) => { - EnumTypeTraversalImpl!( - @FoldVariants($this, $folder) - input($($input)*) - output( - $variant { $($variant_arg),* } => { - $variant { - $($variant_arg: $crate::fold::TypeFoldable::fold_with( - $variant_arg, $folder - )?),* } - } - $($output)* - ) - ) - }; - - (@FoldVariants($this:expr, $folder:expr) - input( ($variant:path), $($input:tt)*) - output( $($output:tt)*) ) => { - EnumTypeTraversalImpl!( - @FoldVariants($this, $folder) - input($($input)*) - output( - $variant => { $variant } - $($output)* - ) - ) - }; - - (@VisitVariants($this:expr, $visitor:expr) input() output($($output:tt)*)) => { - match $this { - $($output)* - } - }; - - (@VisitVariants($this:expr, $visitor:expr) - input( ($variant:path) ( $($variant_arg:ident),* ) , $($input:tt)*) - output( $($output:tt)*) ) => { - EnumTypeTraversalImpl!( - @VisitVariants($this, $visitor) - input($($input)*) - output( - $variant ( $($variant_arg),* ) => { - $($crate::visit::TypeVisitable::visit_with( - $variant_arg, $visitor - )?;)* - ::std::ops::ControlFlow::Continue(()) - } - $($output)* - ) - ) - }; - - (@VisitVariants($this:expr, $visitor:expr) - input( ($variant:path) { $($variant_arg:ident),* $(,)? } , $($input:tt)*) - output( $($output:tt)*) ) => { - EnumTypeTraversalImpl!( - @VisitVariants($this, $visitor) - input($($input)*) - output( - $variant { $($variant_arg),* } => { - $($crate::visit::TypeVisitable::visit_with( - $variant_arg, $visitor - )?;)* - ::std::ops::ControlFlow::Continue(()) - } - $($output)* - ) - ) - }; - - (@VisitVariants($this:expr, $visitor:expr) - input( ($variant:path), $($input:tt)*) - output( $($output:tt)*) ) => { - EnumTypeTraversalImpl!( - @VisitVariants($this, $visitor) - input($($input)*) - output( - $variant => { ::std::ops::ControlFlow::Continue(()) } - $($output)* - ) - ) - }; -} diff --git a/compiler/rustc_type_ir/src/structural_impls.rs b/compiler/rustc_type_ir/src/structural_impls.rs index 3ebe241042f..c90c86b7690 100644 --- a/compiler/rustc_type_ir/src/structural_impls.rs +++ b/compiler/rustc_type_ir/src/structural_impls.rs @@ -70,30 +70,40 @@ impl<I: Interner, A: TypeVisitable<I>, B: TypeVisitable<I>, C: TypeVisitable<I>> } } -EnumTypeTraversalImpl! { - impl<I, T> TypeFoldable<I> for Option<T> { - (Some)(a), - (None), - } where I: Interner, T: TypeFoldable<I> -} -EnumTypeTraversalImpl! { - impl<I, T> TypeVisitable<I> for Option<T> { - (Some)(a), - (None), - } where I: Interner, T: TypeVisitable<I> -} - -EnumTypeTraversalImpl! { - impl<I, T, E> TypeFoldable<I> for Result<T, E> { - (Ok)(a), - (Err)(a), - } where I: Interner, T: TypeFoldable<I>, E: TypeFoldable<I>, -} -EnumTypeTraversalImpl! { - impl<I, T, E> TypeVisitable<I> for Result<T, E> { - (Ok)(a), - (Err)(a), - } where I: Interner, T: TypeVisitable<I>, E: TypeVisitable<I>, +impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Option<T> { + fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> { + Ok(match self { + Some(v) => Some(v.try_fold_with(folder)?), + None => None, + }) + } +} + +impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Option<T> { + fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { + match self { + Some(v) => v.visit_with(visitor), + None => ControlFlow::Continue(()), + } + } +} + +impl<I: Interner, T: TypeFoldable<I>, E: TypeFoldable<I>> TypeFoldable<I> for Result<T, E> { + fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> { + Ok(match self { + Ok(v) => Ok(v.try_fold_with(folder)?), + Err(e) => Err(e.try_fold_with(folder)?), + }) + } +} + +impl<I: Interner, T: TypeVisitable<I>, E: TypeVisitable<I>> TypeVisitable<I> for Result<T, E> { + fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { + match self { + Ok(v) => v.visit_with(visitor), + Err(e) => e.visit_with(visitor), + } + } } impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Rc<T> { diff --git a/compiler/rustc_type_ir/src/sty.rs b/compiler/rustc_type_ir/src/sty.rs index 62e699eefd7..4c1f2dd0e53 100644 --- a/compiler/rustc_type_ir/src/sty.rs +++ b/compiler/rustc_type_ir/src/sty.rs @@ -203,6 +203,10 @@ pub enum TyKind<I: Interner> { /// `for<'a, T> &'a (): Trait<T>` and then convert the introduced bound variables /// back to inference variables in a new inference context when inside of the query. /// + /// It is conventional to render anonymous bound types like `^N` or `^D_N`, + /// where `N` is the bound variable's anonymous index into the binder, and + /// `D` is the debruijn index, or totally omitted if the debruijn index is zero. + /// /// See the `rustc-dev-guide` for more details about /// [higher-ranked trait bounds][1] and [canonical queries][2]. /// @@ -212,6 +216,12 @@ pub enum TyKind<I: Interner> { /// A placeholder type, used during higher ranked subtyping to instantiate /// bound variables. + /// + /// It is conventional to render anonymous placeholer types like `!N` or `!U_N`, + /// where `N` is the placeholder variable's anonymous index (which corresponds + /// to the bound variable's index from the binder from which it was instantiated), + /// and `U` is the universe index in which it is instantiated, or totally omitted + /// if the universe index is zero. Placeholder(I::PlaceholderType), /// A type variable used during type checking. diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index 62239fd2006..878c7aec6c1 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -13,8 +13,11 @@ //! - Types of interest, for which the methods delegate to the visitor. //! - All other types, including generic containers like `Vec` and `Option`. //! It defines a "skeleton" of how they should be visited. -//! - `TypeSuperVisitable`. This is implemented only for each type of interest, -//! and defines the visiting "skeleton" for these types. +//! - `TypeSuperVisitable`. This is implemented only for recursive types of +//! interest, and defines the visiting "skeleton" for these types. (This +//! excludes `Region` because it is non-recursive, i.e. it never contains +//! other types of interest.) +//! //! - `TypeVisitor`. This is implemented for each visitor. This defines how //! types of interest are visited. //! @@ -62,12 +65,13 @@ pub trait TypeVisitable<I: Interner>: fmt::Debug + Clone { fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>; } +// This trait is implemented for types of interest. pub trait TypeSuperVisitable<I: Interner>: TypeVisitable<I> { - /// Provides a default visit for a type of interest. This should only be - /// called within `TypeVisitor` methods, when a non-custom traversal is - /// desired for the value of the type of interest passed to that method. - /// For example, in `MyVisitor::visit_ty(ty)`, it is valid to call - /// `ty.super_visit_with(self)`, but any other visiting should be done + /// Provides a default visit for a recursive type of interest. This should + /// only be called within `TypeVisitor` methods, when a non-custom + /// traversal is desired for the value of the type of interest passed to + /// that method. For example, in `MyVisitor::visit_ty(ty)`, it is valid to + /// call `ty.super_visit_with(self)`, but any other visiting should be done /// with `xyz.visit_with(self)`. fn super_visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>; } @@ -92,11 +96,11 @@ pub trait TypeVisitor<I: Interner>: Sized { t.super_visit_with(self) } - fn visit_region(&mut self, r: I::Region) -> ControlFlow<Self::BreakTy> - where - I::Region: TypeSuperVisitable<I>, - { - r.super_visit_with(self) + // The default region visitor is a no-op because `Region` is non-recursive + // and has no `super_visit_with` method to call. That also explains the + // lack of `I::Region: TypeSuperVisitable<I>` bound. + fn visit_region(&mut self, _r: I::Region) -> ControlFlow<Self::BreakTy> { + ControlFlow::Continue(()) } fn visit_const(&mut self, c: I::Const) -> ControlFlow<Self::BreakTy> |