diff options
Diffstat (limited to 'compiler')
250 files changed, 3436 insertions, 3087 deletions
diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 0e395d70335..4166b4fc2e5 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -4,8 +4,7 @@ use super::LoweringContext; use rustc_ast::ptr::P; use rustc_ast::*; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::stable_set::FxHashSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -145,7 +144,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { InlineAsmRegOrRegClass::Reg(s) => { asm::InlineAsmRegOrRegClass::Reg(if let Some(asm_arch) = asm_arch { asm::InlineAsmReg::parse(asm_arch, s).unwrap_or_else(|e| { - let msg = format!("invalid register `{}`: {}", s.as_str(), e); + let msg = format!("invalid register `{}`: {}", s, e); sess.struct_span_err(*op_sp, &msg).emit(); asm::InlineAsmReg::Err }) @@ -156,7 +155,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { InlineAsmRegOrRegClass::RegClass(s) => { asm::InlineAsmRegOrRegClass::RegClass(if let Some(asm_arch) = asm_arch { asm::InlineAsmRegClass::parse(asm_arch, s).unwrap_or_else(|e| { - let msg = format!("invalid register class `{}`: {}", s.as_str(), e); + let msg = format!("invalid register class `{}`: {}", s, e); sess.struct_span_err(*op_sp, &msg).emit(); asm::InlineAsmRegClass::Err }) diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index ad0e0384acf..ad9ed798e55 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -62,9 +62,9 @@ impl<'a> PostExpansionVisitor<'a> { let ast::StrLit { symbol_unescaped, span, .. } = abi; if let ast::Const::Yes(_) = constness { - match symbol_unescaped.as_str() { + match symbol_unescaped { // Stable - "Rust" | "C" => {} + sym::Rust | sym::C => {} abi => gate_feature_post!( &self, const_extern_fn, @@ -274,10 +274,12 @@ impl<'a> PostExpansionVisitor<'a> { ); } abi => { - self.sess.parse_sess.span_diagnostic.delay_span_bug( - span, - &format!("unrecognized ABI not caught in lowering: {}", abi), - ); + if self.sess.opts.pretty.map_or(true, |ppm| ppm.needs_hir()) { + self.sess.parse_sess.span_diagnostic.delay_span_bug( + span, + &format!("unrecognized ABI not caught in lowering: {}", abi), + ); + } } } } @@ -402,8 +404,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(self, rustdoc_internals, attr.span, msg); } - if nested_meta.has_name(sym::tuple_variadic) { - let msg = "`#[doc(tuple_variadic)]` is meant for internal use only"; + if nested_meta.has_name(sym::fake_variadic) { + let msg = "`#[doc(fake_variadic)]` is meant for internal use only"; gate_feature_post!(self, rustdoc_internals, attr.span, msg); } } diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index dcfbecedfe8..64a6f91f022 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -135,9 +135,42 @@ impl ConstStability { #[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)] #[derive(HashStable_Generic)] pub enum StabilityLevel { - // Reason for the current stability level and the relevant rust-lang issue - Unstable { reason: Option<Symbol>, issue: Option<NonZeroU32>, is_soft: bool }, - Stable { since: Symbol, allowed_through_unstable_modules: bool }, + /// `#[unstable]` + Unstable { + /// Reason for the current stability level. + reason: Option<Symbol>, + /// Relevant `rust-lang/rust` issue. + issue: Option<NonZeroU32>, + is_soft: bool, + /// If part of a feature is stabilized and a new feature is added for the remaining parts, + /// then the `implied_by` attribute is used to indicate which now-stable feature previously + /// contained a item. + /// + /// ```pseudo-Rust + /// #[unstable(feature = "foo", issue = "...")] + /// fn foo() {} + /// #[unstable(feature = "foo", issue = "...")] + /// fn foobar() {} + /// ``` + /// + /// ...becomes... + /// + /// ```pseudo-Rust + /// #[stable(feature = "foo", since = "1.XX.X")] + /// fn foo() {} + /// #[unstable(feature = "foobar", issue = "...", implied_by = "foo")] + /// fn foobar() {} + /// ``` + implied_by: Option<Symbol>, + }, + /// `#[stable]` + Stable { + /// Rust release which stabilized this feature. + since: Symbol, + /// Is this item allowed to be referred to on stable, despite being contained in unstable + /// modules? + allowed_through_unstable_modules: bool, + }, } impl StabilityLevel { @@ -243,6 +276,7 @@ where let mut issue = None; let mut issue_num = None; let mut is_soft = false; + let mut implied_by = None; for meta in metas { let Some(mi) = meta.meta_item() else { handle_errors( @@ -308,6 +342,11 @@ where } is_soft = true; } + sym::implied_by => { + if !get(mi, &mut implied_by) { + continue 'outer; + } + } _ => { handle_errors( &sess.parse_sess, @@ -332,7 +371,7 @@ where ); continue; } - let level = Unstable { reason, issue: issue_num, is_soft }; + let level = Unstable { reason, issue: issue_num, is_soft, implied_by }; if sym::unstable == meta_name { stab = Some((Stability { level, feature }, attr.span)); } else { @@ -391,7 +430,7 @@ where meta.span(), AttrError::UnknownMetaItem( pprust::path_to_string(&mi.path), - &["since", "note"], + &["feature", "since"], ), ); continue 'outer; diff --git a/compiler/rustc_borrowck/src/consumers.rs b/compiler/rustc_borrowck/src/consumers.rs index 97daad201d9..efc17a173f4 100644 --- a/compiler/rustc_borrowck/src/consumers.rs +++ b/compiler/rustc_borrowck/src/consumers.rs @@ -2,7 +2,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_index::vec::IndexVec; -use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt}; use rustc_middle::mir::Body; use rustc_middle::ty::{self, TyCtxt}; @@ -31,7 +31,7 @@ pub fn get_body_with_borrowck_facts<'tcx>( def: ty::WithOptConstParam<LocalDefId>, ) -> BodyWithBorrowckFacts<'tcx> { let (input_body, promoted) = tcx.mir_promoted(def); - tcx.infer_ctxt().with_opaque_type_inference(def.did).enter(|infcx| { + tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(def.did)).enter(|infcx| { let input_body: &Body<'_> = &input_body.borrow(); let promoted: &IndexVec<_, _> = &promoted.borrow(); *super::do_mir_borrowck(&infcx, input_body, promoted, true).1.unwrap() diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index ee96dbc2f60..1b3c6cac9c4 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -2155,9 +2155,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } StorageDeadOrDrop::Destructor(_) => kind, }, - ProjectionElem::OpaqueCast { .. } - | ProjectionElem::Field(..) - | ProjectionElem::Downcast(..) => { + ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => { match place_ty.ty.kind() { ty::Adt(def, _) if def.has_dtor(tcx) => { // Report the outermost adt with a destructor diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index fada3d45fbe..53c07a3d481 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -226,7 +226,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } ProjectionElem::Downcast(..) if including_downcast.0 => return None, ProjectionElem::Downcast(..) => (), - ProjectionElem::OpaqueCast(..) => (), ProjectionElem::Field(field, _ty) => { // FIXME(project-rfc_2229#36): print capture precisely here. if let Some(field) = self.is_upvar_field_projection(PlaceRef { @@ -287,7 +286,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx) } ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx), - ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(*ty), ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type), }, }; diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index cb7077fe621..8134e122662 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -169,7 +169,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { .., ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::OpaqueCast { .. } | ProjectionElem::Subslice { .. } | ProjectionElem::Downcast(..), ], diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 0e6a05478a0..07aba50f03b 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -1,6 +1,6 @@ //! Error reporting machinery for lifetime errors. -use rustc_data_structures::stable_set::FxHashSet; +use rustc_data_structures::fx::FxHashSet; use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 15c2a9f7aef..9dfefe4d236 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -24,7 +24,7 @@ use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_index::bit_set::ChunkedBitSet; use rustc_index::vec::IndexVec; -use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; +use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt}; use rustc_middle::mir::{ traversal, Body, ClearCrossCrate, Local, Location, Mutability, Operand, Place, PlaceElem, PlaceRef, VarDebugInfoContents, @@ -130,11 +130,14 @@ fn mir_borrowck<'tcx>( debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id())); let hir_owner = tcx.hir().local_def_id_to_hir_id(def.did).owner; - let opt_closure_req = tcx.infer_ctxt().with_opaque_type_inference(hir_owner).enter(|infcx| { - let input_body: &Body<'_> = &input_body.borrow(); - let promoted: &IndexVec<_, _> = &promoted.borrow(); - do_mir_borrowck(&infcx, input_body, promoted, false).0 - }); + let opt_closure_req = tcx + .infer_ctxt() + .with_opaque_type_inference(DefiningAnchor::Bind(hir_owner)) + .enter(|infcx| { + let input_body: &Body<'_> = &input_body.borrow(); + let promoted: &IndexVec<_, _> = &promoted.borrow(); + do_mir_borrowck(&infcx, input_body, promoted, false).0 + }); debug!("mir_borrowck done"); tcx.arena.alloc(opt_closure_req) @@ -1788,7 +1791,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { for (place_base, elem) in place.iter_projections().rev() { match elem { ProjectionElem::Index(_/*operand*/) | - ProjectionElem::OpaqueCast(_) | ProjectionElem::ConstantIndex { .. } | // assigning to P[i] requires P to be valid. ProjectionElem::Downcast(_/*adt_def*/, _/*variant_idx*/) => @@ -2180,7 +2182,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { | ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } - | ProjectionElem::OpaqueCast { .. } | ProjectionElem::Downcast(..) => { let upvar_field_projection = self.is_upvar_field_projection(place); if let Some(field) = upvar_field_projection { diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index d2e82274792..0961203d76d 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -1,7 +1,7 @@ //! The entry point of the NLL borrow checker. use rustc_data_structures::vec_map::VecMap; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::LocalDefId; use rustc_index::vec::IndexVec; use rustc_infer::infer::InferCtxt; use rustc_middle::mir::{create_dump_file, dump_enabled, dump_mir, PassWhere}; @@ -44,7 +44,7 @@ pub type PoloniusOutput = Output<RustcFacts>; /// closure requirements to propagate, and any generated errors. pub(crate) struct NllOutput<'tcx> { pub regioncx: RegionInferenceContext<'tcx>, - pub opaque_type_values: VecMap<DefId, OpaqueHiddenType<'tcx>>, + pub opaque_type_values: VecMap<LocalDefId, OpaqueHiddenType<'tcx>>, pub polonius_input: Option<Box<AllFacts>>, pub polonius_output: Option<Rc<PoloniusOutput>>, pub opt_closure_req: Option<ClosureRegionRequirements<'tcx>>, @@ -373,7 +373,7 @@ pub(super) fn dump_annotation<'a, 'tcx>( body: &Body<'tcx>, regioncx: &RegionInferenceContext<'tcx>, closure_region_requirements: &Option<ClosureRegionRequirements<'_>>, - opaque_type_values: &VecMap<DefId, OpaqueHiddenType<'tcx>>, + opaque_type_values: &VecMap<LocalDefId, OpaqueHiddenType<'tcx>>, errors: &mut crate::error::BorrowckErrors<'tcx>, ) { let tcx = infcx.tcx; diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs index 5b67e6aa1cf..97335fd0dff 100644 --- a/compiler/rustc_borrowck/src/places_conflict.rs +++ b/compiler/rustc_borrowck/src/places_conflict.rs @@ -255,7 +255,6 @@ fn place_components_conflict<'tcx>( | (ProjectionElem::Index { .. }, _, _) | (ProjectionElem::ConstantIndex { .. }, _, _) | (ProjectionElem::Subslice { .. }, _, _) - | (ProjectionElem::OpaqueCast { .. }, _, _) | (ProjectionElem::Downcast { .. }, _, _) => { // Recursive case. This can still be disjoint on a // further iteration if this a shallow access and @@ -323,17 +322,6 @@ fn place_projection_conflict<'tcx>( debug!("place_element_conflict: DISJOINT-OR-EQ-DEREF"); Overlap::EqualOrDisjoint } - (ProjectionElem::OpaqueCast(v1), ProjectionElem::OpaqueCast(v2)) => { - if v1 == v2 { - // same type - recur. - debug!("place_element_conflict: DISJOINT-OR-EQ-OPAQUE"); - Overlap::EqualOrDisjoint - } else { - // Different types. Disjoint! - debug!("place_element_conflict: DISJOINT-OPAQUE"); - Overlap::Disjoint - } - } (ProjectionElem::Field(f1, _), ProjectionElem::Field(f2, _)) => { if f1 == f2 { // same field (e.g., `a.y` vs. `a.y`) - recur. @@ -537,7 +525,6 @@ fn place_projection_conflict<'tcx>( | ProjectionElem::Field(..) | ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::OpaqueCast { .. } | ProjectionElem::Subslice { .. } | ProjectionElem::Downcast(..), _, diff --git a/compiler/rustc_borrowck/src/prefixes.rs b/compiler/rustc_borrowck/src/prefixes.rs index 2b50cbac9a0..bdf2becb711 100644 --- a/compiler/rustc_borrowck/src/prefixes.rs +++ b/compiler/rustc_borrowck/src/prefixes.rs @@ -81,7 +81,6 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> { } ProjectionElem::Downcast(..) | ProjectionElem::Subslice { .. } - | ProjectionElem::OpaqueCast { .. } | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Index(_) => { cursor = cursor_base; diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 7c1fa28b8df..407bbf48813 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -1,10 +1,10 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::vec_map::VecMap; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::LocalDefId; use rustc_hir::OpaqueTyOrigin; use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic; -use rustc_infer::infer::InferCtxt; use rustc_infer::infer::TyCtxtInferExt as _; +use rustc_infer::infer::{DefiningAnchor, InferCtxt}; use rustc_infer::traits::{Obligation, ObligationCause, TraitEngine}; use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts}; @@ -63,8 +63,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { &self, infcx: &InferCtxt<'_, 'tcx>, opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>, - ) -> VecMap<DefId, OpaqueHiddenType<'tcx>> { - let mut result: VecMap<DefId, OpaqueHiddenType<'tcx>> = VecMap::new(); + ) -> VecMap<LocalDefId, OpaqueHiddenType<'tcx>> { + let mut result: VecMap<LocalDefId, OpaqueHiddenType<'tcx>> = VecMap::new(); for (opaque_type_key, (concrete_type, origin)) in opaque_ty_decls { let substs = opaque_type_key.substs; debug!(?concrete_type, ?substs); @@ -235,7 +235,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // lifetimes with 'static and remapping only those used in the // `impl Trait` return type, resulting in the parameters // shifting. - let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id); + let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id.to_def_id()); debug!(?id_substs); let map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>> = substs.iter().enumerate().map(|(index, subst)| (subst, id_substs[index])).collect(); @@ -268,60 +268,66 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // This logic duplicates most of `check_opaque_meets_bounds`. // FIXME(oli-obk): Also do region checks here and then consider removing `check_opaque_meets_bounds` entirely. let param_env = self.tcx.param_env(def_id); - let body_id = self.tcx.local_def_id_to_hir_id(def_id.as_local().unwrap()); - self.tcx.infer_ctxt().enter(move |infcx| { - // Require the hidden type to be well-formed with only the generics of the opaque type. - // Defining use functions may have more bounds than the opaque type, which is ok, as long as the - // hidden type is well formed even without those bounds. - let predicate = - ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into())) - .to_predicate(infcx.tcx); - let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx); - - // Require that the hidden type actually fulfills all the bounds of the opaque type, even without - // the bounds that the function supplies. - match infcx.register_hidden_type( - OpaqueTypeKey { def_id, substs: id_substs }, - ObligationCause::misc(instantiated_ty.span, body_id), - param_env, - definition_ty, - origin, - ) { - Ok(infer_ok) => { - for obligation in infer_ok.obligations { - fulfillment_cx.register_predicate_obligation(&infcx, obligation); + let body_id = self.tcx.local_def_id_to_hir_id(def_id); + // HACK This bubble is required for this tests to pass: + // type-alias-impl-trait/issue-67844-nested-opaque.rs + self.tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).enter( + move |infcx| { + // Require the hidden type to be well-formed with only the generics of the opaque type. + // Defining use functions may have more bounds than the opaque type, which is ok, as long as the + // hidden type is well formed even without those bounds. + let predicate = + ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into())) + .to_predicate(infcx.tcx); + let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx); + + // Require that the hidden type actually fulfills all the bounds of the opaque type, even without + // the bounds that the function supplies. + match infcx.register_hidden_type( + OpaqueTypeKey { def_id, substs: id_substs }, + ObligationCause::misc(instantiated_ty.span, body_id), + param_env, + definition_ty, + origin, + ) { + Ok(infer_ok) => { + for obligation in infer_ok.obligations { + fulfillment_cx.register_predicate_obligation(&infcx, obligation); + } + } + Err(err) => { + infcx + .report_mismatched_types( + &ObligationCause::misc(instantiated_ty.span, body_id), + self.tcx.mk_opaque(def_id.to_def_id(), id_substs), + definition_ty, + err, + ) + .emit(); } } - Err(err) => { - infcx - .report_mismatched_types( - &ObligationCause::misc(instantiated_ty.span, body_id), - self.tcx.mk_opaque(def_id, id_substs), - definition_ty, - err, - ) - .emit(); - } - } - fulfillment_cx.register_predicate_obligation( - &infcx, - Obligation::misc(instantiated_ty.span, body_id, param_env, predicate), - ); + fulfillment_cx.register_predicate_obligation( + &infcx, + Obligation::misc(instantiated_ty.span, body_id, param_env, predicate), + ); - // Check that all obligations are satisfied by the implementation's - // version. - let errors = fulfillment_cx.select_all_or_error(&infcx); + // Check that all obligations are satisfied by the implementation's + // version. + let errors = fulfillment_cx.select_all_or_error(&infcx); - let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); + // This is still required for many(half of the tests in ui/type-alias-impl-trait) + // tests to pass + let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); - if errors.is_empty() { - definition_ty - } else { - infcx.report_fulfillment_errors(&errors, None, false); - self.tcx.ty_error() - } - }) + if errors.is_empty() { + definition_ty + } else { + infcx.report_fulfillment_errors(&errors, None, false); + self.tcx.ty_error() + } + }, + ) } else { definition_ty } @@ -423,7 +429,7 @@ fn check_opaque_type_parameter_valid( struct ReverseMapper<'tcx> { tcx: TyCtxt<'tcx>, - opaque_type_def_id: DefId, + opaque_type_def_id: LocalDefId, map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>, map_missing_regions_to_empty: bool, @@ -437,7 +443,7 @@ struct ReverseMapper<'tcx> { impl<'tcx> ReverseMapper<'tcx> { fn new( tcx: TyCtxt<'tcx>, - opaque_type_def_id: DefId, + opaque_type_def_id: LocalDefId, map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>, hidden_ty: Ty<'tcx>, span: Span, diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index 55c0bf05b48..6cfe5efb688 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -39,7 +39,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let TypeOpOutput { output, constraints, error_info } = op.fully_perform(self.infcx)?; - if let Some(data) = &constraints { + if let Some(data) = constraints { self.push_region_constraints(locations, category, data); } diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index 421ef5be812..fe66821ad75 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -335,7 +335,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { /// the same time, compute and add any implied bounds that come /// from this local. #[instrument(level = "debug", skip(self))] - fn add_implied_bounds(&mut self, ty: Ty<'tcx>) -> Option<Rc<QueryRegionConstraints<'tcx>>> { + fn add_implied_bounds(&mut self, ty: Ty<'tcx>) -> Option<&'tcx QueryRegionConstraints<'tcx>> { let TypeOpOutput { output: bounds, constraints, .. } = self .param_env .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty }) diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index 2a6ca5246da..4431a2e8ec6 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -225,7 +225,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { debug!("{:?} normalized to {:?}", t, norm_ty); - for data in constraints.into_iter().collect::<Vec<_>>() { + for data in constraints { ConstraintConversion::new( self.infcx, &self.borrowck_context.universal_regions, diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index 3795378b568..42b577175e4 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -98,7 +98,7 @@ struct LivenessContext<'me, 'typeck, 'flow, 'tcx> { struct DropData<'tcx> { dropck_result: DropckOutlivesResult<'tcx>, - region_constraint_data: Option<Rc<QueryRegionConstraints<'tcx>>>, + region_constraint_data: Option<&'tcx QueryRegionConstraints<'tcx>>, } struct LivenessResults<'me, 'typeck, 'flow, 'tcx> { diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 8e763a02af3..eb9df281e7d 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -21,6 +21,7 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi use rustc_infer::infer::{ InferCtxt, InferOk, LateBoundRegion, LateBoundRegionConversionTime, NllRegionVariableOrigin, }; +use rustc_infer::traits::ObligationCause; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::AssertKind; @@ -224,6 +225,26 @@ pub(crate) fn type_check<'mir, 'tcx>( ) .unwrap(); let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type); + // Check that RPITs are only constrained in their outermost + // function, otherwise report a mismatched types error. + if let OpaqueTyOrigin::FnReturn(parent) | OpaqueTyOrigin::AsyncFn(parent) + = infcx.opaque_ty_origin_unchecked(opaque_type_key.def_id, hidden_type.span) + && parent.to_def_id() != body.source.def_id() + { + infcx + .report_mismatched_types( + &ObligationCause::misc( + hidden_type.span, + infcx.tcx.hir().local_def_id_to_hir_id( + body.source.def_id().expect_local(), + ), + ), + infcx.tcx.mk_opaque(opaque_type_key.def_id.to_def_id(), opaque_type_key.substs), + hidden_type.ty, + ty::error::TypeError::Mismatch, + ) + .emit(); + } trace!( "finalized opaque type {:?} to {:#?}", opaque_type_key, @@ -790,19 +811,6 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { } PlaceTy::from_ty(fty) } - ProjectionElem::OpaqueCast(ty) => { - let ty = self.sanitize_type(place, ty); - let ty = self.cx.normalize(ty, location); - self.cx - .eq_types( - base.ty, - ty, - location.to_locations(), - ConstraintCategory::TypeAnnotation, - ) - .unwrap(); - PlaceTy::from_ty(ty) - } } } @@ -1208,11 +1216,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { tcx, self.param_env, proj, - |this, field, _| { + |this, field, ()| { let ty = this.field_ty(tcx, field); self.normalize(ty, locations) }, - |_, _| unreachable!(), ); curr_projected_ty = projected_ty; } @@ -2507,7 +2514,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } ProjectionElem::Field(..) | ProjectionElem::Downcast(..) - | ProjectionElem::OpaqueCast(..) | ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 076b627ca79..735017aa5a8 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -727,16 +727,8 @@ impl<'a> TraitDef<'a> { let attr = cx.attribute(cx.meta_word(self.span, sym::automatically_derived)); let opt_trait_ref = Some(trait_ref); - let unused_qual = { - let word = rustc_ast::attr::mk_nested_word_item(Ident::new( - sym::unused_qualifications, - self.span, - )); - let list = rustc_ast::attr::mk_list_item(Ident::new(sym::allow, self.span), vec![word]); - cx.attribute(list) - }; - let mut a = vec![attr, unused_qual]; + let mut a = vec![attr]; a.extend(self.attributes.iter().cloned()); cx.item( diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 3b7e2102ffa..ce897abb766 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -485,7 +485,7 @@ impl<'a, 'b> Context<'a, 'b> { if let Some(span) = fmt.width_span { let span = self.fmtsp.from_inner(InnerSpan::new(span.start, span.end)); match fmt.width { - parse::CountIsParam(pos) if pos > self.num_args() => { + parse::CountIsParam(pos) if pos >= self.num_args() => { e.span_label( span, &format!( @@ -1004,9 +1004,7 @@ fn lint_named_arguments_used_positionally( node_id: ast::CRATE_NODE_ID, lint_id: LintId::of(&NAMED_ARGUMENTS_USED_POSITIONALLY), diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally( - arg_span, - span, - symbol.to_string(), + arg_span, span, symbol, ), }); } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 54652623d94..63cd4d6de4c 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -825,7 +825,6 @@ pub(crate) fn codegen_place<'tcx>( cplace = cplace.place_deref(fx); } } - PlaceElem::OpaqueCast(ty) => cplace = cplace.place_opaque_cast(fx, ty), PlaceElem::Field(field, _ty) => { cplace = cplace.place_field(fx, field); } diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 48972321a9f..94a2fb2fbdd 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -195,9 +195,8 @@ pub(crate) fn codegen_const_value<'tcx>( } Scalar::Ptr(ptr, _size) => { let (alloc_id, offset) = ptr.into_parts(); // we know the `offset` is relative - let alloc_kind = fx.tcx.get_global_alloc(alloc_id); - let base_addr = match alloc_kind { - Some(GlobalAlloc::Memory(alloc)) => { + let base_addr = match fx.tcx.global_alloc(alloc_id) { + GlobalAlloc::Memory(alloc) => { let data_id = data_id_for_alloc_id( &mut fx.constants_cx, fx.module, @@ -211,13 +210,27 @@ pub(crate) fn codegen_const_value<'tcx>( } fx.bcx.ins().global_value(fx.pointer_type, local_data_id) } - Some(GlobalAlloc::Function(instance)) => { + GlobalAlloc::Function(instance) => { let func_id = crate::abi::import_function(fx.tcx, fx.module, instance); let local_func_id = fx.module.declare_func_in_func(func_id, &mut fx.bcx.func); fx.bcx.ins().func_addr(fx.pointer_type, local_func_id) } - Some(GlobalAlloc::Static(def_id)) => { + GlobalAlloc::VTable(ty, trait_ref) => { + let alloc_id = fx.tcx.vtable_allocation((ty, trait_ref)); + let alloc = fx.tcx.global_alloc(alloc_id).unwrap_memory(); + // FIXME: factor this common code with the `Memory` arm into a function? + let data_id = data_id_for_alloc_id( + &mut fx.constants_cx, + fx.module, + alloc_id, + alloc.inner().mutability, + ); + let local_data_id = + fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); + fx.bcx.ins().global_value(fx.pointer_type, local_data_id) + } + GlobalAlloc::Static(def_id) => { assert!(fx.tcx.is_static(def_id)); let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false); let local_data_id = @@ -227,7 +240,6 @@ pub(crate) fn codegen_const_value<'tcx>( } fx.bcx.ins().global_value(fx.pointer_type, local_data_id) } - None => bug!("missing allocation {:?}", alloc_id), }; let val = if offset.bytes() != 0 { fx.bcx.ins().iadd_imm(base_addr, i64::try_from(offset.bytes()).unwrap()) @@ -357,10 +369,11 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant while let Some(todo_item) = cx.todo.pop() { let (data_id, alloc, section_name) = match todo_item { TodoItem::Alloc(alloc_id) => { - //println!("alloc_id {}", alloc_id); - let alloc = match tcx.get_global_alloc(alloc_id).unwrap() { + let alloc = match tcx.global_alloc(alloc_id) { GlobalAlloc::Memory(alloc) => alloc, - GlobalAlloc::Function(_) | GlobalAlloc::Static(_) => unreachable!(), + GlobalAlloc::Function(_) | GlobalAlloc::Static(_) | GlobalAlloc::VTable(..) => { + unreachable!() + } }; let data_id = *cx.anon_allocs.entry(alloc_id).or_insert_with(|| { module @@ -424,7 +437,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant read_target_uint(endianness, bytes).unwrap() }; - let reloc_target_alloc = tcx.get_global_alloc(alloc_id).unwrap(); + let reloc_target_alloc = tcx.global_alloc(alloc_id); let data_id = match reloc_target_alloc { GlobalAlloc::Function(instance) => { assert_eq!(addend, 0); @@ -436,6 +449,10 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant GlobalAlloc::Memory(target_alloc) => { data_id_for_alloc_id(cx, module, alloc_id, target_alloc.inner().mutability) } + GlobalAlloc::VTable(ty, trait_ref) => { + let alloc_id = tcx.vtable_allocation((ty, trait_ref)); + data_id_for_alloc_id(cx, module, alloc_id, Mutability::Not) + } GlobalAlloc::Static(def_id) => { if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) { diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 4b2207f3758..d5a79e254a8 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -431,6 +431,16 @@ fn codegen_regular_intrinsic_call<'tcx>( ret.write_cvalue(fx, CValue::by_val(align, usize_layout)); }; + vtable_size, (v vtable) { + let size = crate::vtable::size_of_obj(fx, vtable); + ret.write_cvalue(fx, CValue::by_val(size, usize_layout)); + }; + + vtable_align, (v vtable) { + let align = crate::vtable::min_align_of_obj(fx, vtable); + ret.write_cvalue(fx, CValue::by_val(align, usize_layout)); + }; + unchecked_add | unchecked_sub | unchecked_mul | unchecked_div | exact_div | unchecked_rem | unchecked_shl | unchecked_shr, (c x, c y) { // FIXME trap on overflow diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index 8ff35d2f76d..a68225de58b 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -615,14 +615,6 @@ impl<'tcx> CPlace<'tcx> { } } - pub(crate) fn place_opaque_cast( - self, - fx: &mut FunctionCx<'_, '_, 'tcx>, - ty: Ty<'tcx>, - ) -> CPlace<'tcx> { - CPlace { inner: self.inner, layout: fx.layout_of(ty) } - } - pub(crate) fn place_field( self, fx: &mut FunctionCx<'_, '_, 'tcx>, diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs index 2c796d0f69e..0ed3e1fbe93 100644 --- a/compiler/rustc_codegen_gcc/src/abi.rs +++ b/compiler/rustc_codegen_gcc/src/abi.rs @@ -1,6 +1,6 @@ use gccjit::{ToLValue, ToRValue, Type}; use rustc_codegen_ssa::traits::{AbiBuilderMethods, BaseTypeMethods}; -use rustc_data_structures::stable_set::FxHashSet; +use rustc_data_structures::fx::FxHashSet; use rustc_middle::bug; use rustc_middle::ty::Ty; use rustc_target::abi::call::{CastTarget, FnAbi, PassMode, Reg, RegKind}; diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index fa490fe3f22..6221a7f6d93 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -30,7 +30,7 @@ use rustc_codegen_ssa::traits::{ OverflowOp, StaticBuilderMethods, }; -use rustc_data_structures::stable_set::FxHashSet; +use rustc_data_structures::fx::FxHashSet; use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; use rustc_middle::ty::layout::{FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout}; use rustc_span::Span; diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index fc391f53f18..ccb6cbbc2c8 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -201,6 +201,11 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { GlobalAlloc::Function(fn_instance) => { self.get_fn_addr(fn_instance) }, + GlobalAlloc::VTable(ty, trait_ref) => { + let alloc = self.tcx.global_alloc(self.tcx.vtable_allocation((ty, trait_ref))).unwrap_memory(); + let init = const_alloc_to_gcc(self, alloc); + self.static_addr_of(init, alloc.inner().align, None) + } GlobalAlloc::Static(def_id) => { assert!(self.tcx.is_static(def_id)); self.get_static(def_id).get_address(None) diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 32bfa5094c3..62da99ac3fb 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -299,6 +299,12 @@ pub fn from_fn_attrs<'ll, 'tcx>( } if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) { to_add.push(AttributeKind::Naked.create_attr(cx.llcx)); + // HACK(jubilee): "indirect branch tracking" works by attaching prologues to functions. + // And it is a module-level attribute, so the alternative is pulling naked functions into new LLVM modules. + // Otherwise LLVM's "naked" functions come with endbr prefixes per https://github.com/rust-lang/rust/issues/98768 + to_add.push(AttributeKind::NoCfCheck.create_attr(cx.llcx)); + // Need this for AArch64. + to_add.push(llvm::CreateAttrStringValue(cx.llcx, "branch-target-enforcement", "false")); } if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) { // apply to return place instead of function (unlike all other attributes applied in this function) diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index be539499b56..3731c6bcfe7 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -199,7 +199,7 @@ pub(crate) fn run_thin( pub(crate) fn prepare_thin(module: ModuleCodegen<ModuleLlvm>) -> (String, ThinBuffer) { let name = module.name.clone(); - let buffer = ThinBuffer::new(module.module_llvm.llmod()); + let buffer = ThinBuffer::new(module.module_llvm.llmod(), true); (name, buffer) } @@ -695,9 +695,9 @@ unsafe impl Send for ThinBuffer {} unsafe impl Sync for ThinBuffer {} impl ThinBuffer { - pub fn new(m: &llvm::Module) -> ThinBuffer { + pub fn new(m: &llvm::Module, is_thin: bool) -> ThinBuffer { unsafe { - let buffer = llvm::LLVMRustThinLTOBufferCreate(m); + let buffer = llvm::LLVMRustThinLTOBufferCreate(m, is_thin); ThinBuffer(buffer) } } diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 2b465ce40e7..534d32e8a90 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -790,7 +790,7 @@ pub(crate) unsafe fn codegen( let _timer = cgcx .prof .generic_activity_with_arg("LLVM_module_codegen_make_bitcode", &*module.name); - let thin = ThinBuffer::new(llmod); + let thin = ThinBuffer::new(llmod, config.emit_thin_lto); let data = thin.data(); if let Some(bitcode_filename) = bc_out.file_name() { diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index 77cbbf4c6ca..fb4da9a5f33 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -257,6 +257,15 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { self.get_fn_addr(fn_instance.polymorphize(self.tcx)), self.data_layout().instruction_address_space, ), + GlobalAlloc::VTable(ty, trait_ref) => { + let alloc = self + .tcx + .global_alloc(self.tcx.vtable_allocation((ty, trait_ref))) + .unwrap_memory(); + let init = const_alloc_to_llvm(self, alloc); + let value = self.static_addr_of(init, alloc.inner().align, None); + (value, AddressSpace::DATA) + } GlobalAlloc::Static(def_id) => { assert!(self.tcx.is_static(def_id)); assert!(!self.tcx.is_thread_local_static(def_id)); diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 2b16ae1a88d..18467e37082 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -101,7 +101,9 @@ pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation< let address_space = match cx.tcx.global_alloc(alloc_id) { GlobalAlloc::Function(..) => cx.data_layout().instruction_address_space, - GlobalAlloc::Static(..) | GlobalAlloc::Memory(..) => AddressSpace::DATA, + GlobalAlloc::Static(..) | GlobalAlloc::Memory(..) | GlobalAlloc::VTable(..) => { + AddressSpace::DATA + } }; llvals.push(cx.scalar_to_backend( @@ -535,10 +537,20 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> { // The semantics of #[used] in Rust only require the symbol to make it into the // object file. It is explicitly allowed for the linker to strip the symbol if it - // is dead. As such, use llvm.compiler.used instead of llvm.used. + // is dead, which means we are allowed use `llvm.compiler.used` instead of + // `llvm.used` here. + // // Additionally, https://reviews.llvm.org/D97448 in LLVM 13 started emitting unique // sections with SHF_GNU_RETAIN flag for llvm.used symbols, which may trigger bugs - // in some versions of the gold linker. + // in the handling of `.init_array` (the static constructor list) in versions of + // the gold linker (prior to the one released with binutils 2.36). + // + // That said, we only ever emit these when compiling for ELF targets, unless + // `#[used(compiler)]` is explicitly requested. This is to avoid similar breakage + // on other targets, in particular MachO targets have *their* static constructor + // lists broken if `llvm.compiler.used` is emitted rather than llvm.used. However, + // that check happens when assigning the `CodegenFnAttrFlags` in `rustc_typeck`, + // so we don't need to take care of it here. self.add_compiler_used_global(g); } if attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) { diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs index 5186aee57fb..80fd9726fc7 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs @@ -55,7 +55,7 @@ pub fn get_or_insert_gdb_debug_scripts_section_global<'ll>(cx: &CodegenCx<'ll, ' // The initial byte `4` instructs GDB that the following pretty printer // is defined inline as opposed to in a standalone file. section_contents.extend_from_slice(b"\x04"); - let vis_name = format!("pretty-printer-{}-{}\n", crate_name.as_str(), index); + let vis_name = format!("pretty-printer-{}-{}\n", crate_name, index); section_contents.extend_from_slice(vis_name.as_bytes()); section_contents.extend_from_slice(&visualizer.src); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index f8bd2d234f3..bd84100e0e8 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1420,7 +1420,7 @@ fn build_vtable_type_di_node<'ll, 'tcx>( cx, type_map::stub( cx, - Stub::VtableTy { vtable_holder }, + Stub::VTableTy { vtable_holder }, unique_type_id, &vtable_type_name, (size, pointer_align), diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs index 8fc8118849b..ce2f419c4ac 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs @@ -146,7 +146,7 @@ impl<'ll> DINodeCreationResult<'ll> { pub enum Stub<'ll> { Struct, Union, - VtableTy { vtable_holder: &'ll DIType }, + VTableTy { vtable_holder: &'ll DIType }, } pub struct StubInfo<'ll, 'tcx> { @@ -180,9 +180,9 @@ pub(super) fn stub<'ll, 'tcx>( let unique_type_id_str = unique_type_id.generate_unique_id_string(cx.tcx); let metadata = match kind { - Stub::Struct | Stub::VtableTy { .. } => { + Stub::Struct | Stub::VTableTy { .. } => { let vtable_holder = match kind { - Stub::VtableTy { vtable_holder } => Some(vtable_holder), + Stub::VTableTy { vtable_holder } => Some(vtable_holder), _ => None, }; unsafe { diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 0ad65e5d99b..624ce8d9369 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -191,6 +191,7 @@ pub enum AttributeKind { StackProtect = 32, NoUndef = 33, SanitizeMemTag = 34, + NoCfCheck = 35, } /// LLVMIntPredicate @@ -2469,7 +2470,7 @@ extern "C" { pub fn LLVMRustModuleBufferFree(p: &'static mut ModuleBuffer); pub fn LLVMRustModuleCost(M: &Module) -> u64; - pub fn LLVMRustThinLTOBufferCreate(M: &Module) -> &'static mut ThinLTOBuffer; + pub fn LLVMRustThinLTOBufferCreate(M: &Module, is_thin: bool) -> &'static mut ThinLTOBuffer; pub fn LLVMRustThinLTOBufferFree(M: &'static mut ThinLTOBuffer); pub fn LLVMRustThinLTOBufferPtr(M: &ThinLTOBuffer) -> *const c_char; pub fn LLVMRustThinLTOBufferLen(M: &ThinLTOBuffer) -> size_t; diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index c2ac21eec67..ea60f6055f3 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -99,6 +99,7 @@ pub struct ModuleConfig { pub emit_ir: bool, pub emit_asm: bool, pub emit_obj: EmitObj, + pub emit_thin_lto: bool, pub bc_cmdline: String, // Miscellaneous flags. These are mostly copied from command-line @@ -218,6 +219,7 @@ impl ModuleConfig { false ), emit_obj, + emit_thin_lto: sess.opts.unstable_opts.emit_thin_lto, bc_cmdline: sess.target.bitcode_llvm_cmdline.to_string(), verify_llvm_ir: sess.verify_llvm_ir(), diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 7def30af2b3..d95194e320b 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -171,7 +171,7 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( ); let new_vptr = bx.load(ptr_ty, gep, ptr_align); bx.nonnull_metadata(new_vptr); - // Vtable loads are invariant. + // VTable loads are invariant. bx.set_invariant_load(new_vptr); new_vptr } else { diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs index df42d804566..27d791d90a5 100644 --- a/compiler/rustc_codegen_ssa/src/meth.rs +++ b/compiler/rustc_codegen_ssa/src/meth.rs @@ -39,7 +39,7 @@ impl<'a, 'tcx> VirtualIndex { let gep = bx.inbounds_gep(llty, llvtable, &[bx.const_usize(self.0)]); let ptr = bx.load(llty, gep, ptr_align); bx.nonnull_metadata(ptr); - // Vtable loads are invariant. + // VTable loads are invariant. bx.set_invariant_load(ptr); ptr } @@ -58,7 +58,7 @@ impl<'a, 'tcx> VirtualIndex { let usize_align = bx.tcx().data_layout.pointer_align.abi; let gep = bx.inbounds_gep(llty, llvtable, &[bx.const_usize(self.0)]); let ptr = bx.load(llty, gep, usize_align); - // Vtable loads are invariant. + // VTable loads are invariant. bx.set_invariant_load(ptr); ptr } diff --git a/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs b/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs index a283bf1de76..f1fe495282a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs @@ -9,11 +9,8 @@ use super::FunctionCx; impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn codegen_coverage(&self, bx: &mut Bx, coverage: Coverage, scope: SourceScope) { // Determine the instance that coverage data was originally generated for. - let scope_data = &self.mir.source_scopes[scope]; - let instance = if let Some((inlined_instance, _)) = scope_data.inlined { - self.monomorphize(inlined_instance) - } else if let Some(inlined_scope) = scope_data.inlined_parent_scope { - self.monomorphize(self.mir.source_scopes[inlined_scope].inlined.unwrap().0) + let instance = if let Some(inlined) = scope.inlined_instance(&self.mir.source_scopes) { + self.monomorphize(inlined) } else { self.instance }; diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 645afae30d8..94ac71a4dd2 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -3,12 +3,16 @@ use super::place::PlaceRef; use super::FunctionCx; use crate::common::{span_invalid_monomorphization_error, IntPredicate}; use crate::glue; +use crate::meth; use crate::traits::*; use crate::MemFlags; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::{sym, Span}; -use rustc_target::abi::call::{FnAbi, PassMode}; +use rustc_target::abi::{ + call::{FnAbi, PassMode}, + WrappingRange, +}; fn copy_intrinsic<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, @@ -102,6 +106,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.const_usize(bx.layout_of(tp_ty).align.abi.bytes()) } } + sym::vtable_size | sym::vtable_align => { + let vtable = args[0].immediate(); + let idx = match name { + sym::vtable_size => ty::COMMON_VTABLE_ENTRIES_SIZE, + sym::vtable_align => ty::COMMON_VTABLE_ENTRIES_ALIGN, + _ => bug!(), + }; + let value = meth::VirtualIndex::from_index(idx).get_usize(bx, vtable); + if name == sym::vtable_align { + // Alignment is always nonzero. + bx.range_metadata(value, WrappingRange { start: 1, end: !0 }); + }; + value + } sym::pref_align_of | sym::needs_drop | sym::type_id diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 421d6f807ae..58cee0c8bb0 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -411,21 +411,6 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { downcast } - pub fn project_type<Bx: BuilderMethods<'a, 'tcx, Value = V>>( - &self, - bx: &mut Bx, - ty: Ty<'tcx>, - ) -> Self { - let mut downcast = *self; - downcast.layout = bx.cx().layout_of(ty); - - // Cast to the appropriate type. - let variant_ty = bx.cx().backend_type(downcast.layout); - downcast.llval = bx.pointercast(downcast.llval, bx.cx().type_ptr_to(variant_ty)); - - downcast - } - pub fn storage_live<Bx: BuilderMethods<'a, 'tcx, Value = V>>(&self, bx: &mut Bx) { bx.lifetime_start(self.llval, self.layout.size); } @@ -474,7 +459,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::ProjectionElem::Field(ref field, _) => { cg_base.project_field(bx, field.index()) } - mir::ProjectionElem::OpaqueCast(ty) => cg_base.project_type(bx, ty), mir::ProjectionElem::Index(index) => { let index = &mir::Operand::Copy(mir::Place::from(index)); let index = self.codegen_operand(bx, index); diff --git a/compiler/rustc_codegen_ssa/src/traits/statics.rs b/compiler/rustc_codegen_ssa/src/traits/statics.rs index a2a3cb56c78..413d31bb942 100644 --- a/compiler/rustc_codegen_ssa/src/traits/statics.rs +++ b/compiler/rustc_codegen_ssa/src/traits/statics.rs @@ -13,7 +13,9 @@ pub trait StaticMethods: BackendTypes { /// Same as add_used_global(), but only prevent the compiler from potentially removing an /// otherwise unused symbol. The linker is still permitted to drop it. /// - /// This corresponds to the semantics of the `#[used]` attribute. + /// This corresponds to the documented semantics of the `#[used]` attribute, although + /// on some targets (non-ELF), we may use `add_used_global` for `#[used]` statics + /// instead. fn add_compiler_used_global(&self, global: Self::Value); } diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index e00e667fb71..fc2e6652a3d 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -309,7 +309,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, ecx: &mut InterpCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx>], - dest: &PlaceTy<'tcx, Self::PointerTag>, + dest: &PlaceTy<'tcx, Self::Provenance>, target: Option<mir::BasicBlock>, _unwind: StackPopUnwind, ) -> InterpResult<'tcx> { @@ -369,7 +369,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, // we don't deallocate it. let (alloc_id, _, _) = ecx.ptr_get_alloc_id(ptr)?; let is_allocated_in_another_const = matches!( - ecx.tcx.get_global_alloc(alloc_id), + ecx.tcx.try_get_global_alloc(alloc_id), Some(interpret::GlobalAlloc::Memory(_)) ); @@ -470,14 +470,14 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, #[inline(always)] fn stack<'a>( ecx: &'a InterpCx<'mir, 'tcx, Self>, - ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] { + ) -> &'a [Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>] { &ecx.machine.stack } #[inline(always)] fn stack_mut<'a>( ecx: &'a mut InterpCx<'mir, 'tcx, Self>, - ) -> &'a mut Vec<Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>> { + ) -> &'a mut Vec<Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>> { &mut ecx.machine.stack } diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index edc4c13b6e8..948c3349498 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -138,7 +138,7 @@ pub(crate) fn deref_mir_constant<'tcx>( let mplace = ecx.deref_operand(&op).unwrap(); if let Some(alloc_id) = mplace.ptr.provenance { assert_eq!( - tcx.get_global_alloc(alloc_id).unwrap().unwrap_memory().0.0.mutability, + tcx.global_alloc(alloc_id).unwrap_memory().0.0.mutability, Mutability::Not, "deref_mir_constant cannot be used with mutable allocations as \ that could allow pattern matching to observe mutable statics", diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 5d598b65c72..883387851ea 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -18,10 +18,10 @@ use super::{ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn cast( &mut self, - src: &OpTy<'tcx, M::PointerTag>, + src: &OpTy<'tcx, M::Provenance>, cast_kind: CastKind, cast_ty: Ty<'tcx>, - dest: &PlaceTy<'tcx, M::PointerTag>, + dest: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { use rustc_middle::mir::CastKind::*; // FIXME: In which cases should we trigger UB when the source is uninit? @@ -114,9 +114,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn misc_cast( &mut self, - src: &ImmTy<'tcx, M::PointerTag>, + src: &ImmTy<'tcx, M::Provenance>, cast_ty: Ty<'tcx>, - ) -> InterpResult<'tcx, Immediate<M::PointerTag>> { + ) -> InterpResult<'tcx, Immediate<M::Provenance>> { use rustc_type_ir::sty::TyKind::*; trace!("Casting {:?}: {:?} to {:?}", *src, src.layout.ty, cast_ty); @@ -173,9 +173,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn pointer_expose_address_cast( &mut self, - src: &ImmTy<'tcx, M::PointerTag>, + src: &ImmTy<'tcx, M::Provenance>, cast_ty: Ty<'tcx>, - ) -> InterpResult<'tcx, Immediate<M::PointerTag>> { + ) -> InterpResult<'tcx, Immediate<M::Provenance>> { assert_matches!(src.layout.ty.kind(), ty::RawPtr(_) | ty::FnPtr(_)); assert!(cast_ty.is_integral()); @@ -190,9 +190,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn pointer_from_exposed_address_cast( &mut self, - src: &ImmTy<'tcx, M::PointerTag>, + src: &ImmTy<'tcx, M::Provenance>, cast_ty: Ty<'tcx>, - ) -> InterpResult<'tcx, Immediate<M::PointerTag>> { + ) -> InterpResult<'tcx, Immediate<M::Provenance>> { assert!(src.layout.ty.is_integral()); assert_matches!(cast_ty.kind(), ty::RawPtr(_)); @@ -208,10 +208,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn cast_from_int_like( &self, - scalar: Scalar<M::PointerTag>, // input value (there is no ScalarTy so we separate data+layout) + scalar: Scalar<M::Provenance>, // input value (there is no ScalarTy so we separate data+layout) src_layout: TyAndLayout<'tcx>, cast_ty: Ty<'tcx>, - ) -> InterpResult<'tcx, Scalar<M::PointerTag>> { + ) -> InterpResult<'tcx, Scalar<M::Provenance>> { // Let's make sure v is sign-extended *if* it has a signed type. let signed = src_layout.abi.is_signed(); // Also asserts that abi is `Scalar`. @@ -245,9 +245,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }) } - fn cast_from_float<F>(&self, f: F, dest_ty: Ty<'tcx>) -> Scalar<M::PointerTag> + fn cast_from_float<F>(&self, f: F, dest_ty: Ty<'tcx>) -> Scalar<M::Provenance> where - F: Float + Into<Scalar<M::PointerTag>> + FloatConvert<Single> + FloatConvert<Double>, + F: Float + Into<Scalar<M::Provenance>> + FloatConvert<Single> + FloatConvert<Double>, { use rustc_type_ir::sty::TyKind::*; match *dest_ty.kind() { @@ -279,8 +279,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { fn unsize_into_ptr( &mut self, - src: &OpTy<'tcx, M::PointerTag>, - dest: &PlaceTy<'tcx, M::PointerTag>, + src: &OpTy<'tcx, M::Provenance>, + dest: &PlaceTy<'tcx, M::Provenance>, // The pointee types source_ty: Ty<'tcx>, cast_ty: Ty<'tcx>, @@ -298,30 +298,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.write_immediate(val, dest) } (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => { - let val = self.read_immediate(src)?; - if data_a.principal_def_id() == data_b.principal_def_id() { - return self.write_immediate(*val, dest); - } - // trait upcasting coercion - let vptr_entry_idx = self.tcx.vtable_trait_upcasting_coercion_new_vptr_slot(( - src_pointee_ty, - dest_pointee_ty, - )); - - if let Some(entry_idx) = vptr_entry_idx { - let entry_idx = u64::try_from(entry_idx).unwrap(); - let (old_data, old_vptr) = val.to_scalar_pair()?; - let old_vptr = self.scalar_to_ptr(old_vptr)?; - let new_vptr = self - .read_new_vtable_after_trait_upcasting_from_vtable(old_vptr, entry_idx)?; - self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest) - } else { - self.write_immediate(*val, dest) + let (old_data, old_vptr) = self.read_immediate(src)?.to_scalar_pair()?; + let old_vptr = self.scalar_to_ptr(old_vptr)?; + let (ty, old_trait) = self.get_ptr_vtable(old_vptr)?; + if old_trait != data_a.principal() { + throw_ub_format!("upcast on a pointer whose vtable does not match its type"); } + let new_vptr = self.get_vtable_ptr(ty, data_b.principal())?; + self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest) } (_, &ty::Dynamic(ref data, _)) => { // Initial cast from sized to dyn trait - let vtable = self.get_vtable(src_pointee_ty, data.principal())?; + let vtable = self.get_vtable_ptr(src_pointee_ty, data.principal())?; let ptr = self.read_immediate(src)?.to_scalar()?; let val = Immediate::new_dyn_trait(ptr, vtable, &*self.tcx); self.write_immediate(val, dest) @@ -335,9 +323,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { fn unsize_into( &mut self, - src: &OpTy<'tcx, M::PointerTag>, + src: &OpTy<'tcx, M::Provenance>, cast_ty: TyAndLayout<'tcx>, - dest: &PlaceTy<'tcx, M::PointerTag>, + dest: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { trace!("Unsizing {:?} of type {} into {:?}", *src, src.layout.ty, cast_ty.ty); match (&src.layout.ty.kind(), &cast_ty.ty.kind()) { diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index bacf5d5a59f..fdf243c4108 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -2,10 +2,8 @@ use std::cell::Cell; use std::fmt; use std::mem; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData}; use rustc_index::vec::IndexVec; -use rustc_macros::HashStable; use rustc_middle::mir; use rustc_middle::mir::interpret::{InterpError, InvalidProgramInfo}; use rustc_middle::ty::layout::{ @@ -16,7 +14,6 @@ use rustc_middle::ty::{ self, query::TyCtxtAt, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, }; use rustc_mir_dataflow::storage::always_storage_live_locals; -use rustc_query_system::ich::StableHashingContext; use rustc_session::Limit; use rustc_span::{Pos, Span}; use rustc_target::abi::{call::FnAbi, Align, HasDataLayout, Size, TargetDataLayout}; @@ -84,7 +81,7 @@ impl Drop for SpanGuard { } /// A stack frame. -pub struct Frame<'mir, 'tcx, Tag: Provenance = AllocId, Extra = ()> { +pub struct Frame<'mir, 'tcx, Prov: Provenance = AllocId, Extra = ()> { //////////////////////////////////////////////////////////////////////////////// // Function and callsite information //////////////////////////////////////////////////////////////////////////////// @@ -105,7 +102,7 @@ pub struct Frame<'mir, 'tcx, Tag: Provenance = AllocId, Extra = ()> { /// The location where the result of the current stack frame should be written to, /// and its layout in the caller. - pub return_place: PlaceTy<'tcx, Tag>, + pub return_place: PlaceTy<'tcx, Prov>, /// The list of locals for this stack frame, stored in order as /// `[return_ptr, arguments..., variables..., temporaries...]`. @@ -114,7 +111,7 @@ pub struct Frame<'mir, 'tcx, Tag: Provenance = AllocId, Extra = ()> { /// can either directly contain `Scalar` or refer to some part of an `Allocation`. /// /// Do *not* access this directly; always go through the machine hook! - pub locals: IndexVec<mir::Local, LocalState<'tcx, Tag>>, + pub locals: IndexVec<mir::Local, LocalState<'tcx, Prov>>, /// The span of the `tracing` crate is stored here. /// When the guard is dropped, the span is exited. This gives us @@ -142,7 +139,7 @@ pub struct FrameInfo<'tcx> { } /// Unwind information. -#[derive(Clone, Copy, Eq, PartialEq, Debug, HashStable)] +#[derive(Clone, Copy, Eq, PartialEq, Debug)] pub enum StackPopUnwind { /// The cleanup block. Cleanup(mir::BasicBlock), @@ -152,7 +149,7 @@ pub enum StackPopUnwind { NotAllowed, } -#[derive(Clone, Copy, Eq, PartialEq, Debug, HashStable)] // Miri debug-prints these +#[derive(Clone, Copy, Eq, PartialEq, Debug)] // Miri debug-prints these pub enum StackPopCleanup { /// Jump to the next block in the caller, or cause UB if None (that's a function /// that may never return). Also store layout of return place so @@ -168,17 +165,16 @@ pub enum StackPopCleanup { } /// State of a local variable including a memoized layout -#[derive(Clone, Debug, PartialEq, Eq, HashStable)] -pub struct LocalState<'tcx, Tag: Provenance = AllocId> { - pub value: LocalValue<Tag>, +#[derive(Clone, Debug)] +pub struct LocalState<'tcx, Prov: Provenance = AllocId> { + pub value: LocalValue<Prov>, /// Don't modify if `Some`, this is only used to prevent computing the layout twice - #[stable_hasher(ignore)] pub layout: Cell<Option<TyAndLayout<'tcx>>>, } /// Current value of a local variable -#[derive(Copy, Clone, PartialEq, Eq, HashStable, Debug)] // Miri debug-prints these -pub enum LocalValue<Tag: Provenance = AllocId> { +#[derive(Copy, Clone, Debug)] // Miri debug-prints these +pub enum LocalValue<Prov: Provenance = AllocId> { /// This local is not currently alive, and cannot be used at all. Dead, /// A normal, live local. @@ -186,16 +182,16 @@ pub enum LocalValue<Tag: Provenance = AllocId> { /// This is an optimization over just always having a pointer here; /// we can thus avoid doing an allocation when the local just stores /// immediate values *and* never has its address taken. - Live(Operand<Tag>), + Live(Operand<Prov>), } -impl<'tcx, Tag: Provenance + 'static> LocalState<'tcx, Tag> { +impl<'tcx, Prov: Provenance + 'static> LocalState<'tcx, Prov> { /// Read the local's value or error if the local is not yet live or not live anymore. /// /// Note: This may only be invoked from the `Machine::access_local` hook and not from /// anywhere else. You may be invalidating machine invariants if you do! #[inline] - pub fn access(&self) -> InterpResult<'tcx, &Operand<Tag>> { + pub fn access(&self) -> InterpResult<'tcx, &Operand<Prov>> { match &self.value { LocalValue::Dead => throw_ub!(DeadLocal), // could even be "invalid program"? LocalValue::Live(val) => Ok(val), @@ -208,7 +204,7 @@ impl<'tcx, Tag: Provenance + 'static> LocalState<'tcx, Tag> { /// Note: This may only be invoked from the `Machine::access_local_mut` hook and not from /// anywhere else. You may be invalidating machine invariants if you do! #[inline] - pub fn access_mut(&mut self) -> InterpResult<'tcx, &mut Operand<Tag>> { + pub fn access_mut(&mut self) -> InterpResult<'tcx, &mut Operand<Prov>> { match &mut self.value { LocalValue::Dead => throw_ub!(DeadLocal), // could even be "invalid program"? LocalValue::Live(val) => Ok(val), @@ -216,8 +212,8 @@ impl<'tcx, Tag: Provenance + 'static> LocalState<'tcx, Tag> { } } -impl<'mir, 'tcx, Tag: Provenance> Frame<'mir, 'tcx, Tag> { - pub fn with_extra<Extra>(self, extra: Extra) -> Frame<'mir, 'tcx, Tag, Extra> { +impl<'mir, 'tcx, Prov: Provenance> Frame<'mir, 'tcx, Prov> { + pub fn with_extra<Extra>(self, extra: Extra) -> Frame<'mir, 'tcx, Prov, Extra> { Frame { body: self.body, instance: self.instance, @@ -231,7 +227,7 @@ impl<'mir, 'tcx, Tag: Provenance> Frame<'mir, 'tcx, Tag> { } } -impl<'mir, 'tcx, Tag: Provenance, Extra> Frame<'mir, 'tcx, Tag, Extra> { +impl<'mir, 'tcx, Prov: Provenance, Extra> Frame<'mir, 'tcx, Prov, Extra> { /// Get the current location within the Frame. /// /// If this is `Err`, we are not currently executing any particular statement in @@ -426,14 +422,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } #[inline(always)] - pub(crate) fn stack(&self) -> &[Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>] { + pub(crate) fn stack(&self) -> &[Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>] { M::stack(self) } #[inline(always)] pub(crate) fn stack_mut( &mut self, - ) -> &mut Vec<Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>> { + ) -> &mut Vec<Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>> { M::stack_mut(self) } @@ -445,12 +441,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } #[inline(always)] - pub fn frame(&self) -> &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra> { + pub fn frame(&self) -> &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra> { self.stack().last().expect("no call frames exist") } #[inline(always)] - pub fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra> { + pub fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx, M::Provenance, M::FrameExtra> { self.stack_mut().last_mut().expect("no call frames exist") } @@ -507,7 +503,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// stack frame), to bring it into the proper environment for this interpreter. pub(super) fn subst_from_frame_and_normalize_erasing_regions<T: TypeFoldable<'tcx>>( &self, - frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>, + frame: &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>, value: T, ) -> Result<T, InterpError<'tcx>> { frame @@ -544,7 +540,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { #[inline(always)] pub fn layout_of_local( &self, - frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>, + frame: &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>, local: mir::Local, layout: Option<TyAndLayout<'tcx>>, ) -> InterpResult<'tcx, TyAndLayout<'tcx>> { @@ -573,7 +569,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// This can fail to provide an answer for extern types. pub(super) fn size_and_align_of( &self, - metadata: &MemPlaceMeta<M::PointerTag>, + metadata: &MemPlaceMeta<M::Provenance>, layout: &TyAndLayout<'tcx>, ) -> InterpResult<'tcx, Option<(Size, Align)>> { if !layout.is_unsized() { @@ -635,7 +631,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ty::Dynamic(..) => { let vtable = self.scalar_to_ptr(metadata.unwrap_meta())?; // Read size and align from vtable (already checks size). - Ok(Some(self.read_size_and_align_from_vtable(vtable)?)) + Ok(Some(self.get_vtable_size_and_align(vtable)?)) } ty::Slice(_) | ty::Str => { @@ -659,7 +655,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { #[inline] pub fn size_and_align_of_mplace( &self, - mplace: &MPlaceTy<'tcx, M::PointerTag>, + mplace: &MPlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, Option<(Size, Align)>> { self.size_and_align_of(&mplace.meta, &mplace.layout) } @@ -669,7 +665,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &mut self, instance: ty::Instance<'tcx>, body: &'mir mir::Body<'tcx>, - return_place: &PlaceTy<'tcx, M::PointerTag>, + return_place: &PlaceTy<'tcx, M::Provenance>, return_to_block: StackPopCleanup, ) -> InterpResult<'tcx> { trace!("body: {:#?}", body); @@ -678,7 +674,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { body, loc: Err(body.span), // Span used for errors caused during preamble. return_to_block, - return_place: *return_place, + return_place: return_place.clone(), // empty local array, we fill it in below, after we are inside the stack frame and // all methods actually know about the frame locals: IndexVec::new(), @@ -799,7 +795,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let op = self .local_to_op(self.frame(), mir::RETURN_PLACE, None) .expect("return place should always be live"); - let dest = self.frame().return_place; + let dest = self.frame().return_place.clone(); let err = self.copy_op(&op, &dest, /*allow_transmute*/ true); trace!("return value: {:?}", self.dump_place(*dest)); // We delay actually short-circuiting on this error until *after* the stack frame is @@ -895,7 +891,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } #[instrument(skip(self), level = "debug")] - fn deallocate_local(&mut self, local: LocalValue<M::PointerTag>) -> InterpResult<'tcx> { + fn deallocate_local(&mut self, local: LocalValue<M::Provenance>) -> InterpResult<'tcx> { if let LocalValue::Live(Operand::Indirect(MemPlace { ptr, .. })) = local { // All locals have a backing allocation, even if the allocation is empty // due to the local having ZST type. Hence we can `unwrap`. @@ -913,7 +909,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn eval_to_allocation( &self, gid: GlobalId<'tcx>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { // For statics we pick `ParamEnv::reveal_all`, because statics don't have generics // and thus don't care about the parameter environment. While we could just use // `self.param_env`, that would mean we invoke the query to evaluate the static @@ -931,7 +927,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } #[must_use] - pub fn dump_place(&self, place: Place<M::PointerTag>) -> PlacePrinter<'_, 'mir, 'tcx, M> { + pub fn dump_place(&self, place: Place<M::Provenance>) -> PlacePrinter<'_, 'mir, 'tcx, M> { PlacePrinter { ecx: self, place } } @@ -960,7 +956,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Helper struct for the `dump_place` function. pub struct PlacePrinter<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> { ecx: &'a InterpCx<'mir, 'tcx, M>, - place: Place<M::PointerTag>, + place: Place<M::Provenance>, } impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> std::fmt::Debug @@ -1021,31 +1017,3 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> std::fmt::Debug } } } - -impl<'ctx, 'mir, 'tcx, Tag: Provenance, Extra> HashStable<StableHashingContext<'ctx>> - for Frame<'mir, 'tcx, Tag, Extra> -where - Extra: HashStable<StableHashingContext<'ctx>>, - Tag: HashStable<StableHashingContext<'ctx>>, -{ - fn hash_stable(&self, hcx: &mut StableHashingContext<'ctx>, hasher: &mut StableHasher) { - // Exhaustive match on fields to make sure we forget no field. - let Frame { - body, - instance, - return_to_block, - return_place, - locals, - loc, - extra, - tracing_span: _, - } = self; - body.hash_stable(hcx, hasher); - instance.hash_stable(hcx, hasher); - return_to_block.hash_stable(hcx, hasher); - return_place.hash_stable(hcx, hasher); - locals.hash_stable(hcx, hasher); - loc.hash_stable(hcx, hasher); - extra.hash_stable(hcx, hasher); - } -} diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 7616e7a63d1..23526edcc34 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -33,7 +33,7 @@ pub trait CompileTimeMachine<'mir, 'tcx, T> = Machine< 'mir, 'tcx, MemoryKind = T, - PointerTag = AllocId, + Provenance = AllocId, ExtraFnVal = !, FrameExtra = (), AllocExtra = (), @@ -94,7 +94,7 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval: // to validation to error -- it has the much better error messages, pointing out where // in the value the dangling reference lies. // The `delay_span_bug` ensures that we don't forget such a check in validation. - if tcx.get_global_alloc(alloc_id).is_none() { + if tcx.try_get_global_alloc(alloc_id).is_none() { tcx.sess.delay_span_bug(ecx.tcx.span, "tried to intern dangling pointer"); } // treat dangling pointers like other statics @@ -454,7 +454,7 @@ pub fn intern_const_alloc_recursive< .sess .span_err(ecx.tcx.span, "encountered dangling pointer in final constant"); return Err(reported); - } else if ecx.tcx.get_global_alloc(alloc_id).is_none() { + } else if ecx.tcx.try_get_global_alloc(alloc_id).is_none() { // We have hit an `AllocId` that is neither in local or global memory and isn't // marked as dangling by local memory. That should be impossible. span_bug!(ecx.tcx.span, "encountered unknown alloc id {:?}", alloc_id); @@ -474,7 +474,7 @@ impl<'mir, 'tcx: 'mir, M: super::intern::CompileTimeMachine<'mir, 'tcx, !>> layout: TyAndLayout<'tcx>, f: impl FnOnce( &mut InterpCx<'mir, 'tcx, M>, - &PlaceTy<'tcx, M::PointerTag>, + &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, ()>, ) -> InterpResult<'tcx, ConstAllocation<'tcx>> { let dest = self.allocate(layout, MemoryKind::Stack)?; diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 242e3879e3a..025f8647c95 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -25,7 +25,7 @@ use super::{ mod caller_location; mod type_name; -fn numeric_intrinsic<Tag>(name: Symbol, bits: u128, kind: Primitive) -> Scalar<Tag> { +fn numeric_intrinsic<Prov>(name: Symbol, bits: u128, kind: Primitive) -> Scalar<Prov> { let size = match kind { Primitive::Int(integer, _) => integer.size(), _ => bug!("invalid `{}` argument: {:?}", name, bits), @@ -114,8 +114,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn emulate_intrinsic( &mut self, instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, M::PointerTag>], - dest: &PlaceTy<'tcx, M::PointerTag>, + args: &[OpTy<'tcx, M::Provenance>], + dest: &PlaceTy<'tcx, M::Provenance>, ret: Option<mir::BasicBlock>, ) -> InterpResult<'tcx, bool> { let substs = instance.substs; @@ -455,8 +455,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { for i in 0..dest_len { let place = self.mplace_index(&dest, i)?; - let value = - if i == index { *elem } else { self.mplace_index(&input, i)?.into() }; + let value = if i == index { + elem.clone() + } else { + self.mplace_index(&input, i)?.into() + }; self.copy_op(&value, &place.into(), /*allow_transmute*/ false)?; } } @@ -489,6 +492,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let result = self.raw_eq_intrinsic(&args[0], &args[1])?; self.write_scalar(result, dest)?; } + + sym::vtable_size => { + let ptr = self.read_pointer(&args[0])?; + let (size, _align) = self.get_vtable_size_and_align(ptr)?; + self.write_scalar(Scalar::from_machine_usize(size.bytes(), self), dest)?; + } + sym::vtable_align => { + let ptr = self.read_pointer(&args[0])?; + let (_size, align) = self.get_vtable_size_and_align(ptr)?; + self.write_scalar(Scalar::from_machine_usize(align.bytes(), self), dest)?; + } + _ => return Ok(false), } @@ -499,9 +514,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn exact_div( &mut self, - a: &ImmTy<'tcx, M::PointerTag>, - b: &ImmTy<'tcx, M::PointerTag>, - dest: &PlaceTy<'tcx, M::PointerTag>, + a: &ImmTy<'tcx, M::Provenance>, + b: &ImmTy<'tcx, M::Provenance>, + dest: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { // Performs an exact division, resulting in undefined behavior where // `x % y != 0` or `y == 0` or `x == T::MIN && y == -1`. @@ -518,9 +533,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn saturating_arith( &self, mir_op: BinOp, - l: &ImmTy<'tcx, M::PointerTag>, - r: &ImmTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, Scalar<M::PointerTag>> { + l: &ImmTy<'tcx, M::Provenance>, + r: &ImmTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, Scalar<M::Provenance>> { assert!(matches!(mir_op, BinOp::Add | BinOp::Sub)); let (val, overflowed, _ty) = self.overflowing_binary_op(mir_op, l, r)?; Ok(if overflowed { @@ -563,10 +578,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// 0, so offset-by-0 (and only 0) is okay -- except that null cannot be offset by _any_ value. pub fn ptr_offset_inbounds( &self, - ptr: Pointer<Option<M::PointerTag>>, + ptr: Pointer<Option<M::Provenance>>, pointee_ty: Ty<'tcx>, offset_count: i64, - ) -> InterpResult<'tcx, Pointer<Option<M::PointerTag>>> { + ) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>> { // We cannot overflow i64 as a type's size must be <= isize::MAX. let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap(); // The computed offset, in bytes, must not overflow an isize. @@ -594,9 +609,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Copy `count*size_of::<T>()` many bytes from `*src` to `*dst`. pub(crate) fn copy_intrinsic( &mut self, - src: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>, - dst: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>, - count: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>, + src: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>, + dst: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>, + count: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>, nonoverlapping: bool, ) -> InterpResult<'tcx> { let count = self.read_scalar(&count)?.to_machine_usize(self)?; @@ -619,9 +634,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub(crate) fn write_bytes_intrinsic( &mut self, - dst: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>, - byte: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>, - count: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>, + dst: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>, + byte: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>, + count: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>, ) -> InterpResult<'tcx> { let layout = self.layout_of(dst.layout.ty.builtin_deref(true).unwrap().ty)?; @@ -642,9 +657,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub(crate) fn raw_eq_intrinsic( &mut self, - lhs: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>, - rhs: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>, - ) -> InterpResult<'tcx, Scalar<M::PointerTag>> { + lhs: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>, + rhs: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>, + ) -> InterpResult<'tcx, Scalar<M::Provenance>> { let layout = self.layout_of(lhs.layout.ty.builtin_deref(true).unwrap().ty)?; assert!(!layout.is_unsized()); diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs index 14fde2c305e..5864b921552 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs @@ -79,7 +79,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { filename: Symbol, line: u32, col: u32, - ) -> MPlaceTy<'tcx, M::PointerTag> { + ) -> MPlaceTy<'tcx, M::Provenance> { let loc_details = &self.tcx.sess.opts.unstable_opts.location_detail; let file = if loc_details.file { self.allocate_str(filename.as_str(), MemoryKind::CallerLocation, Mutability::Not) @@ -123,7 +123,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ) } - pub fn alloc_caller_location_for_span(&mut self, span: Span) -> MPlaceTy<'tcx, M::PointerTag> { + pub fn alloc_caller_location_for_span(&mut self, span: Span) -> MPlaceTy<'tcx, M::Provenance> { let (file, line, column) = self.location_triple_for_span(span); self.alloc_caller_location(file, line, column) } diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 7f8eea94aee..a938a9248e0 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -85,11 +85,11 @@ pub trait Machine<'mir, 'tcx>: Sized { type MemoryKind: Debug + std::fmt::Display + MayLeak + Eq + 'static; /// Pointers are "tagged" with provenance information; typically the `AllocId` they belong to. - type PointerTag: Provenance + Eq + Hash + 'static; + type Provenance: Provenance + Eq + Hash + 'static; - /// When getting the AllocId of a pointer, some extra data is also obtained from the tag + /// When getting the AllocId of a pointer, some extra data is also obtained from the provenance /// that is passed to memory access hooks so they can do things with it. - type TagExtra: Copy + 'static; + type ProvenanceExtra: Copy + 'static; /// Machines can define extra (non-instance) things that represent values of function pointers. /// For example, Miri uses this to return a function pointer from `dlsym` @@ -105,7 +105,7 @@ pub trait Machine<'mir, 'tcx>: Sized { /// Memory's allocation map type MemoryMap: AllocMap< AllocId, - (MemoryKind<Self::MemoryKind>, Allocation<Self::PointerTag, Self::AllocExtra>), + (MemoryKind<Self::MemoryKind>, Allocation<Self::Provenance, Self::AllocExtra>), > + Default + Clone; @@ -113,7 +113,7 @@ pub trait Machine<'mir, 'tcx>: Sized { /// or None if such memory should not be mutated and thus any such attempt will cause /// a `ModifiedStatic` error to be raised. /// Statics are copied under two circumstances: When they are mutated, and when - /// `tag_allocation` (see below) returns an owned allocation + /// `adjust_allocation` (see below) returns an owned allocation /// that is added to the memory so that the work is not done twice. const GLOBAL_KIND: Option<Self::MemoryKind>; @@ -126,7 +126,7 @@ pub trait Machine<'mir, 'tcx>: Sized { /// Whether, when checking alignment, we should `force_int` and thus support /// custom alignment logic based on whatever the integer address happens to be. /// - /// Requires PointerTag::OFFSET_IS_ADDR to be true. + /// Requires Provenance::OFFSET_IS_ADDR to be true. fn force_int_for_alignment_check(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool; /// Whether to enforce the validity invariant @@ -170,8 +170,8 @@ pub trait Machine<'mir, 'tcx>: Sized { ecx: &mut InterpCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, abi: CallAbi, - args: &[OpTy<'tcx, Self::PointerTag>], - destination: &PlaceTy<'tcx, Self::PointerTag>, + args: &[OpTy<'tcx, Self::Provenance>], + destination: &PlaceTy<'tcx, Self::Provenance>, target: Option<mir::BasicBlock>, unwind: StackPopUnwind, ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>>; @@ -182,8 +182,8 @@ pub trait Machine<'mir, 'tcx>: Sized { ecx: &mut InterpCx<'mir, 'tcx, Self>, fn_val: Self::ExtraFnVal, abi: CallAbi, - args: &[OpTy<'tcx, Self::PointerTag>], - destination: &PlaceTy<'tcx, Self::PointerTag>, + args: &[OpTy<'tcx, Self::Provenance>], + destination: &PlaceTy<'tcx, Self::Provenance>, target: Option<mir::BasicBlock>, unwind: StackPopUnwind, ) -> InterpResult<'tcx>; @@ -193,8 +193,8 @@ pub trait Machine<'mir, 'tcx>: Sized { fn call_intrinsic( ecx: &mut InterpCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, Self::PointerTag>], - destination: &PlaceTy<'tcx, Self::PointerTag>, + args: &[OpTy<'tcx, Self::Provenance>], + destination: &PlaceTy<'tcx, Self::Provenance>, target: Option<mir::BasicBlock>, unwind: StackPopUnwind, ) -> InterpResult<'tcx>; @@ -217,18 +217,18 @@ pub trait Machine<'mir, 'tcx>: Sized { fn binary_ptr_op( ecx: &InterpCx<'mir, 'tcx, Self>, bin_op: mir::BinOp, - left: &ImmTy<'tcx, Self::PointerTag>, - right: &ImmTy<'tcx, Self::PointerTag>, - ) -> InterpResult<'tcx, (Scalar<Self::PointerTag>, bool, Ty<'tcx>)>; + left: &ImmTy<'tcx, Self::Provenance>, + right: &ImmTy<'tcx, Self::Provenance>, + ) -> InterpResult<'tcx, (Scalar<Self::Provenance>, bool, Ty<'tcx>)>; /// Called to read the specified `local` from the `frame`. /// Since reading a ZST is not actually accessing memory or locals, this is never invoked /// for ZST reads. #[inline] fn access_local<'a>( - frame: &'a Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>, + frame: &'a Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>, local: mir::Local, - ) -> InterpResult<'tcx, &'a Operand<Self::PointerTag>> + ) -> InterpResult<'tcx, &'a Operand<Self::Provenance>> where 'tcx: 'mir, { @@ -243,7 +243,7 @@ pub trait Machine<'mir, 'tcx>: Sized { ecx: &'a mut InterpCx<'mir, 'tcx, Self>, frame: usize, local: mir::Local, - ) -> InterpResult<'tcx, &'a mut Operand<Self::PointerTag>> + ) -> InterpResult<'tcx, &'a mut Operand<Self::Provenance>> where 'tcx: 'mir, { @@ -275,7 +275,7 @@ pub trait Machine<'mir, 'tcx>: Sized { fn thread_local_static_base_pointer( _ecx: &mut InterpCx<'mir, 'tcx, Self>, def_id: DefId, - ) -> InterpResult<'tcx, Pointer<Self::PointerTag>> { + ) -> InterpResult<'tcx, Pointer<Self::Provenance>> { throw_unsup!(ThreadLocalStatic(def_id)) } @@ -283,35 +283,35 @@ pub trait Machine<'mir, 'tcx>: Sized { fn extern_static_base_pointer( ecx: &InterpCx<'mir, 'tcx, Self>, def_id: DefId, - ) -> InterpResult<'tcx, Pointer<Self::PointerTag>>; + ) -> InterpResult<'tcx, Pointer<Self::Provenance>>; /// Return a "base" pointer for the given allocation: the one that is used for direct /// accesses to this static/const/fn allocation, or the one returned from the heap allocator. /// /// Not called on `extern` or thread-local statics (those use the methods above). - fn tag_alloc_base_pointer( + fn adjust_alloc_base_pointer( ecx: &InterpCx<'mir, 'tcx, Self>, ptr: Pointer, - ) -> Pointer<Self::PointerTag>; + ) -> Pointer<Self::Provenance>; /// "Int-to-pointer cast" fn ptr_from_addr_cast( ecx: &InterpCx<'mir, 'tcx, Self>, addr: u64, - ) -> InterpResult<'tcx, Pointer<Option<Self::PointerTag>>>; + ) -> InterpResult<'tcx, Pointer<Option<Self::Provenance>>>; /// Hook for returning a pointer from a transmute-like operation on an addr. /// This is only needed to support Miri's (unsound) "allow-ptr-int-transmute" flag. fn ptr_from_addr_transmute( ecx: &InterpCx<'mir, 'tcx, Self>, addr: u64, - ) -> Pointer<Option<Self::PointerTag>>; + ) -> Pointer<Option<Self::Provenance>>; /// Marks a pointer as exposed, allowing it's provenance /// to be recovered. "Pointer-to-int cast" fn expose_ptr( ecx: &mut InterpCx<'mir, 'tcx, Self>, - ptr: Pointer<Self::PointerTag>, + ptr: Pointer<Self::Provenance>, ) -> InterpResult<'tcx>; /// Convert a pointer with provenance into an allocation-offset pair @@ -322,30 +322,30 @@ pub trait Machine<'mir, 'tcx>: Sized { /// When this fails, that means the pointer does not point to a live allocation. fn ptr_get_alloc( ecx: &InterpCx<'mir, 'tcx, Self>, - ptr: Pointer<Self::PointerTag>, - ) -> Option<(AllocId, Size, Self::TagExtra)>; - - /// Called to initialize the "extra" state of an allocation and make the pointers - /// it contains (in relocations) tagged. The way we construct allocations is - /// to always first construct it without extra and then add the extra. - /// This keeps uniform code paths for handling both allocations created by CTFE - /// for globals, and allocations created by Miri during evaluation. + ptr: Pointer<Self::Provenance>, + ) -> Option<(AllocId, Size, Self::ProvenanceExtra)>; + + /// Called to adjust allocations to the Provenance and AllocExtra of this machine. + /// + /// The way we construct allocations is to always first construct it without extra and then add + /// the extra. This keeps uniform code paths for handling both allocations created by CTFE for + /// globals, and allocations created by Miri during evaluation. /// - /// `kind` is the kind of the allocation being tagged; it can be `None` when + /// `kind` is the kind of the allocation being adjusted; it can be `None` when /// it's a global and `GLOBAL_KIND` is `None`. /// /// This should avoid copying if no work has to be done! If this returns an owned - /// allocation (because a copy had to be done to add tags or metadata), machine memory will + /// allocation (because a copy had to be done to adjust things), machine memory will /// cache the result. (This relies on `AllocMap::get_or` being able to add the /// owned allocation to the map even when the map is shared.) /// /// This must only fail if `alloc` contains relocations. - fn init_allocation_extra<'b>( + fn adjust_allocation<'b>( ecx: &InterpCx<'mir, 'tcx, Self>, id: AllocId, alloc: Cow<'b, Allocation>, kind: Option<MemoryKind<Self::MemoryKind>>, - ) -> InterpResult<'tcx, Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>>>; + ) -> InterpResult<'tcx, Cow<'b, Allocation<Self::Provenance, Self::AllocExtra>>>; /// Hook for performing extra checks on a memory read access. /// @@ -357,7 +357,7 @@ pub trait Machine<'mir, 'tcx>: Sized { _tcx: TyCtxt<'tcx>, _machine: &Self, _alloc_extra: &Self::AllocExtra, - _tag: (AllocId, Self::TagExtra), + _prov: (AllocId, Self::ProvenanceExtra), _range: AllocRange, ) -> InterpResult<'tcx> { Ok(()) @@ -369,7 +369,7 @@ pub trait Machine<'mir, 'tcx>: Sized { _tcx: TyCtxt<'tcx>, _machine: &mut Self, _alloc_extra: &mut Self::AllocExtra, - _tag: (AllocId, Self::TagExtra), + _prov: (AllocId, Self::ProvenanceExtra), _range: AllocRange, ) -> InterpResult<'tcx> { Ok(()) @@ -381,7 +381,7 @@ pub trait Machine<'mir, 'tcx>: Sized { _tcx: TyCtxt<'tcx>, _machine: &mut Self, _alloc_extra: &mut Self::AllocExtra, - _tag: (AllocId, Self::TagExtra), + _prov: (AllocId, Self::ProvenanceExtra), _range: AllocRange, ) -> InterpResult<'tcx> { Ok(()) @@ -392,7 +392,7 @@ pub trait Machine<'mir, 'tcx>: Sized { fn retag( _ecx: &mut InterpCx<'mir, 'tcx, Self>, _kind: mir::RetagKind, - _place: &PlaceTy<'tcx, Self::PointerTag>, + _place: &PlaceTy<'tcx, Self::Provenance>, ) -> InterpResult<'tcx> { Ok(()) } @@ -400,18 +400,18 @@ pub trait Machine<'mir, 'tcx>: Sized { /// Called immediately before a new stack frame gets pushed. fn init_frame_extra( ecx: &mut InterpCx<'mir, 'tcx, Self>, - frame: Frame<'mir, 'tcx, Self::PointerTag>, - ) -> InterpResult<'tcx, Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>>; + frame: Frame<'mir, 'tcx, Self::Provenance>, + ) -> InterpResult<'tcx, Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>>; /// Borrow the current thread's stack. fn stack<'a>( ecx: &'a InterpCx<'mir, 'tcx, Self>, - ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>]; + ) -> &'a [Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>]; /// Mutably borrow the current thread's stack. fn stack_mut<'a>( ecx: &'a mut InterpCx<'mir, 'tcx, Self>, - ) -> &'a mut Vec<Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>>; + ) -> &'a mut Vec<Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>>; /// Called immediately after a stack frame got pushed and its locals got initialized. fn after_stack_push(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { @@ -422,7 +422,7 @@ pub trait Machine<'mir, 'tcx>: Sized { /// The `locals` have already been destroyed! fn after_stack_pop( _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _frame: Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>, + _frame: Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>, unwinding: bool, ) -> InterpResult<'tcx, StackPopJump> { // By default, we do not support unwinding from panics @@ -434,8 +434,8 @@ pub trait Machine<'mir, 'tcx>: Sized { // A lot of the flexibility above is just needed for `Miri`, but all "compile-time" machines // (CTFE and ConstProp) use the same instance. Here, we share that code. pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { - type PointerTag = AllocId; - type TagExtra = (); + type Provenance = AllocId; + type ProvenanceExtra = (); type ExtraFnVal = !; @@ -485,7 +485,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { fn_val: !, _abi: CallAbi, _args: &[OpTy<$tcx>], - _destination: &PlaceTy<$tcx, Self::PointerTag>, + _destination: &PlaceTy<$tcx, Self::Provenance>, _target: Option<mir::BasicBlock>, _unwind: StackPopUnwind, ) -> InterpResult<$tcx> { @@ -493,13 +493,12 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { } #[inline(always)] - fn init_allocation_extra<'b>( + fn adjust_allocation<'b>( _ecx: &InterpCx<$mir, $tcx, Self>, _id: AllocId, alloc: Cow<'b, Allocation>, _kind: Option<MemoryKind<Self::MemoryKind>>, - ) -> InterpResult<$tcx, Cow<'b, Allocation<Self::PointerTag>>> { - // We do not use a tag so we can just cheaply forward the allocation + ) -> InterpResult<$tcx, Cow<'b, Allocation<Self::Provenance>>> { Ok(alloc) } @@ -512,7 +511,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { } #[inline(always)] - fn tag_alloc_base_pointer( + fn adjust_alloc_base_pointer( _ecx: &InterpCx<$mir, $tcx, Self>, ptr: Pointer<AllocId>, ) -> Pointer<AllocId> { @@ -541,7 +540,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { fn ptr_get_alloc( _ecx: &InterpCx<$mir, $tcx, Self>, ptr: Pointer<AllocId>, - ) -> Option<(AllocId, Size, Self::TagExtra)> { + ) -> Option<(AllocId, Size, Self::ProvenanceExtra)> { // We know `offset` is relative to the allocation, so we can use `into_parts`. let (alloc_id, offset) = ptr.into_parts(); Some((alloc_id, offset, ())) diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 509fe576893..86914f50383 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -16,7 +16,7 @@ use std::ptr; use rustc_ast::Mutability; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_middle::mir::display_allocation; -use rustc_middle::ty::{Instance, ParamEnv, TyCtxt}; +use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt}; use rustc_target::abi::{Align, HasDataLayout, Size}; use super::{ @@ -62,6 +62,8 @@ pub enum AllocKind { LiveData, /// A function allocation (that fn ptrs point to). Function, + /// A (symbolic) vtable allocation. + VTable, /// A dead allocation. Dead, } @@ -112,16 +114,16 @@ pub struct Memory<'mir, 'tcx, M: Machine<'mir, 'tcx>> { /// A reference to some allocation that was already bounds-checked for the given region /// and had the on-access machine hooks run. #[derive(Copy, Clone)] -pub struct AllocRef<'a, 'tcx, Tag, Extra> { - alloc: &'a Allocation<Tag, Extra>, +pub struct AllocRef<'a, 'tcx, Prov, Extra> { + alloc: &'a Allocation<Prov, Extra>, range: AllocRange, tcx: TyCtxt<'tcx>, alloc_id: AllocId, } /// A reference to some allocation that was already bounds-checked for the given region /// and had the on-access machine hooks run. -pub struct AllocRefMut<'a, 'tcx, Tag, Extra> { - alloc: &'a mut Allocation<Tag, Extra>, +pub struct AllocRefMut<'a, 'tcx, Prov, Extra> { + alloc: &'a mut Allocation<Prov, Extra>, range: AllocRange, tcx: TyCtxt<'tcx>, alloc_id: AllocId, @@ -156,10 +158,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn global_base_pointer( &self, ptr: Pointer<AllocId>, - ) -> InterpResult<'tcx, Pointer<M::PointerTag>> { + ) -> InterpResult<'tcx, Pointer<M::Provenance>> { let alloc_id = ptr.provenance; // We need to handle `extern static`. - match self.tcx.get_global_alloc(alloc_id) { + match self.tcx.try_get_global_alloc(alloc_id) { Some(GlobalAlloc::Static(def_id)) if self.tcx.is_thread_local_static(def_id) => { bug!("global memory cannot point to thread-local static") } @@ -168,14 +170,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } _ => {} } - // And we need to get the tag. - Ok(M::tag_alloc_base_pointer(self, ptr)) + // And we need to get the provenance. + Ok(M::adjust_alloc_base_pointer(self, ptr)) } pub fn create_fn_alloc_ptr( &mut self, fn_val: FnVal<'tcx, M::ExtraFnVal>, - ) -> Pointer<M::PointerTag> { + ) -> Pointer<M::Provenance> { let id = match fn_val { FnVal::Instance(instance) => self.tcx.create_fn_alloc(instance), FnVal::Other(extra) => { @@ -196,7 +198,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { size: Size, align: Align, kind: MemoryKind<M::MemoryKind>, - ) -> InterpResult<'tcx, Pointer<M::PointerTag>> { + ) -> InterpResult<'tcx, Pointer<M::Provenance>> { let alloc = Allocation::uninit(size, align, M::PANIC_ON_ALLOC_FAIL)?; // We can `unwrap` since `alloc` contains no pointers. Ok(self.allocate_raw_ptr(alloc, kind).unwrap()) @@ -208,7 +210,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { align: Align, kind: MemoryKind<M::MemoryKind>, mutability: Mutability, - ) -> Pointer<M::PointerTag> { + ) -> Pointer<M::Provenance> { let alloc = Allocation::from_bytes(bytes, align, mutability); // We can `unwrap` since `alloc` contains no pointers. self.allocate_raw_ptr(alloc, kind).unwrap() @@ -219,27 +221,27 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &mut self, alloc: Allocation, kind: MemoryKind<M::MemoryKind>, - ) -> InterpResult<'tcx, Pointer<M::PointerTag>> { + ) -> InterpResult<'tcx, Pointer<M::Provenance>> { let id = self.tcx.reserve_alloc_id(); debug_assert_ne!( Some(kind), M::GLOBAL_KIND.map(MemoryKind::Machine), "dynamically allocating global memory" ); - let alloc = M::init_allocation_extra(self, id, Cow::Owned(alloc), Some(kind))?; + let alloc = M::adjust_allocation(self, id, Cow::Owned(alloc), Some(kind))?; self.memory.alloc_map.insert(id, (kind, alloc.into_owned())); - Ok(M::tag_alloc_base_pointer(self, Pointer::from(id))) + Ok(M::adjust_alloc_base_pointer(self, Pointer::from(id))) } pub fn reallocate_ptr( &mut self, - ptr: Pointer<Option<M::PointerTag>>, + ptr: Pointer<Option<M::Provenance>>, old_size_and_align: Option<(Size, Align)>, new_size: Size, new_align: Align, kind: MemoryKind<M::MemoryKind>, - ) -> InterpResult<'tcx, Pointer<M::PointerTag>> { - let (alloc_id, offset, _tag) = self.ptr_get_alloc_id(ptr)?; + ) -> InterpResult<'tcx, Pointer<M::Provenance>> { + let (alloc_id, offset, _prov) = self.ptr_get_alloc_id(ptr)?; if offset.bytes() != 0 { throw_ub_format!( "reallocating {:?} which does not point to the beginning of an object", @@ -271,11 +273,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { #[instrument(skip(self), level = "debug")] pub fn deallocate_ptr( &mut self, - ptr: Pointer<Option<M::PointerTag>>, + ptr: Pointer<Option<M::Provenance>>, old_size_and_align: Option<(Size, Align)>, kind: MemoryKind<M::MemoryKind>, ) -> InterpResult<'tcx> { - let (alloc_id, offset, tag) = self.ptr_get_alloc_id(ptr)?; + let (alloc_id, offset, prov) = self.ptr_get_alloc_id(ptr)?; trace!("deallocating: {alloc_id:?}"); if offset.bytes() != 0 { @@ -287,10 +289,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let Some((alloc_kind, mut alloc)) = self.memory.alloc_map.remove(&alloc_id) else { // Deallocating global memory -- always an error - return Err(match self.tcx.get_global_alloc(alloc_id) { + return Err(match self.tcx.try_get_global_alloc(alloc_id) { Some(GlobalAlloc::Function(..)) => { err_ub_format!("deallocating {alloc_id:?}, which is a function") } + Some(GlobalAlloc::VTable(..)) => { + err_ub_format!("deallocating {alloc_id:?}, which is a vtable") + } Some(GlobalAlloc::Static(..) | GlobalAlloc::Memory(..)) => { err_ub_format!("deallocating {alloc_id:?}, which is static memory") } @@ -327,7 +332,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { *self.tcx, &mut self.machine, &mut alloc.extra, - (alloc_id, tag), + (alloc_id, prov), alloc_range(Size::ZERO, size), )?; @@ -344,19 +349,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { #[inline(always)] fn get_ptr_access( &self, - ptr: Pointer<Option<M::PointerTag>>, + ptr: Pointer<Option<M::Provenance>>, size: Size, align: Align, - ) -> InterpResult<'tcx, Option<(AllocId, Size, M::TagExtra)>> { + ) -> InterpResult<'tcx, Option<(AllocId, Size, M::ProvenanceExtra)>> { let align = M::enforce_alignment(&self).then_some(align); self.check_and_deref_ptr( ptr, size, align, CheckInAllocMsg::MemoryAccessTest, - |alloc_id, offset, tag| { + |alloc_id, offset, prov| { let (size, align) = self.get_live_alloc_size_and_align(alloc_id)?; - Ok((size, align, (alloc_id, offset, tag))) + Ok((size, align, (alloc_id, offset, prov))) }, ) } @@ -367,7 +372,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { #[inline(always)] pub fn check_ptr_access_align( &self, - ptr: Pointer<Option<M::PointerTag>>, + ptr: Pointer<Option<M::Provenance>>, size: Size, align: Align, msg: CheckInAllocMsg, @@ -385,11 +390,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// is done. Returns `None` for size 0, and otherwise `Some` of what `alloc_size` returned. fn check_and_deref_ptr<T>( &self, - ptr: Pointer<Option<M::PointerTag>>, + ptr: Pointer<Option<M::Provenance>>, size: Size, align: Option<Align>, msg: CheckInAllocMsg, - alloc_size: impl FnOnce(AllocId, Size, M::TagExtra) -> InterpResult<'tcx, (Size, Align, T)>, + alloc_size: impl FnOnce( + AllocId, + Size, + M::ProvenanceExtra, + ) -> InterpResult<'tcx, (Size, Align, T)>, ) -> InterpResult<'tcx, Option<T>> { fn check_offset_align<'tcx>(offset: u64, align: Align) -> InterpResult<'tcx> { if offset % align.bytes() == 0 { @@ -417,8 +426,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } None } - Ok((alloc_id, offset, tag)) => { - let (alloc_size, alloc_align, ret_val) = alloc_size(alloc_id, offset, tag)?; + Ok((alloc_id, offset, prov)) => { + let (alloc_size, alloc_align, ret_val) = alloc_size(alloc_id, offset, prov)?; // Test bounds. This also ensures non-null. // It is sufficient to check this for the end pointer. Also check for overflow! if offset.checked_add(size, &self.tcx).map_or(true, |end| end > alloc_size) { @@ -431,7 +440,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }) } // Ensure we never consider the null pointer dereferencable. - if M::PointerTag::OFFSET_IS_ADDR { + if M::Provenance::OFFSET_IS_ADDR { assert_ne!(ptr.addr(), Size::ZERO); } // Test align. Check this last; if both bounds and alignment are violated @@ -462,19 +471,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Helper function to obtain a global (tcx) allocation. /// This attempts to return a reference to an existing allocation if /// one can be found in `tcx`. That, however, is only possible if `tcx` and - /// this machine use the same pointer tag, so it is indirected through - /// `M::tag_allocation`. + /// this machine use the same pointer provenance, so it is indirected through + /// `M::adjust_allocation`. fn get_global_alloc( &self, id: AllocId, is_write: bool, - ) -> InterpResult<'tcx, Cow<'tcx, Allocation<M::PointerTag, M::AllocExtra>>> { - let (alloc, def_id) = match self.tcx.get_global_alloc(id) { + ) -> InterpResult<'tcx, Cow<'tcx, Allocation<M::Provenance, M::AllocExtra>>> { + let (alloc, def_id) = match self.tcx.try_get_global_alloc(id) { Some(GlobalAlloc::Memory(mem)) => { // Memory of a constant or promoted or anonymous memory referenced by a static. (mem, None) } Some(GlobalAlloc::Function(..)) => throw_ub!(DerefFunctionPointer(id)), + Some(GlobalAlloc::VTable(..)) => throw_ub!(DerefVTablePointer(id)), None => throw_ub!(PointerUseAfterFree(id)), Some(GlobalAlloc::Static(def_id)) => { assert!(self.tcx.is_static(def_id)); @@ -490,6 +500,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // contains a reference to memory that was created during its evaluation (i.e., not // to another static), those inner references only exist in "resolved" form. if self.tcx.is_foreign_item(def_id) { + // This is unreachable in Miri, but can happen in CTFE where we actually *do* support + // referencing arbitrary (declared) extern statics. throw_unsup!(ReadExternStatic(def_id)); } @@ -499,7 +511,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }; M::before_access_global(*self.tcx, &self.machine, id, alloc, def_id, is_write)?; // We got tcx memory. Let the machine initialize its "extra" stuff. - M::init_allocation_extra( + M::adjust_allocation( self, id, // always use the ID we got as input, not the "hidden" one. Cow::Borrowed(alloc.inner()), @@ -512,11 +524,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { fn get_alloc_raw( &self, id: AllocId, - ) -> InterpResult<'tcx, &Allocation<M::PointerTag, M::AllocExtra>> { + ) -> InterpResult<'tcx, &Allocation<M::Provenance, M::AllocExtra>> { // The error type of the inner closure here is somewhat funny. We have two // ways of "erroring": An actual error, or because we got a reference from // `get_global_alloc` that we can actually use directly without inserting anything anywhere. - // So the error type is `InterpResult<'tcx, &Allocation<M::PointerTag>>`. + // So the error type is `InterpResult<'tcx, &Allocation<M::Provenance>>`. let a = self.memory.alloc_map.get_or(id, || { let alloc = self.get_global_alloc(id, /*is_write*/ false).map_err(Err)?; match alloc { @@ -545,24 +557,24 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// "Safe" (bounds and align-checked) allocation access. pub fn get_ptr_alloc<'a>( &'a self, - ptr: Pointer<Option<M::PointerTag>>, + ptr: Pointer<Option<M::Provenance>>, size: Size, align: Align, - ) -> InterpResult<'tcx, Option<AllocRef<'a, 'tcx, M::PointerTag, M::AllocExtra>>> { + ) -> InterpResult<'tcx, Option<AllocRef<'a, 'tcx, M::Provenance, M::AllocExtra>>> { let align = M::enforce_alignment(self).then_some(align); let ptr_and_alloc = self.check_and_deref_ptr( ptr, size, align, CheckInAllocMsg::MemoryAccessTest, - |alloc_id, offset, tag| { + |alloc_id, offset, prov| { let alloc = self.get_alloc_raw(alloc_id)?; - Ok((alloc.size(), alloc.align, (alloc_id, offset, tag, alloc))) + Ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc))) }, )?; - if let Some((alloc_id, offset, tag, alloc)) = ptr_and_alloc { + if let Some((alloc_id, offset, prov, alloc)) = ptr_and_alloc { let range = alloc_range(offset, size); - M::memory_read(*self.tcx, &self.machine, &alloc.extra, (alloc_id, tag), range)?; + M::memory_read(*self.tcx, &self.machine, &alloc.extra, (alloc_id, prov), range)?; Ok(Some(AllocRef { alloc, range, tcx: *self.tcx, alloc_id })) } else { // Even in this branch we have to be sure that we actually access the allocation, in @@ -586,7 +598,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { fn get_alloc_raw_mut( &mut self, id: AllocId, - ) -> InterpResult<'tcx, (&mut Allocation<M::PointerTag, M::AllocExtra>, &mut M)> { + ) -> InterpResult<'tcx, (&mut Allocation<M::Provenance, M::AllocExtra>, &mut M)> { // We have "NLL problem case #3" here, which cannot be worked around without loss of // efficiency even for the common case where the key is in the map. // <https://rust-lang.github.io/rfcs/2094-nll.html#problem-case-3-conditional-control-flow-across-functions> @@ -612,18 +624,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// "Safe" (bounds and align-checked) allocation access. pub fn get_ptr_alloc_mut<'a>( &'a mut self, - ptr: Pointer<Option<M::PointerTag>>, + ptr: Pointer<Option<M::Provenance>>, size: Size, align: Align, - ) -> InterpResult<'tcx, Option<AllocRefMut<'a, 'tcx, M::PointerTag, M::AllocExtra>>> { + ) -> InterpResult<'tcx, Option<AllocRefMut<'a, 'tcx, M::Provenance, M::AllocExtra>>> { let parts = self.get_ptr_access(ptr, size, align)?; - if let Some((alloc_id, offset, tag)) = parts { + if let Some((alloc_id, offset, prov)) = parts { let tcx = *self.tcx; // FIXME: can we somehow avoid looking up the allocation twice here? // We cannot call `get_raw_mut` inside `check_and_deref_ptr` as that would duplicate `&mut self`. let (alloc, machine) = self.get_alloc_raw_mut(alloc_id)?; let range = alloc_range(offset, size); - M::memory_written(tcx, machine, &mut alloc.extra, (alloc_id, tag), range)?; + M::memory_written(tcx, machine, &mut alloc.extra, (alloc_id, prov), range)?; Ok(Some(AllocRefMut { alloc, range, tcx, alloc_id })) } else { Ok(None) @@ -659,12 +671,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // # Statics // Can't do this in the match argument, we may get cycle errors since the lock would // be held throughout the match. - match self.tcx.get_global_alloc(id) { - Some(GlobalAlloc::Static(did)) => { - assert!(!self.tcx.is_thread_local_static(did)); + match self.tcx.try_get_global_alloc(id) { + Some(GlobalAlloc::Static(def_id)) => { + assert!(self.tcx.is_static(def_id)); + assert!(!self.tcx.is_thread_local_static(def_id)); // Use size and align of the type. - let ty = self.tcx.type_of(did); + let ty = self.tcx.type_of(def_id); let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap(); + assert!(!layout.is_unsized()); (layout.size, layout.align.abi, AllocKind::LiveData) } Some(GlobalAlloc::Memory(alloc)) => { @@ -674,6 +688,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { (alloc.size(), alloc.align, AllocKind::LiveData) } Some(GlobalAlloc::Function(_)) => bug!("We already checked function pointers above"), + Some(GlobalAlloc::VTable(..)) => { + // No data to be accessed here. But vtables are pointer-aligned. + return (Size::ZERO, self.tcx.data_layout.pointer_align.abi, AllocKind::VTable); + } // The rest must be dead. None => { // Deallocated pointers are allowed, we should be able to find @@ -701,7 +719,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if let Some(extra) = self.memory.extra_fn_ptr_map.get(&id) { Some(FnVal::Other(*extra)) } else { - match self.tcx.get_global_alloc(id) { + match self.tcx.try_get_global_alloc(id) { Some(GlobalAlloc::Function(instance)) => Some(FnVal::Instance(instance)), _ => None, } @@ -710,10 +728,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn get_ptr_fn( &self, - ptr: Pointer<Option<M::PointerTag>>, + ptr: Pointer<Option<M::Provenance>>, ) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> { - trace!("get_fn({:?})", ptr); - let (alloc_id, offset, _tag) = self.ptr_get_alloc_id(ptr)?; + trace!("get_ptr_fn({:?})", ptr); + let (alloc_id, offset, _prov) = self.ptr_get_alloc_id(ptr)?; if offset.bytes() != 0 { throw_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset))) } @@ -721,6 +739,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { .ok_or_else(|| err_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset))).into()) } + pub fn get_ptr_vtable( + &self, + ptr: Pointer<Option<M::Provenance>>, + ) -> InterpResult<'tcx, (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>)> { + trace!("get_ptr_vtable({:?})", ptr); + let (alloc_id, offset, _tag) = self.ptr_get_alloc_id(ptr)?; + if offset.bytes() != 0 { + throw_ub!(InvalidVTablePointer(Pointer::new(alloc_id, offset))) + } + match self.tcx.try_get_global_alloc(alloc_id) { + Some(GlobalAlloc::VTable(ty, trait_ref)) => Ok((ty, trait_ref)), + _ => throw_ub!(InvalidVTablePointer(Pointer::new(alloc_id, offset))), + } + } + pub fn alloc_mark_immutable(&mut self, id: AllocId) -> InterpResult<'tcx> { self.get_alloc_raw_mut(id)?.0.mutability = Mutability::Not; Ok(()) @@ -759,7 +792,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // This is a new allocation, add its relocations to `todo`. if let Some((_, alloc)) = self.memory.alloc_map.get(id) { todo.extend( - alloc.relocations().values().filter_map(|tag| tag.get_alloc_id()), + alloc.relocations().values().filter_map(|prov| prov.get_alloc_id()), ); } } @@ -788,14 +821,14 @@ pub struct DumpAllocs<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> { impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a, 'mir, 'tcx, M> { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - // Cannot be a closure because it is generic in `Tag`, `Extra`. - fn write_allocation_track_relocs<'tcx, Tag: Provenance, Extra>( + // Cannot be a closure because it is generic in `Prov`, `Extra`. + fn write_allocation_track_relocs<'tcx, Prov: Provenance, Extra>( fmt: &mut std::fmt::Formatter<'_>, tcx: TyCtxt<'tcx>, allocs_to_print: &mut VecDeque<AllocId>, - alloc: &Allocation<Tag, Extra>, + alloc: &Allocation<Prov, Extra>, ) -> std::fmt::Result { - for alloc_id in alloc.relocations().values().filter_map(|tag| tag.get_alloc_id()) { + for alloc_id in alloc.relocations().values().filter_map(|prov| prov.get_alloc_id()) { allocs_to_print.push_back(alloc_id); } write!(fmt, "{}", display_allocation(tcx, alloc)) @@ -825,7 +858,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a, } None => { // global alloc - match self.ecx.tcx.get_global_alloc(id) { + match self.ecx.tcx.try_get_global_alloc(id) { Some(GlobalAlloc::Memory(alloc)) => { write!(fmt, " (unchanged global, ")?; write_allocation_track_relocs( @@ -836,7 +869,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a, )?; } Some(GlobalAlloc::Function(func)) => { - write!(fmt, " (fn: {})", func)?; + write!(fmt, " (fn: {func})")?; + } + Some(GlobalAlloc::VTable(ty, Some(trait_ref))) => { + write!(fmt, " (vtable: impl {trait_ref} for {ty})")?; + } + Some(GlobalAlloc::VTable(ty, None)) => { + write!(fmt, " (vtable: impl <auto trait> for {ty})")?; } Some(GlobalAlloc::Static(did)) => { write!(fmt, " (static: {})", self.ecx.tcx.def_path_str(did))?; @@ -854,12 +893,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a, } /// Reading and writing. -impl<'tcx, 'a, Tag: Provenance, Extra> AllocRefMut<'a, 'tcx, Tag, Extra> { +impl<'tcx, 'a, Prov: Provenance, Extra> AllocRefMut<'a, 'tcx, Prov, Extra> { /// `range` is relative to this allocation reference, not the base of the allocation. pub fn write_scalar( &mut self, range: AllocRange, - val: ScalarMaybeUninit<Tag>, + val: ScalarMaybeUninit<Prov>, ) -> InterpResult<'tcx> { let range = self.range.subrange(range); debug!("write_scalar at {:?}{range:?}: {val:?}", self.alloc_id); @@ -873,7 +912,7 @@ impl<'tcx, 'a, Tag: Provenance, Extra> AllocRefMut<'a, 'tcx, Tag, Extra> { pub fn write_ptr_sized( &mut self, offset: Size, - val: ScalarMaybeUninit<Tag>, + val: ScalarMaybeUninit<Prov>, ) -> InterpResult<'tcx> { self.write_scalar(alloc_range(offset, self.tcx.data_layout().pointer_size), val) } @@ -887,13 +926,13 @@ impl<'tcx, 'a, Tag: Provenance, Extra> AllocRefMut<'a, 'tcx, Tag, Extra> { } } -impl<'tcx, 'a, Tag: Provenance, Extra> AllocRef<'a, 'tcx, Tag, Extra> { +impl<'tcx, 'a, Prov: Provenance, Extra> AllocRef<'a, 'tcx, Prov, Extra> { /// `range` is relative to this allocation reference, not the base of the allocation. pub fn read_scalar( &self, range: AllocRange, read_provenance: bool, - ) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> { + ) -> InterpResult<'tcx, ScalarMaybeUninit<Prov>> { let range = self.range.subrange(range); let res = self .alloc @@ -904,12 +943,12 @@ impl<'tcx, 'a, Tag: Provenance, Extra> AllocRef<'a, 'tcx, Tag, Extra> { } /// `range` is relative to this allocation reference, not the base of the allocation. - pub fn read_integer(&self, range: AllocRange) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> { + pub fn read_integer(&self, range: AllocRange) -> InterpResult<'tcx, ScalarMaybeUninit<Prov>> { self.read_scalar(range, /*read_provenance*/ false) } /// `offset` is relative to this allocation reference, not the base of the allocation. - pub fn read_pointer(&self, offset: Size) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> { + pub fn read_pointer(&self, offset: Size) -> InterpResult<'tcx, ScalarMaybeUninit<Prov>> { self.read_scalar( alloc_range(offset, self.tcx.data_layout().pointer_size), /*read_provenance*/ true, @@ -941,7 +980,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Performs appropriate bounds checks. pub fn read_bytes_ptr( &self, - ptr: Pointer<Option<M::PointerTag>>, + ptr: Pointer<Option<M::Provenance>>, size: Size, ) -> InterpResult<'tcx, &[u8]> { let Some(alloc_ref) = self.get_ptr_alloc(ptr, size, Align::ONE)? else { @@ -961,7 +1000,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Performs appropriate bounds checks. pub fn write_bytes_ptr( &mut self, - ptr: Pointer<Option<M::PointerTag>>, + ptr: Pointer<Option<M::Provenance>>, src: impl IntoIterator<Item = u8>, ) -> InterpResult<'tcx> { let mut src = src.into_iter(); @@ -998,9 +1037,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn mem_copy( &mut self, - src: Pointer<Option<M::PointerTag>>, + src: Pointer<Option<M::Provenance>>, src_align: Align, - dest: Pointer<Option<M::PointerTag>>, + dest: Pointer<Option<M::Provenance>>, dest_align: Align, size: Size, nonoverlapping: bool, @@ -1010,9 +1049,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn mem_copy_repeatedly( &mut self, - src: Pointer<Option<M::PointerTag>>, + src: Pointer<Option<M::Provenance>>, src_align: Align, - dest: Pointer<Option<M::PointerTag>>, + dest: Pointer<Option<M::Provenance>>, dest_align: Align, size: Size, num_copies: u64, @@ -1027,16 +1066,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // and once below to get the underlying `&[mut] Allocation`. // Source alloc preparations and access hooks. - let Some((src_alloc_id, src_offset, src_tag)) = src_parts else { + let Some((src_alloc_id, src_offset, src_prov)) = src_parts else { // Zero-sized *source*, that means dst is also zero-sized and we have nothing to do. return Ok(()); }; let src_alloc = self.get_alloc_raw(src_alloc_id)?; let src_range = alloc_range(src_offset, size); - M::memory_read(*tcx, &self.machine, &src_alloc.extra, (src_alloc_id, src_tag), src_range)?; + M::memory_read(*tcx, &self.machine, &src_alloc.extra, (src_alloc_id, src_prov), src_range)?; // We need the `dest` ptr for the next operation, so we get it now. // We already did the source checks and called the hooks so we are good to return early. - let Some((dest_alloc_id, dest_offset, dest_tag)) = dest_parts else { + let Some((dest_alloc_id, dest_offset, dest_prov)) = dest_parts else { // Zero-sized *destination*. return Ok(()); }; @@ -1062,7 +1101,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { *tcx, extra, &mut dest_alloc.extra, - (dest_alloc_id, dest_tag), + (dest_alloc_id, dest_prov), dest_range, )?; let dest_bytes = dest_alloc @@ -1135,8 +1174,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn scalar_to_ptr( &self, - scalar: Scalar<M::PointerTag>, - ) -> InterpResult<'tcx, Pointer<Option<M::PointerTag>>> { + scalar: Scalar<M::Provenance>, + ) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>> { // We use `to_bits_or_ptr_internal` since we are just implementing the method people need to // call to force getting out a pointer. Ok( @@ -1155,7 +1194,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Test if this value might be null. /// If the machine does not support ptr-to-int casts, this is conservative. - pub fn scalar_may_be_null(&self, scalar: Scalar<M::PointerTag>) -> InterpResult<'tcx, bool> { + pub fn scalar_may_be_null(&self, scalar: Scalar<M::Provenance>) -> InterpResult<'tcx, bool> { Ok(match scalar.try_to_int() { Ok(int) => int.is_null(), Err(_) => { @@ -1178,13 +1217,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// about where it points), or an absolute address. pub fn ptr_try_get_alloc_id( &self, - ptr: Pointer<Option<M::PointerTag>>, - ) -> Result<(AllocId, Size, M::TagExtra), u64> { + ptr: Pointer<Option<M::Provenance>>, + ) -> Result<(AllocId, Size, M::ProvenanceExtra), u64> { match ptr.into_pointer_or_addr() { Ok(ptr) => match M::ptr_get_alloc(self, ptr) { Some((alloc_id, offset, extra)) => Ok((alloc_id, offset, extra)), None => { - assert!(M::PointerTag::OFFSET_IS_ADDR); + assert!(M::Provenance::OFFSET_IS_ADDR); let (_, addr) = ptr.into_parts(); Err(addr.bytes()) } @@ -1197,8 +1236,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { #[inline(always)] pub fn ptr_get_alloc_id( &self, - ptr: Pointer<Option<M::PointerTag>>, - ) -> InterpResult<'tcx, (AllocId, Size, M::TagExtra)> { + ptr: Pointer<Option<M::Provenance>>, + ) -> InterpResult<'tcx, (AllocId, Size, M::ProvenanceExtra)> { self.ptr_try_get_alloc_id(ptr).map_err(|offset| { err_ub!(DanglingIntPointer(offset, CheckInAllocMsg::InboundsTest)).into() }) diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 22dc1e80f13..7e5c6feb048 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -4,7 +4,6 @@ use std::fmt::Write; use rustc_hir::def::Namespace; -use rustc_macros::HashStable; use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt, TyAndLayout}; use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Printer}; use rustc_middle::ty::{ConstInt, DelaySpanBugEmitted, Ty}; @@ -25,15 +24,15 @@ use super::{ /// operations and wide pointers. This idea was taken from rustc's codegen. /// In particular, thanks to `ScalarPair`, arithmetic operations and casts can be entirely /// defined on `Immediate`, and do not have to work with a `Place`. -#[derive(Copy, Clone, PartialEq, Eq, HashStable, Hash, Debug)] -pub enum Immediate<Tag: Provenance = AllocId> { +#[derive(Copy, Clone, Debug)] +pub enum Immediate<Prov: Provenance = AllocId> { /// A single scalar value (must have *initialized* `Scalar` ABI). /// FIXME: we also currently often use this for ZST. /// `ScalarMaybeUninit` should reject ZST, and we should use `Uninit` for them instead. - Scalar(ScalarMaybeUninit<Tag>), + Scalar(ScalarMaybeUninit<Prov>), /// A pair of two scalar value (must have `ScalarPair` ABI where both fields are /// `Scalar::Initialized`). - ScalarPair(ScalarMaybeUninit<Tag>, ScalarMaybeUninit<Tag>), + ScalarPair(ScalarMaybeUninit<Prov>, ScalarMaybeUninit<Prov>), /// A value of fully uninitialized memory. Can have and size and layout. Uninit, } @@ -41,36 +40,36 @@ pub enum Immediate<Tag: Provenance = AllocId> { #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] rustc_data_structures::static_assert_size!(Immediate, 56); -impl<Tag: Provenance> From<ScalarMaybeUninit<Tag>> for Immediate<Tag> { +impl<Prov: Provenance> From<ScalarMaybeUninit<Prov>> for Immediate<Prov> { #[inline(always)] - fn from(val: ScalarMaybeUninit<Tag>) -> Self { + fn from(val: ScalarMaybeUninit<Prov>) -> Self { Immediate::Scalar(val) } } -impl<Tag: Provenance> From<Scalar<Tag>> for Immediate<Tag> { +impl<Prov: Provenance> From<Scalar<Prov>> for Immediate<Prov> { #[inline(always)] - fn from(val: Scalar<Tag>) -> Self { + fn from(val: Scalar<Prov>) -> Self { Immediate::Scalar(val.into()) } } -impl<'tcx, Tag: Provenance> Immediate<Tag> { - pub fn from_pointer(p: Pointer<Tag>, cx: &impl HasDataLayout) -> Self { +impl<'tcx, Prov: Provenance> Immediate<Prov> { + pub fn from_pointer(p: Pointer<Prov>, cx: &impl HasDataLayout) -> Self { Immediate::Scalar(ScalarMaybeUninit::from_pointer(p, cx)) } - pub fn from_maybe_pointer(p: Pointer<Option<Tag>>, cx: &impl HasDataLayout) -> Self { + pub fn from_maybe_pointer(p: Pointer<Option<Prov>>, cx: &impl HasDataLayout) -> Self { Immediate::Scalar(ScalarMaybeUninit::from_maybe_pointer(p, cx)) } - pub fn new_slice(val: Scalar<Tag>, len: u64, cx: &impl HasDataLayout) -> Self { + pub fn new_slice(val: Scalar<Prov>, len: u64, cx: &impl HasDataLayout) -> Self { Immediate::ScalarPair(val.into(), Scalar::from_machine_usize(len, cx).into()) } pub fn new_dyn_trait( - val: Scalar<Tag>, - vtable: Pointer<Option<Tag>>, + val: Scalar<Prov>, + vtable: Pointer<Option<Prov>>, cx: &impl HasDataLayout, ) -> Self { Immediate::ScalarPair(val.into(), ScalarMaybeUninit::from_maybe_pointer(vtable, cx)) @@ -78,7 +77,7 @@ impl<'tcx, Tag: Provenance> Immediate<Tag> { #[inline] #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) - pub fn to_scalar_or_uninit(self) -> ScalarMaybeUninit<Tag> { + pub fn to_scalar_or_uninit(self) -> ScalarMaybeUninit<Prov> { match self { Immediate::Scalar(val) => val, Immediate::ScalarPair(..) => bug!("Got a scalar pair where a scalar was expected"), @@ -88,13 +87,13 @@ impl<'tcx, Tag: Provenance> Immediate<Tag> { #[inline] #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) - pub fn to_scalar(self) -> InterpResult<'tcx, Scalar<Tag>> { + pub fn to_scalar(self) -> InterpResult<'tcx, Scalar<Prov>> { self.to_scalar_or_uninit().check_init() } #[inline] #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) - pub fn to_scalar_or_uninit_pair(self) -> (ScalarMaybeUninit<Tag>, ScalarMaybeUninit<Tag>) { + pub fn to_scalar_or_uninit_pair(self) -> (ScalarMaybeUninit<Prov>, ScalarMaybeUninit<Prov>) { match self { Immediate::ScalarPair(val1, val2) => (val1, val2), Immediate::Scalar(..) => bug!("Got a scalar where a scalar pair was expected"), @@ -104,7 +103,7 @@ impl<'tcx, Tag: Provenance> Immediate<Tag> { #[inline] #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) - pub fn to_scalar_pair(self) -> InterpResult<'tcx, (Scalar<Tag>, Scalar<Tag>)> { + pub fn to_scalar_pair(self) -> InterpResult<'tcx, (Scalar<Prov>, Scalar<Prov>)> { let (val1, val2) = self.to_scalar_or_uninit_pair(); Ok((val1.check_init()?, val2.check_init()?)) } @@ -112,21 +111,21 @@ impl<'tcx, Tag: Provenance> Immediate<Tag> { // ScalarPair needs a type to interpret, so we often have an immediate and a type together // as input for binary and cast operations. -#[derive(Copy, Clone, Debug)] -pub struct ImmTy<'tcx, Tag: Provenance = AllocId> { - imm: Immediate<Tag>, +#[derive(Clone, Debug)] +pub struct ImmTy<'tcx, Prov: Provenance = AllocId> { + imm: Immediate<Prov>, pub layout: TyAndLayout<'tcx>, } #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] rustc_data_structures::static_assert_size!(ImmTy<'_>, 72); -impl<Tag: Provenance> std::fmt::Display for ImmTy<'_, Tag> { +impl<Prov: Provenance> std::fmt::Display for ImmTy<'_, Prov> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { /// Helper function for printing a scalar to a FmtPrinter - fn p<'a, 'tcx, Tag: Provenance>( + fn p<'a, 'tcx, Prov: Provenance>( cx: FmtPrinter<'a, 'tcx>, - s: ScalarMaybeUninit<Tag>, + s: ScalarMaybeUninit<Prov>, ty: Ty<'tcx>, ) -> Result<FmtPrinter<'a, 'tcx>, std::fmt::Error> { match s { @@ -171,10 +170,10 @@ impl<Tag: Provenance> std::fmt::Display for ImmTy<'_, Tag> { } } -impl<'tcx, Tag: Provenance> std::ops::Deref for ImmTy<'tcx, Tag> { - type Target = Immediate<Tag>; +impl<'tcx, Prov: Provenance> std::ops::Deref for ImmTy<'tcx, Prov> { + type Target = Immediate<Prov>; #[inline(always)] - fn deref(&self) -> &Immediate<Tag> { + fn deref(&self) -> &Immediate<Prov> { &self.imm } } @@ -182,15 +181,18 @@ impl<'tcx, Tag: Provenance> std::ops::Deref for ImmTy<'tcx, Tag> { /// An `Operand` is the result of computing a `mir::Operand`. It can be immediate, /// or still in memory. The latter is an optimization, to delay reading that chunk of /// memory and to avoid having to store arbitrary-sized data here. -#[derive(Copy, Clone, PartialEq, Eq, HashStable, Hash, Debug)] -pub enum Operand<Tag: Provenance = AllocId> { - Immediate(Immediate<Tag>), - Indirect(MemPlace<Tag>), +#[derive(Copy, Clone, Debug)] +pub enum Operand<Prov: Provenance = AllocId> { + Immediate(Immediate<Prov>), + Indirect(MemPlace<Prov>), } -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub struct OpTy<'tcx, Tag: Provenance = AllocId> { - op: Operand<Tag>, // Keep this private; it helps enforce invariants. +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +rustc_data_structures::static_assert_size!(Operand, 64); + +#[derive(Clone, Debug)] +pub struct OpTy<'tcx, Prov: Provenance = AllocId> { + op: Operand<Prov>, // Keep this private; it helps enforce invariants. pub layout: TyAndLayout<'tcx>, /// rustc does not have a proper way to represent the type of a field of a `repr(packed)` struct: /// it needs to have a different alignment than the field type would usually have. @@ -205,50 +207,50 @@ pub struct OpTy<'tcx, Tag: Provenance = AllocId> { #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] rustc_data_structures::static_assert_size!(OpTy<'_>, 88); -impl<'tcx, Tag: Provenance> std::ops::Deref for OpTy<'tcx, Tag> { - type Target = Operand<Tag>; +impl<'tcx, Prov: Provenance> std::ops::Deref for OpTy<'tcx, Prov> { + type Target = Operand<Prov>; #[inline(always)] - fn deref(&self) -> &Operand<Tag> { + fn deref(&self) -> &Operand<Prov> { &self.op } } -impl<'tcx, Tag: Provenance> From<MPlaceTy<'tcx, Tag>> for OpTy<'tcx, Tag> { +impl<'tcx, Prov: Provenance> From<MPlaceTy<'tcx, Prov>> for OpTy<'tcx, Prov> { #[inline(always)] - fn from(mplace: MPlaceTy<'tcx, Tag>) -> Self { + fn from(mplace: MPlaceTy<'tcx, Prov>) -> Self { OpTy { op: Operand::Indirect(*mplace), layout: mplace.layout, align: Some(mplace.align) } } } -impl<'tcx, Tag: Provenance> From<&'_ MPlaceTy<'tcx, Tag>> for OpTy<'tcx, Tag> { +impl<'tcx, Prov: Provenance> From<&'_ MPlaceTy<'tcx, Prov>> for OpTy<'tcx, Prov> { #[inline(always)] - fn from(mplace: &MPlaceTy<'tcx, Tag>) -> Self { + fn from(mplace: &MPlaceTy<'tcx, Prov>) -> Self { OpTy { op: Operand::Indirect(**mplace), layout: mplace.layout, align: Some(mplace.align) } } } -impl<'tcx, Tag: Provenance> From<&'_ mut MPlaceTy<'tcx, Tag>> for OpTy<'tcx, Tag> { +impl<'tcx, Prov: Provenance> From<&'_ mut MPlaceTy<'tcx, Prov>> for OpTy<'tcx, Prov> { #[inline(always)] - fn from(mplace: &mut MPlaceTy<'tcx, Tag>) -> Self { + fn from(mplace: &mut MPlaceTy<'tcx, Prov>) -> Self { OpTy { op: Operand::Indirect(**mplace), layout: mplace.layout, align: Some(mplace.align) } } } -impl<'tcx, Tag: Provenance> From<ImmTy<'tcx, Tag>> for OpTy<'tcx, Tag> { +impl<'tcx, Prov: Provenance> From<ImmTy<'tcx, Prov>> for OpTy<'tcx, Prov> { #[inline(always)] - fn from(val: ImmTy<'tcx, Tag>) -> Self { + fn from(val: ImmTy<'tcx, Prov>) -> Self { OpTy { op: Operand::Immediate(val.imm), layout: val.layout, align: None } } } -impl<'tcx, Tag: Provenance> ImmTy<'tcx, Tag> { +impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { #[inline] - pub fn from_scalar(val: Scalar<Tag>, layout: TyAndLayout<'tcx>) -> Self { + pub fn from_scalar(val: Scalar<Prov>, layout: TyAndLayout<'tcx>) -> Self { ImmTy { imm: val.into(), layout } } #[inline] - pub fn from_immediate(imm: Immediate<Tag>, layout: TyAndLayout<'tcx>) -> Self { + pub fn from_immediate(imm: Immediate<Prov>, layout: TyAndLayout<'tcx>) -> Self { ImmTy { imm, layout } } @@ -284,7 +286,7 @@ impl<'tcx, Tag: Provenance> ImmTy<'tcx, Tag> { } } -impl<'tcx, Tag: Provenance> OpTy<'tcx, Tag> { +impl<'tcx, Prov: Provenance> OpTy<'tcx, Prov> { pub fn len(&self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> { if self.layout.is_unsized() { // There are no unsized immediates. @@ -300,7 +302,7 @@ impl<'tcx, Tag: Provenance> OpTy<'tcx, Tag> { pub fn offset_with_meta( &self, offset: Size, - meta: MemPlaceMeta<Tag>, + meta: MemPlaceMeta<Prov>, layout: TyAndLayout<'tcx>, cx: &impl HasDataLayout, ) -> InterpResult<'tcx, Self> { @@ -336,9 +338,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// This is an internal function; call `read_immediate` instead. fn read_immediate_from_mplace_raw( &self, - mplace: &MPlaceTy<'tcx, M::PointerTag>, + mplace: &MPlaceTy<'tcx, M::Provenance>, force: bool, - ) -> InterpResult<'tcx, Option<ImmTy<'tcx, M::PointerTag>>> { + ) -> InterpResult<'tcx, Option<ImmTy<'tcx, M::Provenance>>> { if mplace.layout.is_unsized() { // Don't touch unsized return Ok(None); @@ -416,9 +418,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// ConstProp needs it, though. pub fn read_immediate_raw( &self, - src: &OpTy<'tcx, M::PointerTag>, + src: &OpTy<'tcx, M::Provenance>, force: bool, - ) -> InterpResult<'tcx, Result<ImmTy<'tcx, M::PointerTag>, MPlaceTy<'tcx, M::PointerTag>>> { + ) -> InterpResult<'tcx, Result<ImmTy<'tcx, M::Provenance>, MPlaceTy<'tcx, M::Provenance>>> { Ok(match src.try_as_mplace() { Ok(ref mplace) => { if let Some(val) = self.read_immediate_from_mplace_raw(mplace, force)? { @@ -435,8 +437,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { #[inline(always)] pub fn read_immediate( &self, - op: &OpTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> { + op: &OpTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { if let Ok(imm) = self.read_immediate_raw(op, /*force*/ false)? { Ok(imm) } else { @@ -447,21 +449,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Read a scalar from a place pub fn read_scalar( &self, - op: &OpTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, ScalarMaybeUninit<M::PointerTag>> { + op: &OpTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, ScalarMaybeUninit<M::Provenance>> { Ok(self.read_immediate(op)?.to_scalar_or_uninit()) } /// Read a pointer from a place. pub fn read_pointer( &self, - op: &OpTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, Pointer<Option<M::PointerTag>>> { + op: &OpTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>> { self.scalar_to_ptr(self.read_scalar(op)?.check_init()?) } /// Turn the wide MPlace into a string (must already be dereferenced!) - pub fn read_str(&self, mplace: &MPlaceTy<'tcx, M::PointerTag>) -> InterpResult<'tcx, &str> { + pub fn read_str(&self, mplace: &MPlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx, &str> { let len = mplace.len(self)?; let bytes = self.read_bytes_ptr(mplace.ptr, Size::from_bytes(len))?; let str = std::str::from_utf8(bytes).map_err(|err| err_ub!(InvalidStr(err)))?; @@ -474,8 +476,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Can (but does not always) trigger UB if `op` is uninitialized. pub fn operand_to_simd( &self, - op: &OpTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, u64)> { + op: &OpTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, u64)> { // Basically we just transmute this place into an array following simd_size_and_type. // This only works in memory, but repr(simd) types should never be immediates anyway. assert!(op.layout.ty.is_simd()); @@ -499,10 +501,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// OpTy from a local. pub fn local_to_op( &self, - frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>, + frame: &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>, local: mir::Local, layout: Option<TyAndLayout<'tcx>>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { let layout = self.layout_of_local(frame, local, layout)?; let op = if layout.is_zst() { // Bypass `access_local` (helps in ConstProp) @@ -519,8 +521,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { #[inline(always)] pub fn place_to_op( &self, - place: &PlaceTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + place: &PlaceTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { let op = match **place { Place::Ptr(mplace) => Operand::Indirect(mplace), Place::Local { frame, local } => { @@ -536,7 +538,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &self, mir_place: mir::Place<'tcx>, layout: Option<TyAndLayout<'tcx>>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { // Do not use the layout passed in as argument if the base we are looking at // here is not the entire place. let layout = if mir_place.projection.is_empty() { layout } else { None }; @@ -573,7 +575,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &self, mir_op: &mir::Operand<'tcx>, layout: Option<TyAndLayout<'tcx>>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { use rustc_middle::mir::Operand::*; let op = match *mir_op { // FIXME: do some more logic on `move` to invalidate the old location @@ -598,7 +600,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub(super) fn eval_operands( &self, ops: &[mir::Operand<'tcx>], - ) -> InterpResult<'tcx, Vec<OpTy<'tcx, M::PointerTag>>> { + ) -> InterpResult<'tcx, Vec<OpTy<'tcx, M::Provenance>>> { ops.iter().map(|op| self.eval_operand(op, None)).collect() } @@ -610,7 +612,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &self, c: ty::Const<'tcx>, layout: Option<TyAndLayout<'tcx>>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { match c.kind() { ty::ConstKind::Param(_) | ty::ConstKind::Bound(..) => throw_inval!(TooGeneric), ty::ConstKind::Error(DelaySpanBugEmitted { reported, .. }) => { @@ -635,7 +637,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &self, val: &mir::ConstantKind<'tcx>, layout: Option<TyAndLayout<'tcx>>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { match val { mir::ConstantKind::Ty(ct) => self.const_to_op(*ct, layout), mir::ConstantKind::Val(val, ty) => self.const_val_to_op(*val, *ty, layout), @@ -647,9 +649,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { val_val: ConstValue<'tcx>, ty: Ty<'tcx>, layout: Option<TyAndLayout<'tcx>>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { // Other cases need layout. - let tag_scalar = |scalar| -> InterpResult<'tcx, _> { + let adjust_scalar = |scalar| -> InterpResult<'tcx, _> { Ok(match scalar { Scalar::Ptr(ptr, size) => Scalar::Ptr(self.global_base_pointer(ptr)?, size), Scalar::Int(int) => Scalar::Int(int), @@ -664,7 +666,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let ptr = self.global_base_pointer(Pointer::new(id, offset))?; Operand::Indirect(MemPlace::from_ptr(ptr.into())) } - ConstValue::Scalar(x) => Operand::Immediate(tag_scalar(x)?.into()), + ConstValue::Scalar(x) => Operand::Immediate(adjust_scalar(x)?.into()), ConstValue::ZeroSized => Operand::Immediate(Immediate::Uninit), ConstValue::Slice { data, start, end } => { // We rely on mutability being set correctly in `data` to prevent writes @@ -687,8 +689,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Can also legally be called on non-enums (e.g. through the discriminant_value intrinsic)! pub fn read_discriminant( &self, - op: &OpTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, (Scalar<M::PointerTag>, VariantIdx)> { + op: &OpTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, (Scalar<M::Provenance>, VariantIdx)> { trace!("read_discriminant_value {:#?}", op.layout); // Get type and layout of the discriminant. let discr_layout = self.layout_of(op.layout.ty.discriminant_ty(*self.tcx))?; diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index 88999e3b47b..f9912d706fb 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -19,9 +19,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &mut self, op: mir::BinOp, force_overflow_checks: bool, - left: &ImmTy<'tcx, M::PointerTag>, - right: &ImmTy<'tcx, M::PointerTag>, - dest: &PlaceTy<'tcx, M::PointerTag>, + left: &ImmTy<'tcx, M::Provenance>, + right: &ImmTy<'tcx, M::Provenance>, + dest: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { let (val, overflowed, ty) = self.overflowing_binary_op(op, &left, &right)?; debug_assert_eq!( @@ -58,9 +58,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn binop_ignore_overflow( &mut self, op: mir::BinOp, - left: &ImmTy<'tcx, M::PointerTag>, - right: &ImmTy<'tcx, M::PointerTag>, - dest: &PlaceTy<'tcx, M::PointerTag>, + left: &ImmTy<'tcx, M::Provenance>, + right: &ImmTy<'tcx, M::Provenance>, + dest: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { let (val, _overflowed, ty) = self.overflowing_binary_op(op, left, right)?; assert_eq!(ty, dest.layout.ty, "type mismatch for result of {:?}", op); @@ -74,7 +74,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { bin_op: mir::BinOp, l: char, r: char, - ) -> (Scalar<M::PointerTag>, bool, Ty<'tcx>) { + ) -> (Scalar<M::Provenance>, bool, Ty<'tcx>) { use rustc_middle::mir::BinOp::*; let res = match bin_op { @@ -94,7 +94,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { bin_op: mir::BinOp, l: bool, r: bool, - ) -> (Scalar<M::PointerTag>, bool, Ty<'tcx>) { + ) -> (Scalar<M::Provenance>, bool, Ty<'tcx>) { use rustc_middle::mir::BinOp::*; let res = match bin_op { @@ -112,13 +112,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { (Scalar::from_bool(res), false, self.tcx.types.bool) } - fn binary_float_op<F: Float + Into<Scalar<M::PointerTag>>>( + fn binary_float_op<F: Float + Into<Scalar<M::Provenance>>>( &self, bin_op: mir::BinOp, ty: Ty<'tcx>, l: F, r: F, - ) -> (Scalar<M::PointerTag>, bool, Ty<'tcx>) { + ) -> (Scalar<M::Provenance>, bool, Ty<'tcx>) { use rustc_middle::mir::BinOp::*; let (val, ty) = match bin_op { @@ -146,7 +146,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { left_layout: TyAndLayout<'tcx>, r: u128, right_layout: TyAndLayout<'tcx>, - ) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool, Ty<'tcx>)> { + ) -> InterpResult<'tcx, (Scalar<M::Provenance>, bool, Ty<'tcx>)> { use rustc_middle::mir::BinOp::*; // Shift ops can have an RHS with a different numeric type. @@ -314,9 +314,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn overflowing_binary_op( &self, bin_op: mir::BinOp, - left: &ImmTy<'tcx, M::PointerTag>, - right: &ImmTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool, Ty<'tcx>)> { + left: &ImmTy<'tcx, M::Provenance>, + right: &ImmTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, (Scalar<M::Provenance>, bool, Ty<'tcx>)> { trace!( "Running binary op {:?}: {:?} ({:?}), {:?} ({:?})", bin_op, @@ -393,9 +393,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn binary_op( &self, bin_op: mir::BinOp, - left: &ImmTy<'tcx, M::PointerTag>, - right: &ImmTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> { + left: &ImmTy<'tcx, M::Provenance>, + right: &ImmTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { let (val, _overflow, ty) = self.overflowing_binary_op(bin_op, left, right)?; Ok(ImmTy::from_scalar(val, self.layout_of(ty)?)) } @@ -405,8 +405,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn overflowing_unary_op( &self, un_op: mir::UnOp, - val: &ImmTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool, Ty<'tcx>)> { + val: &ImmTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, (Scalar<M::Provenance>, bool, Ty<'tcx>)> { use rustc_middle::mir::UnOp::*; let layout = val.layout; @@ -455,8 +455,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn unary_op( &self, un_op: mir::UnOp, - val: &ImmTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> { + val: &ImmTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { let (val, _overflow, ty) = self.overflowing_unary_op(un_op, val)?; Ok(ImmTy::from_scalar(val, self.layout_of(ty)?)) } diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index a29a1492c8e..c7d8a744f7c 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -5,7 +5,6 @@ use std::hash::Hash; use rustc_ast::Mutability; -use rustc_macros::HashStable; use rustc_middle::mir; use rustc_middle::ty; use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt, TyAndLayout}; @@ -17,11 +16,11 @@ use super::{ Pointer, Provenance, Scalar, ScalarMaybeUninit, }; -#[derive(Copy, Clone, Hash, PartialEq, Eq, HashStable, Debug)] +#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)] /// Information required for the sound usage of a `MemPlace`. -pub enum MemPlaceMeta<Tag: Provenance = AllocId> { +pub enum MemPlaceMeta<Prov: Provenance = AllocId> { /// The unsized payload (e.g. length for slices or vtable pointer for trait objects). - Meta(Scalar<Tag>), + Meta(Scalar<Prov>), /// `Sized` types or unsized `extern type` None, } @@ -29,8 +28,8 @@ pub enum MemPlaceMeta<Tag: Provenance = AllocId> { #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] rustc_data_structures::static_assert_size!(MemPlaceMeta, 24); -impl<Tag: Provenance> MemPlaceMeta<Tag> { - pub fn unwrap_meta(self) -> Scalar<Tag> { +impl<Prov: Provenance> MemPlaceMeta<Prov> { + pub fn unwrap_meta(self) -> Scalar<Prov> { match self { Self::Meta(s) => s, Self::None => { @@ -47,23 +46,38 @@ impl<Tag: Provenance> MemPlaceMeta<Tag> { } } -#[derive(Copy, Clone, Hash, PartialEq, Eq, HashStable, Debug)] -pub struct MemPlace<Tag: Provenance = AllocId> { - /// The pointer can be a pure integer, with the `None` tag. - pub ptr: Pointer<Option<Tag>>, +#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)] +pub struct MemPlace<Prov: Provenance = AllocId> { + /// The pointer can be a pure integer, with the `None` provenance. + pub ptr: Pointer<Option<Prov>>, /// Metadata for unsized places. Interpretation is up to the type. /// Must not be present for sized types, but can be missing for unsized types /// (e.g., `extern type`). - pub meta: MemPlaceMeta<Tag>, + pub meta: MemPlaceMeta<Prov>, } #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] rustc_data_structures::static_assert_size!(MemPlace, 40); -#[derive(Copy, Clone, Hash, PartialEq, Eq, HashStable, Debug)] -pub enum Place<Tag: Provenance = AllocId> { +/// A MemPlace with its layout. Constructing it is only possible in this module. +#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)] +pub struct MPlaceTy<'tcx, Prov: Provenance = AllocId> { + mplace: MemPlace<Prov>, + pub layout: TyAndLayout<'tcx>, + /// rustc does not have a proper way to represent the type of a field of a `repr(packed)` struct: + /// it needs to have a different alignment than the field type would usually have. + /// So we represent this here with a separate field that "overwrites" `layout.align`. + /// This means `layout.align` should never be used for a `MPlaceTy`! + pub align: Align, +} + +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +rustc_data_structures::static_assert_size!(MPlaceTy<'_>, 64); + +#[derive(Copy, Clone, Debug)] +pub enum Place<Prov: Provenance = AllocId> { /// A place referring to a value allocated in the `Memory` system. - Ptr(MemPlace<Tag>), + Ptr(MemPlace<Prov>), /// To support alloc-free locals, we are able to write directly to a local. /// (Without that optimization, we'd just always be a `MemPlace`.) @@ -73,9 +87,9 @@ pub enum Place<Tag: Provenance = AllocId> { #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] rustc_data_structures::static_assert_size!(Place, 48); -#[derive(Copy, Clone, Debug)] -pub struct PlaceTy<'tcx, Tag: Provenance = AllocId> { - place: Place<Tag>, // Keep this private; it helps enforce invariants. +#[derive(Clone, Debug)] +pub struct PlaceTy<'tcx, Prov: Provenance = AllocId> { + place: Place<Prov>, // Keep this private; it helps enforce invariants. pub layout: TyAndLayout<'tcx>, /// rustc does not have a proper way to represent the type of a field of a `repr(packed)` struct: /// it needs to have a different alignment than the field type would usually have. @@ -87,73 +101,58 @@ pub struct PlaceTy<'tcx, Tag: Provenance = AllocId> { #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] rustc_data_structures::static_assert_size!(PlaceTy<'_>, 72); -impl<'tcx, Tag: Provenance> std::ops::Deref for PlaceTy<'tcx, Tag> { - type Target = Place<Tag>; +impl<'tcx, Prov: Provenance> std::ops::Deref for PlaceTy<'tcx, Prov> { + type Target = Place<Prov>; #[inline(always)] - fn deref(&self) -> &Place<Tag> { + fn deref(&self) -> &Place<Prov> { &self.place } } -/// A MemPlace with its layout. Constructing it is only possible in this module. -#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)] -pub struct MPlaceTy<'tcx, Tag: Provenance = AllocId> { - mplace: MemPlace<Tag>, - pub layout: TyAndLayout<'tcx>, - /// rustc does not have a proper way to represent the type of a field of a `repr(packed)` struct: - /// it needs to have a different alignment than the field type would usually have. - /// So we represent this here with a separate field that "overwrites" `layout.align`. - /// This means `layout.align` should never be used for a `MPlaceTy`! - pub align: Align, -} - -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(MPlaceTy<'_>, 64); - -impl<'tcx, Tag: Provenance> std::ops::Deref for MPlaceTy<'tcx, Tag> { - type Target = MemPlace<Tag>; +impl<'tcx, Prov: Provenance> std::ops::Deref for MPlaceTy<'tcx, Prov> { + type Target = MemPlace<Prov>; #[inline(always)] - fn deref(&self) -> &MemPlace<Tag> { + fn deref(&self) -> &MemPlace<Prov> { &self.mplace } } -impl<'tcx, Tag: Provenance> From<MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> { +impl<'tcx, Prov: Provenance> From<MPlaceTy<'tcx, Prov>> for PlaceTy<'tcx, Prov> { #[inline(always)] - fn from(mplace: MPlaceTy<'tcx, Tag>) -> Self { + fn from(mplace: MPlaceTy<'tcx, Prov>) -> Self { PlaceTy { place: Place::Ptr(*mplace), layout: mplace.layout, align: mplace.align } } } -impl<'tcx, Tag: Provenance> From<&'_ MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> { +impl<'tcx, Prov: Provenance> From<&'_ MPlaceTy<'tcx, Prov>> for PlaceTy<'tcx, Prov> { #[inline(always)] - fn from(mplace: &MPlaceTy<'tcx, Tag>) -> Self { + fn from(mplace: &MPlaceTy<'tcx, Prov>) -> Self { PlaceTy { place: Place::Ptr(**mplace), layout: mplace.layout, align: mplace.align } } } -impl<'tcx, Tag: Provenance> From<&'_ mut MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> { +impl<'tcx, Prov: Provenance> From<&'_ mut MPlaceTy<'tcx, Prov>> for PlaceTy<'tcx, Prov> { #[inline(always)] - fn from(mplace: &mut MPlaceTy<'tcx, Tag>) -> Self { + fn from(mplace: &mut MPlaceTy<'tcx, Prov>) -> Self { PlaceTy { place: Place::Ptr(**mplace), layout: mplace.layout, align: mplace.align } } } -impl<Tag: Provenance> MemPlace<Tag> { +impl<Prov: Provenance> MemPlace<Prov> { #[inline(always)] - pub fn from_ptr(ptr: Pointer<Option<Tag>>) -> Self { + pub fn from_ptr(ptr: Pointer<Option<Prov>>) -> Self { MemPlace { ptr, meta: MemPlaceMeta::None } } /// Adjust the provenance of the main pointer (metadata is unaffected). - pub fn map_provenance(self, f: impl FnOnce(Option<Tag>) -> Option<Tag>) -> Self { + pub fn map_provenance(self, f: impl FnOnce(Option<Prov>) -> Option<Prov>) -> Self { MemPlace { ptr: self.ptr.map_provenance(f), ..self } } /// Turn a mplace into a (thin or wide) pointer, as a reference, pointing to the same space. /// This is the inverse of `ref_to_mplace`. #[inline(always)] - pub fn to_ref(self, cx: &impl HasDataLayout) -> Immediate<Tag> { + pub fn to_ref(self, cx: &impl HasDataLayout) -> Immediate<Prov> { match self.meta { MemPlaceMeta::None => Immediate::from(Scalar::from_maybe_pointer(self.ptr, cx)), MemPlaceMeta::Meta(meta) => { @@ -166,14 +165,14 @@ impl<Tag: Provenance> MemPlace<Tag> { pub fn offset_with_meta<'tcx>( self, offset: Size, - meta: MemPlaceMeta<Tag>, + meta: MemPlaceMeta<Prov>, cx: &impl HasDataLayout, ) -> InterpResult<'tcx, Self> { Ok(MemPlace { ptr: self.ptr.offset(offset, cx)?, meta }) } } -impl<Tag: Provenance> Place<Tag> { +impl<Prov: Provenance> Place<Prov> { /// Asserts that this points to some local variable. /// Returns the frame idx and the variable idx. #[inline] @@ -186,7 +185,7 @@ impl<Tag: Provenance> Place<Tag> { } } -impl<'tcx, Tag: Provenance> MPlaceTy<'tcx, Tag> { +impl<'tcx, Prov: Provenance> MPlaceTy<'tcx, Prov> { /// Produces a MemPlace that works for ZST but nothing else. /// Conceptually this is a new allocation, but it doesn't actually create an allocation so you /// don't need to worry about memory leaks. @@ -202,7 +201,7 @@ impl<'tcx, Tag: Provenance> MPlaceTy<'tcx, Tag> { pub fn offset_with_meta( &self, offset: Size, - meta: MemPlaceMeta<Tag>, + meta: MemPlaceMeta<Prov>, layout: TyAndLayout<'tcx>, cx: &impl HasDataLayout, ) -> InterpResult<'tcx, Self> { @@ -224,15 +223,15 @@ impl<'tcx, Tag: Provenance> MPlaceTy<'tcx, Tag> { } #[inline] - pub fn from_aligned_ptr(ptr: Pointer<Option<Tag>>, layout: TyAndLayout<'tcx>) -> Self { + pub fn from_aligned_ptr(ptr: Pointer<Option<Prov>>, layout: TyAndLayout<'tcx>) -> Self { MPlaceTy { mplace: MemPlace::from_ptr(ptr), layout, align: layout.align.abi } } #[inline] pub fn from_aligned_ptr_with_meta( - ptr: Pointer<Option<Tag>>, + ptr: Pointer<Option<Prov>>, layout: TyAndLayout<'tcx>, - meta: MemPlaceMeta<Tag>, + meta: MemPlaceMeta<Prov>, ) -> Self { let mut mplace = MemPlace::from_ptr(ptr); mplace.meta = meta; @@ -259,7 +258,7 @@ impl<'tcx, Tag: Provenance> MPlaceTy<'tcx, Tag> { } #[inline] - pub(super) fn vtable(&self) -> Scalar<Tag> { + pub(super) fn vtable(&self) -> Scalar<Prov> { match self.layout.ty.kind() { ty::Dynamic(..) => self.mplace.meta.unwrap_meta(), _ => bug!("vtable not supported on type {:?}", self.layout.ty), @@ -268,11 +267,11 @@ impl<'tcx, Tag: Provenance> MPlaceTy<'tcx, Tag> { } // These are defined here because they produce a place. -impl<'tcx, Tag: Provenance> OpTy<'tcx, Tag> { +impl<'tcx, Prov: Provenance> OpTy<'tcx, Prov> { #[inline(always)] /// Note: do not call `as_ref` on the resulting place. This function should only be used to /// read from the resulting mplace, not to get its address back. - pub fn try_as_mplace(&self) -> Result<MPlaceTy<'tcx, Tag>, ImmTy<'tcx, Tag>> { + pub fn try_as_mplace(&self) -> Result<MPlaceTy<'tcx, Prov>, ImmTy<'tcx, Prov>> { match **self { Operand::Indirect(mplace) => { Ok(MPlaceTy { mplace, layout: self.layout, align: self.align.unwrap() }) @@ -285,15 +284,15 @@ impl<'tcx, Tag: Provenance> OpTy<'tcx, Tag> { #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) /// Note: do not call `as_ref` on the resulting place. This function should only be used to /// read from the resulting mplace, not to get its address back. - pub fn assert_mem_place(&self) -> MPlaceTy<'tcx, Tag> { + pub fn assert_mem_place(&self) -> MPlaceTy<'tcx, Prov> { self.try_as_mplace().unwrap() } } -impl<'tcx, Tag: Provenance> PlaceTy<'tcx, Tag> { +impl<'tcx, Prov: Provenance> PlaceTy<'tcx, Prov> { /// A place is either an mplace or some local. #[inline] - pub fn try_as_mplace(&self) -> Result<MPlaceTy<'tcx, Tag>, (usize, mir::Local)> { + pub fn try_as_mplace(&self) -> Result<MPlaceTy<'tcx, Prov>, (usize, mir::Local)> { match **self { Place::Ptr(mplace) => Ok(MPlaceTy { mplace, layout: self.layout, align: self.align }), Place::Local { frame, local } => Err((frame, local)), @@ -302,16 +301,16 @@ impl<'tcx, Tag: Provenance> PlaceTy<'tcx, Tag> { #[inline(always)] #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) - pub fn assert_mem_place(self) -> MPlaceTy<'tcx, Tag> { + pub fn assert_mem_place(self) -> MPlaceTy<'tcx, Prov> { self.try_as_mplace().unwrap() } } // FIXME: Working around https://github.com/rust-lang/rust/issues/54385 -impl<'mir, 'tcx: 'mir, Tag, M> InterpCx<'mir, 'tcx, M> +impl<'mir, 'tcx: 'mir, Prov, M> InterpCx<'mir, 'tcx, M> where - Tag: Provenance + Eq + Hash + 'static, - M: Machine<'mir, 'tcx, PointerTag = Tag>, + Prov: Provenance + Eq + Hash + 'static, + M: Machine<'mir, 'tcx, Provenance = Prov>, { /// Take a value, which represents a (thin or wide) reference, and make it a place. /// Alignment is just based on the type. This is the inverse of `MemPlace::to_ref()`. @@ -321,8 +320,8 @@ where /// Generally prefer `deref_operand`. pub fn ref_to_mplace( &self, - val: &ImmTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + val: &ImmTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { let pointee_type = val.layout.ty.builtin_deref(true).expect("`ref_to_mplace` called on non-ptr type").ty; let layout = self.layout_of(pointee_type)?; @@ -343,8 +342,8 @@ where #[instrument(skip(self), level = "debug")] pub fn deref_operand( &self, - src: &OpTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + src: &OpTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { let val = self.read_immediate(src)?; trace!("deref to {} on {:?}", val.layout.ty, *val); @@ -360,8 +359,8 @@ where #[inline] pub(super) fn get_place_alloc( &self, - place: &MPlaceTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, Option<AllocRef<'_, 'tcx, M::PointerTag, M::AllocExtra>>> { + place: &MPlaceTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, Option<AllocRef<'_, 'tcx, M::Provenance, M::AllocExtra>>> { assert!(!place.layout.is_unsized()); assert!(!place.meta.has_meta()); let size = place.layout.size; @@ -371,8 +370,8 @@ where #[inline] pub(super) fn get_place_alloc_mut( &mut self, - place: &MPlaceTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, Option<AllocRefMut<'_, 'tcx, M::PointerTag, M::AllocExtra>>> { + place: &MPlaceTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, Option<AllocRefMut<'_, 'tcx, M::Provenance, M::AllocExtra>>> { assert!(!place.layout.is_unsized()); assert!(!place.meta.has_meta()); let size = place.layout.size; @@ -382,7 +381,7 @@ where /// Check if this mplace is dereferenceable and sufficiently aligned. fn check_mplace_access( &self, - mplace: MPlaceTy<'tcx, M::PointerTag>, + mplace: MPlaceTy<'tcx, M::Provenance>, msg: CheckInAllocMsg, ) -> InterpResult<'tcx> { let (size, align) = self @@ -398,8 +397,8 @@ where /// Also returns the number of elements. pub fn mplace_to_simd( &self, - mplace: &MPlaceTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, u64)> { + mplace: &MPlaceTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, u64)> { // Basically we just transmute this place into an array following simd_size_and_type. // (Transmuting is okay since this is an in-memory place. We also double-check the size // stays the same.) @@ -414,8 +413,8 @@ where /// Also returns the number of elements. pub fn place_to_simd( &mut self, - place: &PlaceTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, u64)> { + place: &PlaceTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, u64)> { let mplace = self.force_allocation(place)?; self.mplace_to_simd(&mplace) } @@ -424,7 +423,7 @@ where &self, frame: usize, local: mir::Local, - ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> { let layout = self.layout_of_local(&self.stack()[frame], local, None)?; let place = Place::Local { frame, local }; Ok(PlaceTy { place, layout, align: layout.align.abi }) @@ -436,7 +435,7 @@ where pub fn eval_place( &mut self, mir_place: mir::Place<'tcx>, - ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> { let mut place = self.local_to_place(self.frame_idx(), mir_place.local)?; // Using `try_fold` turned out to be bad for performance, hence the loop. for elem in mir_place.projection.iter() { @@ -466,8 +465,8 @@ where #[instrument(skip(self), level = "debug")] pub fn write_immediate( &mut self, - src: Immediate<M::PointerTag>, - dest: &PlaceTy<'tcx, M::PointerTag>, + src: Immediate<M::Provenance>, + dest: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { self.write_immediate_no_validate(src, dest)?; @@ -483,8 +482,8 @@ where #[inline(always)] pub fn write_scalar( &mut self, - val: impl Into<ScalarMaybeUninit<M::PointerTag>>, - dest: &PlaceTy<'tcx, M::PointerTag>, + val: impl Into<ScalarMaybeUninit<M::Provenance>>, + dest: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { self.write_immediate(Immediate::Scalar(val.into()), dest) } @@ -493,8 +492,8 @@ where #[inline(always)] pub fn write_pointer( &mut self, - ptr: impl Into<Pointer<Option<M::PointerTag>>>, - dest: &PlaceTy<'tcx, M::PointerTag>, + ptr: impl Into<Pointer<Option<M::Provenance>>>, + dest: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { self.write_scalar(Scalar::from_maybe_pointer(ptr.into(), self), dest) } @@ -504,8 +503,8 @@ where /// right type. fn write_immediate_no_validate( &mut self, - src: Immediate<M::PointerTag>, - dest: &PlaceTy<'tcx, M::PointerTag>, + src: Immediate<M::Provenance>, + dest: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { assert!(!dest.layout.is_unsized(), "Cannot write unsized data"); trace!("write_immediate: {:?} <- {:?}: {}", *dest, src, dest.layout.ty); @@ -538,10 +537,10 @@ where /// right layout. fn write_immediate_to_mplace_no_validate( &mut self, - value: Immediate<M::PointerTag>, + value: Immediate<M::Provenance>, layout: TyAndLayout<'tcx>, align: Align, - dest: MemPlace<M::PointerTag>, + dest: MemPlace<M::Provenance>, ) -> InterpResult<'tcx> { // Note that it is really important that the type here is the right one, and matches the // type things are read at. In case `value` is a `ScalarPair`, we don't do any magic here @@ -590,7 +589,7 @@ where } } - pub fn write_uninit(&mut self, dest: &PlaceTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> { + pub fn write_uninit(&mut self, dest: &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx> { let mplace = match dest.try_as_mplace() { Ok(mplace) => mplace, Err((frame, local)) => { @@ -620,8 +619,8 @@ where #[instrument(skip(self), level = "debug")] pub fn copy_op( &mut self, - src: &OpTy<'tcx, M::PointerTag>, - dest: &PlaceTy<'tcx, M::PointerTag>, + src: &OpTy<'tcx, M::Provenance>, + dest: &PlaceTy<'tcx, M::Provenance>, allow_transmute: bool, ) -> InterpResult<'tcx> { self.copy_op_no_validate(src, dest, allow_transmute)?; @@ -641,8 +640,8 @@ where #[instrument(skip(self), level = "debug")] fn copy_op_no_validate( &mut self, - src: &OpTy<'tcx, M::PointerTag>, - dest: &PlaceTy<'tcx, M::PointerTag>, + src: &OpTy<'tcx, M::Provenance>, + dest: &PlaceTy<'tcx, M::Provenance>, allow_transmute: bool, ) -> InterpResult<'tcx> { // We do NOT compare the types for equality, because well-typed code can @@ -714,8 +713,8 @@ where #[instrument(skip(self), level = "debug")] pub fn force_allocation( &mut self, - place: &PlaceTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + place: &PlaceTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { let mplace = match place.place { Place::Local { frame, local } => { match M::access_local_mut(self, frame, local)? { @@ -761,7 +760,7 @@ where &mut self, layout: TyAndLayout<'tcx>, kind: MemoryKind<M::MemoryKind>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { assert!(!layout.is_unsized()); let ptr = self.allocate_ptr(layout.size, layout.align.abi, kind)?; Ok(MPlaceTy::from_aligned_ptr(ptr.into(), layout)) @@ -773,7 +772,7 @@ where str: &str, kind: MemoryKind<M::MemoryKind>, mutbl: Mutability, - ) -> MPlaceTy<'tcx, M::PointerTag> { + ) -> MPlaceTy<'tcx, M::Provenance> { let ptr = self.allocate_bytes_ptr(str.as_bytes(), Align::ONE, kind, mutbl); let meta = Scalar::from_machine_usize(u64::try_from(str.len()).unwrap(), self); let mplace = MemPlace { ptr: ptr.into(), meta: MemPlaceMeta::Meta(meta) }; @@ -791,7 +790,7 @@ where pub fn write_discriminant( &mut self, variant_index: VariantIdx, - dest: &PlaceTy<'tcx, M::PointerTag>, + dest: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { // This must be an enum or generator. match dest.layout.ty.kind() { @@ -877,7 +876,7 @@ where pub fn raw_const_to_mplace( &self, raw: ConstAlloc<'tcx>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { // This must be an allocation in `tcx` let _ = self.tcx.global_alloc(raw.alloc_id); let ptr = self.global_base_pointer(Pointer::from(raw.alloc_id))?; @@ -886,28 +885,19 @@ where } /// Turn a place with a `dyn Trait` type into a place with the actual dynamic type. - /// Also return some more information so drop doesn't have to run the same code twice. pub(super) fn unpack_dyn_trait( &self, - mplace: &MPlaceTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, (ty::Instance<'tcx>, MPlaceTy<'tcx, M::PointerTag>)> { + mplace: &MPlaceTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { let vtable = self.scalar_to_ptr(mplace.vtable())?; // also sanity checks the type - let (instance, ty) = self.read_drop_type_from_vtable(vtable)?; + let (ty, _) = self.get_ptr_vtable(vtable)?; let layout = self.layout_of(ty)?; - // More sanity checks - if cfg!(debug_assertions) { - let (size, align) = self.read_size_and_align_from_vtable(vtable)?; - assert_eq!(size, layout.size); - // only ABI alignment is preserved - assert_eq!(align, layout.align.abi); - } - let mplace = MPlaceTy { mplace: MemPlace { meta: MemPlaceMeta::None, ..**mplace }, layout, align: layout.align.abi, }; - Ok((instance, mplace)) + Ok(mplace) } } diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index 704dc6db060..742339f2b0a 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -20,10 +20,10 @@ use super::{ }; // FIXME: Working around https://github.com/rust-lang/rust/issues/54385 -impl<'mir, 'tcx: 'mir, Tag, M> InterpCx<'mir, 'tcx, M> +impl<'mir, 'tcx: 'mir, Prov, M> InterpCx<'mir, 'tcx, M> where - Tag: Provenance + Eq + Hash + 'static, - M: Machine<'mir, 'tcx, PointerTag = Tag>, + Prov: Provenance + Eq + Hash + 'static, + M: Machine<'mir, 'tcx, Provenance = Prov>, { //# Field access @@ -35,9 +35,9 @@ where /// For indexing into arrays, use `mplace_index`. pub fn mplace_field( &self, - base: &MPlaceTy<'tcx, M::PointerTag>, + base: &MPlaceTy<'tcx, M::Provenance>, field: usize, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { let offset = base.layout.fields.offset(field); let field_layout = base.layout.field(self, field); @@ -72,9 +72,9 @@ where /// into the field of a local `ScalarPair`, we have to first allocate it. pub fn place_field( &mut self, - base: &PlaceTy<'tcx, M::PointerTag>, + base: &PlaceTy<'tcx, M::Provenance>, field: usize, - ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> { // FIXME: We could try to be smarter and avoid allocation for fields that span the // entire place. let base = self.force_allocation(base)?; @@ -83,9 +83,9 @@ where pub fn operand_field( &self, - base: &OpTy<'tcx, M::PointerTag>, + base: &OpTy<'tcx, M::Provenance>, field: usize, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { let base = match base.try_as_mplace() { Ok(ref mplace) => { // We can reuse the mplace field computation logic for indirect operands. @@ -139,9 +139,9 @@ where pub fn mplace_downcast( &self, - base: &MPlaceTy<'tcx, M::PointerTag>, + base: &MPlaceTy<'tcx, M::Provenance>, variant: VariantIdx, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { // Downcasts only change the layout. // (In particular, no check about whether this is even the active variant -- that's by design, // see https://github.com/rust-lang/rust/issues/93688#issuecomment-1032929496.) @@ -153,22 +153,22 @@ where pub fn place_downcast( &self, - base: &PlaceTy<'tcx, M::PointerTag>, + base: &PlaceTy<'tcx, M::Provenance>, variant: VariantIdx, - ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> { // Downcast just changes the layout - let mut base = *base; + let mut base = base.clone(); base.layout = base.layout.for_variant(self, variant); Ok(base) } pub fn operand_downcast( &self, - base: &OpTy<'tcx, M::PointerTag>, + base: &OpTy<'tcx, M::Provenance>, variant: VariantIdx, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { // Downcast just changes the layout - let mut base = *base; + let mut base = base.clone(); base.layout = base.layout.for_variant(self, variant); Ok(base) } @@ -178,9 +178,9 @@ where #[inline(always)] pub fn operand_index( &self, - base: &OpTy<'tcx, M::PointerTag>, + base: &OpTy<'tcx, M::Provenance>, index: u64, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { // Not using the layout method because we want to compute on u64 match base.layout.fields { abi::FieldsShape::Array { stride, count: _ } => { @@ -207,8 +207,8 @@ where // same by repeatedly calling `operand_index`. pub fn operand_array_fields<'a>( &self, - base: &'a OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx, impl Iterator<Item = InterpResult<'tcx, OpTy<'tcx, Tag>>> + 'a> { + base: &'a OpTy<'tcx, Prov>, + ) -> InterpResult<'tcx, impl Iterator<Item = InterpResult<'tcx, OpTy<'tcx, Prov>>> + 'a> { let len = base.len(self)?; // also asserts that we have a type where this makes sense let abi::FieldsShape::Array { stride, .. } = base.layout.fields else { span_bug!(self.cur_span(), "operand_array_fields: expected an array layout"); @@ -222,17 +222,17 @@ where /// Index into an array. pub fn mplace_index( &self, - base: &MPlaceTy<'tcx, M::PointerTag>, + base: &MPlaceTy<'tcx, M::Provenance>, index: u64, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { Ok(self.operand_index(&base.into(), index)?.assert_mem_place()) } pub fn place_index( &mut self, - base: &PlaceTy<'tcx, M::PointerTag>, + base: &PlaceTy<'tcx, M::Provenance>, index: u64, - ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> { // There's not a lot we can do here, since we cannot have a place to a part of a local. If // we are accessing the only element of a 1-element array, it's still the entire local... // that doesn't seem worth it. @@ -244,11 +244,11 @@ where fn operand_constant_index( &self, - base: &OpTy<'tcx, M::PointerTag>, + base: &OpTy<'tcx, M::Provenance>, offset: u64, min_length: u64, from_end: bool, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { let n = base.len(self)?; if n < min_length { // This can only be reached in ConstProp and non-rustc-MIR. @@ -268,11 +268,11 @@ where fn place_constant_index( &mut self, - base: &PlaceTy<'tcx, M::PointerTag>, + base: &PlaceTy<'tcx, M::Provenance>, offset: u64, min_length: u64, from_end: bool, - ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> { let base = self.force_allocation(base)?; Ok(self .operand_constant_index(&base.into(), offset, min_length, from_end)? @@ -284,11 +284,11 @@ where fn operand_subslice( &self, - base: &OpTy<'tcx, M::PointerTag>, + base: &OpTy<'tcx, M::Provenance>, from: u64, to: u64, from_end: bool, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { let len = base.len(self)?; // also asserts that we have a type where this makes sense let actual_to = if from_end { if from.checked_add(to).map_or(true, |to| to > len) { @@ -329,11 +329,11 @@ where pub fn place_subslice( &mut self, - base: &PlaceTy<'tcx, M::PointerTag>, + base: &PlaceTy<'tcx, M::Provenance>, from: u64, to: u64, from_end: bool, - ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> { let base = self.force_allocation(base)?; Ok(self.operand_subslice(&base.into(), from, to, from_end)?.assert_mem_place().into()) } @@ -344,16 +344,11 @@ where #[instrument(skip(self), level = "trace")] pub fn place_projection( &mut self, - base: &PlaceTy<'tcx, M::PointerTag>, + base: &PlaceTy<'tcx, M::Provenance>, proj_elem: mir::PlaceElem<'tcx>, - ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> { use rustc_middle::mir::ProjectionElem::*; Ok(match proj_elem { - OpaqueCast(ty) => { - let mut place = *base; - place.layout = self.layout_of(ty)?; - place - } Field(field, _) => self.place_field(base, field.index())?, Downcast(_, variant) => self.place_downcast(base, variant)?, Deref => self.deref_operand(&self.place_to_op(base)?)?.into(), @@ -373,16 +368,11 @@ where #[instrument(skip(self), level = "trace")] pub fn operand_projection( &self, - base: &OpTy<'tcx, M::PointerTag>, + base: &OpTy<'tcx, M::Provenance>, proj_elem: mir::PlaceElem<'tcx>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { use rustc_middle::mir::ProjectionElem::*; Ok(match proj_elem { - OpaqueCast(ty) => { - let mut op = *base; - op.layout = self.layout_of(ty)?; - op - } Field(field, _) => self.operand_field(base, field.index())?, Downcast(_, variant) => self.operand_downcast(base, variant)?, Deref => self.deref_operand(base)?.into(), diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index 20122f8131c..e7e60b5fa23 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -1,5 +1,4 @@ use std::borrow::Cow; -use std::convert::TryFrom; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf}; use rustc_middle::ty::Instance; @@ -267,10 +266,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { fn pass_argument<'x, 'y>( &mut self, caller_args: &mut impl Iterator< - Item = (&'x OpTy<'tcx, M::PointerTag>, &'y ArgAbi<'tcx, Ty<'tcx>>), + Item = (&'x OpTy<'tcx, M::Provenance>, &'y ArgAbi<'tcx, Ty<'tcx>>), >, callee_abi: &ArgAbi<'tcx, Ty<'tcx>>, - callee_arg: &PlaceTy<'tcx, M::PointerTag>, + callee_arg: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx> where 'tcx: 'x, @@ -336,9 +335,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &mut self, fn_val: FnVal<'tcx, M::ExtraFnVal>, (caller_abi, caller_fn_abi): (Abi, &FnAbi<'tcx, Ty<'tcx>>), - args: &[OpTy<'tcx, M::PointerTag>], + args: &[OpTy<'tcx, M::Provenance>], with_caller_location: bool, - destination: &PlaceTy<'tcx, M::PointerTag>, + destination: &PlaceTy<'tcx, M::Provenance>, target: Option<mir::BasicBlock>, mut unwind: StackPopUnwind, ) -> InterpResult<'tcx> { @@ -365,7 +364,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // caller_fn_abi is not relevant here, we interpret the arguments directly for each intrinsic. M::call_intrinsic(self, instance, args, destination, target, unwind) } - ty::InstanceDef::VtableShim(..) + ty::InstanceDef::VTableShim(..) | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::ClosureOnceShim { .. } | ty::InstanceDef::FnPtrShim(..) @@ -437,19 +436,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // last incoming argument. These two iterators do not have the same type, // so to keep the code paths uniform we accept an allocation // (for RustCall ABI only). - let caller_args: Cow<'_, [OpTy<'tcx, M::PointerTag>]> = + let caller_args: Cow<'_, [OpTy<'tcx, M::Provenance>]> = if caller_abi == Abi::RustCall && !args.is_empty() { // Untuple let (untuple_arg, args) = args.split_last().unwrap(); trace!("eval_fn_call: Will pass last argument by untupling"); Cow::from( args.iter() - .map(|&a| Ok(a)) + .map(|a| Ok(a.clone())) .chain( (0..untuple_arg.layout.fields.count()) .map(|i| self.operand_field(untuple_arg, i)), ) - .collect::<InterpResult<'_, Vec<OpTy<'tcx, M::PointerTag>>>>( + .collect::<InterpResult<'_, Vec<OpTy<'tcx, M::Provenance>>>>( )?, ) } else { @@ -520,12 +519,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } // cannot use the shim here, because that will only result in infinite recursion - ty::InstanceDef::Virtual(_, idx) => { + ty::InstanceDef::Virtual(def_id, idx) => { let mut args = args.to_vec(); // We have to implement all "object safe receivers". So we have to go search for a // pointer or `dyn Trait` type, but it could be wrapped in newtypes. So recursively // unwrap those newtypes until we are there. - let mut receiver = args[0]; + let mut receiver = args[0].clone(); let receiver_place = loop { match receiver.layout.ty.kind() { ty::Ref(..) | ty::RawPtr(..) => break self.deref_operand(&receiver)?, @@ -553,17 +552,53 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } }; - // Find and consult vtable. The type now could be something like RcBox<dyn Trait>, - // i.e., it is still not necessarily `ty::Dynamic` (so we cannot use - // `place.vtable()`), but it should have a `dyn Trait` tail. - assert!(matches!( - self.tcx - .struct_tail_erasing_lifetimes(receiver_place.layout.ty, self.param_env) - .kind(), - ty::Dynamic(..) - )); - let vtable = self.scalar_to_ptr(receiver_place.meta.unwrap_meta())?; - let fn_val = self.get_vtable_slot(vtable, u64::try_from(idx).unwrap())?; + // Obtain the underlying trait we are working on. + let receiver_tail = self + .tcx + .struct_tail_erasing_lifetimes(receiver_place.layout.ty, self.param_env); + let ty::Dynamic(data, ..) = receiver_tail.kind() else { + span_bug!(self.cur_span(), "dyanmic call on non-`dyn` type {}", receiver_tail) + }; + + // Get the required information from the vtable. + let vptr = self.scalar_to_ptr(receiver_place.meta.unwrap_meta())?; + let (dyn_ty, dyn_trait) = self.get_ptr_vtable(vptr)?; + if dyn_trait != data.principal() { + throw_ub_format!( + "`dyn` call on a pointer whose vtable does not match its type" + ); + } + + // Now determine the actual method to call. We can do that in two different ways and + // compare them to ensure everything fits. + let ty::VtblEntry::Method(fn_inst) = self.get_vtable_entries(vptr)?[idx] else { + span_bug!(self.cur_span(), "dyn call index points at something that is not a method") + }; + if cfg!(debug_assertions) { + let tcx = *self.tcx; + + let trait_def_id = tcx.trait_of_item(def_id).unwrap(); + let virtual_trait_ref = + ty::TraitRef::from_method(tcx, trait_def_id, instance.substs); + assert_eq!( + receiver_tail, + virtual_trait_ref.self_ty(), + "mismatch in underlying dyn trait computation within Miri and MIR building", + ); + let existential_trait_ref = + ty::ExistentialTraitRef::erase_self_ty(tcx, virtual_trait_ref); + let concrete_trait_ref = existential_trait_ref.with_self_ty(tcx, dyn_ty); + + let concrete_method = Instance::resolve( + tcx, + self.param_env, + def_id, + instance.substs.rebase_onto(tcx, trait_def_id, concrete_trait_ref.substs), + ) + .unwrap() + .unwrap(); + assert_eq!(fn_inst, concrete_method); + } // `*mut receiver_place.layout.ty` is almost the layout that we // want for args[0]: We have to project to field 0 because we want @@ -579,7 +614,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { trace!("Patched receiver operand to {:#?}", args[0]); // recurse with concrete function self.eval_fn_call( - fn_val, + FnVal::Instance(fn_inst), (caller_abi, caller_fn_abi), &args, with_caller_location, @@ -593,7 +628,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { fn drop_in_place( &mut self, - place: &PlaceTy<'tcx, M::PointerTag>, + place: &PlaceTy<'tcx, M::Provenance>, instance: ty::Instance<'tcx>, target: mir::BasicBlock, unwind: Option<mir::BasicBlock>, @@ -606,8 +641,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let (instance, place) = match place.layout.ty.kind() { ty::Dynamic(..) => { - // Dropping a trait object. - self.unpack_dyn_trait(&place)? + // Dropping a trait object. Need to find actual drop fn. + let place = self.unpack_dyn_trait(&place)?; + let instance = ty::Instance::resolve_drop_in_place(*self.tcx, place.layout.ty); + (instance, place) } _ => (instance, place), }; diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs index 22c23df7b1a..b3a511d5a49 100644 --- a/compiler/rustc_const_eval/src/interpret/traits.rs +++ b/compiler/rustc_const_eval/src/interpret/traits.rs @@ -1,27 +1,24 @@ -use std::convert::TryFrom; - -use rustc_middle::mir::interpret::{alloc_range, InterpResult, Pointer, PointerArithmetic}; -use rustc_middle::ty::{ - self, Ty, TyCtxt, COMMON_VTABLE_ENTRIES_ALIGN, COMMON_VTABLE_ENTRIES_DROPINPLACE, - COMMON_VTABLE_ENTRIES_SIZE, -}; +use rustc_middle::mir::interpret::{InterpResult, Pointer}; +use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_target::abi::{Align, Size}; use super::util::ensure_monomorphic_enough; -use super::{FnVal, InterpCx, Machine}; +use super::{InterpCx, Machine}; impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Creates a dynamic vtable for the given type and vtable origin. This is used only for /// objects. /// - /// The `trait_ref` encodes the erased self type. Hence, if we are - /// making an object `Foo<Trait>` from a value of type `Foo<T>`, then - /// `trait_ref` would map `T: Trait`. - pub fn get_vtable( - &mut self, + /// The `trait_ref` encodes the erased self type. Hence, if we are making an object `Foo<Trait>` + /// from a value of type `Foo<T>`, then `trait_ref` would map `T: Trait`. `None` here means that + /// this is an auto trait without any methods, so we only need the basic vtable (drop, size, + /// align). + pub fn get_vtable_ptr( + &self, ty: Ty<'tcx>, poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>, - ) -> InterpResult<'tcx, Pointer<Option<M::PointerTag>>> { + ) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>> { trace!("get_vtable(trait_ref={:?})", poly_trait_ref); let (ty, poly_trait_ref) = self.tcx.erase_regions((ty, poly_trait_ref)); @@ -30,114 +27,33 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ensure_monomorphic_enough(*self.tcx, ty)?; ensure_monomorphic_enough(*self.tcx, poly_trait_ref)?; - let vtable_allocation = self.tcx.vtable_allocation((ty, poly_trait_ref)); - - let vtable_ptr = self.global_base_pointer(Pointer::from(vtable_allocation))?; - + let vtable_symbolic_allocation = self.tcx.create_vtable_alloc(ty, poly_trait_ref); + let vtable_ptr = self.global_base_pointer(Pointer::from(vtable_symbolic_allocation))?; Ok(vtable_ptr.into()) } - /// Resolves the function at the specified slot in the provided - /// vtable. Currently an index of '3' (`TyCtxt::COMMON_VTABLE_ENTRIES.len()`) - /// corresponds to the first method declared in the trait of the provided vtable. - pub fn get_vtable_slot( - &self, - vtable: Pointer<Option<M::PointerTag>>, - idx: u64, - ) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> { - let ptr_size = self.pointer_size(); - let vtable_slot = vtable.offset(ptr_size * idx, self)?; - let vtable_slot = self - .get_ptr_alloc(vtable_slot, ptr_size, self.tcx.data_layout.pointer_align.abi)? - .expect("cannot be a ZST"); - let fn_ptr = self.scalar_to_ptr(vtable_slot.read_pointer(Size::ZERO)?.check_init()?)?; - self.get_ptr_fn(fn_ptr) - } - - /// Returns the drop fn instance as well as the actual dynamic type. - pub fn read_drop_type_from_vtable( + /// Returns a high-level representation of the entires of the given vtable. + pub fn get_vtable_entries( &self, - vtable: Pointer<Option<M::PointerTag>>, - ) -> InterpResult<'tcx, (ty::Instance<'tcx>, Ty<'tcx>)> { - let pointer_size = self.pointer_size(); - // We don't care about the pointee type; we just want a pointer. - let vtable = self - .get_ptr_alloc( - vtable, - pointer_size * u64::try_from(TyCtxt::COMMON_VTABLE_ENTRIES.len()).unwrap(), - self.tcx.data_layout.pointer_align.abi, - )? - .expect("cannot be a ZST"); - let drop_fn = vtable - .read_pointer(pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_DROPINPLACE).unwrap())? - .check_init()?; - // We *need* an instance here, no other kind of function value, to be able - // to determine the type. - let drop_instance = self.get_ptr_fn(self.scalar_to_ptr(drop_fn)?)?.as_instance()?; - trace!("Found drop fn: {:?}", drop_instance); - let fn_sig = drop_instance.ty(*self.tcx, self.param_env).fn_sig(*self.tcx); - let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig); - // The drop function takes `*mut T` where `T` is the type being dropped, so get that. - let args = fn_sig.inputs(); - if args.len() != 1 { - throw_ub!(InvalidVtableDropFn(fn_sig)); - } - let ty = - args[0].builtin_deref(true).ok_or_else(|| err_ub!(InvalidVtableDropFn(fn_sig)))?.ty; - Ok((drop_instance, ty)) + vtable: Pointer<Option<M::Provenance>>, + ) -> InterpResult<'tcx, &'tcx [ty::VtblEntry<'tcx>]> { + let (ty, poly_trait_ref) = self.get_ptr_vtable(vtable)?; + Ok(if let Some(poly_trait_ref) = poly_trait_ref { + let trait_ref = poly_trait_ref.with_self_ty(*self.tcx, ty); + let trait_ref = self.tcx.erase_regions(trait_ref); + self.tcx.vtable_entries(trait_ref) + } else { + TyCtxt::COMMON_VTABLE_ENTRIES + }) } - pub fn read_size_and_align_from_vtable( + pub fn get_vtable_size_and_align( &self, - vtable: Pointer<Option<M::PointerTag>>, + vtable: Pointer<Option<M::Provenance>>, ) -> InterpResult<'tcx, (Size, Align)> { - let pointer_size = self.pointer_size(); - // We check for `size = 3 * ptr_size`, which covers the drop fn (unused here), - // the size, and the align (which we read below). - let vtable = self - .get_ptr_alloc( - vtable, - pointer_size * u64::try_from(TyCtxt::COMMON_VTABLE_ENTRIES.len()).unwrap(), - self.tcx.data_layout.pointer_align.abi, - )? - .expect("cannot be a ZST"); - let size = vtable - .read_integer(alloc_range( - pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_SIZE).unwrap(), - pointer_size, - ))? - .check_init()?; - let size = size.to_machine_usize(self)?; - let size = Size::from_bytes(size); - let align = vtable - .read_integer(alloc_range( - pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_ALIGN).unwrap(), - pointer_size, - ))? - .check_init()?; - let align = align.to_machine_usize(self)?; - let align = Align::from_bytes(align).map_err(|e| err_ub!(InvalidVtableAlignment(e)))?; - - if size > self.max_size_of_val() { - throw_ub!(InvalidVtableSize); - } - Ok((size, align)) - } - - pub fn read_new_vtable_after_trait_upcasting_from_vtable( - &self, - vtable: Pointer<Option<M::PointerTag>>, - idx: u64, - ) -> InterpResult<'tcx, Pointer<Option<M::PointerTag>>> { - let pointer_size = self.pointer_size(); - - let vtable_slot = vtable.offset(pointer_size * idx, self)?; - let new_vtable = self - .get_ptr_alloc(vtable_slot, pointer_size, self.tcx.data_layout.pointer_align.abi)? - .expect("cannot be a ZST"); - - let new_vtable = self.scalar_to_ptr(new_vtable.read_pointer(Size::ZERO)?.check_init()?)?; - - Ok(new_vtable) + let (ty, _trait_ref) = self.get_ptr_vtable(vtable)?; + let layout = self.layout_of(ty)?; + assert!(!layout.is_unsized(), "there are no vtables for unsized types"); + Ok((layout.size, layout.align.abi)) } } diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 2e5492ecf56..f2e104da04a 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -206,7 +206,7 @@ struct ValidityVisitor<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> { /// starts must not be changed! `visit_fields` and `visit_array` rely on /// this stack discipline. path: Vec<PathElem>, - ref_tracking: Option<&'rt mut RefTracking<MPlaceTy<'tcx, M::PointerTag>, Vec<PathElem>>>, + ref_tracking: Option<&'rt mut RefTracking<MPlaceTy<'tcx, M::Provenance>, Vec<PathElem>>>, /// `None` indicates this is not validating for CTFE (but for runtime). ctfe_mode: Option<CtfeValidationMode>, ecx: &'rt InterpCx<'mir, 'tcx, M>, @@ -306,57 +306,22 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' fn check_wide_ptr_meta( &mut self, - meta: MemPlaceMeta<M::PointerTag>, + meta: MemPlaceMeta<M::Provenance>, pointee: TyAndLayout<'tcx>, ) -> InterpResult<'tcx> { let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(pointee.ty, self.ecx.param_env); match tail.kind() { ty::Dynamic(..) => { let vtable = self.ecx.scalar_to_ptr(meta.unwrap_meta())?; - // Direct call to `check_ptr_access_align` checks alignment even on CTFE machines. - try_validation!( - self.ecx.check_ptr_access_align( - vtable, - 3 * self.ecx.tcx.data_layout.pointer_size, // drop, size, align - self.ecx.tcx.data_layout.pointer_align.abi, - CheckInAllocMsg::InboundsTest, // will anyway be replaced by validity message - ), - self.path, - err_ub!(DanglingIntPointer(..)) | - err_ub!(PointerUseAfterFree(..)) => - { "dangling vtable pointer in wide pointer" }, - err_ub!(AlignmentCheckFailed { .. }) => - { "unaligned vtable pointer in wide pointer" }, - err_ub!(PointerOutOfBounds { .. }) => - { "too small vtable" }, - ); - try_validation!( - self.ecx.read_drop_type_from_vtable(vtable), + // Make sure it is a genuine vtable pointer. + let (_ty, _trait) = try_validation!( + self.ecx.get_ptr_vtable(vtable), self.path, err_ub!(DanglingIntPointer(..)) | - err_ub!(InvalidFunctionPointer(..)) => - { "invalid drop function pointer in vtable (not pointing to a function)" }, - err_ub!(InvalidVtableDropFn(..)) => - { "invalid drop function pointer in vtable (function has incompatible signature)" }, - // Stacked Borrows errors can happen here, see https://github.com/rust-lang/miri/issues/2123. - // (We assume there are no other MachineStop errors possible here.) - InterpError::MachineStop(_) => - { "vtable pointer does not have permission to read drop function pointer" }, - ); - try_validation!( - self.ecx.read_size_and_align_from_vtable(vtable), - self.path, - err_ub!(InvalidVtableSize) => - { "invalid vtable: size is bigger than largest supported object" }, - err_ub!(InvalidVtableAlignment(msg)) => - { "invalid vtable: alignment {}", msg }, - err_unsup!(ReadPointerAsBytes) => { "invalid size or align in vtable" }, - // Stacked Borrows errors can happen here, see https://github.com/rust-lang/miri/issues/2123. - // (We assume there are no other MachineStop errors possible here.) - InterpError::MachineStop(_) => - { "vtable pointer does not have permission to read size and alignment" }, + err_ub!(InvalidVTablePointer(..)) => + { "{vtable}" } expected { "a vtable pointer" }, ); - // FIXME: More checks for the vtable. + // FIXME: check if the type/trait match what ty::Dynamic says? } ty::Slice(..) | ty::Str => { let _len = try_validation!( @@ -380,7 +345,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' /// Check a reference or `Box`. fn check_safe_pointer( &mut self, - value: &OpTy<'tcx, M::PointerTag>, + value: &OpTy<'tcx, M::Provenance>, kind: &str, ) -> InterpResult<'tcx> { let value = try_validation!( @@ -445,9 +410,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' if let Some(ref mut ref_tracking) = self.ref_tracking { // Proceed recursively even for ZST, no reason to skip them! // `!` is a ZST and we want to validate it. - if let Ok((alloc_id, _offset, _tag)) = self.ecx.ptr_try_get_alloc_id(place.ptr) { + if let Ok((alloc_id, _offset, _prov)) = self.ecx.ptr_try_get_alloc_id(place.ptr) { // Special handling for pointers to statics (irrespective of their type). - let alloc_kind = self.ecx.tcx.get_global_alloc(alloc_id); + let alloc_kind = self.ecx.tcx.try_get_global_alloc(alloc_id); if let Some(GlobalAlloc::Static(did)) = alloc_kind { assert!(!self.ecx.tcx.is_thread_local_static(did)); assert!(self.ecx.tcx.is_static(did)); @@ -491,8 +456,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' fn read_scalar( &self, - op: &OpTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, ScalarMaybeUninit<M::PointerTag>> { + op: &OpTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, ScalarMaybeUninit<M::Provenance>> { Ok(try_validation!( self.ecx.read_scalar(op), self.path, @@ -502,8 +467,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' fn read_immediate_forced( &self, - op: &OpTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, Immediate<M::PointerTag>> { + op: &OpTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, Immediate<M::Provenance>> { Ok(*try_validation!( self.ecx.read_immediate_raw(op, /*force*/ true), self.path, @@ -515,7 +480,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' /// at that type. Return `true` if the type is indeed primitive. fn try_visit_primitive( &mut self, - value: &OpTy<'tcx, M::PointerTag>, + value: &OpTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, bool> { // Go over all the primitive types let ty = value.layout.ty; @@ -607,11 +572,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' let _fn = try_validation!( self.ecx.get_ptr_fn(ptr), self.path, - err_ub!(DanglingIntPointer(0, _)) => - { "a null function pointer" }, err_ub!(DanglingIntPointer(..)) | err_ub!(InvalidFunctionPointer(..)) => - { "{:x}", value } expected { "a function pointer" }, + { "{ptr}" } expected { "a function pointer" }, ); // FIXME: Check if the signature matches } else { @@ -652,7 +615,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' fn visit_scalar( &mut self, - scalar: ScalarMaybeUninit<M::PointerTag>, + scalar: ScalarMaybeUninit<M::Provenance>, scalar_layout: ScalarAbi, ) -> InterpResult<'tcx> { // We check `is_full_range` in a slightly complicated way because *if* we are checking @@ -735,7 +698,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> for ValidityVisitor<'rt, 'mir, 'tcx, M> { - type V = OpTy<'tcx, M::PointerTag>; + type V = OpTy<'tcx, M::Provenance>; #[inline(always)] fn ecx(&self) -> &InterpCx<'mir, 'tcx, M> { @@ -744,7 +707,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> fn read_discriminant( &mut self, - op: &OpTy<'tcx, M::PointerTag>, + op: &OpTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, VariantIdx> { self.with_elem(PathElem::EnumTag, move |this| { Ok(try_validation!( @@ -764,9 +727,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> #[inline] fn visit_field( &mut self, - old_op: &OpTy<'tcx, M::PointerTag>, + old_op: &OpTy<'tcx, M::Provenance>, field: usize, - new_op: &OpTy<'tcx, M::PointerTag>, + new_op: &OpTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { let elem = self.aggregate_field_path_elem(old_op.layout, field); self.with_elem(elem, move |this| this.visit_value(new_op)) @@ -775,9 +738,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> #[inline] fn visit_variant( &mut self, - old_op: &OpTy<'tcx, M::PointerTag>, + old_op: &OpTy<'tcx, M::Provenance>, variant_id: VariantIdx, - new_op: &OpTy<'tcx, M::PointerTag>, + new_op: &OpTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { let name = match old_op.layout.ty.kind() { ty::Adt(adt, _) => PathElem::Variant(adt.variant(variant_id).name), @@ -791,7 +754,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> #[inline(always)] fn visit_union( &mut self, - op: &OpTy<'tcx, M::PointerTag>, + op: &OpTy<'tcx, M::Provenance>, _fields: NonZeroUsize, ) -> InterpResult<'tcx> { // Special check preventing `UnsafeCell` inside unions in the inner part of constants. @@ -804,13 +767,13 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> } #[inline] - fn visit_box(&mut self, op: &OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> { + fn visit_box(&mut self, op: &OpTy<'tcx, M::Provenance>) -> InterpResult<'tcx> { self.check_safe_pointer(op, "box")?; Ok(()) } #[inline] - fn visit_value(&mut self, op: &OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> { + fn visit_value(&mut self, op: &OpTy<'tcx, M::Provenance>) -> InterpResult<'tcx> { trace!("visit_value: {:?}, {:?}", *op, op.layout); // Check primitive types -- the leaves of our recursive descent. @@ -881,7 +844,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> fn visit_aggregate( &mut self, - op: &OpTy<'tcx, M::PointerTag>, + op: &OpTy<'tcx, M::Provenance>, fields: impl Iterator<Item = InterpResult<'tcx, Self::V>>, ) -> InterpResult<'tcx> { match op.layout.ty.kind() { @@ -992,9 +955,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { fn validate_operand_internal( &self, - op: &OpTy<'tcx, M::PointerTag>, + op: &OpTy<'tcx, M::Provenance>, path: Vec<PathElem>, - ref_tracking: Option<&mut RefTracking<MPlaceTy<'tcx, M::PointerTag>, Vec<PathElem>>>, + ref_tracking: Option<&mut RefTracking<MPlaceTy<'tcx, M::Provenance>, Vec<PathElem>>>, ctfe_mode: Option<CtfeValidationMode>, ) -> InterpResult<'tcx> { trace!("validate_operand_internal: {:?}, {:?}", *op, op.layout.ty); @@ -1031,9 +994,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { #[inline(always)] pub fn const_validate_operand( &self, - op: &OpTy<'tcx, M::PointerTag>, + op: &OpTy<'tcx, M::Provenance>, path: Vec<PathElem>, - ref_tracking: &mut RefTracking<MPlaceTy<'tcx, M::PointerTag>, Vec<PathElem>>, + ref_tracking: &mut RefTracking<MPlaceTy<'tcx, M::Provenance>, Vec<PathElem>>, ctfe_mode: CtfeValidationMode, ) -> InterpResult<'tcx> { self.validate_operand_internal(op, path, Some(ref_tracking), Some(ctfe_mode)) @@ -1043,7 +1006,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// `op` is assumed to cover valid memory if it is an indirect operand. /// It will error if the bits at the destination do not match the ones described by the layout. #[inline(always)] - pub fn validate_operand(&self, op: &OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> { + pub fn validate_operand(&self, op: &OpTy<'tcx, M::Provenance>) -> InterpResult<'tcx> { self.validate_operand_internal(op, vec![], None, None) } } diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs index f6a0c19d259..aee1f93b1a3 100644 --- a/compiler/rustc_const_eval/src/interpret/visitor.rs +++ b/compiler/rustc_const_eval/src/interpret/visitor.rs @@ -13,7 +13,7 @@ use super::{InterpCx, MPlaceTy, Machine, OpTy, PlaceTy}; /// A thing that we can project into, and that has a layout. /// This wouldn't have to depend on `Machine` but with the current type inference, /// that's just more convenient to work with (avoids repeating all the `Machine` bounds). -pub trait Value<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Copy { +pub trait Value<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Sized { /// Gets this value's layout. fn layout(&self) -> TyAndLayout<'tcx>; @@ -21,20 +21,20 @@ pub trait Value<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Copy { fn to_op_for_read( &self, ecx: &InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>>; + ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>>; /// Makes this into an `OpTy`, in a potentially more expensive way that is good for projections. fn to_op_for_proj( &self, ecx: &InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { self.to_op_for_read(ecx) } /// Creates this from an `OpTy`. /// /// If `to_op_for_proj` only ever produces `Indirect` operands, then this one is definitely `Indirect`. - fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self; + fn from_op(op: &OpTy<'tcx, M::Provenance>) -> Self; /// Projects to the given enum variant. fn project_downcast( @@ -54,7 +54,7 @@ pub trait Value<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Copy { /// A thing that we can project into given *mutable* access to `ecx`, and that has a layout. /// This wouldn't have to depend on `Machine` but with the current type inference, /// that's just more convenient to work with (avoids repeating all the `Machine` bounds). -pub trait ValueMut<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Copy { +pub trait ValueMut<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Sized { /// Gets this value's layout. fn layout(&self) -> TyAndLayout<'tcx>; @@ -62,18 +62,18 @@ pub trait ValueMut<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Copy { fn to_op_for_read( &self, ecx: &InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>>; + ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>>; /// Makes this into an `OpTy`, in a potentially more expensive way that is good for projections. fn to_op_for_proj( &self, ecx: &mut InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>>; + ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>>; /// Creates this from an `OpTy`. /// /// If `to_op_for_proj` only ever produces `Indirect` operands, then this one is definitely `Indirect`. - fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self; + fn from_op(op: &OpTy<'tcx, M::Provenance>) -> Self; /// Projects to the given enum variant. fn project_downcast( @@ -95,7 +95,7 @@ pub trait ValueMut<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Copy { // So we have some copy-paste here. (We could have a macro but since we only have 2 types with this // double-impl, that would barely make the code shorter, if at all.) -impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for OpTy<'tcx, M::PointerTag> { +impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for OpTy<'tcx, M::Provenance> { #[inline(always)] fn layout(&self) -> TyAndLayout<'tcx> { self.layout @@ -105,13 +105,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for OpTy<'tc fn to_op_for_read( &self, _ecx: &InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { - Ok(*self) + ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { + Ok(self.clone()) } #[inline(always)] - fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self { - *op + fn from_op(op: &OpTy<'tcx, M::Provenance>) -> Self { + op.clone() } #[inline(always)] @@ -134,7 +134,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for OpTy<'tc } impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M> - for OpTy<'tcx, M::PointerTag> + for OpTy<'tcx, M::Provenance> { #[inline(always)] fn layout(&self) -> TyAndLayout<'tcx> { @@ -145,21 +145,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M> fn to_op_for_read( &self, _ecx: &InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { - Ok(*self) + ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { + Ok(self.clone()) } #[inline(always)] fn to_op_for_proj( &self, _ecx: &mut InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { - Ok(*self) + ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { + Ok(self.clone()) } #[inline(always)] - fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self { - *op + fn from_op(op: &OpTy<'tcx, M::Provenance>) -> Self { + op.clone() } #[inline(always)] @@ -182,7 +182,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M> } impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> - for MPlaceTy<'tcx, M::PointerTag> + for MPlaceTy<'tcx, M::Provenance> { #[inline(always)] fn layout(&self) -> TyAndLayout<'tcx> { @@ -193,12 +193,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> fn to_op_for_read( &self, _ecx: &InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { Ok(self.into()) } #[inline(always)] - fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self { + fn from_op(op: &OpTy<'tcx, M::Provenance>) -> Self { // assert is justified because our `to_op_for_read` only ever produces `Indirect` operands. op.assert_mem_place() } @@ -223,7 +223,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> } impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M> - for MPlaceTy<'tcx, M::PointerTag> + for MPlaceTy<'tcx, M::Provenance> { #[inline(always)] fn layout(&self) -> TyAndLayout<'tcx> { @@ -234,7 +234,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M> fn to_op_for_read( &self, _ecx: &InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { Ok(self.into()) } @@ -242,12 +242,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M> fn to_op_for_proj( &self, _ecx: &mut InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { Ok(self.into()) } #[inline(always)] - fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self { + fn from_op(op: &OpTy<'tcx, M::Provenance>) -> Self { // assert is justified because our `to_op_for_proj` only ever produces `Indirect` operands. op.assert_mem_place() } @@ -272,7 +272,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M> } impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M> - for PlaceTy<'tcx, M::PointerTag> + for PlaceTy<'tcx, M::Provenance> { #[inline(always)] fn layout(&self) -> TyAndLayout<'tcx> { @@ -283,7 +283,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M> fn to_op_for_read( &self, ecx: &InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { // We `force_allocation` here so that `from_op` below can work. ecx.place_to_op(self) } @@ -292,13 +292,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M> fn to_op_for_proj( &self, ecx: &mut InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { // We `force_allocation` here so that `from_op` below can work. Ok(ecx.force_allocation(self)?.into()) } #[inline(always)] - fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self { + fn from_op(op: &OpTy<'tcx, M::Provenance>) -> Self { // assert is justified because our `to_op` only ever produces `Indirect` operands. op.assert_mem_place().into() } @@ -336,7 +336,7 @@ macro_rules! make_value_visitor { #[inline(always)] fn read_discriminant( &mut self, - op: &OpTy<'tcx, M::PointerTag>, + op: &OpTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, VariantIdx> { Ok(self.ecx().read_discriminant(op)?.1) } @@ -425,7 +425,7 @@ macro_rules! make_value_visitor { // unsized values are never immediate, so we can assert_mem_place let op = v.to_op_for_read(self.ecx())?; let dest = op.assert_mem_place(); - let inner_mplace = self.ecx().unpack_dyn_trait(&dest)?.1; + let inner_mplace = self.ecx().unpack_dyn_trait(&dest)?; trace!("walk_value: dyn object layout: {:#?}", inner_mplace.layout); // recurse with the inner type return self.visit_field(&v, 0, &$value_trait::from_op(&inner_mplace.into())); @@ -473,6 +473,9 @@ macro_rules! make_value_visitor { // The second `Box` field is the allocator, which we recursively check for validity // like in regular structs. self.visit_field(v, 1, &alloc)?; + + // We visited all parts of this one. + return Ok(()); } _ => {}, }; 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 0581f491978..628298df473 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -652,7 +652,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { ProjectionElem::ConstantIndex { .. } | ProjectionElem::Downcast(..) - | ProjectionElem::OpaqueCast(..) | ProjectionElem::Subslice { .. } | ProjectionElem::Field(..) | ProjectionElem::Index(_) => {} 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 c2b4f6eca5c..29464cf8c4e 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -316,7 +316,6 @@ where ProjectionElem::Deref | ProjectionElem::Field(_, _) - | ProjectionElem::OpaqueCast(_) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } | ProjectionElem::Downcast(_, _) diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index daa154576ae..ed4d8c95d1e 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -361,7 +361,7 @@ impl<'tcx> Validator<'_, 'tcx> { return Err(Unpromotable); } } - ProjectionElem::OpaqueCast(..) | ProjectionElem::Downcast(..) => { + ProjectionElem::Downcast(..) => { return Err(Unpromotable); } diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 0a2d2b40709..265f45b72d1 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -61,12 +61,10 @@ pub mod sip128; pub mod small_c_str; pub mod small_str; pub mod snapshot_map; -pub mod stable_map; pub mod svh; pub use ena::snapshot_vec; pub mod memmap; pub mod sorted_map; -pub mod stable_set; #[macro_use] pub mod stable_hasher; mod atomic_ref; diff --git a/compiler/rustc_data_structures/src/stable_map.rs b/compiler/rustc_data_structures/src/stable_map.rs deleted file mode 100644 index 670452d0d8c..00000000000 --- a/compiler/rustc_data_structures/src/stable_map.rs +++ /dev/null @@ -1,100 +0,0 @@ -pub use rustc_hash::FxHashMap; -use std::borrow::Borrow; -use std::collections::hash_map::Entry; -use std::fmt; -use std::hash::Hash; - -/// A deterministic wrapper around FxHashMap that does not provide iteration support. -/// -/// It supports insert, remove, get and get_mut functions from FxHashMap. -/// It also allows to convert hashmap to a sorted vector with the method `into_sorted_vector()`. -#[derive(Clone)] -pub struct StableMap<K, V> { - base: FxHashMap<K, V>, -} - -impl<K, V> Default for StableMap<K, V> -where - K: Eq + Hash, -{ - fn default() -> StableMap<K, V> { - StableMap::new() - } -} - -impl<K, V> fmt::Debug for StableMap<K, V> -where - K: Eq + Hash + fmt::Debug, - V: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self.base) - } -} - -impl<K, V> PartialEq for StableMap<K, V> -where - K: Eq + Hash, - V: PartialEq, -{ - fn eq(&self, other: &StableMap<K, V>) -> bool { - self.base == other.base - } -} - -impl<K, V> Eq for StableMap<K, V> -where - K: Eq + Hash, - V: Eq, -{ -} - -impl<K, V> StableMap<K, V> -where - K: Eq + Hash, -{ - pub fn new() -> StableMap<K, V> { - StableMap { base: FxHashMap::default() } - } - - pub fn into_sorted_vector(self) -> Vec<(K, V)> - where - K: Ord + Copy, - { - let mut vector = self.base.into_iter().collect::<Vec<_>>(); - vector.sort_unstable_by_key(|pair| pair.0); - vector - } - - pub fn entry(&mut self, k: K) -> Entry<'_, K, V> { - self.base.entry(k) - } - - pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V> - where - K: Borrow<Q>, - Q: Hash + Eq, - { - self.base.get(k) - } - - pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V> - where - K: Borrow<Q>, - Q: Hash + Eq, - { - self.base.get_mut(k) - } - - pub fn insert(&mut self, k: K, v: V) -> Option<V> { - self.base.insert(k, v) - } - - pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V> - where - K: Borrow<Q>, - Q: Hash + Eq, - { - self.base.remove(k) - } -} diff --git a/compiler/rustc_data_structures/src/stable_set.rs b/compiler/rustc_data_structures/src/stable_set.rs deleted file mode 100644 index c7ca74f5fbd..00000000000 --- a/compiler/rustc_data_structures/src/stable_set.rs +++ /dev/null @@ -1,77 +0,0 @@ -pub use rustc_hash::FxHashSet; -use std::borrow::Borrow; -use std::fmt; -use std::hash::Hash; - -/// A deterministic wrapper around FxHashSet that does not provide iteration support. -/// -/// It supports insert, remove, get functions from FxHashSet. -/// It also allows to convert hashset to a sorted vector with the method `into_sorted_vector()`. -#[derive(Clone)] -pub struct StableSet<T> { - base: FxHashSet<T>, -} - -impl<T> Default for StableSet<T> -where - T: Eq + Hash, -{ - fn default() -> StableSet<T> { - StableSet::new() - } -} - -impl<T> fmt::Debug for StableSet<T> -where - T: Eq + Hash + fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self.base) - } -} - -impl<T> PartialEq<StableSet<T>> for StableSet<T> -where - T: Eq + Hash, -{ - fn eq(&self, other: &StableSet<T>) -> bool { - self.base == other.base - } -} - -impl<T> Eq for StableSet<T> where T: Eq + Hash {} - -impl<T: Hash + Eq> StableSet<T> { - pub fn new() -> StableSet<T> { - StableSet { base: FxHashSet::default() } - } - - pub fn into_sorted_vector(self) -> Vec<T> - where - T: Ord, - { - let mut vector = self.base.into_iter().collect::<Vec<_>>(); - vector.sort_unstable(); - vector - } - - pub fn get<Q: ?Sized>(&self, value: &Q) -> Option<&T> - where - T: Borrow<Q>, - Q: Hash + Eq, - { - self.base.get(value) - } - - pub fn insert(&mut self, value: T) -> bool { - self.base.insert(value) - } - - pub fn remove<Q: ?Sized>(&mut self, value: &Q) -> bool - where - T: Borrow<Q>, - Q: Hash + Eq, - { - self.base.remove(value) - } -} diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index cf0940df9e4..52952a7932d 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -146,7 +146,7 @@ cfg_if! { t.into_iter() } - pub fn par_for_each_in<T: IntoIterator>(t: T, for_each: impl Fn(T::Item) + Sync + Send) { + pub fn par_for_each_in<T: IntoIterator>(t: T, mut for_each: impl FnMut(T::Item) + Sync + Send) { // We catch panics here ensuring that all the loop iterations execute. // This makes behavior consistent with the parallel compiler. let mut panic = None; diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 977318b8589..854625579ee 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -492,6 +492,7 @@ E0785: include_str!("./error_codes/E0785.md"), E0786: include_str!("./error_codes/E0786.md"), E0787: include_str!("./error_codes/E0787.md"), E0788: include_str!("./error_codes/E0788.md"), +E0790: include_str!("./error_codes/E0790.md"), ; // E0006, // merged with E0005 // E0008, // cannot bind by-move into a pattern guard @@ -558,7 +559,7 @@ E0788: include_str!("./error_codes/E0788.md"), // E0273, // on_unimplemented #1 // E0274, // on_unimplemented #2 // E0278, // requirement is not satisfied - E0279, // requirement is not satisfied +// E0279, E0280, // requirement is not satisfied // E0285, // overflow evaluation builtin bounds // E0296, // replaced with a generic attribute input check diff --git a/compiler/rustc_error_codes/src/error_codes/E0118.md b/compiler/rustc_error_codes/src/error_codes/E0118.md index 8033aa8384c..cfabae1a634 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0118.md +++ b/compiler/rustc_error_codes/src/error_codes/E0118.md @@ -4,7 +4,7 @@ enum, union, or trait object. Erroneous code example: ```compile_fail,E0118 -impl fn(u8) { // error: no nominal type found for inherent implementation +impl<T> T { // error: no nominal type found for inherent implementation fn get_state(&self) -> String { // ... } @@ -20,8 +20,8 @@ trait LiveLongAndProsper { fn get_state(&self) -> String; } -// and now you can implement it on fn(u8) -impl LiveLongAndProsper for fn(u8) { +// and now you can implement it on T +impl<T> LiveLongAndProsper for T { fn get_state(&self) -> String { "He's dead, Jim!".to_owned() } @@ -33,9 +33,9 @@ For example, `NewType` is a newtype over `Foo` in `struct NewType(Foo)`. Example: ``` -struct TypeWrapper(fn(u8)); +struct TypeWrapper<T>(T); -impl TypeWrapper { +impl<T> TypeWrapper<T> { fn get_state(&self) -> String { "Fascinating!".to_owned() } diff --git a/compiler/rustc_error_codes/src/error_codes/E0283.md b/compiler/rustc_error_codes/src/error_codes/E0283.md index 6885f9a486d..79d2c8204f9 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0283.md +++ b/compiler/rustc_error_codes/src/error_codes/E0283.md @@ -3,48 +3,27 @@ An implementation cannot be chosen unambiguously because of lack of information. Erroneous code example: ```compile_fail,E0283 -trait Generator { - fn create() -> u32; -} - -struct Impl; - -impl Generator for Impl { - fn create() -> u32 { 1 } -} - -struct AnotherImpl; +struct Foo; -impl Generator for AnotherImpl { - fn create() -> u32 { 2 } +impl Into<u32> for Foo { + fn into(self) -> u32 { 1 } } -fn main() { - let cont: u32 = Generator::create(); - // error, impossible to choose one of Generator trait implementation - // Should it be Impl or AnotherImpl, maybe something else? -} +let foo = Foo; +let bar: u32 = foo.into() * 1u32; ``` This error can be solved by adding type annotations that provide the missing -information to the compiler. In this case, the solution is to use a concrete -type: +information to the compiler. In this case, the solution is to specify the +trait's type parameter: ``` -trait Generator { - fn create() -> u32; -} - -struct AnotherImpl; +struct Foo; -impl Generator for AnotherImpl { - fn create() -> u32 { 2 } +impl Into<u32> for Foo { + fn into(self) -> u32 { 1 } } -fn main() { - let gen1 = AnotherImpl::create(); - - // if there are multiple methods with same name (different traits) - let gen2 = <AnotherImpl as Generator>::create(); -} +let foo = Foo; +let bar: u32 = Into::<u32>::into(foo) * 1u32; ``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0790.md b/compiler/rustc_error_codes/src/error_codes/E0790.md new file mode 100644 index 00000000000..2aee9dfbdbd --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0790.md @@ -0,0 +1,47 @@ +You need to specify a specific implementation of the trait in order to call the +method. + +Erroneous code example: + +```compile_fail,E0790 +trait Generator { + fn create() -> u32; +} + +struct Impl; + +impl Generator for Impl { + fn create() -> u32 { 1 } +} + +struct AnotherImpl; + +impl Generator for AnotherImpl { + fn create() -> u32 { 2 } +} + +let cont: u32 = Generator::create(); +// error, impossible to choose one of Generator trait implementation +// Should it be Impl or AnotherImpl, maybe something else? +``` + +This error can be solved by adding type annotations that provide the missing +information to the compiler. In this case, the solution is to use a concrete +type: + +``` +trait Generator { + fn create() -> u32; +} + +struct AnotherImpl; + +impl Generator for AnotherImpl { + fn create() -> u32 { 2 } +} + +let gen1 = AnotherImpl::create(); + +// if there are multiple methods with same name (different traits) +let gen2 = <AnotherImpl as Generator>::create(); +``` diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index e7e07093c03..55e96e58e46 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -247,11 +247,6 @@ lint-atomic-ordering-invalid = `{$method}`'s failure ordering may not be `Releas .label = invalid failure ordering .help = consider using `Acquire` or `Relaxed` failure ordering instead -lint-atomic-ordering-invalid-fail-success = `{$method}`'s success ordering must be at least as strong as its failure ordering - .fail-label = `{$fail_ordering}` failure ordering - .success-label = `{$success_ordering}` success ordering - .suggestion = consider using `{$success_suggestion}` success ordering instead - lint-unused-op = unused {$op} that must be used .label = the {$op} produces a value .suggestion = use `let _ = ...` to ignore the resulting value diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index e4c9a4dad7b..04c67cf8ff7 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -81,8 +81,8 @@ passes-doc-keyword-not-mod = `#[doc(keyword = "...")]` should be used on modules passes-doc-keyword-invalid-ident = `{$doc_keyword}` is not a valid identifier -passes-doc-tuple-variadic-not-first = - `#[doc(tuple_variadic)]` must be used on the first of a set of tuple trait impls with varying arity +passes-doc-fake-variadic-not-valid = + `#[doc(fake_variadic)]` must be used on the first of a set of tuple or fn pointer trait impls with varying arity passes-doc-keyword-only-impl = `#[doc(keyword = "...")]` should be used on impl blocks diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 6b961eaeb42..2ac5c1960cd 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -299,7 +299,7 @@ impl DiagnosticMessage { /// - If `self` is non-translatable then return `self`'s message. pub fn with_subdiagnostic_message(&self, sub: SubdiagnosticMessage) -> Self { let attr = match sub { - SubdiagnosticMessage::Str(s) => return DiagnosticMessage::Str(s.clone()), + SubdiagnosticMessage::Str(s) => return DiagnosticMessage::Str(s), SubdiagnosticMessage::FluentIdentifier(id) => { return DiagnosticMessage::FluentIdentifier(id, None); } diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 7d7f3e18335..2a4f609a2d8 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -3,7 +3,7 @@ use crate::{ CodeSuggestion, DiagnosticMessage, EmissionGuarantee, Level, LintDiagnosticBuilder, MultiSpan, SubdiagnosticMessage, Substitution, SubstitutionPart, SuggestionStyle, }; -use rustc_data_structures::stable_map::FxHashMap; +use rustc_data_structures::fx::FxHashMap; use rustc_error_messages::FluentValue; use rustc_hir as hir; use rustc_lint_defs::{Applicability, LintExpectationId}; @@ -390,18 +390,17 @@ impl Diagnostic { expected: DiagnosticStyledString, found: DiagnosticStyledString, ) -> &mut Self { - let mut msg: Vec<_> = - vec![("required when trying to coerce from type `".to_string(), Style::NoStyle)]; + let mut msg: Vec<_> = vec![("required when trying to coerce from type `", Style::NoStyle)]; msg.extend(expected.0.iter().map(|x| match *x { - StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle), - StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight), + StringPart::Normal(ref s) => (s.as_str(), Style::NoStyle), + StringPart::Highlighted(ref s) => (s.as_str(), Style::Highlight), })); - msg.push(("` to type '".to_string(), Style::NoStyle)); + msg.push(("` to type '", Style::NoStyle)); msg.extend(found.0.iter().map(|x| match *x { - StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle), - StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight), + StringPart::Normal(ref s) => (s.as_str(), Style::NoStyle), + StringPart::Highlighted(ref s) => (s.as_str(), Style::Highlight), })); - msg.push(("`".to_string(), Style::NoStyle)); + msg.push(("`", Style::NoStyle)); // For now, just attach these as notes self.highlighted_note(msg); diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 85ea8eb3937..61d953cd6f1 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -399,11 +399,11 @@ pub trait Emitter { ) { // Check for spans in macros, before `fix_multispans_in_extern_macros` // has a chance to replace them. - let has_macro_spans = iter::once(&*span) + let has_macro_spans: Vec<_> = iter::once(&*span) .chain(children.iter().map(|child| &child.span)) .flat_map(|span| span.primary_spans()) .flat_map(|sp| sp.macro_backtrace()) - .find_map(|expn_data| { + .filter_map(|expn_data| { match expn_data.kind { ExpnKind::Root => None, @@ -413,7 +413,8 @@ pub trait Emitter { ExpnKind::Macro(macro_kind, name) => Some((macro_kind, name)), } - }); + }) + .collect(); if !backtrace { self.fix_multispans_in_extern_macros(source_map, span, children); @@ -422,11 +423,22 @@ pub trait Emitter { self.render_multispans_macro_backtrace(span, children, backtrace); if !backtrace { - if let Some((macro_kind, name)) = has_macro_spans { - let descr = macro_kind.descr(); + if let Some((macro_kind, name)) = has_macro_spans.first() { + // Mark the actual macro this originates from + let and_then = if let Some((macro_kind, last_name)) = has_macro_spans.last() + && last_name != name + { + let descr = macro_kind.descr(); + format!( + " which comes from the expansion of the {descr} `{last_name}`", + ) + } else { + "".to_string() + }; + let descr = macro_kind.descr(); let msg = format!( - "this {level} originates in the {descr} `{name}` \ + "this {level} originates in the {descr} `{name}`{and_then} \ (in Nightly builds, run with -Z macro-backtrace for more info)", ); diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index e59a74e380a..b173ac0e916 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -6,6 +6,7 @@ #![feature(drain_filter)] #![feature(backtrace)] #![feature(if_let_guard)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(let_else)] #![feature(never_type)] #![feature(adt_const_params)] diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index d4b8563a036..707cb73f097 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -234,6 +234,8 @@ fn parse_tree( sess, &Token { kind: token::Dollar, span }, ); + } else { + maybe_emit_macro_metavar_expr_feature(features, sess, span); } TokenTree::token(token::Dollar, span) } diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index fdd8dc93fc1..3037855ae28 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -512,7 +512,18 @@ fn out_of_bounds_err<'a>( span: Span, ty: &str, ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { - cx.struct_span_err(span, &format!("{ty} depth must be less than {max}")) + let msg = if max == 0 { + format!( + "meta-variable expression `{ty}` with depth parameter \ + must be called inside of a macro repetition" + ) + } else { + format!( + "depth parameter on meta-variable expression `{ty}` \ + must be less than {max}" + ) + }; + cx.struct_span_err(span, &msg) } fn transcribe_metavar_expr<'a>( diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 411d6be9c44..176c77ca6ed 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -11,13 +11,14 @@ use rustc_parse::lexer::nfc_normalize; use rustc_parse::parse_stream_from_source_str; use rustc_session::parse::ParseSess; use rustc_span::def_id::CrateNum; -use rustc_span::symbol::{self, kw, sym, Symbol}; +use rustc_span::symbol::{self, sym, Symbol}; use rustc_span::{BytePos, FileName, Pos, SourceFile, Span}; -use pm::bridge::{server, DelimSpan, ExpnGlobals, Group, Punct, TokenTree}; +use pm::bridge::{ + server, DelimSpan, ExpnGlobals, Group, Ident, LitKind, Literal, Punct, TokenTree, +}; use pm::{Delimiter, Level, LineColumn}; use std::ops::Bound; -use std::{ascii, panic}; trait FromInternal<T> { fn from_internal(x: T) -> Self; @@ -49,9 +50,40 @@ impl ToInternal<token::Delimiter> for Delimiter { } } -impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> - for Vec<TokenTree<TokenStream, Span, Ident, Literal>> -{ +impl FromInternal<token::LitKind> for LitKind { + fn from_internal(kind: token::LitKind) -> Self { + match kind { + token::Byte => LitKind::Byte, + token::Char => LitKind::Char, + token::Integer => LitKind::Integer, + token::Float => LitKind::Float, + token::Str => LitKind::Str, + token::StrRaw(n) => LitKind::StrRaw(n), + token::ByteStr => LitKind::ByteStr, + token::ByteStrRaw(n) => LitKind::ByteStrRaw(n), + token::Err => LitKind::Err, + token::Bool => unreachable!(), + } + } +} + +impl ToInternal<token::LitKind> for LitKind { + fn to_internal(self) -> token::LitKind { + match self { + LitKind::Byte => token::Byte, + LitKind::Char => token::Char, + LitKind::Integer => token::Integer, + LitKind::Float => token::Float, + LitKind::Str => token::Str, + LitKind::StrRaw(n) => token::StrRaw(n), + LitKind::ByteStr => token::ByteStr, + LitKind::ByteStrRaw(n) => token::ByteStrRaw(n), + LitKind::Err => token::Err, + } + } +} + +impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStream, Span, Symbol>> { fn from_internal((stream, rustc): (TokenStream, &mut Rustc<'_, '_>)) -> Self { use rustc_ast::token::*; @@ -135,16 +167,22 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> Question => op("?"), SingleQuote => op("'"), - Ident(name, false) if name == kw::DollarCrate => trees.push(TokenTree::Ident(Ident::dollar_crate(span))), - Ident(name, is_raw) => trees.push(TokenTree::Ident(Ident::new(rustc.sess(), name, is_raw, span))), + Ident(sym, is_raw) => trees.push(TokenTree::Ident(Ident { sym, is_raw, span })), Lifetime(name) => { let ident = symbol::Ident::new(name, span).without_first_quote(); trees.extend([ TokenTree::Punct(Punct { ch: b'\'', joint: true, span }), - TokenTree::Ident(Ident::new(rustc.sess(), ident.name, false, span)), + TokenTree::Ident(Ident { sym: ident.name, is_raw: false, span }), ]); } - Literal(lit) => trees.push(TokenTree::Literal(self::Literal { lit, span })), + Literal(token::Lit { kind, symbol, suffix }) => { + trees.push(TokenTree::Literal(self::Literal { + kind: FromInternal::from_internal(kind), + symbol, + suffix, + span, + })); + } DocComment(_, attr_style, data) => { let mut escaped = String::new(); for ch in data.as_str().chars() { @@ -170,7 +208,7 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> } Interpolated(nt) if let NtIdent(ident, is_raw) = *nt => { - trees.push(TokenTree::Ident(Ident::new(rustc.sess(), ident.name, is_raw, ident.span))) + trees.push(TokenTree::Ident(Ident { sym: ident.name, is_raw, span: ident.span })) } Interpolated(nt) => { @@ -200,11 +238,12 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> } } -impl ToInternal<TokenStream> for TokenTree<TokenStream, Span, Ident, Literal> { +impl ToInternal<TokenStream> for (TokenTree<TokenStream, Span, Symbol>, &mut Rustc<'_, '_>) { fn to_internal(self) -> TokenStream { use rustc_ast::token::*; - let (ch, joint, span) = match self { + let (tree, rustc) = self; + let (ch, joint, span) = match tree { TokenTree::Punct(Punct { ch, joint, span }) => (ch, joint, span), TokenTree::Group(Group { delimiter, stream, span: DelimSpan { open, close, .. } }) => { return tokenstream::TokenTree::Delimited( @@ -215,10 +254,13 @@ impl ToInternal<TokenStream> for TokenTree<TokenStream, Span, Ident, Literal> { .into(); } TokenTree::Ident(self::Ident { sym, is_raw, span }) => { + rustc.sess().symbol_gallery.insert(sym, span); return tokenstream::TokenTree::token(Ident(sym, is_raw), span).into(); } TokenTree::Literal(self::Literal { - lit: token::Lit { kind: token::Integer, symbol, suffix }, + kind: self::LitKind::Integer, + symbol, + suffix, span, }) if symbol.as_str().starts_with('-') => { let minus = BinOp(BinOpToken::Minus); @@ -229,7 +271,9 @@ impl ToInternal<TokenStream> for TokenTree<TokenStream, Span, Ident, Literal> { return [a, b].into_iter().collect(); } TokenTree::Literal(self::Literal { - lit: token::Lit { kind: token::Float, symbol, suffix }, + kind: self::LitKind::Float, + symbol, + suffix, span, }) if symbol.as_str().starts_with('-') => { let minus = BinOp(BinOpToken::Minus); @@ -239,8 +283,12 @@ impl ToInternal<TokenStream> for TokenTree<TokenStream, Span, Ident, Literal> { let b = tokenstream::TokenTree::token(float, span); return [a, b].into_iter().collect(); } - TokenTree::Literal(self::Literal { lit, span }) => { - return tokenstream::TokenTree::token(Literal(lit), span).into(); + TokenTree::Literal(self::Literal { kind, symbol, suffix, span }) => { + return tokenstream::TokenTree::token( + TokenKind::lit(kind.to_internal(), symbol, suffix), + span, + ) + .into(); } }; @@ -289,40 +337,6 @@ impl ToInternal<rustc_errors::Level> for Level { pub struct FreeFunctions; -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -pub struct Ident { - sym: Symbol, - is_raw: bool, - span: Span, -} - -impl Ident { - fn new(sess: &ParseSess, sym: Symbol, is_raw: bool, span: Span) -> Ident { - let sym = nfc_normalize(sym.as_str()); - let string = sym.as_str(); - if !rustc_lexer::is_ident(string) { - panic!("`{:?}` is not a valid identifier", string) - } - if is_raw && !sym.can_be_raw() { - panic!("`{}` cannot be a raw identifier", string); - } - sess.symbol_gallery.insert(sym, span); - Ident { sym, is_raw, span } - } - - fn dollar_crate(span: Span) -> Ident { - // `$crate` is accepted as an ident only if it comes from the compiler. - Ident { sym: kw::DollarCrate, is_raw: false, span } - } -} - -// FIXME(eddyb) `Literal` should not expose internal `Debug` impls. -#[derive(Clone, Debug)] -pub struct Literal { - lit: token::Lit, - span: Span, -} - pub(crate) struct Rustc<'a, 'b> { ecx: &'a mut ExtCtxt<'b>, def_site: Span, @@ -348,21 +362,16 @@ impl<'a, 'b> Rustc<'a, 'b> { fn sess(&self) -> &ParseSess { self.ecx.parse_sess() } - - fn lit(&mut self, kind: token::LitKind, symbol: Symbol, suffix: Option<Symbol>) -> Literal { - Literal { lit: token::Lit::new(kind, symbol, suffix), span: self.call_site } - } } impl server::Types for Rustc<'_, '_> { type FreeFunctions = FreeFunctions; type TokenStream = TokenStream; - type Ident = Ident; - type Literal = Literal; type SourceFile = Lrc<SourceFile>; type MultiSpan = Vec<Span>; type Diagnostic = Diagnostic; type Span = Span; + type Symbol = Symbol; } impl server::FreeFunctions for Rustc<'_, '_> { @@ -376,6 +385,57 @@ impl server::FreeFunctions for Rustc<'_, '_> { fn track_path(&mut self, path: &str) { self.sess().file_depinfo.borrow_mut().insert(Symbol::intern(path)); } + + fn literal_from_str(&mut self, s: &str) -> Result<Literal<Self::Span, Self::Symbol>, ()> { + let name = FileName::proc_macro_source_code(s); + let mut parser = rustc_parse::new_parser_from_source_str(self.sess(), name, s.to_owned()); + + let first_span = parser.token.span.data(); + let minus_present = parser.eat(&token::BinOp(token::Minus)); + + let lit_span = parser.token.span.data(); + let token::Literal(mut lit) = parser.token.kind else { + return Err(()); + }; + + // Check no comment or whitespace surrounding the (possibly negative) + // literal, or more tokens after it. + if (lit_span.hi.0 - first_span.lo.0) as usize != s.len() { + return Err(()); + } + + if minus_present { + // If minus is present, check no comment or whitespace in between it + // and the literal token. + if first_span.hi.0 != lit_span.lo.0 { + return Err(()); + } + + // Check literal is a kind we allow to be negated in a proc macro token. + match lit.kind { + token::LitKind::Bool + | token::LitKind::Byte + | token::LitKind::Char + | token::LitKind::Str + | token::LitKind::StrRaw(_) + | token::LitKind::ByteStr + | token::LitKind::ByteStrRaw(_) + | token::LitKind::Err => return Err(()), + token::LitKind::Integer | token::LitKind::Float => {} + } + + // Synthesize a new symbol that includes the minus sign. + let symbol = Symbol::intern(&s[..1 + lit.symbol.as_str().len()]); + lit = token::Lit::new(lit.kind, symbol, lit.suffix); + } + let token::Lit { kind, symbol, suffix } = lit; + Ok(Literal { + kind: FromInternal::from_internal(kind), + symbol, + suffix, + span: self.call_site, + }) + } } impl server::TokenStream for Rustc<'_, '_> { @@ -453,22 +513,22 @@ impl server::TokenStream for Rustc<'_, '_> { fn from_token_tree( &mut self, - tree: TokenTree<Self::TokenStream, Self::Span, Self::Ident, Self::Literal>, + tree: TokenTree<Self::TokenStream, Self::Span, Self::Symbol>, ) -> Self::TokenStream { - tree.to_internal() + (tree, &mut *self).to_internal() } fn concat_trees( &mut self, base: Option<Self::TokenStream>, - trees: Vec<TokenTree<Self::TokenStream, Self::Span, Self::Ident, Self::Literal>>, + trees: Vec<TokenTree<Self::TokenStream, Self::Span, Self::Symbol>>, ) -> Self::TokenStream { let mut builder = tokenstream::TokenStreamBuilder::new(); if let Some(base) = base { builder.push(base); } for tree in trees { - builder.push(tree.to_internal()); + builder.push((tree, &mut *self).to_internal()); } builder.build() } @@ -491,178 +551,11 @@ impl server::TokenStream for Rustc<'_, '_> { fn into_trees( &mut self, stream: Self::TokenStream, - ) -> Vec<TokenTree<Self::TokenStream, Self::Span, Self::Ident, Self::Literal>> { + ) -> Vec<TokenTree<Self::TokenStream, Self::Span, Self::Symbol>> { FromInternal::from_internal((stream, self)) } } -impl server::Ident for Rustc<'_, '_> { - fn new(&mut self, string: &str, span: Self::Span, is_raw: bool) -> Self::Ident { - Ident::new(self.sess(), Symbol::intern(string), is_raw, span) - } - - fn span(&mut self, ident: Self::Ident) -> Self::Span { - ident.span - } - - fn with_span(&mut self, ident: Self::Ident, span: Self::Span) -> Self::Ident { - Ident { span, ..ident } - } -} - -impl server::Literal for Rustc<'_, '_> { - fn from_str(&mut self, s: &str) -> Result<Self::Literal, ()> { - let name = FileName::proc_macro_source_code(s); - let mut parser = rustc_parse::new_parser_from_source_str(self.sess(), name, s.to_owned()); - - let first_span = parser.token.span.data(); - let minus_present = parser.eat(&token::BinOp(token::Minus)); - - let lit_span = parser.token.span.data(); - let token::Literal(mut lit) = parser.token.kind else { - return Err(()); - }; - - // Check no comment or whitespace surrounding the (possibly negative) - // literal, or more tokens after it. - if (lit_span.hi.0 - first_span.lo.0) as usize != s.len() { - return Err(()); - } - - if minus_present { - // If minus is present, check no comment or whitespace in between it - // and the literal token. - if first_span.hi.0 != lit_span.lo.0 { - return Err(()); - } - - // Check literal is a kind we allow to be negated in a proc macro token. - match lit.kind { - token::LitKind::Bool - | token::LitKind::Byte - | token::LitKind::Char - | token::LitKind::Str - | token::LitKind::StrRaw(_) - | token::LitKind::ByteStr - | token::LitKind::ByteStrRaw(_) - | token::LitKind::Err => return Err(()), - token::LitKind::Integer | token::LitKind::Float => {} - } - - // Synthesize a new symbol that includes the minus sign. - let symbol = Symbol::intern(&s[..1 + lit.symbol.as_str().len()]); - lit = token::Lit::new(lit.kind, symbol, lit.suffix); - } - - Ok(Literal { lit, span: self.call_site }) - } - - fn to_string(&mut self, literal: &Self::Literal) -> String { - literal.lit.to_string() - } - - fn debug_kind(&mut self, literal: &Self::Literal) -> String { - format!("{:?}", literal.lit.kind) - } - - fn symbol(&mut self, literal: &Self::Literal) -> String { - literal.lit.symbol.to_string() - } - - fn suffix(&mut self, literal: &Self::Literal) -> Option<String> { - literal.lit.suffix.as_ref().map(Symbol::to_string) - } - - fn integer(&mut self, n: &str) -> Self::Literal { - self.lit(token::Integer, Symbol::intern(n), None) - } - - fn typed_integer(&mut self, n: &str, kind: &str) -> Self::Literal { - self.lit(token::Integer, Symbol::intern(n), Some(Symbol::intern(kind))) - } - - fn float(&mut self, n: &str) -> Self::Literal { - self.lit(token::Float, Symbol::intern(n), None) - } - - fn f32(&mut self, n: &str) -> Self::Literal { - self.lit(token::Float, Symbol::intern(n), Some(sym::f32)) - } - - fn f64(&mut self, n: &str) -> Self::Literal { - self.lit(token::Float, Symbol::intern(n), Some(sym::f64)) - } - - fn string(&mut self, string: &str) -> Self::Literal { - let quoted = format!("{:?}", string); - assert!(quoted.starts_with('"') && quoted.ends_with('"')); - let symbol = "ed[1..quoted.len() - 1]; - self.lit(token::Str, Symbol::intern(symbol), None) - } - - fn character(&mut self, ch: char) -> Self::Literal { - let quoted = format!("{:?}", ch); - assert!(quoted.starts_with('\'') && quoted.ends_with('\'')); - let symbol = "ed[1..quoted.len() - 1]; - self.lit(token::Char, Symbol::intern(symbol), None) - } - - fn byte_string(&mut self, bytes: &[u8]) -> Self::Literal { - let string = bytes - .iter() - .cloned() - .flat_map(ascii::escape_default) - .map(Into::<char>::into) - .collect::<String>(); - self.lit(token::ByteStr, Symbol::intern(&string), None) - } - - fn span(&mut self, literal: &Self::Literal) -> Self::Span { - literal.span - } - - fn set_span(&mut self, literal: &mut Self::Literal, span: Self::Span) { - literal.span = span; - } - - fn subspan( - &mut self, - literal: &Self::Literal, - start: Bound<usize>, - end: Bound<usize>, - ) -> Option<Self::Span> { - let span = literal.span; - let length = span.hi().to_usize() - span.lo().to_usize(); - - let start = match start { - Bound::Included(lo) => lo, - Bound::Excluded(lo) => lo.checked_add(1)?, - Bound::Unbounded => 0, - }; - - let end = match end { - Bound::Included(hi) => hi.checked_add(1)?, - Bound::Excluded(hi) => hi, - Bound::Unbounded => length, - }; - - // Bounds check the values, preventing addition overflow and OOB spans. - if start > u32::MAX as usize - || end > u32::MAX as usize - || (u32::MAX - start as u32) < span.lo().to_u32() - || (u32::MAX - end as u32) < span.lo().to_u32() - || start >= end - || end > length - { - return None; - } - - let new_lo = span.lo() + BytePos::from_usize(start); - let new_hi = span.lo() + BytePos::from_usize(end); - Some(span.with_lo(new_lo).with_hi(new_hi)) - } -} - impl server::SourceFile for Rustc<'_, '_> { fn eq(&mut self, file1: &Self::SourceFile, file2: &Self::SourceFile) -> bool { Lrc::ptr_eq(file1, file2) @@ -767,6 +660,42 @@ impl server::Span for Rustc<'_, '_> { Some(first.to(second)) } + fn subspan( + &mut self, + span: Self::Span, + start: Bound<usize>, + end: Bound<usize>, + ) -> Option<Self::Span> { + let length = span.hi().to_usize() - span.lo().to_usize(); + + let start = match start { + Bound::Included(lo) => lo, + Bound::Excluded(lo) => lo.checked_add(1)?, + Bound::Unbounded => 0, + }; + + let end = match end { + Bound::Included(hi) => hi.checked_add(1)?, + Bound::Excluded(hi) => hi, + Bound::Unbounded => length, + }; + + // Bounds check the values, preventing addition overflow and OOB spans. + if start > u32::MAX as usize + || end > u32::MAX as usize + || (u32::MAX - start as u32) < span.lo().to_u32() + || (u32::MAX - end as u32) < span.lo().to_u32() + || start >= end + || end > length + { + return None; + } + + let new_lo = span.lo() + BytePos::from_usize(start); + let new_hi = span.lo() + BytePos::from_usize(end); + Some(span.with_lo(new_lo).with_hi(new_hi)) + } + fn resolved_at(&mut self, span: Self::Span, at: Self::Span) -> Self::Span { span.with_ctxt(at.ctxt()) } @@ -812,6 +741,13 @@ impl server::Span for Rustc<'_, '_> { } } +impl server::Symbol for Rustc<'_, '_> { + fn normalize_and_validate_ident(&mut self, string: &str) -> Result<Self::Symbol, ()> { + let sym = nfc_normalize(string); + if rustc_lexer::is_ident(sym.as_str()) { Ok(sym) } else { Err(()) } + } +} + impl server::Server for Rustc<'_, '_> { fn globals(&mut self) -> ExpnGlobals<Self::Span> { ExpnGlobals { @@ -820,4 +756,12 @@ impl server::Server for Rustc<'_, '_> { mixed_site: self.mixed_site, } } + + fn intern_symbol(string: &str) -> Self::Symbol { + Symbol::intern(string) + } + + fn with_symbol_string(symbol: &Self::Symbol, f: impl FnOnce(&str)) { + f(&symbol.as_str()) + } } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 48a41c8bd24..18ffc227fed 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -954,6 +954,16 @@ pub struct Block<'hir> { pub targeted_by_break: bool, } +impl<'hir> Block<'hir> { + pub fn innermost_block(&self) -> &Block<'hir> { + let mut block = self; + while let Some(Expr { kind: ExprKind::Block(inner_block, _), .. }) = block.expr { + block = inner_block; + } + block + } +} + #[derive(Debug, HashStable_Generic)] pub struct Pat<'hir> { #[stable_hasher(ignore)] diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index b0bfac8e1f5..13b3e954e1f 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -11,7 +11,7 @@ use crate::def_id::DefId; use crate::{MethodKind, Target}; use rustc_ast as ast; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_macros::HashStable_Generic; use rustc_span::symbol::{kw, sym, Symbol}; @@ -134,8 +134,8 @@ macro_rules! language_item_table { } /// A mapping from the name of the lang item to its order and the form it must be of. - pub static ITEM_REFS: LazyLock<FxHashMap<Symbol, (usize, Target)>> = LazyLock::new(|| { - let mut item_refs = FxHashMap::default(); + pub static ITEM_REFS: LazyLock<FxIndexMap<Symbol, (usize, Target)>> = LazyLock::new(|| { + let mut item_refs = FxIndexMap::default(); $( item_refs.insert($module::$name, (LangItem::$variant as usize, $target)); )* item_refs }); diff --git a/compiler/rustc_hir/src/pat_util.rs b/compiler/rustc_hir/src/pat_util.rs index b30076100bb..93112199b60 100644 --- a/compiler/rustc_hir/src/pat_util.rs +++ b/compiler/rustc_hir/src/pat_util.rs @@ -1,7 +1,7 @@ use crate::def::{CtorOf, DefKind, Res}; use crate::def_id::DefId; use crate::hir::{self, HirId, PatKind}; -use rustc_data_structures::stable_set::FxHashSet; +use rustc_data_structures::fx::FxHashSet; use rustc_span::hygiene::DesugaringKind; use rustc_span::symbol::Ident; use rustc_span::Span; diff --git a/compiler/rustc_hir/src/weak_lang_items.rs b/compiler/rustc_hir/src/weak_lang_items.rs index dad22725511..b6a85c0472e 100644 --- a/compiler/rustc_hir/src/weak_lang_items.rs +++ b/compiler/rustc_hir/src/weak_lang_items.rs @@ -4,7 +4,7 @@ use crate::def_id::DefId; use crate::{lang_items, LangItem, LanguageItems}; use rustc_ast as ast; -use rustc_data_structures::stable_map::StableMap; +use rustc_data_structures::fx::FxIndexMap; use rustc_span::symbol::{sym, Symbol}; use std::sync::LazyLock; @@ -12,8 +12,8 @@ use std::sync::LazyLock; macro_rules! weak_lang_items { ($($name:ident, $item:ident, $sym:ident;)*) => ( -pub static WEAK_ITEMS_REFS: LazyLock<StableMap<Symbol, LangItem>> = LazyLock::new(|| { - let mut map = StableMap::default(); +pub static WEAK_ITEMS_REFS: LazyLock<FxIndexMap<Symbol, LangItem>> = LazyLock::new(|| { + let mut map = FxIndexMap::default(); $(map.insert(sym::$name, LangItem::$item);)* map }); diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 18b671d410d..e0179bd3ed1 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -211,6 +211,10 @@ pub fn path_to_string(segment: &hir::Path<'_>) -> String { to_string(NO_ANN, |s| s.print_path(segment, false)) } +pub fn qpath_to_string(segment: &hir::QPath<'_>) -> String { + to_string(NO_ANN, |s| s.print_qpath(segment, false)) +} + pub fn fn_to_string( decl: &hir::FnDecl<'_>, header: hir::FnHeader, diff --git a/compiler/rustc_incremental/src/assert_module_sources.rs b/compiler/rustc_incremental/src/assert_module_sources.rs index 00aefac645f..89d419bc8e9 100644 --- a/compiler/rustc_incremental/src/assert_module_sources.rs +++ b/compiler/rustc_incremental/src/assert_module_sources.rs @@ -23,7 +23,7 @@ //! was re-used. use rustc_ast as ast; -use rustc_data_structures::stable_set::FxHashSet; +use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::mir::mono::CodegenUnitNameBuilder; use rustc_middle::ty::TyCtxt; diff --git a/compiler/rustc_incremental/src/persist/work_product.rs b/compiler/rustc_incremental/src/persist/work_product.rs index 1b184eca964..2f1853c441e 100644 --- a/compiler/rustc_incremental/src/persist/work_product.rs +++ b/compiler/rustc_incremental/src/persist/work_product.rs @@ -3,7 +3,7 @@ //! [work products]: WorkProduct use crate::persist::fs::*; -use rustc_data_structures::stable_map::FxHashMap; +use rustc_data_structures::fx::FxHashMap; use rustc_fs_util::link_or_copy; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_session::Session; diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 1a55519d7b1..30ff364210d 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -234,7 +234,9 @@ impl<I: Idx, T> IndexVec<I, T> { self.raw.get_mut(index.index()) } - /// Returns mutable references to two distinct elements, a and b. Panics if a == b. + /// Returns mutable references to two distinct elements, `a` and `b`. + /// + /// Panics if `a == b`. #[inline] pub fn pick2_mut(&mut self, a: I, b: I) -> (&mut T, &mut T) { let (ai, bi) = (a.index(), b.index()); @@ -249,7 +251,9 @@ impl<I: Idx, T> IndexVec<I, T> { } } - /// Returns mutable references to three distinct elements or panics otherwise. + /// Returns mutable references to three distinct elements. + /// + /// Panics if the elements are not distinct. #[inline] pub fn pick3_mut(&mut self, a: I, b: I, c: I) -> (&mut T, &mut T, &mut T) { let (ai, bi, ci) = (a.index(), b.index(), c.index()); diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index ce2698ef44c..130214a653f 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -65,6 +65,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { Self { tcx: self.tcx, defining_use_anchor: self.defining_use_anchor, + considering_regions: self.considering_regions, in_progress_typeck_results: self.in_progress_typeck_results, inner: self.inner.clone(), skip_leak_check: self.skip_leak_check.clone(), diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 1e8b212276f..8dc20544f1b 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -153,7 +153,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { .opaque_type_storage .take_opaque_types() .into_iter() - .map(|(k, v)| (self.tcx.mk_opaque(k.def_id, k.substs), v.hidden_type.ty)) + .map(|(k, v)| (self.tcx.mk_opaque(k.def_id.to_def_id(), k.substs), v.hidden_type.ty)) .collect() } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index d7505717bf3..4e87ec86658 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -316,37 +316,6 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>( err } -/// Structurally compares two types, modulo any inference variables. -/// -/// Returns `true` if two types are equal, or if one type is an inference variable compatible -/// with the other type. A TyVar inference type is compatible with any type, and an IntVar or -/// FloatVar inference type are compatible with themselves or their concrete types (Int and -/// Float types, respectively). When comparing two ADTs, these rules apply recursively. -pub fn same_type_modulo_infer<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { - match (&a.kind(), &b.kind()) { - (&ty::Adt(did_a, substs_a), &ty::Adt(did_b, substs_b)) => { - if did_a != did_b { - return false; - } - - substs_a.types().zip(substs_b.types()).all(|(a, b)| same_type_modulo_infer(a, b)) - } - (&ty::Int(_), &ty::Infer(ty::InferTy::IntVar(_))) - | (&ty::Infer(ty::InferTy::IntVar(_)), &ty::Int(_) | &ty::Infer(ty::InferTy::IntVar(_))) - | (&ty::Float(_), &ty::Infer(ty::InferTy::FloatVar(_))) - | ( - &ty::Infer(ty::InferTy::FloatVar(_)), - &ty::Float(_) | &ty::Infer(ty::InferTy::FloatVar(_)), - ) - | (&ty::Infer(ty::InferTy::TyVar(_)), _) - | (_, &ty::Infer(ty::InferTy::TyVar(_))) => true, - (&ty::Ref(_, ty_a, mut_a), &ty::Ref(_, ty_b, mut_b)) => { - mut_a == mut_b && same_type_modulo_infer(*ty_a, *ty_b) - } - _ => a == b, - } -} - impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn report_region_errors( &self, @@ -645,13 +614,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err.span_label(span, "expected due to this"); } ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { - semi_span, + arm_block_id, + arm_span, + arm_ty, + prior_arm_block_id, + prior_arm_span, + prior_arm_ty, source, ref prior_arms, - last_ty, scrut_hir_id, opt_suggest_box_span, - arm_span, scrut_span, .. }) => match source { @@ -682,10 +654,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } _ => { - // `last_ty` can be `!`, `expected` will have better info when present. + // `prior_arm_ty` can be `!`, `expected` will have better info when present. let t = self.resolve_vars_if_possible(match exp_found { Some(ty::error::ExpectedFound { expected, .. }) => expected, - _ => last_ty, + _ => prior_arm_ty, }); let source_map = self.tcx.sess.source_map(); let mut any_multiline_arm = source_map.is_multiline(arm_span); @@ -710,37 +682,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }; let msg = "`match` arms have incompatible types"; err.span_label(outer_error_span, msg); - if let Some((sp, boxed)) = semi_span { - if let (StatementAsExpression::NeedsBoxing, [.., prior_arm]) = - (boxed, &prior_arms[..]) - { - err.multipart_suggestion( - "consider removing this semicolon and boxing the expressions", - vec![ - (prior_arm.shrink_to_lo(), "Box::new(".to_string()), - (prior_arm.shrink_to_hi(), ")".to_string()), - (arm_span.shrink_to_lo(), "Box::new(".to_string()), - (arm_span.shrink_to_hi(), ")".to_string()), - (sp, String::new()), - ], - Applicability::HasPlaceholders, - ); - } else if matches!(boxed, StatementAsExpression::NeedsBoxing) { - err.span_suggestion_short( - sp, - "consider removing this semicolon and boxing the expressions", - "", - Applicability::MachineApplicable, - ); - } else { - err.span_suggestion_short( - sp, - "consider removing this semicolon", - "", - Applicability::MachineApplicable, - ); - } - } + self.suggest_remove_semi_or_return_binding( + err, + prior_arm_block_id, + prior_arm_ty, + prior_arm_span, + arm_block_id, + arm_ty, + arm_span, + ); if let Some(ret_sp) = opt_suggest_box_span { // Get return type span and point to it. self.suggest_boxing_for_return_impl_trait( @@ -752,43 +702,33 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } }, ObligationCauseCode::IfExpression(box IfExpressionCause { - then, - else_sp, - outer, - semicolon, + then_id, + else_id, + then_ty, + else_ty, + outer_span, opt_suggest_box_span, }) => { - err.span_label(then, "expected because of this"); - if let Some(sp) = outer { + let then_span = self.find_block_span_from_hir_id(then_id); + let else_span = self.find_block_span_from_hir_id(then_id); + err.span_label(then_span, "expected because of this"); + if let Some(sp) = outer_span { err.span_label(sp, "`if` and `else` have incompatible types"); } - if let Some((sp, boxed)) = semicolon { - if matches!(boxed, StatementAsExpression::NeedsBoxing) { - err.multipart_suggestion( - "consider removing this semicolon and boxing the expression", - vec![ - (then.shrink_to_lo(), "Box::new(".to_string()), - (then.shrink_to_hi(), ")".to_string()), - (else_sp.shrink_to_lo(), "Box::new(".to_string()), - (else_sp.shrink_to_hi(), ")".to_string()), - (sp, String::new()), - ], - Applicability::MachineApplicable, - ); - } else { - err.span_suggestion_short( - sp, - "consider removing this semicolon", - "", - Applicability::MachineApplicable, - ); - } - } + self.suggest_remove_semi_or_return_binding( + err, + Some(then_id), + then_ty, + then_span, + Some(else_id), + else_ty, + else_span, + ); if let Some(ret_sp) = opt_suggest_box_span { self.suggest_boxing_for_return_impl_trait( err, ret_sp, - [then, else_sp].into_iter(), + [then_span, else_span].into_iter(), ); } } @@ -808,6 +748,56 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } + fn suggest_remove_semi_or_return_binding( + &self, + err: &mut Diagnostic, + first_id: Option<hir::HirId>, + first_ty: Ty<'tcx>, + first_span: Span, + second_id: Option<hir::HirId>, + second_ty: Ty<'tcx>, + second_span: Span, + ) { + let remove_semicolon = + [(first_id, second_ty), (second_id, first_ty)].into_iter().find_map(|(id, ty)| { + let hir::Node::Block(blk) = self.tcx.hir().get(id?) else { return None }; + self.could_remove_semicolon(blk, ty) + }); + match remove_semicolon { + Some((sp, StatementAsExpression::NeedsBoxing)) => { + err.multipart_suggestion( + "consider removing this semicolon and boxing the expressions", + vec![ + (first_span.shrink_to_lo(), "Box::new(".to_string()), + (first_span.shrink_to_hi(), ")".to_string()), + (second_span.shrink_to_lo(), "Box::new(".to_string()), + (second_span.shrink_to_hi(), ")".to_string()), + (sp, String::new()), + ], + Applicability::MachineApplicable, + ); + } + Some((sp, StatementAsExpression::CorrectType)) => { + err.span_suggestion_short( + sp, + "consider removing this semicolon", + "", + Applicability::MachineApplicable, + ); + } + None => { + for (id, ty) in [(first_id, second_ty), (second_id, first_ty)] { + if let Some(id) = id + && let hir::Node::Block(blk) = self.tcx.hir().get(id) + && self.consider_returning_binding(blk, ty, err) + { + break; + } + } + } + } + } + fn suggest_boxing_for_return_impl_trait( &self, err: &mut Diagnostic, @@ -1723,15 +1713,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }; debug!("exp_found {:?} terr {:?} cause.code {:?}", exp_found, terr, cause.code()); if let Some(exp_found) = exp_found { - let should_suggest_fixes = if let ObligationCauseCode::Pattern { root_ty, .. } = - cause.code() - { - // Skip if the root_ty of the pattern is not the same as the expected_ty. - // If these types aren't equal then we've probably peeled off a layer of arrays. - same_type_modulo_infer(self.resolve_vars_if_possible(*root_ty), exp_found.expected) - } else { - true - }; + let should_suggest_fixes = + if let ObligationCauseCode::Pattern { root_ty, .. } = cause.code() { + // Skip if the root_ty of the pattern is not the same as the expected_ty. + // If these types aren't equal then we've probably peeled off a layer of arrays. + self.same_type_modulo_infer(*root_ty, exp_found.expected) + } else { + true + }; if should_suggest_fixes { self.suggest_tuple_pattern(cause, &exp_found, diag); @@ -1786,7 +1775,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .filter_map(|variant| { let sole_field = &variant.fields[0]; let sole_field_ty = sole_field.ty(self.tcx, substs); - if same_type_modulo_infer(sole_field_ty, exp_found.found) { + if self.same_type_modulo_infer(sole_field_ty, exp_found.found) { let variant_path = with_no_trimmed_paths!(self.tcx.def_path_str(variant.def_id)); // FIXME #56861: DRYer prelude filtering @@ -1902,12 +1891,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.get_impl_future_output_ty(exp_found.expected).map(Binder::skip_binder), self.get_impl_future_output_ty(exp_found.found).map(Binder::skip_binder), ) { - (Some(exp), Some(found)) if same_type_modulo_infer(exp, found) => match cause.code() { - ObligationCauseCode::IfExpression(box IfExpressionCause { then, .. }) => { + (Some(exp), Some(found)) if self.same_type_modulo_infer(exp, found) => match cause + .code() + { + ObligationCauseCode::IfExpression(box IfExpressionCause { then_id, .. }) => { + let then_span = self.find_block_span_from_hir_id(*then_id); diag.multipart_suggestion( "consider `await`ing on both `Future`s", vec![ - (then.shrink_to_hi(), ".await".to_string()), + (then_span.shrink_to_hi(), ".await".to_string()), (exp_span.shrink_to_hi(), ".await".to_string()), ], Applicability::MaybeIncorrect, @@ -1934,7 +1926,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { diag.help("consider `await`ing on both `Future`s"); } }, - (_, Some(ty)) if same_type_modulo_infer(exp_found.expected, ty) => { + (_, Some(ty)) if self.same_type_modulo_infer(exp_found.expected, ty) => { diag.span_suggestion_verbose( exp_span.shrink_to_hi(), "consider `await`ing on the `Future`", @@ -1942,11 +1934,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { Applicability::MaybeIncorrect, ); } - (Some(ty), _) if same_type_modulo_infer(ty, exp_found.found) => match cause.code() { - ObligationCauseCode::Pattern { span: Some(span), .. } - | ObligationCauseCode::IfExpression(box IfExpressionCause { then: span, .. }) => { + (Some(ty), _) if self.same_type_modulo_infer(ty, exp_found.found) => match cause.code() + { + ObligationCauseCode::Pattern { span: Some(then_span), .. } => { diag.span_suggestion_verbose( - span.shrink_to_hi(), + then_span.shrink_to_hi(), + "consider `await`ing on the `Future`", + ".await", + Applicability::MaybeIncorrect, + ); + } + ObligationCauseCode::IfExpression(box IfExpressionCause { then_id, .. }) => { + let then_span = self.find_block_span_from_hir_id(*then_id); + diag.span_suggestion_verbose( + then_span.shrink_to_hi(), "consider `await`ing on the `Future`", ".await", Applicability::MaybeIncorrect, @@ -1992,7 +1993,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .iter() .filter(|field| field.vis.is_accessible_from(field.did, self.tcx)) .map(|field| (field.name, field.ty(self.tcx, expected_substs))) - .find(|(_, ty)| same_type_modulo_infer(*ty, exp_found.found)) + .find(|(_, ty)| self.same_type_modulo_infer(*ty, exp_found.found)) { if let ObligationCauseCode::Pattern { span: Some(span), .. } = *cause.code() { if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { @@ -2057,7 +2058,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { | (_, ty::Infer(_)) | (ty::Param(_), _) | (ty::Infer(_), _) => {} - _ if same_type_modulo_infer(exp_ty, found_ty) => {} + _ if self.same_type_modulo_infer(exp_ty, found_ty) => {} _ => show_suggestion = false, }; } @@ -2179,7 +2180,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ) { let [expected_tup_elem] = expected_fields[..] else { return }; - if !same_type_modulo_infer(expected_tup_elem, found) { + if !self.same_type_modulo_infer(expected_tup_elem, found) { return; } @@ -2647,6 +2648,76 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { span.is_desugaring(DesugaringKind::QuestionMark) && self.tcx.is_diagnostic_item(sym::From, trait_def_id) } + + /// Structurally compares two types, modulo any inference variables. + /// + /// Returns `true` if two types are equal, or if one type is an inference variable compatible + /// with the other type. A TyVar inference type is compatible with any type, and an IntVar or + /// FloatVar inference type are compatible with themselves or their concrete types (Int and + /// Float types, respectively). When comparing two ADTs, these rules apply recursively. + pub fn same_type_modulo_infer(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool { + let (a, b) = self.resolve_vars_if_possible((a, b)); + match (a.kind(), b.kind()) { + (&ty::Adt(def_a, substs_a), &ty::Adt(def_b, substs_b)) => { + if def_a != def_b { + return false; + } + + substs_a + .types() + .zip(substs_b.types()) + .all(|(a, b)| self.same_type_modulo_infer(a, b)) + } + (&ty::FnDef(did_a, substs_a), &ty::FnDef(did_b, substs_b)) => { + if did_a != did_b { + return false; + } + + substs_a + .types() + .zip(substs_b.types()) + .all(|(a, b)| self.same_type_modulo_infer(a, b)) + } + (&ty::Int(_) | &ty::Uint(_), &ty::Infer(ty::InferTy::IntVar(_))) + | ( + &ty::Infer(ty::InferTy::IntVar(_)), + &ty::Int(_) | &ty::Uint(_) | &ty::Infer(ty::InferTy::IntVar(_)), + ) + | (&ty::Float(_), &ty::Infer(ty::InferTy::FloatVar(_))) + | ( + &ty::Infer(ty::InferTy::FloatVar(_)), + &ty::Float(_) | &ty::Infer(ty::InferTy::FloatVar(_)), + ) + | (&ty::Infer(ty::InferTy::TyVar(_)), _) + | (_, &ty::Infer(ty::InferTy::TyVar(_))) => true, + (&ty::Ref(_, ty_a, mut_a), &ty::Ref(_, ty_b, mut_b)) => { + mut_a == mut_b && self.same_type_modulo_infer(ty_a, ty_b) + } + (&ty::RawPtr(a), &ty::RawPtr(b)) => { + a.mutbl == b.mutbl && self.same_type_modulo_infer(a.ty, b.ty) + } + (&ty::Slice(a), &ty::Slice(b)) => self.same_type_modulo_infer(a, b), + (&ty::Array(a_ty, a_ct), &ty::Array(b_ty, b_ct)) => { + self.same_type_modulo_infer(a_ty, b_ty) && a_ct == b_ct + } + (&ty::Tuple(a), &ty::Tuple(b)) => { + if a.len() != b.len() { + return false; + } + std::iter::zip(a.iter(), b.iter()).all(|(a, b)| self.same_type_modulo_infer(a, b)) + } + (&ty::FnPtr(a), &ty::FnPtr(b)) => { + let a = a.skip_binder().inputs_and_output; + let b = b.skip_binder().inputs_and_output; + if a.len() != b.len() { + return false; + } + std::iter::zip(a.iter(), b.iter()).all(|(a, b)| self.same_type_modulo_infer(a, b)) + } + // FIXME(compiler-errors): This needs to be generalized more + _ => a == b, + } + } } impl<'a, 'tcx> InferCtxt<'a, 'tcx> { @@ -2798,3 +2869,237 @@ impl TyCategory { } } } + +impl<'tcx> InferCtxt<'_, 'tcx> { + /// Given a [`hir::Block`], get the span of its last expression or + /// statement, peeling off any inner blocks. + pub fn find_block_span(&self, block: &'tcx hir::Block<'tcx>) -> Span { + let block = block.innermost_block(); + if let Some(expr) = &block.expr { + expr.span + } else if let Some(stmt) = block.stmts.last() { + // possibly incorrect trailing `;` in the else arm + stmt.span + } else { + // empty block; point at its entirety + block.span + } + } + + /// Given a [`hir::HirId`] for a block, get the span of its last expression + /// or statement, peeling off any inner blocks. + pub fn find_block_span_from_hir_id(&self, hir_id: hir::HirId) -> Span { + match self.tcx.hir().get(hir_id) { + hir::Node::Block(blk) => self.find_block_span(blk), + // The parser was in a weird state if either of these happen, but + // it's better not to panic. + hir::Node::Expr(e) => e.span, + _ => rustc_span::DUMMY_SP, + } + } + + /// Be helpful when the user wrote `{... expr; }` and taking the `;` off + /// is enough to fix the error. + pub fn could_remove_semicolon( + &self, + blk: &'tcx hir::Block<'tcx>, + expected_ty: Ty<'tcx>, + ) -> Option<(Span, StatementAsExpression)> { + let blk = blk.innermost_block(); + // Do not suggest if we have a tail expr. + if blk.expr.is_some() { + return None; + } + let last_stmt = blk.stmts.last()?; + let hir::StmtKind::Semi(ref last_expr) = last_stmt.kind else { + return None; + }; + let last_expr_ty = self.in_progress_typeck_results?.borrow().expr_ty_opt(*last_expr)?; + let needs_box = match (last_expr_ty.kind(), expected_ty.kind()) { + _ if last_expr_ty.references_error() => return None, + _ if self.same_type_modulo_infer(last_expr_ty, expected_ty) => { + StatementAsExpression::CorrectType + } + (ty::Opaque(last_def_id, _), ty::Opaque(exp_def_id, _)) + if last_def_id == exp_def_id => + { + StatementAsExpression::CorrectType + } + (ty::Opaque(last_def_id, last_bounds), ty::Opaque(exp_def_id, exp_bounds)) => { + debug!( + "both opaque, likely future {:?} {:?} {:?} {:?}", + last_def_id, last_bounds, exp_def_id, exp_bounds + ); + + let last_local_id = last_def_id.as_local()?; + let exp_local_id = exp_def_id.as_local()?; + + match ( + &self.tcx.hir().expect_item(last_local_id).kind, + &self.tcx.hir().expect_item(exp_local_id).kind, + ) { + ( + hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: last_bounds, .. }), + hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: exp_bounds, .. }), + ) if iter::zip(*last_bounds, *exp_bounds).all(|(left, right)| { + match (left, right) { + ( + hir::GenericBound::Trait(tl, ml), + hir::GenericBound::Trait(tr, mr), + ) if tl.trait_ref.trait_def_id() == tr.trait_ref.trait_def_id() + && ml == mr => + { + true + } + ( + hir::GenericBound::LangItemTrait(langl, _, _, argsl), + hir::GenericBound::LangItemTrait(langr, _, _, argsr), + ) if langl == langr => { + // FIXME: consider the bounds! + debug!("{:?} {:?}", argsl, argsr); + true + } + _ => false, + } + }) => + { + StatementAsExpression::NeedsBoxing + } + _ => StatementAsExpression::CorrectType, + } + } + _ => return None, + }; + let span = if last_stmt.span.from_expansion() { + let mac_call = rustc_span::source_map::original_sp(last_stmt.span, blk.span); + self.tcx.sess.source_map().mac_call_stmt_semi_span(mac_call)? + } else { + last_stmt.span.with_lo(last_stmt.span.hi() - BytePos(1)) + }; + Some((span, needs_box)) + } + + /// Suggest returning a local binding with a compatible type if the block + /// has no return expression. + pub fn consider_returning_binding( + &self, + blk: &'tcx hir::Block<'tcx>, + expected_ty: Ty<'tcx>, + err: &mut Diagnostic, + ) -> bool { + let blk = blk.innermost_block(); + // Do not suggest if we have a tail expr. + if blk.expr.is_some() { + return false; + } + let mut shadowed = FxHashSet::default(); + let mut candidate_idents = vec![]; + let mut find_compatible_candidates = |pat: &hir::Pat<'_>| { + if let hir::PatKind::Binding(_, hir_id, ident, _) = &pat.kind + && let Some(pat_ty) = self + .in_progress_typeck_results + .and_then(|typeck_results| typeck_results.borrow().node_type_opt(*hir_id)) + { + let pat_ty = self.resolve_vars_if_possible(pat_ty); + if self.same_type_modulo_infer(pat_ty, expected_ty) + && !(pat_ty, expected_ty).references_error() + && shadowed.insert(ident.name) + { + candidate_idents.push((*ident, pat_ty)); + } + } + true + }; + + let hir = self.tcx.hir(); + for stmt in blk.stmts.iter().rev() { + let hir::StmtKind::Local(local) = &stmt.kind else { continue; }; + local.pat.walk(&mut find_compatible_candidates); + } + match hir.find(hir.get_parent_node(blk.hir_id)) { + Some(hir::Node::Expr(hir::Expr { hir_id, .. })) => { + match hir.find(hir.get_parent_node(*hir_id)) { + Some(hir::Node::Arm(hir::Arm { pat, .. })) => { + pat.walk(&mut find_compatible_candidates); + } + Some( + hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body), .. }) + | hir::Node::ImplItem(hir::ImplItem { + kind: hir::ImplItemKind::Fn(_, body), + .. + }) + | hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body)), + .. + }) + | hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Closure(hir::Closure { body, .. }), + .. + }), + ) => { + for param in hir.body(*body).params { + param.pat.walk(&mut find_compatible_candidates); + } + } + Some(hir::Node::Expr(hir::Expr { + kind: + hir::ExprKind::If( + hir::Expr { kind: hir::ExprKind::Let(let_), .. }, + then_block, + _, + ), + .. + })) if then_block.hir_id == *hir_id => { + let_.pat.walk(&mut find_compatible_candidates); + } + _ => {} + } + } + _ => {} + } + + match &candidate_idents[..] { + [(ident, _ty)] => { + let sm = self.tcx.sess.source_map(); + if let Some(stmt) = blk.stmts.last() { + let stmt_span = sm.stmt_span(stmt.span, blk.span); + let sugg = if sm.is_multiline(blk.span) + && let Some(spacing) = sm.indentation_before(stmt_span) + { + format!("\n{spacing}{ident}") + } else { + format!(" {ident}") + }; + err.span_suggestion_verbose( + stmt_span.shrink_to_hi(), + format!("consider returning the local binding `{ident}`"), + sugg, + Applicability::MaybeIncorrect, + ); + } else { + let sugg = if sm.is_multiline(blk.span) + && let Some(spacing) = sm.indentation_before(blk.span.shrink_to_lo()) + { + format!("\n{spacing} {ident}\n{spacing}") + } else { + format!(" {ident} ") + }; + let left_span = sm.span_through_char(blk.span, '{').shrink_to_hi(); + err.span_suggestion_verbose( + sm.span_extend_while(left_span, |c| c.is_whitespace()).unwrap_or(left_span), + format!("consider returning the local binding `{ident}`"), + sugg, + Applicability::MaybeIncorrect, + ); + } + true + } + values if (1..3).contains(&values.len()) => { + let spans = values.iter().map(|(ident, _)| ident.span).collect::<Vec<_>>(); + err.span_note(spans, "consider returning one of these bindings"); + true + } + _ => false, + } + } +} diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs index b744594ddb7..9a2ab3e3224 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs @@ -228,7 +228,7 @@ pub fn suggest_adding_lifetime_params<'tcx>( if is_impl { sugg.push_str(" and update trait if needed"); } - err.multipart_suggestion(sugg.as_str(), suggestions, Applicability::MaybeIncorrect); + err.multipart_suggestion(sugg, suggestions, Applicability::MaybeIncorrect); true } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs index 43d5c9fdf33..893ca3cf79d 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs @@ -6,7 +6,7 @@ use crate::infer::error_reporting::note_and_explain_region; use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::{SubregionOrigin, TypeTrace}; use crate::traits::ObligationCauseCode; -use rustc_data_structures::stable_set::FxHashSet; +use rustc_data_structures::fx::FxHashSet; use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; use rustc_hir::intravisit::Visitor; 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 02928c4aa57..246d27be71c 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 @@ -4,7 +4,7 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::{SubregionOrigin, TypeTrace}; use crate::traits::{ObligationCauseCode, UnifyReceiverContext}; -use rustc_data_structures::stable_set::FxHashSet; +use rustc_data_structures::fx::FxHashSet; use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{walk_ty, Visitor}; diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index 67bbace39e3..b6d41bedd56 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -357,7 +357,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let trait_predicates = self.tcx.explicit_predicates_of(trait_item_def_id); let impl_predicates = self.tcx.explicit_predicates_of(impl_item_def_id); - let impl_predicates: rustc_data_structures::stable_set::FxHashSet<_> = + let impl_predicates: rustc_data_structures::fx::FxHashSet<_> = impl_predicates.predicates.into_iter().map(|(pred, _)| pred).collect(); let clauses: Vec<_> = trait_predicates .predicates diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index c5a342c1ba2..85692e109be 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -239,17 +239,36 @@ impl<'tcx> InferCtxtInner<'tcx> { } } +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum DefiningAnchor { + /// `DefId` of the item. + Bind(LocalDefId), + /// When opaque types are not resolved, we `Bubble` up, meaning + /// return the opaque/hidden type pair from query, for caller of query to handle it. + Bubble, + /// Used to catch type mismatch errors when handling opaque types. + Error, +} + pub struct InferCtxt<'a, 'tcx> { pub tcx: TyCtxt<'tcx>, /// The `DefId` of the item in whose context we are performing inference or typeck. /// It is used to check whether an opaque type use is a defining use. /// - /// If it is `None`, we can't resolve opaque types here and need to bubble up + /// If it is `DefiningAnchor::Bubble`, we can't resolve opaque types here and need to bubble up /// the obligation. This frequently happens for /// short lived InferCtxt within queries. The opaque type obligations are forwarded /// to the outside until the end up in an `InferCtxt` for typeck or borrowck. - pub defining_use_anchor: Option<LocalDefId>, + /// + /// It is default value is `DefiningAnchor::Error`, this way it is easier to catch errors that + /// might come up during inference or typeck. + pub defining_use_anchor: DefiningAnchor, + + /// Whether this inference context should care about region obligations in + /// the root universe. Most notably, this is used during hir typeck as region + /// solving is left to borrowck instead. + pub considering_regions: bool, /// During type-checking/inference of a body, `in_progress_typeck_results` /// contains a reference to the typeck results being built up, which are @@ -525,8 +544,9 @@ impl<'tcx> fmt::Display for FixupError<'tcx> { /// without using `Rc` or something similar. pub struct InferCtxtBuilder<'tcx> { tcx: TyCtxt<'tcx>, + defining_use_anchor: DefiningAnchor, + considering_regions: bool, fresh_typeck_results: Option<RefCell<ty::TypeckResults<'tcx>>>, - defining_use_anchor: Option<LocalDefId>, } pub trait TyCtxtInferExt<'tcx> { @@ -535,7 +555,12 @@ pub trait TyCtxtInferExt<'tcx> { impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> { fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> { - InferCtxtBuilder { tcx: self, defining_use_anchor: None, fresh_typeck_results: None } + InferCtxtBuilder { + tcx: self, + defining_use_anchor: DefiningAnchor::Error, + considering_regions: true, + fresh_typeck_results: None, + } } } @@ -545,7 +570,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { /// Will also change the scope for opaque type defining use checks to the given owner. pub fn with_fresh_in_progress_typeck_results(mut self, table_owner: LocalDefId) -> Self { self.fresh_typeck_results = Some(RefCell::new(ty::TypeckResults::new(table_owner))); - self.with_opaque_type_inference(table_owner) + self.with_opaque_type_inference(DefiningAnchor::Bind(table_owner)) } /// Whenever the `InferCtxt` should be able to handle defining uses of opaque types, @@ -554,8 +579,13 @@ impl<'tcx> InferCtxtBuilder<'tcx> { /// It is only meant to be called in two places, for typeck /// (via `with_fresh_in_progress_typeck_results`) and for the inference context used /// in mir borrowck. - pub fn with_opaque_type_inference(mut self, defining_use_anchor: LocalDefId) -> Self { - self.defining_use_anchor = Some(defining_use_anchor); + pub fn with_opaque_type_inference(mut self, defining_use_anchor: DefiningAnchor) -> Self { + self.defining_use_anchor = defining_use_anchor; + self + } + + pub fn ignoring_regions(mut self) -> Self { + self.considering_regions = false; self } @@ -583,11 +613,17 @@ impl<'tcx> InferCtxtBuilder<'tcx> { } pub fn enter<R>(&mut self, f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>) -> R) -> R { - let InferCtxtBuilder { tcx, defining_use_anchor, ref fresh_typeck_results } = *self; + let InferCtxtBuilder { + tcx, + defining_use_anchor, + considering_regions, + ref fresh_typeck_results, + } = *self; let in_progress_typeck_results = fresh_typeck_results.as_ref(); f(InferCtxt { tcx, defining_use_anchor, + considering_regions, in_progress_typeck_results, inner: RefCell::new(InferCtxtInner::new()), lexical_region_resolutions: RefCell::new(None), @@ -938,7 +974,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { #[instrument(skip(self), level = "debug")] pub fn member_constraint( &self, - opaque_type_def_id: DefId, + opaque_type_def_id: LocalDefId, definition_span: Span, hidden_ty: Ty<'tcx>, region: ty::Region<'tcx>, @@ -1025,16 +1061,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &self, cause: &traits::ObligationCause<'tcx>, predicate: ty::PolyRegionOutlivesPredicate<'tcx>, - ) -> UnitResult<'tcx> { - self.commit_if_ok(|_snapshot| { - let ty::OutlivesPredicate(r_a, r_b) = - self.replace_bound_vars_with_placeholders(predicate); - let origin = SubregionOrigin::from_obligation_cause(cause, || { - RelateRegionParamBound(cause.span) - }); - self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b` - Ok(()) - }) + ) { + let ty::OutlivesPredicate(r_a, r_b) = self.replace_bound_vars_with_placeholders(predicate); + let origin = + SubregionOrigin::from_obligation_cause(cause, || RelateRegionParamBound(cause.span)); + self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b` } /// Number of type variables created so far. diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index f11701bba6f..7b0ff9552a3 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -1,4 +1,4 @@ -use crate::infer::{InferCtxt, InferOk}; +use crate::infer::{DefiningAnchor, InferCtxt, InferOk}; use crate::traits; use hir::def_id::{DefId, LocalDefId}; use hir::{HirId, OpaqueTyOrigin}; @@ -51,7 +51,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { return InferOk { value: ty, obligations: vec![] }; } let mut obligations = vec![]; - let replace_opaque_type = |def_id| self.opaque_type_origin(def_id, span).is_some(); + let replace_opaque_type = |def_id: DefId| { + def_id + .as_local() + .map_or(false, |def_id| self.opaque_type_origin(def_id, span).is_some()) + }; let value = ty.fold_with(&mut ty::fold::BottomUpFolder { tcx: self.tcx, lt_op: |lt| lt, @@ -96,44 +100,47 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let (a, b) = if a_is_expected { (a, b) } else { (b, a) }; let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() { ty::Opaque(def_id, substs) if def_id.is_local() => { - let origin = if self.defining_use_anchor.is_some() { - // Check that this is `impl Trait` type is - // declared by `parent_def_id` -- i.e., one whose - // value we are inferring. At present, this is - // always true during the first phase of - // type-check, but not always true later on during - // NLL. Once we support named opaque types more fully, - // this same scenario will be able to arise during all phases. - // - // Here is an example using type alias `impl Trait` - // that indicates the distinction we are checking for: - // - // ```rust - // mod a { - // pub type Foo = impl Iterator; - // pub fn make_foo() -> Foo { .. } - // } - // - // mod b { - // fn foo() -> a::Foo { a::make_foo() } - // } - // ``` - // - // Here, the return type of `foo` references an - // `Opaque` indeed, but not one whose value is - // presently being inferred. You can get into a - // similar situation with closure return types - // today: - // - // ```rust - // fn foo() -> impl Iterator { .. } - // fn bar() { - // let x = || foo(); // returns the Opaque assoc with `foo` - // } - // ``` - self.opaque_type_origin(def_id, cause.span)? - } else { - self.opaque_ty_origin_unchecked(def_id, cause.span) + let def_id = def_id.expect_local(); + let origin = match self.defining_use_anchor { + DefiningAnchor::Bind(_) => { + // Check that this is `impl Trait` type is + // declared by `parent_def_id` -- i.e., one whose + // value we are inferring. At present, this is + // always true during the first phase of + // type-check, but not always true later on during + // NLL. Once we support named opaque types more fully, + // this same scenario will be able to arise during all phases. + // + // Here is an example using type alias `impl Trait` + // that indicates the distinction we are checking for: + // + // ```rust + // mod a { + // pub type Foo = impl Iterator; + // pub fn make_foo() -> Foo { .. } + // } + // + // mod b { + // fn foo() -> a::Foo { a::make_foo() } + // } + // ``` + // + // Here, the return type of `foo` references an + // `Opaque` indeed, but not one whose value is + // presently being inferred. You can get into a + // similar situation with closure return types + // today: + // + // ```rust + // fn foo() -> impl Iterator { .. } + // fn bar() { + // let x = || foo(); // returns the Opaque assoc with `foo` + // } + // ``` + self.opaque_type_origin(def_id, cause.span)? + } + DefiningAnchor::Bubble => self.opaque_ty_origin_unchecked(def_id, cause.span), + DefiningAnchor::Error => return None, }; if let ty::Opaque(did2, _) = *b.kind() { // We could accept this, but there are various ways to handle this situation, and we don't @@ -141,7 +148,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // no one encounters it in practice. // It does occur however in `fn fut() -> impl Future<Output = i32> { async { 42 } }`, // where it is of no concern, so we only check for TAITs. - if let Some(OpaqueTyOrigin::TyAlias) = self.opaque_type_origin(did2, cause.span) + if let Some(OpaqueTyOrigin::TyAlias) = + did2.as_local().and_then(|did2| self.opaque_type_origin(did2, cause.span)) { self.tcx .sess @@ -399,17 +407,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } #[instrument(skip(self), level = "trace")] - pub fn opaque_type_origin(&self, opaque_def_id: DefId, span: Span) -> Option<OpaqueTyOrigin> { - let def_id = opaque_def_id.as_local()?; + pub fn opaque_type_origin(&self, def_id: LocalDefId, span: Span) -> Option<OpaqueTyOrigin> { let opaque_hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); - let parent_def_id = self.defining_use_anchor?; + let parent_def_id = match self.defining_use_anchor { + DefiningAnchor::Bubble | DefiningAnchor::Error => return None, + DefiningAnchor::Bind(bind) => bind, + }; let item_kind = &self.tcx.hir().expect_item(def_id).kind; let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item_kind else { span_bug!( span, "weird opaque type: {:#?}, {:#?}", - opaque_def_id, + def_id, item_kind ) }; @@ -428,12 +438,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } #[instrument(skip(self), level = "trace")] - fn opaque_ty_origin_unchecked(&self, opaque_def_id: DefId, span: Span) -> OpaqueTyOrigin { - let def_id = opaque_def_id.as_local().unwrap(); + pub fn opaque_ty_origin_unchecked(&self, def_id: LocalDefId, span: Span) -> OpaqueTyOrigin { let origin = match self.tcx.hir().expect_item(def_id).kind { hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => origin, ref itemkind => { - span_bug!(span, "weird opaque type: {:?}, {:#?}", opaque_def_id, itemkind) + span_bug!(span, "weird opaque type: {:?}, {:#?}", def_id, itemkind) } }; trace!(?origin); @@ -557,7 +566,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { obligations = self.at(&cause, param_env).eq(prev, hidden_ty)?.obligations; } - let item_bounds = tcx.bound_explicit_item_bounds(def_id); + let item_bounds = tcx.bound_explicit_item_bounds(def_id.to_def_id()); for predicate in item_bounds.transpose_iter().map(|e| e.map_bound(|(p, _)| *p)) { debug!(?predicate); @@ -579,7 +588,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } // Replace all other mentions of the same opaque type with the hidden type, // as the bounds must hold on the hidden type after all. - ty::Opaque(def_id2, substs2) if def_id == def_id2 && substs == substs2 => { + ty::Opaque(def_id2, substs2) + if def_id.to_def_id() == def_id2 && substs == substs2 => + { hidden_ty } _ => ty, diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index c5747ecf702..551f398e0c2 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -12,7 +12,7 @@ use rustc_data_structures::intern::Interned; use rustc_data_structures::sync::Lrc; use rustc_data_structures::undo_log::UndoLogs; use rustc_data_structures::unify as ut; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::LocalDefId; use rustc_index::vec::IndexVec; use rustc_middle::infer::unify_key::{RegionVidKey, UnifiedRegion}; use rustc_middle::ty::ReStatic; @@ -533,7 +533,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { pub fn member_constraint( &mut self, - opaque_type_def_id: DefId, + opaque_type_def_id: LocalDefId, definition_span: Span, hidden_ty: Ty<'tcx>, member_region: ty::Region<'tcx>, diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 9c0b534798e..d07e17f6792 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -718,6 +718,7 @@ fn test_unstable_options_tracking_hash() { tracked!(asm_comments, true); tracked!(assume_incomplete_release, true); tracked!(binary_dep_depinfo, true); + tracked!(box_noalias, Some(false)); tracked!( branch_protection, Some(BranchProtection { @@ -734,6 +735,7 @@ fn test_unstable_options_tracking_hash() { tracked!(drop_tracking, true); tracked!(dual_proc_macros, true); tracked!(dwarf_version, Some(5)); + tracked!(emit_thin_lto, false); tracked!(fewer_names, Some(true)); tracked!(force_unstable_if_unmarked, true); tracked!(fuel, Some(("abc".to_string(), 99))); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index a0472f98d72..9e4dc702f07 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -2858,9 +2858,10 @@ impl ClashingExternDeclarations { let a_poly_sig = a.fn_sig(tcx); let b_poly_sig = b.fn_sig(tcx); - // As we don't compare regions, skip_binder is fine. - let a_sig = a_poly_sig.skip_binder(); - let b_sig = b_poly_sig.skip_binder(); + // We don't compare regions, but leaving bound regions around ICEs, so + // we erase them. + let a_sig = tcx.erase_late_bound_regions(a_poly_sig); + let b_sig = tcx.erase_late_bound_regions(b_poly_sig); (a_sig.abi, a_sig.unsafety, a_sig.c_variadic) == (b_sig.abi, b_sig.unsafety, b_sig.c_variadic) diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index aca481df2e1..5c07afeb7aa 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1434,10 +1434,6 @@ declare_lint! { /// - Passing `Ordering::Release` or `Ordering::AcqRel` as the failure /// ordering for any of `AtomicType::compare_exchange`, /// `AtomicType::compare_exchange_weak`, or `AtomicType::fetch_update`. - /// - /// - Passing in a pair of orderings to `AtomicType::compare_exchange`, - /// `AtomicType::compare_exchange_weak`, or `AtomicType::fetch_update` - /// where the failure ordering is stronger than the success ordering. INVALID_ATOMIC_ORDERING, Deny, "usage of invalid atomic ordering in atomic operations and memory fences" @@ -1544,9 +1540,9 @@ impl InvalidAtomicOrdering { let Some((method, args)) = Self::inherent_atomic_method_call(cx, expr, &[sym::fetch_update, sym::compare_exchange, sym::compare_exchange_weak]) else {return }; - let (success_order_arg, fail_order_arg) = match method { - sym::fetch_update => (&args[1], &args[2]), - sym::compare_exchange | sym::compare_exchange_weak => (&args[3], &args[4]), + let fail_order_arg = match method { + sym::fetch_update => &args[2], + sym::compare_exchange | sym::compare_exchange_weak => &args[4], _ => return, }; @@ -1568,37 +1564,6 @@ impl InvalidAtomicOrdering { InvalidAtomicOrderingDiag { method, fail_order_arg_span: fail_order_arg.span }, ); } - - let Some(success_ordering) = Self::match_ordering(cx, success_order_arg) else { return }; - - if matches!( - (success_ordering, fail_ordering), - (sym::Relaxed | sym::Release, sym::Acquire) - | (sym::Relaxed | sym::Release | sym::Acquire | sym::AcqRel, sym::SeqCst) - ) { - let success_suggestion = - if success_ordering == sym::Release && fail_ordering == sym::Acquire { - sym::AcqRel - } else { - fail_ordering - }; - cx.struct_span_lint(INVALID_ATOMIC_ORDERING, success_order_arg.span, |diag| { - diag.build(fluent::lint::atomic_ordering_invalid_fail_success) - .set_arg("method", method) - .set_arg("fail_ordering", fail_ordering) - .set_arg("success_ordering", success_ordering) - .set_arg("success_suggestion", success_suggestion) - .span_label(fail_order_arg.span, fluent::lint::fail_label) - .span_label(success_order_arg.span, fluent::lint::success_label) - .span_suggestion_short( - success_order_arg.span, - fluent::lint::suggestion, - format!("std::sync::atomic::Ordering::{success_suggestion}"), - Applicability::MaybeIncorrect, - ) - .emit(); - }); - } } } diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 4fd57ed8533..3872d866dee 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -467,7 +467,7 @@ pub enum BuiltinLintDiagnostics { /// If true, the lifetime will be fully elided. use_span: Option<(Span, bool)>, }, - NamedArgumentUsedPositionally(Option<Span>, Span, String), + NamedArgumentUsedPositionally(Option<Span>, Span, Symbol), } /// Lints that are buffered up early on in the `Session` before the diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index 7729ec6bef4..62ef5804dce 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -4,6 +4,29 @@ use std::fmt::Display; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; +const OPTIONAL_COMPONENTS: &[&str] = &[ + "x86", + "arm", + "aarch64", + "amdgpu", + "avr", + "m68k", + "mips", + "powerpc", + "systemz", + "jsbackend", + "webassembly", + "msp430", + "sparc", + "nvptx", + "hexagon", + "riscv", + "bpf", +]; + +const REQUIRED_COMPONENTS: &[&str] = + &["ipo", "bitreader", "bitwriter", "linker", "asmparser", "lto", "coverage", "instrumentation"]; + fn detect_llvm_link() -> (&'static str, &'static str) { // Force the link mode we want, preferring static by default, but // possibly overridden by `configure --enable-llvm-link-shared`. @@ -76,6 +99,10 @@ fn output(cmd: &mut Command) -> String { } fn main() { + for component in REQUIRED_COMPONENTS.iter().chain(OPTIONAL_COMPONENTS.iter()) { + println!("cargo:rustc-check-cfg=values(llvm_component,\"{}\")", component); + } + if tracked_env_var_os("RUST_CHECK").is_some() { // If we're just running `check`, there's no need for LLVM to be built. return; @@ -131,42 +158,11 @@ fn main() { let host = env::var("HOST").expect("HOST was not set"); let is_crossed = target != host; - let optional_components = &[ - "x86", - "arm", - "aarch64", - "amdgpu", - "avr", - "m68k", - "mips", - "powerpc", - "systemz", - "jsbackend", - "webassembly", - "msp430", - "sparc", - "nvptx", - "hexagon", - "riscv", - "bpf", - ]; - - let required_components = &[ - "ipo", - "bitreader", - "bitwriter", - "linker", - "asmparser", - "lto", - "coverage", - "instrumentation", - ]; - let components = output(Command::new(&llvm_config).arg("--components")); let mut components = components.split_whitespace().collect::<Vec<_>>(); - components.retain(|c| optional_components.contains(c) || required_components.contains(c)); + components.retain(|c| OPTIONAL_COMPONENTS.contains(c) || REQUIRED_COMPONENTS.contains(c)); - for component in required_components { + for component in REQUIRED_COMPONENTS { if !components.contains(component) { panic!("require llvm component {} but wasn't found", component); } diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h index a2b0e9b4d29..9fe84a6309b 100644 --- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h +++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h @@ -84,6 +84,7 @@ enum LLVMRustAttribute { StackProtect = 32, NoUndef = 33, SanitizeMemTag = 34, + NoCfCheck = 35, }; typedef struct OpaqueRustString *RustStringRef; diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index be8fbf7677b..e0f10f77e89 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -34,6 +34,7 @@ #include "llvm/Transforms/Utils/AddDiscriminators.h" #include "llvm/Transforms/Utils/FunctionImportUtils.h" #include "llvm/LTO/LTO.h" +#include "llvm/Bitcode/BitcodeWriterPass.h" #include "llvm-c/Transforms/PassManagerBuilder.h" #include "llvm/Transforms/Instrumentation.h" @@ -1638,13 +1639,17 @@ struct LLVMRustThinLTOBuffer { }; extern "C" LLVMRustThinLTOBuffer* -LLVMRustThinLTOBufferCreate(LLVMModuleRef M) { +LLVMRustThinLTOBufferCreate(LLVMModuleRef M, bool is_thin) { auto Ret = std::make_unique<LLVMRustThinLTOBuffer>(); { raw_string_ostream OS(Ret->data); { legacy::PassManager PM; - PM.add(createWriteThinLTOBitcodePass(OS)); + if (is_thin) { + PM.add(createWriteThinLTOBitcodePass(OS)); + } else { + PM.add(createBitcodeWriterPass(OS)); + } PM.run(*unwrap(M)); } } diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 7ac3157e7a1..2d35ee8976e 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -176,6 +176,8 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) { return Attribute::NoAlias; case NoCapture: return Attribute::NoCapture; + case NoCfCheck: + return Attribute::NoCfCheck; case NoInline: return Attribute::NoInline; case NonNull: diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs index 5c5275b7cfb..6c9561925fe 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -212,7 +212,7 @@ impl DiagnosticDeriveBuilder { } NestedMeta::Meta(meta @ Meta::NameValue(_)) if !is_help_note_or_warn - && meta.path().segments.last().unwrap().ident.to_string() == "code" => + && meta.path().segments.last().unwrap().ident == "code" => { // don't error for valid follow-up attributes } diff --git a/compiler/rustc_macros/src/diagnostics/fluent.rs b/compiler/rustc_macros/src/diagnostics/fluent.rs index 1170d2b3c59..562d5e9f4d2 100644 --- a/compiler/rustc_macros/src/diagnostics/fluent.rs +++ b/compiler/rustc_macros/src/diagnostics/fluent.rs @@ -194,8 +194,8 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok let snake_name = Ident::new( // FIXME: should probably trim prefix, not replace all occurrences &name - .replace(&format!("{}-", res.ident).replace("_", "-"), "") - .replace("-", "_"), + .replace(&format!("{}-", res.ident).replace('_', "-"), "") + .replace('-', "_"), span, ); constants.extend(quote! { @@ -207,7 +207,7 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok }); for Attribute { id: Identifier { name: attr_name }, .. } in attributes { - let snake_name = Ident::new(&attr_name.replace("-", "_"), span); + let snake_name = Ident::new(&attr_name.replace('-', "_"), span); if !previous_attrs.insert(snake_name.clone()) { continue; } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index f0874f8f2da..aa5705d3fcd 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -951,6 +951,13 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { tcx.arena.alloc_from_iter(self.root.lib_features.decode(self)) } + /// Iterates over the stability implications in the given crate (when a `#[unstable]` attribute + /// has an `implied_by` meta item, then the mapping from the implied feature to the actual + /// feature is a stability implication). + fn get_stability_implications(self, tcx: TyCtxt<'tcx>) -> &'tcx [(Symbol, Symbol)] { + tcx.arena.alloc_from_iter(self.root.stability_implications.decode(self)) + } + /// Iterates over the language items in the given crate. fn get_lang_items(self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, usize)] { tcx.arena.alloc_from_iter( diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 565eec18ea9..65cae29c58d 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -291,6 +291,9 @@ provide! { <'tcx> tcx, def_id, other, cdata, tcx.arena.alloc_slice(&result) } defined_lib_features => { cdata.get_lib_features(tcx) } + stability_implications => { + cdata.get_stability_implications(tcx).iter().copied().collect() + } is_intrinsic => { cdata.get_is_intrinsic(def_id.index) } defined_lang_items => { cdata.get_lang_items(tcx) } diagnostic_items => { cdata.get_diagnostic_items() } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 8e973009777..50d983754e8 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -538,6 +538,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let lib_features = self.encode_lib_features(); let lib_feature_bytes = self.position() - i; + // Encode the stability implications. + i = self.position(); + let stability_implications = self.encode_stability_implications(); + let stability_implications_bytes = self.position() - i; + // Encode the language items. i = self.position(); let lang_items = self.encode_lang_items(); @@ -686,6 +691,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { crate_deps, dylib_dependency_formats, lib_features, + stability_implications, lang_items, diagnostic_items, lang_items_missing, @@ -710,6 +716,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let computed_total_bytes = preamble_bytes + dep_bytes + lib_feature_bytes + + stability_implications_bytes + lang_item_bytes + diagnostic_item_bytes + native_lib_bytes @@ -761,6 +768,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { p("preamble", preamble_bytes); p("dep", dep_bytes); p("lib feature", lib_feature_bytes); + p("stability_implications", stability_implications_bytes); p("lang item", lang_item_bytes); p("diagnostic item", diagnostic_item_bytes); p("native lib", native_lib_bytes); @@ -1777,6 +1785,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.lazy_array(lib_features.to_vec()) } + fn encode_stability_implications(&mut self) -> LazyArray<(Symbol, Symbol)> { + empty_proc_macro!(self); + let tcx = self.tcx; + let implications = tcx.stability_implications(LOCAL_CRATE); + self.lazy_array(implications.iter().map(|(k, v)| (*k, *v))) + } + fn encode_diagnostic_items(&mut self) -> LazyArray<(Symbol, DefIndex)> { empty_proc_macro!(self); let tcx = self.tcx; diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index af1c09f4ae8..0f291f92647 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -226,6 +226,7 @@ pub(crate) struct CrateRoot { crate_deps: LazyArray<CrateDep>, dylib_dependency_formats: LazyArray<Option<LinkagePreference>>, lib_features: LazyArray<(Symbol, Option<Symbol>)>, + stability_implications: LazyArray<(Symbol, Symbol)>, lang_items: LazyArray<(DefIndex, usize)>, lang_items_missing: LazyArray<lang_items::LangItem>, diagnostic_items: LazyArray<(Symbol, DefIndex)>, diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 661a9b1944c..b94de537dc8 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -55,6 +55,7 @@ macro_rules! arena_types { [] dtorck_constraint: rustc_middle::traits::query::DropckConstraint<'tcx>, [] candidate_step: rustc_middle::traits::query::CandidateStep<'tcx>, [] autoderef_bad_ty: rustc_middle::traits::query::MethodAutoderefBadTy<'tcx>, + [] query_region_constraints: rustc_middle::infer::canonical::QueryRegionConstraints<'tcx>, [] type_op_subtype: rustc_middle::infer::canonical::Canonical<'tcx, rustc_middle::infer::canonical::QueryResponse<'tcx, ()> diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 3a59b2069b3..0001e1aa53e 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -491,9 +491,7 @@ impl<'hir> Map<'hir> { } pub fn par_body_owners<F: Fn(LocalDefId) + Sync + Send>(self, f: F) { - use rustc_data_structures::sync::{par_iter, ParallelIterator}; - - par_iter(&self.tcx.hir_crate_items(()).body_owners[..]).for_each(|&def_id| f(def_id)); + par_for_each_in(&self.tcx.hir_crate_items(()).body_owners[..], |&def_id| f(def_id)); } pub fn ty_param_owner(self, def_id: LocalDefId) -> LocalDefId { diff --git a/compiler/rustc_middle/src/infer/mod.rs b/compiler/rustc_middle/src/infer/mod.rs index 55e00c4c0d8..8b2f9bdfd48 100644 --- a/compiler/rustc_middle/src/infer/mod.rs +++ b/compiler/rustc_middle/src/infer/mod.rs @@ -4,7 +4,7 @@ pub mod unify_key; use crate::ty::Region; use crate::ty::Ty; use rustc_data_structures::sync::Lrc; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::LocalDefId; use rustc_span::Span; /// Requires that `region` must be equal to one of the regions in `choice_regions`. @@ -16,7 +16,7 @@ use rustc_span::Span; #[derive(Debug, Clone, HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct MemberConstraint<'tcx> { /// The `DefId` of the opaque type causing this constraint: used for error reporting. - pub opaque_type_def_id: DefId, + pub opaque_type_def_id: LocalDefId, /// The span where the hidden type was instantiated. pub definition_span: Span, diff --git a/compiler/rustc_middle/src/middle/mod.rs b/compiler/rustc_middle/src/middle/mod.rs index fc35cafcc77..8dc68b1f5a8 100644 --- a/compiler/rustc_middle/src/middle/mod.rs +++ b/compiler/rustc_middle/src/middle/mod.rs @@ -3,14 +3,14 @@ pub mod dependency_format; pub mod exported_symbols; pub mod lang_items; pub mod lib_features { - use rustc_data_structures::fx::{FxHashMap, FxHashSet}; - use rustc_span::symbol::Symbol; + use rustc_data_structures::fx::FxHashMap; + use rustc_span::{symbol::Symbol, Span}; #[derive(HashStable, Debug)] pub struct LibFeatures { - // A map from feature to stabilisation version. - pub stable: FxHashMap<Symbol, Symbol>, - pub unstable: FxHashSet<Symbol>, + /// A map from feature to stabilisation version. + pub stable: FxHashMap<Symbol, (Symbol, Span)>, + pub unstable: FxHashMap<Symbol, Span>, } impl LibFeatures { @@ -18,8 +18,8 @@ pub mod lib_features { let mut all_features: Vec<_> = self .stable .iter() - .map(|(f, s)| (*f, Some(*s))) - .chain(self.unstable.iter().map(|f| (*f, None))) + .map(|(f, (s, _))| (*f, Some(*s))) + .chain(self.unstable.iter().map(|(f, _)| (*f, None))) .collect(); all_features.sort_unstable_by(|a, b| a.0.as_str().partial_cmp(b.0.as_str()).unwrap()); all_features diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 96e068a3601..0fbad3f0f0f 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -62,6 +62,19 @@ pub struct Index { pub stab_map: FxHashMap<LocalDefId, Stability>, pub const_stab_map: FxHashMap<LocalDefId, ConstStability>, pub depr_map: FxHashMap<LocalDefId, DeprecationEntry>, + /// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]` + /// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute + /// exists, then this map will have a `impliee -> implier` entry. + /// + /// This mapping is necessary unless both the `#[stable]` and `#[unstable]` attributes should + /// specify their implications (both `implies` and `implied_by`). If only one of the two + /// attributes do (as in the current implementation, `implied_by` in `#[unstable]`), then this + /// mapping is necessary for diagnostics. When a "unnecessary feature attribute" error is + /// reported, only the `#[stable]` attribute information is available, so the map is necessary + /// to know that the feature implies another feature. If it were reversed, and the `#[stable]` + /// attribute had an `implies` meta item, then a map would be necessary when avoiding a "use of + /// unstable feature" error for a feature that was implied. + pub implications: FxHashMap<Symbol, Symbol>, } impl Index { @@ -423,7 +436,9 @@ impl<'tcx> TyCtxt<'tcx> { match stability { Some(Stability { - level: attr::Unstable { reason, issue, is_soft }, feature, .. + level: attr::Unstable { reason, issue, is_soft, implied_by }, + feature, + .. }) => { if span.allows_unstable(feature) { debug!("stability: skipping span={:?} since it is internal", span); @@ -433,6 +448,13 @@ impl<'tcx> TyCtxt<'tcx> { return EvalResult::Allow; } + // If this item was previously part of a now-stabilized feature which is still + // active (i.e. the user hasn't removed the attribute for the stabilized feature + // yet) then allow use of this item. + if let Some(implied_by) = implied_by && self.features().active(implied_by) { + return EvalResult::Allow; + } + // When we're compiling the compiler itself we may pull in // crates from crates.io, but those crates may depend on other // crates also pulled in from crates.io. We want to ideally be diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index eed52ca3eea..db7e0fb8a3b 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -30,7 +30,7 @@ use crate::ty; // hashed. (see the `Hash` impl below for more details), so the impl is not derived. #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)] #[derive(HashStable)] -pub struct Allocation<Tag = AllocId, Extra = ()> { +pub struct Allocation<Prov = AllocId, Extra = ()> { /// The actual bytes of the allocation. /// Note that the bytes of a pointer represent the offset of the pointer. bytes: Box<[u8]>, @@ -38,7 +38,7 @@ pub struct Allocation<Tag = AllocId, Extra = ()> { /// Only the first byte of a pointer is inserted into the map; i.e., /// every entry in this map applies to `pointer_size` consecutive bytes starting /// at the given offset. - relocations: Relocations<Tag>, + relocations: Relocations<Prov>, /// Denotes which part of this allocation is initialized. init_mask: InitMask, /// The alignment of the allocation to detect unaligned reads. @@ -102,8 +102,8 @@ impl hash::Hash for Allocation { /// (`ConstAllocation`) are used quite a bit. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)] #[rustc_pass_by_value] -pub struct ConstAllocation<'tcx, Tag = AllocId, Extra = ()>( - pub Interned<'tcx, Allocation<Tag, Extra>>, +pub struct ConstAllocation<'tcx, Prov = AllocId, Extra = ()>( + pub Interned<'tcx, Allocation<Prov, Extra>>, ); impl<'tcx> fmt::Debug for ConstAllocation<'tcx> { @@ -114,8 +114,8 @@ impl<'tcx> fmt::Debug for ConstAllocation<'tcx> { } } -impl<'tcx, Tag, Extra> ConstAllocation<'tcx, Tag, Extra> { - pub fn inner(self) -> &'tcx Allocation<Tag, Extra> { +impl<'tcx, Prov, Extra> ConstAllocation<'tcx, Prov, Extra> { + pub fn inner(self) -> &'tcx Allocation<Prov, Extra> { self.0.0 } } @@ -200,7 +200,7 @@ impl AllocRange { } // The constructors are all without extra; the extra gets added by a machine hook later. -impl<Tag> Allocation<Tag> { +impl<Prov> Allocation<Prov> { /// Creates an allocation initialized by the given bytes pub fn from_bytes<'a>( slice: impl Into<Cow<'a, [u8]>>, @@ -256,14 +256,15 @@ impl<Tag> Allocation<Tag> { } impl Allocation { - /// Convert Tag and add Extra fields - pub fn convert_tag_add_extra<Tag, Extra, Err>( + /// Adjust allocation from the ones in tcx to a custom Machine instance + /// with a different Provenance and Extra type. + pub fn adjust_from_tcx<Prov, Extra, Err>( self, cx: &impl HasDataLayout, extra: Extra, - mut tagger: impl FnMut(Pointer<AllocId>) -> Result<Pointer<Tag>, Err>, - ) -> Result<Allocation<Tag, Extra>, Err> { - // Compute new pointer tags, which also adjusts the bytes. + mut adjust_ptr: impl FnMut(Pointer<AllocId>) -> Result<Pointer<Prov>, Err>, + ) -> Result<Allocation<Prov, Extra>, Err> { + // Compute new pointer provenance, which also adjusts the bytes. let mut bytes = self.bytes; let mut new_relocations = Vec::with_capacity(self.relocations.0.len()); let ptr_size = cx.data_layout().pointer_size.bytes_usize(); @@ -272,10 +273,10 @@ impl Allocation { let idx = offset.bytes_usize(); let ptr_bytes = &mut bytes[idx..idx + ptr_size]; let bits = read_target_uint(endian, ptr_bytes).unwrap(); - let (ptr_tag, ptr_offset) = - tagger(Pointer::new(alloc_id, Size::from_bytes(bits)))?.into_parts(); + let (ptr_prov, ptr_offset) = + adjust_ptr(Pointer::new(alloc_id, Size::from_bytes(bits)))?.into_parts(); write_target_uint(endian, ptr_bytes, ptr_offset.bytes().into()).unwrap(); - new_relocations.push((offset, ptr_tag)); + new_relocations.push((offset, ptr_prov)); } // Create allocation. Ok(Allocation { @@ -290,7 +291,7 @@ impl Allocation { } /// Raw accessors. Provide access to otherwise private bytes. -impl<Tag, Extra> Allocation<Tag, Extra> { +impl<Prov, Extra> Allocation<Prov, Extra> { pub fn len(&self) -> usize { self.bytes.len() } @@ -313,13 +314,13 @@ impl<Tag, Extra> Allocation<Tag, Extra> { } /// Returns the relocation list. - pub fn relocations(&self) -> &Relocations<Tag> { + pub fn relocations(&self) -> &Relocations<Prov> { &self.relocations } } /// Byte accessors. -impl<Tag: Provenance, Extra> Allocation<Tag, Extra> { +impl<Prov: Provenance, Extra> Allocation<Prov, Extra> { /// This is the entirely abstraction-violating way to just grab the raw bytes without /// caring about relocations. It just deduplicates some code between `read_scalar` /// and `get_bytes_internal`. @@ -413,7 +414,7 @@ impl<Tag: Provenance, Extra> Allocation<Tag, Extra> { } /// Reading and writing. -impl<Tag: Provenance, Extra> Allocation<Tag, Extra> { +impl<Prov: Provenance, Extra> Allocation<Prov, Extra> { /// Validates that `ptr.offset` and `ptr.offset + size` do not point to the middle of a /// relocation. If `allow_uninit`/`allow_ptr` is `false`, also enforces that the memory in the /// given range contains no uninitialized bytes/relocations. @@ -451,7 +452,7 @@ impl<Tag: Provenance, Extra> Allocation<Tag, Extra> { cx: &impl HasDataLayout, range: AllocRange, read_provenance: bool, - ) -> AllocResult<ScalarMaybeUninit<Tag>> { + ) -> AllocResult<ScalarMaybeUninit<Prov>> { if read_provenance { assert_eq!(range.size, cx.data_layout().pointer_size); } @@ -475,7 +476,7 @@ impl<Tag: Provenance, Extra> Allocation<Tag, Extra> { // If we are *not* reading a pointer, and we can just ignore relocations, // then do exactly that. - if !read_provenance && Tag::OFFSET_IS_ADDR { + if !read_provenance && Prov::OFFSET_IS_ADDR { // We just strip provenance. let bytes = self.get_bytes_even_more_internal(range); let bits = read_target_uint(cx.data_layout().endian, bytes).unwrap(); @@ -506,7 +507,7 @@ impl<Tag: Provenance, Extra> Allocation<Tag, Extra> { &mut self, cx: &impl HasDataLayout, range: AllocRange, - val: ScalarMaybeUninit<Tag>, + val: ScalarMaybeUninit<Prov>, ) -> AllocResult { assert!(self.mutability == Mutability::Mut); @@ -548,9 +549,9 @@ impl<Tag: Provenance, Extra> Allocation<Tag, Extra> { } /// Relocations. -impl<Tag: Copy, Extra> Allocation<Tag, Extra> { +impl<Prov: Copy, Extra> Allocation<Prov, Extra> { /// Returns all relocations overlapping with the given pointer-offset pair. - fn get_relocations(&self, cx: &impl HasDataLayout, range: AllocRange) -> &[(Size, Tag)] { + fn get_relocations(&self, cx: &impl HasDataLayout, range: AllocRange) -> &[(Size, Prov)] { // We have to go back `pointer_size - 1` bytes, as that one would still overlap with // the beginning of this range. let start = range.start.bytes().saturating_sub(cx.data_layout().pointer_size.bytes() - 1); @@ -580,7 +581,7 @@ impl<Tag: Copy, Extra> Allocation<Tag, Extra> { /// immediately in that case. fn clear_relocations(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult where - Tag: Provenance, + Prov: Provenance, { // Find the start and end of the given range and its outermost relocations. let (first, last) = { @@ -602,7 +603,7 @@ impl<Tag: Copy, Extra> Allocation<Tag, Extra> { // FIXME: Miri should preserve partial relocations; see // https://github.com/rust-lang/miri/issues/2181. if first < start { - if Tag::ERR_ON_PARTIAL_PTR_OVERWRITE { + if Prov::ERR_ON_PARTIAL_PTR_OVERWRITE { return Err(AllocError::PartialPointerOverwrite(first)); } warn!( @@ -611,7 +612,7 @@ impl<Tag: Copy, Extra> Allocation<Tag, Extra> { self.init_mask.set_range(first, start, false); } if last > end { - if Tag::ERR_ON_PARTIAL_PTR_OVERWRITE { + if Prov::ERR_ON_PARTIAL_PTR_OVERWRITE { return Err(AllocError::PartialPointerOverwrite( last - cx.data_layout().pointer_size, )); @@ -642,22 +643,22 @@ impl<Tag: Copy, Extra> Allocation<Tag, Extra> { /// "Relocations" stores the provenance information of pointers stored in memory. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] -pub struct Relocations<Tag = AllocId>(SortedMap<Size, Tag>); +pub struct Relocations<Prov = AllocId>(SortedMap<Size, Prov>); -impl<Tag> Relocations<Tag> { +impl<Prov> Relocations<Prov> { pub fn new() -> Self { Relocations(SortedMap::new()) } // The caller must guarantee that the given relocations are already sorted // by address and contain no duplicates. - pub fn from_presorted(r: Vec<(Size, Tag)>) -> Self { + pub fn from_presorted(r: Vec<(Size, Prov)>) -> Self { Relocations(SortedMap::from_presorted_elements(r)) } } -impl<Tag> Deref for Relocations<Tag> { - type Target = SortedMap<Size, Tag>; +impl<Prov> Deref for Relocations<Prov> { + type Target = SortedMap<Size, Prov>; fn deref(&self) -> &Self::Target { &self.0 @@ -667,18 +668,18 @@ impl<Tag> Deref for Relocations<Tag> { /// A partial, owned list of relocations to transfer into another allocation. /// /// Offsets are already adjusted to the destination allocation. -pub struct AllocationRelocations<Tag> { - dest_relocations: Vec<(Size, Tag)>, +pub struct AllocationRelocations<Prov> { + dest_relocations: Vec<(Size, Prov)>, } -impl<Tag: Copy, Extra> Allocation<Tag, Extra> { +impl<Prov: Copy, Extra> Allocation<Prov, Extra> { pub fn prepare_relocation_copy( &self, cx: &impl HasDataLayout, src: AllocRange, dest: Size, count: u64, - ) -> AllocationRelocations<Tag> { + ) -> AllocationRelocations<Prov> { let relocations = self.get_relocations(cx, src); if relocations.is_empty() { return AllocationRelocations { dest_relocations: Vec::new() }; @@ -688,7 +689,7 @@ impl<Tag: Copy, Extra> Allocation<Tag, Extra> { let mut new_relocations = Vec::with_capacity(relocations.len() * (count as usize)); // If `count` is large, this is rather wasteful -- we are allocating a big array here, which - // is mostly filled with redundant information since it's just N copies of the same `Tag`s + // is mostly filled with redundant information since it's just N copies of the same `Prov`s // at slightly adjusted offsets. The reason we do this is so that in `mark_relocation_range` // we can use `insert_presorted`. That wouldn't work with an `Iterator` that just produces // the right sequence of relocations for all N copies. @@ -713,7 +714,7 @@ impl<Tag: Copy, Extra> Allocation<Tag, Extra> { /// /// This is dangerous to use as it can violate internal `Allocation` invariants! /// It only exists to support an efficient implementation of `mem_copy_repeatedly`. - pub fn mark_relocation_range(&mut self, relocations: AllocationRelocations<Tag>) { + pub fn mark_relocation_range(&mut self, relocations: AllocationRelocations<Prov>) { self.relocations.0.insert_presorted(relocations.dest_relocations); } } @@ -1178,7 +1179,7 @@ impl<'a> Iterator for InitChunkIter<'a> { } /// Uninitialized bytes. -impl<Tag: Copy, Extra> Allocation<Tag, Extra> { +impl<Prov: Copy, Extra> Allocation<Prov, Extra> { /// Checks whether the given range is entirely initialized. /// /// Returns `Ok(())` if it's initialized. Otherwise returns the range of byte @@ -1226,7 +1227,7 @@ impl InitMaskCompressed { } /// Transferring the initialization mask to other allocations. -impl<Tag, Extra> Allocation<Tag, Extra> { +impl<Prov, Extra> Allocation<Prov, Extra> { /// Creates a run-length encoding of the initialization mask; panics if range is empty. /// /// This is essentially a more space-efficient version of diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 795f23edb31..cecb55578d3 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -1,7 +1,7 @@ use super::{AllocId, AllocRange, ConstAlloc, Pointer, Scalar}; use crate::mir::interpret::ConstValue; -use crate::ty::{layout, query::TyCtxtAt, tls, FnSig, Ty, ValTree}; +use crate::ty::{layout, query::TyCtxtAt, tls, Ty, ValTree}; use rustc_data_structures::sync::Lock; use rustc_errors::{pluralize, struct_span_err, DiagnosticBuilder, ErrorGuaranteed}; @@ -219,7 +219,7 @@ pub struct ScalarSizeMismatch { } /// Error information for when the program caused Undefined Behavior. -pub enum UndefinedBehaviorInfo<'tcx> { +pub enum UndefinedBehaviorInfo { /// Free-form case. Only for errors that are never caught! Ub(String), /// Unreachable code was executed. @@ -241,12 +241,6 @@ pub enum UndefinedBehaviorInfo<'tcx> { PointerArithOverflow, /// Invalid metadata in a wide pointer (using `str` to avoid allocations). InvalidMeta(&'static str), - /// Invalid drop function in vtable. - InvalidVtableDropFn(FnSig<'tcx>), - /// Invalid size in a vtable: too large. - InvalidVtableSize, - /// Invalid alignment in a vtable: too large, or not a power of 2. - InvalidVtableAlignment(String), /// Reading a C string that does not end within its allocation. UnterminatedCString(Pointer), /// Dereferencing a dangling pointer after it got freed. @@ -271,6 +265,8 @@ pub enum UndefinedBehaviorInfo<'tcx> { WriteToReadOnly(AllocId), // Trying to access the data behind a function pointer. DerefFunctionPointer(AllocId), + // Trying to access the data behind a vtable pointer. + DerefVTablePointer(AllocId), /// The value validity check found a problem. /// Should only be thrown by `validity.rs` and always point out which part of the value /// is the problem. @@ -288,6 +284,8 @@ pub enum UndefinedBehaviorInfo<'tcx> { InvalidTag(Scalar), /// Using a pointer-not-to-a-function as function pointer. InvalidFunctionPointer(Pointer), + /// Using a pointer-not-to-a-vtable as vtable pointer. + InvalidVTablePointer(Pointer), /// Using a string that is not valid UTF-8, InvalidStr(std::str::Utf8Error), /// Using uninitialized data where it is not allowed. @@ -300,7 +298,7 @@ pub enum UndefinedBehaviorInfo<'tcx> { UninhabitedEnumVariantWritten, } -impl fmt::Display for UndefinedBehaviorInfo<'_> { +impl fmt::Display for UndefinedBehaviorInfo { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use UndefinedBehaviorInfo::*; match self { @@ -315,14 +313,6 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> { RemainderOverflow => write!(f, "overflow in signed remainder (dividing MIN by -1)"), PointerArithOverflow => write!(f, "overflowing in-bounds pointer arithmetic"), InvalidMeta(msg) => write!(f, "invalid metadata in wide pointer: {msg}"), - InvalidVtableDropFn(sig) => write!( - f, - "invalid drop function signature: got {sig}, expected exactly one argument which must be a pointer type", - ), - InvalidVtableSize => { - write!(f, "invalid vtable: size is bigger than largest supported object") - } - InvalidVtableAlignment(msg) => write!(f, "invalid vtable: alignment {msg}"), UnterminatedCString(p) => write!( f, "reading a null-terminated string starting at {p:?} with no null found before end of allocation", @@ -359,6 +349,7 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> { ), WriteToReadOnly(a) => write!(f, "writing to {a:?} which is read-only"), DerefFunctionPointer(a) => write!(f, "accessing {a:?} which contains a function"), + DerefVTablePointer(a) => write!(f, "accessing {a:?} which contains a vtable"), ValidationFailure { path: None, msg } => { write!(f, "constructing invalid value: {msg}") } @@ -375,6 +366,9 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> { InvalidFunctionPointer(p) => { write!(f, "using {p:?} as function pointer but it does not point to a function") } + InvalidVTablePointer(p) => { + write!(f, "using {p:?} as vtable pointer but it does not point to a vtable") + } InvalidStr(err) => write!(f, "this string is not valid UTF-8: {err}"), InvalidUninitBytes(Some((alloc, info))) => write!( f, @@ -494,7 +488,7 @@ impl dyn MachineStopType { pub enum InterpError<'tcx> { /// The program caused undefined behavior. - UndefinedBehavior(UndefinedBehaviorInfo<'tcx>), + UndefinedBehavior(UndefinedBehaviorInfo), /// The program did something the interpreter does not support (some of these *might* be UB /// but the interpreter is not sure). Unsupported(UnsupportedOpInfo), diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 698024b2330..967f8ece16c 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -196,6 +196,7 @@ impl fmt::Debug for AllocId { enum AllocDiscriminant { Alloc, Fn, + VTable, Static, } @@ -215,6 +216,12 @@ pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>>( AllocDiscriminant::Fn.encode(encoder); fn_instance.encode(encoder); } + GlobalAlloc::VTable(ty, poly_trait_ref) => { + trace!("encoding {:?} with {ty:#?}, {poly_trait_ref:#?}", alloc_id); + AllocDiscriminant::VTable.encode(encoder); + ty.encode(encoder); + poly_trait_ref.encode(encoder); + } GlobalAlloc::Static(did) => { assert!(!tcx.is_thread_local_static(did)); // References to statics doesn't need to know about their allocations, @@ -305,7 +312,9 @@ impl<'s> AllocDecodingSession<'s> { State::InProgress(TinyList::new_single(self.session_id), alloc_id); Some(alloc_id) } - AllocDiscriminant::Fn | AllocDiscriminant::Static => { + AllocDiscriminant::Fn + | AllocDiscriminant::Static + | AllocDiscriminant::VTable => { // Fns and statics cannot be cyclic, and their `AllocId` // is determined later by interning. *entry = @@ -355,6 +364,16 @@ impl<'s> AllocDecodingSession<'s> { let alloc_id = decoder.interner().create_fn_alloc(instance); alloc_id } + AllocDiscriminant::VTable => { + assert!(alloc_id.is_none()); + trace!("creating vtable alloc ID"); + let ty = <Ty<'_> as Decodable<D>>::decode(decoder); + let poly_trait_ref = + <Option<ty::PolyExistentialTraitRef<'_>> as Decodable<D>>::decode(decoder); + trace!("decoded vtable alloc instance: {ty:?}, {poly_trait_ref:?}"); + let alloc_id = decoder.interner().create_vtable_alloc(ty, poly_trait_ref); + alloc_id + } AllocDiscriminant::Static => { assert!(alloc_id.is_none()); trace!("creating extern static alloc ID"); @@ -380,6 +399,8 @@ impl<'s> AllocDecodingSession<'s> { pub enum GlobalAlloc<'tcx> { /// The alloc ID is used as a function pointer. Function(Instance<'tcx>), + /// This alloc ID points to a symbolic (not-reified) vtable. + VTable(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), /// The alloc ID points to a "lazy" static variable that did not get computed (yet). /// This is also used to break the cycle in recursive statics. Static(DefId), @@ -407,6 +428,16 @@ impl<'tcx> GlobalAlloc<'tcx> { _ => bug!("expected function, got {:?}", self), } } + + /// Panics if the `GlobalAlloc` is not `GlobalAlloc::VTable` + #[track_caller] + #[inline] + pub fn unwrap_vtable(&self) -> (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>) { + match *self { + GlobalAlloc::VTable(ty, poly_trait_ref) => (ty, poly_trait_ref), + _ => bug!("expected vtable, got {:?}", self), + } + } } pub(crate) struct AllocMap<'tcx> { @@ -454,12 +485,12 @@ impl<'tcx> TyCtxt<'tcx> { } /// Reserves a new ID *if* this allocation has not been dedup-reserved before. - /// Should only be used for function pointers and statics, we don't want - /// to dedup IDs for "real" memory! + /// Should only be used for "symbolic" allocations (function pointers, vtables, statics), we + /// don't want to dedup IDs for "real" memory! fn reserve_and_set_dedup(self, alloc: GlobalAlloc<'tcx>) -> AllocId { let mut alloc_map = self.alloc_map.lock(); match alloc { - GlobalAlloc::Function(..) | GlobalAlloc::Static(..) => {} + GlobalAlloc::Function(..) | GlobalAlloc::Static(..) | GlobalAlloc::VTable(..) => {} GlobalAlloc::Memory(..) => bug!("Trying to dedup-reserve memory with real data!"), } if let Some(&alloc_id) = alloc_map.dedup.get(&alloc) { @@ -504,6 +535,15 @@ impl<'tcx> TyCtxt<'tcx> { } } + /// Generates an `AllocId` for a (symbolic, not-reified) vtable. Will get deduplicated. + pub fn create_vtable_alloc( + self, + ty: Ty<'tcx>, + poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>, + ) -> AllocId { + self.reserve_and_set_dedup(GlobalAlloc::VTable(ty, poly_trait_ref)) + } + /// Interns the `Allocation` and return a new `AllocId`, even if there's already an identical /// `Allocation` with a different `AllocId`. /// Statics with identical content will still point to the same `Allocation`, i.e., @@ -521,7 +561,7 @@ impl<'tcx> TyCtxt<'tcx> { /// This function exists to allow const eval to detect the difference between evaluation- /// local dangling pointers and allocations in constants/statics. #[inline] - pub fn get_global_alloc(self, id: AllocId) -> Option<GlobalAlloc<'tcx>> { + pub fn try_get_global_alloc(self, id: AllocId) -> Option<GlobalAlloc<'tcx>> { self.alloc_map.lock().alloc_map.get(&id).cloned() } @@ -532,7 +572,7 @@ impl<'tcx> TyCtxt<'tcx> { /// ids), this function is frequently used throughout rustc, but should not be used within /// the miri engine. pub fn global_alloc(self, id: AllocId) -> GlobalAlloc<'tcx> { - match self.get_global_alloc(id) { + match self.try_get_global_alloc(id) { Some(alloc) => alloc, None => bug!("could not find allocation for {id:?}"), } diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs index d4cdf45d186..384954cbbd5 100644 --- a/compiler/rustc_middle/src/mir/interpret/pointer.rs +++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs @@ -159,34 +159,34 @@ impl Provenance for AllocId { /// Pointers are "tagged" with provenance information; typically the `AllocId` they belong to. #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, TyEncodable, TyDecodable, Hash)] #[derive(HashStable)] -pub struct Pointer<Tag = AllocId> { - pub(super) offset: Size, // kept private to avoid accidental misinterpretation (meaning depends on `Tag` type) - pub provenance: Tag, +pub struct Pointer<Prov = AllocId> { + pub(super) offset: Size, // kept private to avoid accidental misinterpretation (meaning depends on `Prov` type) + pub provenance: Prov, } static_assert_size!(Pointer, 16); -// `Option<Tag>` pointers are also passed around quite a bit +// `Option<Prov>` pointers are also passed around quite a bit // (but not stored in permanent machine state). static_assert_size!(Pointer<Option<AllocId>>, 16); // We want the `Debug` output to be readable as it is used by `derive(Debug)` for // all the Miri types. -impl<Tag: Provenance> fmt::Debug for Pointer<Tag> { +impl<Prov: Provenance> fmt::Debug for Pointer<Prov> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Provenance::fmt(self, f) } } -impl<Tag: Provenance> fmt::Debug for Pointer<Option<Tag>> { +impl<Prov: Provenance> fmt::Debug for Pointer<Option<Prov>> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.provenance { - Some(tag) => Provenance::fmt(&Pointer::new(tag, self.offset), f), + Some(prov) => Provenance::fmt(&Pointer::new(prov, self.offset), f), None => write!(f, "{:#x}[noalloc]", self.offset.bytes()), } } } -impl<Tag: Provenance> fmt::Display for Pointer<Option<Tag>> { +impl<Prov: Provenance> fmt::Display for Pointer<Option<Prov>> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if self.provenance.is_none() && self.offset.bytes() == 0 { write!(f, "null pointer") @@ -204,38 +204,38 @@ impl From<AllocId> for Pointer { } } -impl<Tag> From<Pointer<Tag>> for Pointer<Option<Tag>> { +impl<Prov> From<Pointer<Prov>> for Pointer<Option<Prov>> { #[inline(always)] - fn from(ptr: Pointer<Tag>) -> Self { - let (tag, offset) = ptr.into_parts(); - Pointer::new(Some(tag), offset) + fn from(ptr: Pointer<Prov>) -> Self { + let (prov, offset) = ptr.into_parts(); + Pointer::new(Some(prov), offset) } } -impl<Tag> Pointer<Option<Tag>> { - /// Convert this pointer that *might* have a tag into a pointer that *definitely* has a tag, or - /// an absolute address. +impl<Prov> Pointer<Option<Prov>> { + /// Convert this pointer that *might* have a provenance into a pointer that *definitely* has a + /// provenance, or an absolute address. /// /// This is rarely what you want; call `ptr_try_get_alloc_id` instead. - pub fn into_pointer_or_addr(self) -> Result<Pointer<Tag>, Size> { + pub fn into_pointer_or_addr(self) -> Result<Pointer<Prov>, Size> { match self.provenance { - Some(tag) => Ok(Pointer::new(tag, self.offset)), + Some(prov) => Ok(Pointer::new(prov, self.offset)), None => Err(self.offset), } } /// Returns the absolute address the pointer points to. - /// Only works if Tag::OFFSET_IS_ADDR is true! + /// Only works if Prov::OFFSET_IS_ADDR is true! pub fn addr(self) -> Size where - Tag: Provenance, + Prov: Provenance, { - assert!(Tag::OFFSET_IS_ADDR); + assert!(Prov::OFFSET_IS_ADDR); self.offset } } -impl<Tag> Pointer<Option<Tag>> { +impl<Prov> Pointer<Option<Prov>> { #[inline(always)] pub fn from_addr(addr: u64) -> Self { Pointer { provenance: None, offset: Size::from_bytes(addr) } @@ -247,21 +247,21 @@ impl<Tag> Pointer<Option<Tag>> { } } -impl<'tcx, Tag> Pointer<Tag> { +impl<'tcx, Prov> Pointer<Prov> { #[inline(always)] - pub fn new(provenance: Tag, offset: Size) -> Self { + pub fn new(provenance: Prov, offset: Size) -> Self { Pointer { provenance, offset } } - /// Obtain the constituents of this pointer. Not that the meaning of the offset depends on the type `Tag`! + /// Obtain the constituents of this pointer. Not that the meaning of the offset depends on the type `Prov`! /// This function must only be used in the implementation of `Machine::ptr_get_alloc`, /// and when a `Pointer` is taken apart to be stored efficiently in an `Allocation`. #[inline(always)] - pub fn into_parts(self) -> (Tag, Size) { + pub fn into_parts(self) -> (Prov, Size) { (self.provenance, self.offset) } - pub fn map_provenance(self, f: impl FnOnce(Tag) -> Tag) -> Self { + pub fn map_provenance(self, f: impl FnOnce(Prov) -> Prov) -> Self { Pointer { provenance: f(self.provenance), ..self } } diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index 22bbe29c105..17088cf13a5 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -126,7 +126,7 @@ impl<'tcx> ConstValue<'tcx> { /// Do *not* match on a `Scalar`! Use the various `to_*` methods instead. #[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, TyEncodable, TyDecodable, Hash)] #[derive(HashStable)] -pub enum Scalar<Tag = AllocId> { +pub enum Scalar<Prov = AllocId> { /// The raw bytes of a simple value. Int(ScalarInt), @@ -137,7 +137,7 @@ pub enum Scalar<Tag = AllocId> { /// We also store the size of the pointer, such that a `Scalar` always knows how big it is. /// The size is always the pointer size of the current target, but this is not information /// that we always have readily available. - Ptr(Pointer<Tag>, u8), + Ptr(Pointer<Prov>, u8), } #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] @@ -145,7 +145,7 @@ static_assert_size!(Scalar, 24); // We want the `Debug` output to be readable as it is used by `derive(Debug)` for // all the Miri types. -impl<Tag: Provenance> fmt::Debug for Scalar<Tag> { +impl<Prov: Provenance> fmt::Debug for Scalar<Prov> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Scalar::Ptr(ptr, _size) => write!(f, "{:?}", ptr), @@ -154,7 +154,7 @@ impl<Tag: Provenance> fmt::Debug for Scalar<Tag> { } } -impl<Tag: Provenance> fmt::Display for Scalar<Tag> { +impl<Prov: Provenance> fmt::Display for Scalar<Prov> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Scalar::Ptr(ptr, _size) => write!(f, "pointer to {:?}", ptr), @@ -163,7 +163,7 @@ impl<Tag: Provenance> fmt::Display for Scalar<Tag> { } } -impl<Tag: Provenance> fmt::LowerHex for Scalar<Tag> { +impl<Prov: Provenance> fmt::LowerHex for Scalar<Prov> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Scalar::Ptr(ptr, _size) => write!(f, "pointer to {:?}", ptr), @@ -172,37 +172,38 @@ impl<Tag: Provenance> fmt::LowerHex for Scalar<Tag> { } } -impl<Tag> From<Single> for Scalar<Tag> { +impl<Prov> From<Single> for Scalar<Prov> { #[inline(always)] fn from(f: Single) -> Self { Scalar::from_f32(f) } } -impl<Tag> From<Double> for Scalar<Tag> { +impl<Prov> From<Double> for Scalar<Prov> { #[inline(always)] fn from(f: Double) -> Self { Scalar::from_f64(f) } } -impl<Tag> From<ScalarInt> for Scalar<Tag> { +impl<Prov> From<ScalarInt> for Scalar<Prov> { #[inline(always)] fn from(ptr: ScalarInt) -> Self { Scalar::Int(ptr) } } -impl<Tag> Scalar<Tag> { +impl<Prov> Scalar<Prov> { #[inline(always)] - pub fn from_pointer(ptr: Pointer<Tag>, cx: &impl HasDataLayout) -> Self { + pub fn from_pointer(ptr: Pointer<Prov>, cx: &impl HasDataLayout) -> Self { Scalar::Ptr(ptr, u8::try_from(cx.pointer_size().bytes()).unwrap()) } - /// Create a Scalar from a pointer with an `Option<_>` tag (where `None` represents a plain integer). - pub fn from_maybe_pointer(ptr: Pointer<Option<Tag>>, cx: &impl HasDataLayout) -> Self { + /// Create a Scalar from a pointer with an `Option<_>` provenance (where `None` represents a + /// plain integer / "invalid" pointer). + pub fn from_maybe_pointer(ptr: Pointer<Option<Prov>>, cx: &impl HasDataLayout) -> Self { match ptr.into_parts() { - (Some(tag), offset) => Scalar::from_pointer(Pointer::new(tag, offset), cx), + (Some(prov), offset) => Scalar::from_pointer(Pointer::new(prov, offset), cx), (None, offset) => { Scalar::Int(ScalarInt::try_from_uint(offset.bytes(), cx.pointer_size()).unwrap()) } @@ -310,7 +311,7 @@ impl<Tag> Scalar<Tag> { pub fn to_bits_or_ptr_internal( self, target_size: Size, - ) -> Result<Result<u128, Pointer<Tag>>, ScalarSizeMismatch> { + ) -> Result<Result<u128, Pointer<Prov>>, ScalarSizeMismatch> { assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST"); Ok(match self { Scalar::Int(int) => Ok(int.to_bits(target_size).map_err(|size| { @@ -329,7 +330,7 @@ impl<Tag> Scalar<Tag> { } } -impl<'tcx, Tag: Provenance> Scalar<Tag> { +impl<'tcx, Prov: Provenance> Scalar<Prov> { /// Fundamental scalar-to-int (cast) operation. Many convenience wrappers exist below, that you /// likely want to use instead. /// @@ -341,13 +342,13 @@ impl<'tcx, Tag: Provenance> Scalar<Tag> { match self { Scalar::Int(int) => Ok(int), Scalar::Ptr(ptr, sz) => { - if Tag::OFFSET_IS_ADDR { + if Prov::OFFSET_IS_ADDR { Ok(ScalarInt::try_from_uint(ptr.offset.bytes(), Size::from_bytes(sz)).unwrap()) } else { // We know `offset` is relative, since `OFFSET_IS_ADDR == false`. - let (tag, offset) = ptr.into_parts(); + let (prov, offset) = ptr.into_parts(); // Because `OFFSET_IS_ADDR == false`, this unwrap can never fail. - Err(Scalar::Ptr(Pointer::new(tag.get_alloc_id().unwrap(), offset), sz)) + Err(Scalar::Ptr(Pointer::new(prov.get_alloc_id().unwrap(), offset), sz)) } } } @@ -489,24 +490,24 @@ impl<'tcx, Tag: Provenance> Scalar<Tag> { } #[derive(Clone, Copy, Eq, PartialEq, TyEncodable, TyDecodable, HashStable, Hash)] -pub enum ScalarMaybeUninit<Tag = AllocId> { - Scalar(Scalar<Tag>), +pub enum ScalarMaybeUninit<Prov = AllocId> { + Scalar(Scalar<Prov>), Uninit, } #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] static_assert_size!(ScalarMaybeUninit, 24); -impl<Tag> From<Scalar<Tag>> for ScalarMaybeUninit<Tag> { +impl<Prov> From<Scalar<Prov>> for ScalarMaybeUninit<Prov> { #[inline(always)] - fn from(s: Scalar<Tag>) -> Self { + fn from(s: Scalar<Prov>) -> Self { ScalarMaybeUninit::Scalar(s) } } // We want the `Debug` output to be readable as it is used by `derive(Debug)` for // all the Miri types. -impl<Tag: Provenance> fmt::Debug for ScalarMaybeUninit<Tag> { +impl<Prov: Provenance> fmt::Debug for ScalarMaybeUninit<Prov> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { ScalarMaybeUninit::Uninit => write!(f, "<uninitialized>"), @@ -515,7 +516,7 @@ impl<Tag: Provenance> fmt::Debug for ScalarMaybeUninit<Tag> { } } -impl<Tag: Provenance> fmt::LowerHex for ScalarMaybeUninit<Tag> { +impl<Prov: Provenance> fmt::LowerHex for ScalarMaybeUninit<Prov> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { ScalarMaybeUninit::Uninit => write!(f, "uninitialized bytes"), @@ -524,19 +525,19 @@ impl<Tag: Provenance> fmt::LowerHex for ScalarMaybeUninit<Tag> { } } -impl<Tag> ScalarMaybeUninit<Tag> { +impl<Prov> ScalarMaybeUninit<Prov> { #[inline] - pub fn from_pointer(ptr: Pointer<Tag>, cx: &impl HasDataLayout) -> Self { + pub fn from_pointer(ptr: Pointer<Prov>, cx: &impl HasDataLayout) -> Self { ScalarMaybeUninit::Scalar(Scalar::from_pointer(ptr, cx)) } #[inline] - pub fn from_maybe_pointer(ptr: Pointer<Option<Tag>>, cx: &impl HasDataLayout) -> Self { + pub fn from_maybe_pointer(ptr: Pointer<Option<Prov>>, cx: &impl HasDataLayout) -> Self { ScalarMaybeUninit::Scalar(Scalar::from_maybe_pointer(ptr, cx)) } #[inline] - pub fn check_init<'tcx>(self) -> InterpResult<'tcx, Scalar<Tag>> { + pub fn check_init<'tcx>(self) -> InterpResult<'tcx, Scalar<Prov>> { match self { ScalarMaybeUninit::Scalar(scalar) => Ok(scalar), ScalarMaybeUninit::Uninit => throw_ub!(InvalidUninitBytes(None)), @@ -544,7 +545,7 @@ impl<Tag> ScalarMaybeUninit<Tag> { } } -impl<'tcx, Tag: Provenance> ScalarMaybeUninit<Tag> { +impl<'tcx, Prov: Provenance> ScalarMaybeUninit<Prov> { #[inline(always)] pub fn to_bool(self) -> InterpResult<'tcx, bool> { self.check_init()?.to_bool() diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 0b5d23be58d..702cc48ff7b 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1397,7 +1397,6 @@ impl<V, T> ProjectionElem<V, T> { Self::Field(_, _) | Self::Index(_) - | Self::OpaqueCast(_) | Self::ConstantIndex { .. } | Self::Subslice { .. } | Self::Downcast(_, _) => false, @@ -1575,9 +1574,7 @@ impl Debug for Place<'_> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { for elem in self.projection.iter().rev() { match elem { - ProjectionElem::OpaqueCast(_) - | ProjectionElem::Downcast(_, _) - | ProjectionElem::Field(_, _) => { + ProjectionElem::Downcast(_, _) | ProjectionElem::Field(_, _) => { write!(fmt, "(").unwrap(); } ProjectionElem::Deref => { @@ -1593,9 +1590,6 @@ impl Debug for Place<'_> { for elem in self.projection.iter() { match elem { - ProjectionElem::OpaqueCast(ty) => { - write!(fmt, " as {})", ty)?; - } ProjectionElem::Downcast(Some(name), _index) => { write!(fmt, " as {})", name)?; } @@ -1668,6 +1662,22 @@ impl SourceScope { ClearCrossCrate::Clear => None, } } + + /// The instance this source scope was inlined from, if any. + #[inline] + pub fn inlined_instance<'tcx>( + self, + source_scopes: &IndexVec<SourceScope, SourceScopeData<'tcx>>, + ) -> Option<ty::Instance<'tcx>> { + let scope_data = &source_scopes[self]; + if let Some((inlined_instance, _)) = scope_data.inlined { + Some(inlined_instance) + } else if let Some(inlined_scope) = scope_data.inlined_parent_scope { + Some(source_scopes[inlined_scope].inlined.unwrap().0) + } else { + None + } + } } #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 8b51c5b3da5..21ae121e1ce 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -362,7 +362,7 @@ impl<'tcx> CodegenUnit<'tcx> { // the codegen tests and can even make item order // unstable. InstanceDef::Item(def) => def.did.as_local().map(Idx::index), - InstanceDef::VtableShim(..) + InstanceDef::VTableShim(..) | InstanceDef::ReifyShim(..) | InstanceDef::Intrinsic(..) | InstanceDef::FnPtrShim(..) diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 970043d427f..78b5131bac6 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -720,11 +720,17 @@ pub fn write_allocations<'tcx>( write!(w, "{}", display_allocation(tcx, alloc.inner())) }; write!(w, "\n{id:?}")?; - match tcx.get_global_alloc(id) { + match tcx.try_get_global_alloc(id) { // This can't really happen unless there are bugs, but it doesn't cost us anything to // gracefully handle it and allow buggy rustc to be debugged via allocation printing. None => write!(w, " (deallocated)")?, Some(GlobalAlloc::Function(inst)) => write!(w, " (fn: {inst})")?, + Some(GlobalAlloc::VTable(ty, Some(trait_ref))) => { + write!(w, " (vtable: impl {trait_ref} for {ty})")? + } + Some(GlobalAlloc::VTable(ty, None)) => { + write!(w, " (vtable: impl <auto trait> for {ty})")? + } Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => { match tcx.eval_static_initializer(did) { Ok(alloc) => { @@ -767,21 +773,21 @@ pub fn write_allocations<'tcx>( /// After the hex dump, an ascii dump follows, replacing all unprintable characters (control /// characters or characters whose value is larger than 127) with a `.` /// This also prints relocations adequately. -pub fn display_allocation<'a, 'tcx, Tag, Extra>( +pub fn display_allocation<'a, 'tcx, Prov, Extra>( tcx: TyCtxt<'tcx>, - alloc: &'a Allocation<Tag, Extra>, -) -> RenderAllocation<'a, 'tcx, Tag, Extra> { + alloc: &'a Allocation<Prov, Extra>, +) -> RenderAllocation<'a, 'tcx, Prov, Extra> { RenderAllocation { tcx, alloc } } #[doc(hidden)] -pub struct RenderAllocation<'a, 'tcx, Tag, Extra> { +pub struct RenderAllocation<'a, 'tcx, Prov, Extra> { tcx: TyCtxt<'tcx>, - alloc: &'a Allocation<Tag, Extra>, + alloc: &'a Allocation<Prov, Extra>, } -impl<'a, 'tcx, Tag: Provenance, Extra> std::fmt::Display - for RenderAllocation<'a, 'tcx, Tag, Extra> +impl<'a, 'tcx, Prov: Provenance, Extra> std::fmt::Display + for RenderAllocation<'a, 'tcx, Prov, Extra> { fn fmt(&self, w: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let RenderAllocation { tcx, alloc } = *self; @@ -825,9 +831,9 @@ fn write_allocation_newline( /// The `prefix` argument allows callers to add an arbitrary prefix before each line (even if there /// is only one line). Note that your prefix should contain a trailing space as the lines are /// printed directly after it. -fn write_allocation_bytes<'tcx, Tag: Provenance, Extra>( +fn write_allocation_bytes<'tcx, Prov: Provenance, Extra>( tcx: TyCtxt<'tcx>, - alloc: &Allocation<Tag, Extra>, + alloc: &Allocation<Prov, Extra>, w: &mut dyn std::fmt::Write, prefix: &str, ) -> std::fmt::Result { @@ -861,7 +867,7 @@ fn write_allocation_bytes<'tcx, Tag: Provenance, Extra>( if i != line_start { write!(w, " ")?; } - if let Some(&tag) = alloc.relocations().get(&i) { + if let Some(&prov) = alloc.relocations().get(&i) { // Memory with a relocation must be defined assert!(alloc.init_mask().is_range_initialized(i, i + ptr_size).is_ok()); let j = i.bytes_usize(); @@ -870,7 +876,7 @@ fn write_allocation_bytes<'tcx, Tag: Provenance, Extra>( let offset = read_target_uint(tcx.data_layout.endian, offset).unwrap(); let offset = Size::from_bytes(offset); let relocation_width = |bytes| bytes * 3; - let ptr = Pointer::new(tag, offset); + let ptr = Pointer::new(prov, offset); let mut target = format!("{:?}", ptr); if target.len() > relocation_width(ptr_size.bytes_usize() - 1) { // This is too long, try to save some space. diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 6a6ed3dc728..dd9f8795f94 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -2,7 +2,7 @@ use crate::mir::{Body, ConstantKind, Promoted}; use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt}; -use rustc_data_structures::stable_map::FxHashMap; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::vec_map::VecMap; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; @@ -235,7 +235,7 @@ pub struct BorrowCheckResult<'tcx> { /// All the opaque types that are restricted to concrete types /// by this function. Unlike the value in `TypeckResults`, this has /// unerased regions. - pub concrete_opaque_types: VecMap<DefId, OpaqueHiddenType<'tcx>>, + pub concrete_opaque_types: VecMap<LocalDefId, OpaqueHiddenType<'tcx>>, pub closure_requirements: Option<ClosureRegionRequirements<'tcx>>, pub used_mut_upvars: SmallVec<[Field; 8]>, pub tainted_by_errors: Option<ErrorGuaranteed>, diff --git a/compiler/rustc_middle/src/mir/switch_sources.rs b/compiler/rustc_middle/src/mir/switch_sources.rs index d1f3e6b6fe6..b91c0c25782 100644 --- a/compiler/rustc_middle/src/mir/switch_sources.rs +++ b/compiler/rustc_middle/src/mir/switch_sources.rs @@ -1,8 +1,8 @@ //! Lazily compute the inverse of each `SwitchInt`'s switch targets. Modeled after //! `Predecessors`/`PredecessorCache`. +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::stable_map::FxHashMap; use rustc_data_structures::sync::OnceCell; use rustc_index::vec::IndexVec; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 263c2ca3c70..510316c778b 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -754,9 +754,6 @@ pub type AssertMessage<'tcx> = AssertKind<Operand<'tcx>>; /// generator has more than one variant, the parent place's variant index must be set, indicating /// which variant is being used. If it has just one variant, the variant index may or may not be /// included - the single possible variant is inferred if it is not included. -/// - [`OpaqueCast`](ProjectionElem::OpaqueCast): This projection changes the place's type to the -/// given one, and makes no other changes. A `OpaqueCast` projection on any type other than an -/// opaque type from the current crate is not well-formed. /// - [`ConstantIndex`](ProjectionElem::ConstantIndex): Computes an offset in units of `T` into the /// place as described in the documentation for the `ProjectionElem`. The resulting address is /// the parent's address plus that offset, and the type is `T`. This is only legal if the parent @@ -859,10 +856,6 @@ pub enum ProjectionElem<V, T> { /// /// The included Symbol is the name of the variant, used for printing MIR. Downcast(Option<Symbol>, VariantIdx), - - /// Like an explicit cast from an opaque type to a concrete type, but without - /// requiring an intermediate variable. - OpaqueCast(T), } /// Alias for projections as they appear in places, where the base is a place diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index c6975df45ef..fd3359ea80f 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -57,7 +57,7 @@ impl<'tcx> PlaceTy<'tcx> { /// `PlaceElem`, where we can just use the `Ty` that is already /// stored inline on field projection elems. pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: PlaceElem<'tcx>) -> PlaceTy<'tcx> { - self.projection_ty_core(tcx, ty::ParamEnv::empty(), &elem, |_, _, ty| ty, |_, ty| ty) + self.projection_ty_core(tcx, ty::ParamEnv::empty(), &elem, |_, _, ty| ty) } /// `place_ty.projection_ty_core(tcx, elem, |...| { ... })` @@ -71,7 +71,6 @@ impl<'tcx> PlaceTy<'tcx> { param_env: ty::ParamEnv<'tcx>, elem: &ProjectionElem<V, T>, mut handle_field: impl FnMut(&Self, Field, T) -> Ty<'tcx>, - mut handle_opaque_cast: impl FnMut(&Self, T) -> Ty<'tcx>, ) -> PlaceTy<'tcx> where V: ::std::fmt::Debug, @@ -110,7 +109,6 @@ impl<'tcx> PlaceTy<'tcx> { PlaceTy { ty: self.ty, variant_index: Some(index) } } ProjectionElem::Field(f, fty) => PlaceTy::from_ty(handle_field(&self, f, fty)), - ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(handle_opaque_cast(&self, ty)), }; debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer); answer diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs index a73ef23e281..82a6b0c506f 100644 --- a/compiler/rustc_middle/src/mir/type_foldable.rs +++ b/compiler/rustc_middle/src/mir/type_foldable.rs @@ -182,7 +182,6 @@ impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> { Ok(match self { Deref => Deref, Field(f, ty) => Field(f, ty.try_fold_with(folder)?), - OpaqueCast(ty) => OpaqueCast(ty.try_fold_with(folder)?), Index(v) => Index(v.try_fold_with(folder)?), Downcast(symbol, variantidx) => Downcast(symbol, variantidx), ConstantIndex { offset, min_length, from_end } => { diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index e5599fb15ad..89160876401 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -394,7 +394,7 @@ macro_rules! make_mir_visitor { ty::InstanceDef::Item(_def_id) => {} ty::InstanceDef::Intrinsic(_def_id) | - ty::InstanceDef::VtableShim(_def_id) | + ty::InstanceDef::VTableShim(_def_id) | ty::InstanceDef::ReifyShim(_def_id) | ty::InstanceDef::Virtual(_def_id, _) | ty::InstanceDef::ClosureOnceShim { call_once: _def_id, track_caller: _ } | @@ -1064,11 +1064,6 @@ macro_rules! visit_place_fns { self.visit_ty(&mut new_ty, TyContext::Location(location)); if ty != new_ty { Some(PlaceElem::Field(field, new_ty)) } else { None } } - PlaceElem::OpaqueCast(ty) => { - let mut new_ty = ty; - self.visit_ty(&mut new_ty, TyContext::Location(location)); - if ty != new_ty { Some(PlaceElem::OpaqueCast(new_ty)) } else { None } - } PlaceElem::Deref | PlaceElem::ConstantIndex { .. } | PlaceElem::Subslice { .. } @@ -1138,7 +1133,7 @@ macro_rules! visit_place_fns { location: Location, ) { match elem { - ProjectionElem::OpaqueCast(ty) | ProjectionElem::Field(_, ty) => { + ProjectionElem::Field(_field, ty) => { self.visit_ty(ty, TyContext::Location(location)); } ProjectionElem::Index(local) => { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 0581ef41f66..466a0fc25f7 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1634,11 +1634,15 @@ rustc_queries! { storage(ArenaCacheSelector<'tcx>) desc { "calculating the lib features map" } } - query defined_lib_features(_: CrateNum) - -> &'tcx [(Symbol, Option<Symbol>)] { + query defined_lib_features(_: CrateNum) -> &'tcx [(Symbol, Option<Symbol>)] { desc { "calculating the lib features defined in a crate" } separate_provide_extern } + query stability_implications(_: CrateNum) -> FxHashMap<Symbol, Symbol> { + storage(ArenaCacheSelector<'tcx>) + desc { "calculating the implications between `#[unstable]` features defined in a crate" } + separate_provide_extern + } /// Whether the function is an intrinsic query is_intrinsic(def_id: DefId) -> bool { desc { |tcx| "is_intrinsic({})", tcx.def_path_str(def_id) } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 75559d4f8b8..c55971557fa 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -351,7 +351,7 @@ pub enum ObligationCauseCode<'tcx> { ConstPatternStructural, /// Computing common supertype in an if expression - IfExpression(Box<IfExpressionCause>), + IfExpression(Box<IfExpressionCause<'tcx>>), /// Computing common supertype of an if expression with no else counter-part IfExpressionWithNoElse, @@ -488,22 +488,27 @@ impl<'tcx> ty::Lift<'tcx> for StatementAsExpression { #[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)] pub struct MatchExpressionArmCause<'tcx> { + pub arm_block_id: Option<hir::HirId>, + pub arm_ty: Ty<'tcx>, pub arm_span: Span, + pub prior_arm_block_id: Option<hir::HirId>, + pub prior_arm_ty: Ty<'tcx>, + pub prior_arm_span: Span, pub scrut_span: Span, - pub semi_span: Option<(Span, StatementAsExpression)>, pub source: hir::MatchSource, pub prior_arms: Vec<Span>, - pub last_ty: Ty<'tcx>, pub scrut_hir_id: hir::HirId, pub opt_suggest_box_span: Option<Span>, } -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct IfExpressionCause { - pub then: Span, - pub else_sp: Span, - pub outer: Option<Span>, - pub semicolon: Option<(Span, StatementAsExpression)>, +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Lift, TypeFoldable, TypeVisitable)] +pub struct IfExpressionCause<'tcx> { + pub then_id: hir::HirId, + pub else_id: hir::HirId, + pub then_ty: Ty<'tcx>, + pub else_ty: Ty<'tcx>, + pub outer_span: Option<Span>, pub opt_suggest_box_span: Option<Span>, } diff --git a/compiler/rustc_middle/src/traits/structural_impls.rs b/compiler/rustc_middle/src/traits/structural_impls.rs index 8f1a1564fc8..7fbd57ac735 100644 --- a/compiler/rustc_middle/src/traits/structural_impls.rs +++ b/compiler/rustc_middle/src/traits/structural_impls.rs @@ -130,7 +130,6 @@ impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceConstDestructData<N> { // Lift implementations TrivialTypeTraversalAndLiftImpls! { - super::IfExpressionCause, super::ImplSourceDiscriminantKindData, super::ImplSourcePointeeData, } diff --git a/compiler/rustc_middle/src/traits/util.rs b/compiler/rustc_middle/src/traits/util.rs index 8ce428c9799..d54b8c599d9 100644 --- a/compiler/rustc_middle/src/traits/util.rs +++ b/compiler/rustc_middle/src/traits/util.rs @@ -1,4 +1,4 @@ -use rustc_data_structures::stable_set::FxHashSet; +use rustc_data_structures::fx::FxHashSet; use crate::ty::{PolyTraitRef, TyCtxt}; diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index 8ead0512274..27b9d27b8bb 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -182,7 +182,11 @@ impl<'tcx> CapturedPlace<'tcx> { .unwrap(); } ty => { - bug!("Unexpected type {:?} for `Field` projection", ty) + span_bug!( + self.get_capture_kind_span(tcx), + "Unexpected type {:?} for `Field` projection", + ty + ) } }, diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index e6ea3d88853..51137c52659 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -523,4 +523,5 @@ impl_binder_encode_decode! { ty::ExistentialPredicate<'tcx>, ty::TraitRef<'tcx>, Vec<ty::GeneratorInteriorTypeCause<'tcx>>, + ty::ExistentialTraitRef<'tcx>, } diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index 973dc3dd4a1..c7653bdbe84 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -88,19 +88,17 @@ impl<'tcx> ValTree<'tcx> { let leafs = self .unwrap_branch() .into_iter() - .map(|v| v.unwrap_leaf().try_to_u8().unwrap()) - .collect::<Vec<_>>(); + .map(|v| v.unwrap_leaf().try_to_u8().unwrap()); - return Some(tcx.arena.alloc_from_iter(leafs.into_iter())); + return Some(tcx.arena.alloc_from_iter(leafs)); } ty::Slice(slice_ty) if *slice_ty == tcx.types.u8 => { let leafs = self .unwrap_branch() .into_iter() - .map(|v| v.unwrap_leaf().try_to_u8().unwrap()) - .collect::<Vec<_>>(); + .map(|v| v.unwrap_leaf().try_to_u8().unwrap()); - return Some(tcx.arena.alloc_from_iter(leafs.into_iter())); + return Some(tcx.arena.alloc_from_iter(leafs)); } _ => {} }, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index a594dab2e20..0f98d19820e 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -542,7 +542,7 @@ pub struct TypeckResults<'tcx> { /// even if they are only set in dead code (which doesn't show up in MIR). /// For type-alias-impl-trait, this map is only used to prevent query cycles, /// so the hidden types are all `None`. - pub concrete_opaque_types: VecMap<DefId, Option<Ty<'tcx>>>, + pub concrete_opaque_types: VecMap<LocalDefId, Option<Ty<'tcx>>>, /// Tracks the minimum captures required for a closure; /// see `MinCaptureInformationMap` for more details. diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index f8893ae29f5..878f31af00f 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -445,10 +445,13 @@ impl<'a, 'tcx> TypeFolder<'tcx> for BoundVarReplacer<'a, 'tcx> { let ct = (self.fld_c)(bound_const, ct.ty()); ty::fold::shift_vars(self.tcx, ct, self.current_index.as_u32()) } - _ if ct.has_vars_bound_at_or_above(self.current_index) => ct.super_fold_with(self), - _ => ct, + _ => ct.super_fold_with(self), } } + + fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p } + } } impl<'tcx> TyCtxt<'tcx> { diff --git a/compiler/rustc_middle/src/ty/impls_ty.rs b/compiler/rustc_middle/src/ty/impls_ty.rs index 88397a2bb56..263d64a5777 100644 --- a/compiler/rustc_middle/src/ty/impls_ty.rs +++ b/compiler/rustc_middle/src/ty/impls_ty.rs @@ -147,15 +147,15 @@ impl<'a> HashStable<StableHashingContext<'a>> for mir::interpret::AllocId { ty::tls::with_opt(|tcx| { trace!("hashing {:?}", *self); let tcx = tcx.expect("can't hash AllocIds during hir lowering"); - tcx.get_global_alloc(*self).hash_stable(hcx, hasher); + tcx.try_get_global_alloc(*self).hash_stable(hcx, hasher); }); } } // `Relocations` with default type parameters is a sorted map. -impl<'a, Tag> HashStable<StableHashingContext<'a>> for mir::interpret::Relocations<Tag> +impl<'a, Prov> HashStable<StableHashingContext<'a>> for mir::interpret::Relocations<Prov> where - Tag: HashStable<StableHashingContext<'a>>, + Prov: HashStable<StableHashingContext<'a>>, { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { self.len().hash_stable(hcx, hasher); diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 4f9bbc135ec..33a46f809b0 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -49,7 +49,7 @@ pub enum InstanceDef<'tcx> { /// /// The generated shim will take `Self` via `*mut Self` - conceptually this is `&owned Self` - /// and dereference the argument to call the original function. - VtableShim(DefId), + VTableShim(DefId), /// `fn()` pointer where the function itself cannot be turned into a pointer. /// @@ -145,7 +145,7 @@ impl<'tcx> InstanceDef<'tcx> { pub fn def_id(self) -> DefId { match self { InstanceDef::Item(def) => def.did, - InstanceDef::VtableShim(def_id) + InstanceDef::VTableShim(def_id) | InstanceDef::ReifyShim(def_id) | InstanceDef::FnPtrShim(def_id, _) | InstanceDef::Virtual(def_id, _) @@ -161,7 +161,7 @@ impl<'tcx> InstanceDef<'tcx> { match self { ty::InstanceDef::Item(def) => Some(def.did), ty::InstanceDef::DropGlue(def_id, Some(_)) => Some(def_id), - InstanceDef::VtableShim(..) + InstanceDef::VTableShim(..) | InstanceDef::ReifyShim(..) | InstanceDef::FnPtrShim(..) | InstanceDef::Virtual(..) @@ -176,7 +176,7 @@ impl<'tcx> InstanceDef<'tcx> { pub fn with_opt_param(self) -> ty::WithOptConstParam<DefId> { match self { InstanceDef::Item(def) => def, - InstanceDef::VtableShim(def_id) + InstanceDef::VTableShim(def_id) | InstanceDef::ReifyShim(def_id) | InstanceDef::FnPtrShim(def_id, _) | InstanceDef::Virtual(def_id, _) @@ -273,7 +273,7 @@ impl<'tcx> InstanceDef<'tcx> { | InstanceDef::Intrinsic(..) | InstanceDef::ReifyShim(..) | InstanceDef::Virtual(..) - | InstanceDef::VtableShim(..) => true, + | InstanceDef::VTableShim(..) => true, } } } @@ -290,7 +290,7 @@ impl<'tcx> fmt::Display for Instance<'tcx> { match self.def { InstanceDef::Item(_) => Ok(()), - InstanceDef::VtableShim(_) => write!(f, " - shim(vtable)"), + InstanceDef::VTableShim(_) => write!(f, " - shim(vtable)"), InstanceDef::ReifyShim(_) => write!(f, " - shim(reify)"), InstanceDef::Intrinsic(_) => write!(f, " - intrinsic"), InstanceDef::Virtual(_, num) => write!(f, " - virtual#{}", num), @@ -434,7 +434,7 @@ impl<'tcx> Instance<'tcx> { && tcx.generics_of(def_id).has_self; if is_vtable_shim { debug!(" => associated item with unsizeable self: Self"); - Some(Instance { def: InstanceDef::VtableShim(def_id), substs }) + Some(Instance { def: InstanceDef::VTableShim(def_id), substs }) } else { Instance::resolve(tcx, param_env, def_id, substs).ok().flatten().map(|mut resolved| { match resolved.def { diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index c41a8318ec5..ab76ad50984 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -2771,7 +2771,7 @@ impl<'tcx> ty::Instance<'tcx> { _ => unreachable!(), }; - if let ty::InstanceDef::VtableShim(..) = self.def { + if let ty::InstanceDef::VTableShim(..) = self.def { // Modify `fn(self, ...)` to `fn(self: *mut Self, ...)`. sig = sig.map_bound(|mut sig| { let mut inputs_and_output = sig.inputs_and_output.to_vec(); @@ -3266,7 +3266,12 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // this attribute doesn't make it UB for the pointed-to data to be undef. attrs.set(ArgAttribute::NoUndef); - // `Box` pointer parameters never alias because ownership is transferred + // The aliasing rules for `Box<T>` are still not decided, but currently we emit + // `noalias` for it. This can be turned off using an unstable flag. + // See https://github.com/rust-lang/unsafe-code-guidelines/issues/326 + let noalias_for_box = + self.tcx().sess.opts.unstable_opts.box_noalias.unwrap_or(true); + // `&mut` pointer parameters never alias other parameters, // or mutable global data // @@ -3281,7 +3286,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // `-Zmutable-noalias` debugging option. let no_alias = match kind { PointerKind::Shared | PointerKind::UniqueBorrowed => false, - PointerKind::UniqueOwned => true, + PointerKind::UniqueOwned => noalias_for_box, PointerKind::Frozen => !is_return, }; if no_alias { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 3536d946db2..4346dbdb16b 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -790,22 +790,15 @@ pub struct TraitPredicate<'tcx> { pub type PolyTraitPredicate<'tcx> = ty::Binder<'tcx, TraitPredicate<'tcx>>; impl<'tcx> TraitPredicate<'tcx> { - pub fn remap_constness(&mut self, tcx: TyCtxt<'tcx>, param_env: &mut ParamEnv<'tcx>) { - if std::intrinsics::unlikely(Some(self.trait_ref.def_id) == tcx.lang_items().drop_trait()) { - // remap without changing constness of this predicate. - // this is because `T: ~const Drop` has a different meaning to `T: Drop` - // FIXME(fee1-dead): remove this logic after beta bump - param_env.remap_constness_with(self.constness) - } else { - *param_env = param_env.with_constness(self.constness.and(param_env.constness())) - } + pub fn remap_constness(&mut self, param_env: &mut ParamEnv<'tcx>) { + *param_env = param_env.with_constness(self.constness.and(param_env.constness())) } /// Remap the constness of this predicate before emitting it for diagnostics. pub fn remap_constness_diag(&mut self, param_env: ParamEnv<'tcx>) { // this is different to `remap_constness` that callees want to print this predicate // in case of selection errors. `T: ~const Drop` bounds cannot end up here when the - // param_env is not const because we it is always satisfied in non-const contexts. + // param_env is not const because it is always satisfied in non-const contexts. if let hir::Constness::NotConst = param_env.constness() { self.constness = ty::BoundConstness::NotConst; } @@ -1108,8 +1101,7 @@ impl<'tcx> InstantiatedPredicates<'tcx> { #[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable, Lift)] #[derive(TypeFoldable, TypeVisitable)] pub struct OpaqueTypeKey<'tcx> { - // FIXME(oli-obk): make this a LocalDefId - pub def_id: DefId, + pub def_id: LocalDefId, pub substs: SubstsRef<'tcx>, } @@ -2136,7 +2128,7 @@ impl<'tcx> TyCtxt<'tcx> { } } } - ty::InstanceDef::VtableShim(..) + ty::InstanceDef::VTableShim(..) | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::Intrinsic(..) | ty::InstanceDef::FnPtrShim(..) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 96e84bc8f0a..03bb515904c 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1269,7 +1269,7 @@ pub trait PrettyPrinter<'tcx>: if let ty::Array(elem, len) = inner.kind() { if let ty::Uint(ty::UintTy::U8) = elem.kind() { if let ty::ConstKind::Value(ty::ValTree::Leaf(int)) = len.kind() { - match self.tcx().get_global_alloc(alloc_id) { + match self.tcx().try_get_global_alloc(alloc_id) { Some(GlobalAlloc::Memory(alloc)) => { let len = int.assert_bits(self.tcx().data_layout.pointer_size); let range = @@ -1282,11 +1282,12 @@ pub trait PrettyPrinter<'tcx>: p!("<too short allocation>") } } - // FIXME: for statics and functions, we could in principle print more detail. + // FIXME: for statics, vtables, and functions, we could in principle print more detail. Some(GlobalAlloc::Static(def_id)) => { p!(write("<static({:?})>", def_id)) } Some(GlobalAlloc::Function(_)) => p!("<function>"), + Some(GlobalAlloc::VTable(..)) => p!("<vtable>"), None => p!("<dangling pointer>"), } return Ok(self); @@ -1297,7 +1298,8 @@ pub trait PrettyPrinter<'tcx>: ty::FnPtr(_) => { // FIXME: We should probably have a helper method to share code with the "Byte strings" // printing above (which also has to handle pointers to all sorts of things). - if let Some(GlobalAlloc::Function(instance)) = self.tcx().get_global_alloc(alloc_id) + if let Some(GlobalAlloc::Function(instance)) = + self.tcx().try_get_global_alloc(alloc_id) { self = self.typed_value( |this| this.print_value_path(instance.def_id(), instance.substs), @@ -1377,9 +1379,9 @@ pub trait PrettyPrinter<'tcx>: /// This is overridden for MIR printing because we only want to hide alloc ids from users, not /// from MIR where it is actually useful. - fn pretty_print_const_pointer<Tag: Provenance>( + fn pretty_print_const_pointer<Prov: Provenance>( mut self, - _: Pointer<Tag>, + _: Pointer<Prov>, ty: Ty<'tcx>, print_ty: bool, ) -> Result<Self::Const, Self::Error> { @@ -1727,7 +1729,7 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> { } fn print_const(self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> { - self.pretty_print_const(ct, true) + self.pretty_print_const(ct, false) } fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> { @@ -1952,9 +1954,9 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { } } - fn pretty_print_const_pointer<Tag: Provenance>( + fn pretty_print_const_pointer<Prov: Provenance>( self, - p: Pointer<Tag>, + p: Pointer<Prov>, ty: Ty<'tcx>, print_ty: bool, ) -> Result<Self::Const, Self::Error> { diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 391a0a20c96..a4be3d02d19 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -624,7 +624,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::InstanceDef<'a> { fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { match self { ty::InstanceDef::Item(def_id) => Some(ty::InstanceDef::Item(def_id)), - ty::InstanceDef::VtableShim(def_id) => Some(ty::InstanceDef::VtableShim(def_id)), + ty::InstanceDef::VTableShim(def_id) => Some(ty::InstanceDef::VTableShim(def_id)), ty::InstanceDef::ReifyShim(def_id) => Some(ty::InstanceDef::ReifyShim(def_id)), ty::InstanceDef::Intrinsic(def_id) => Some(ty::InstanceDef::Intrinsic(def_id)), ty::InstanceDef::FnPtrShim(def_id, ty) => { @@ -927,7 +927,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> { substs: self.substs.try_fold_with(folder)?, def: match self.def { Item(def) => Item(def.try_fold_with(folder)?), - VtableShim(did) => VtableShim(did.try_fold_with(folder)?), + VTableShim(did) => VTableShim(did.try_fold_with(folder)?), ReifyShim(did) => ReifyShim(did.try_fold_with(folder)?), Intrinsic(did) => Intrinsic(did.try_fold_with(folder)?), FnPtrShim(did, ty) => { @@ -954,7 +954,7 @@ impl<'tcx> TypeVisitable<'tcx> for ty::instance::Instance<'tcx> { self.substs.visit_with(visitor)?; match self.def { Item(def) => def.visit_with(visitor), - VtableShim(did) | ReifyShim(did) | Intrinsic(did) | Virtual(did, _) => { + VTableShim(did) | ReifyShim(did) | Intrinsic(did) | Virtual(did, _) => { did.visit_with(visitor) } FnPtrShim(did, ty) | CloneShim(did, ty) => { diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index d663f1a3ec6..9f622ad6cd2 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1707,13 +1707,6 @@ impl<'tcx> Ty<'tcx> { } } - pub fn expect_opaque_type(self) -> ty::OpaqueTypeKey<'tcx> { - match *self.kind() { - Opaque(def_id, substs) => ty::OpaqueTypeKey { def_id, substs }, - _ => bug!("`expect_opaque_type` called on non-opaque type: {}", self), - } - } - pub fn simd_size_and_type(self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) { match self.kind() { Adt(def, substs) => { diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index 826c16dda4a..541dace5cc2 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -74,6 +74,10 @@ impl TraitImpls { pub fn blanket_impls(&self) -> &[DefId] { self.blanket_impls.as_slice() } + + pub fn non_blanket_impls(&self) -> &FxIndexMap<SimplifiedType, Vec<DefId>> { + &self.non_blanket_impls + } } impl<'tcx> TraitDef { 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 6abf419dd49..e88f9dc1f08 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -7,7 +7,6 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::hir::place::Projection as HirProjection; use rustc_middle::hir::place::ProjectionKind as HirProjectionKind; use rustc_middle::middle::region; -use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::AssertKind::BoundsCheck; use rustc_middle::mir::*; use rustc_middle::thir::*; @@ -72,7 +71,7 @@ pub(crate) enum PlaceBase { /// This is used internally when building a place for an expression like `a.b.c`. The fields `b` /// and `c` can be progressively pushed onto the place builder that is created when converting `a`. #[derive(Clone, Debug, PartialEq)] -pub(in crate::build) struct PlaceBuilder<'tcx> { +pub(crate) struct PlaceBuilder<'tcx> { base: PlaceBase, projection: Vec<PlaceElem<'tcx>>, } @@ -105,8 +104,6 @@ fn convert_to_hir_projections_and_truncate_for_capture<'tcx>( variant = Some(*idx); continue; } - // These do not affect anything, they just make sure we know the right type. - ProjectionElem::OpaqueCast(_) => continue, ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { @@ -204,10 +201,10 @@ fn find_capture_matching_projections<'a, 'tcx>( /// `PlaceBuilder` now starts from `PlaceBase::Local`. /// /// Returns a Result with the error being the PlaceBuilder (`from_builder`) that was not found. -#[instrument(level = "trace", skip(cx))] -fn to_upvars_resolved_place_builder<'tcx>( +fn to_upvars_resolved_place_builder<'a, 'tcx>( from_builder: PlaceBuilder<'tcx>, - cx: &Builder<'_, 'tcx>, + tcx: TyCtxt<'tcx>, + typeck_results: &'a ty::TypeckResults<'tcx>, ) -> Result<PlaceBuilder<'tcx>, PlaceBuilder<'tcx>> { match from_builder.base { PlaceBase::Local(_) => Ok(from_builder), @@ -222,13 +219,13 @@ fn to_upvars_resolved_place_builder<'tcx>( let Some((capture_index, capture)) = find_capture_matching_projections( - cx.typeck_results, + typeck_results, var_hir_id, closure_def_id, &from_builder.projection, ) else { - let closure_span = cx.tcx.def_span(closure_def_id); - if !enable_precise_capture(cx.tcx, closure_span) { + let closure_span = tcx.def_span(closure_def_id); + if !enable_precise_capture(tcx, closure_span) { bug!( "No associated capture found for {:?}[{:#?}] even though \ capture_disjoint_fields isn't enabled", @@ -245,8 +242,8 @@ fn to_upvars_resolved_place_builder<'tcx>( }; // We won't be building MIR if the closure wasn't local - let closure_hir_id = cx.tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local()); - let closure_ty = cx.typeck_results.node_type(closure_hir_id); + let closure_hir_id = tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local()); + let closure_ty = typeck_results.node_type(closure_hir_id); let substs = match closure_ty.kind() { ty::Closure(_, substs) => ty::UpvarSubsts::Closure(substs), @@ -273,14 +270,12 @@ fn to_upvars_resolved_place_builder<'tcx>( // We used some of the projections to build the capture itself, // now we apply the remaining to the upvar resolved place. - trace!(?capture.place, ?from_builder.projection); let remaining_projections = strip_prefix( capture.place.base_ty, from_builder.projection, &capture.place.projections, ); upvar_resolved_place_builder.projection.extend(remaining_projections); - trace!(?upvar_resolved_place_builder); Ok(upvar_resolved_place_builder) } @@ -299,21 +294,16 @@ fn strip_prefix<'tcx>( prefix_projections: &[HirProjection<'tcx>], ) -> impl Iterator<Item = PlaceElem<'tcx>> { let mut iter = projections.into_iter(); - let mut next = || match iter.next()? { - // Filter out opaque casts, they are unnecessary in the prefix. - ProjectionElem::OpaqueCast(..) => iter.next(), - other => Some(other), - }; for projection in prefix_projections { match projection.kind { HirProjectionKind::Deref => { - assert!(matches!(next(), Some(ProjectionElem::Deref))); + assert!(matches!(iter.next(), Some(ProjectionElem::Deref))); } HirProjectionKind::Field(..) => { if base_ty.is_enum() { - assert!(matches!(next(), Some(ProjectionElem::Downcast(..)))); + assert!(matches!(iter.next(), Some(ProjectionElem::Downcast(..)))); } - assert!(matches!(next(), Some(ProjectionElem::Field(..)))); + assert!(matches!(iter.next(), Some(ProjectionElem::Field(..)))); } HirProjectionKind::Index | HirProjectionKind::Subslice => { bug!("unexpected projection kind: {:?}", projection); @@ -325,32 +315,24 @@ fn strip_prefix<'tcx>( } impl<'tcx> PlaceBuilder<'tcx> { - pub(crate) fn into_place(self, cx: &Builder<'_, 'tcx>) -> Place<'tcx> { + pub(crate) fn into_place<'a>( + self, + tcx: TyCtxt<'tcx>, + typeck_results: &'a ty::TypeckResults<'tcx>, + ) -> Place<'tcx> { if let PlaceBase::Local(local) = self.base { - let mut projections = vec![]; - let mut ty = PlaceTy::from_ty(cx.local_decls[local].ty); - for projection in self.projection { - // Only preserve those opaque casts that actually go from an opaque type - // to another type. - if let ProjectionElem::OpaqueCast(t) = projection { - if let ty::Opaque(..) = ty.ty.kind() { - if t != ty.ty { - projections.push(ProjectionElem::OpaqueCast(t)); - } - } - } else { - projections.push(projection); - } - ty = ty.projection_ty(cx.tcx, projection); - } - Place { local, projection: cx.tcx.intern_place_elems(&projections) } + Place { local, projection: tcx.intern_place_elems(&self.projection) } } else { - self.expect_upvars_resolved(cx).into_place(cx) + self.expect_upvars_resolved(tcx, typeck_results).into_place(tcx, typeck_results) } } - fn expect_upvars_resolved(self, cx: &Builder<'_, 'tcx>) -> PlaceBuilder<'tcx> { - to_upvars_resolved_place_builder(self, cx).unwrap() + fn expect_upvars_resolved<'a>( + self, + tcx: TyCtxt<'tcx>, + typeck_results: &'a ty::TypeckResults<'tcx>, + ) -> PlaceBuilder<'tcx> { + to_upvars_resolved_place_builder(self, tcx, typeck_results).unwrap() } /// Attempts to resolve the `PlaceBuilder`. @@ -364,11 +346,12 @@ impl<'tcx> PlaceBuilder<'tcx> { /// not captured. This can happen because the final mir that will be /// generated doesn't require a read for this place. Failures will only /// happen inside closures. - pub(crate) fn try_upvars_resolved( + pub(crate) fn try_upvars_resolved<'a>( self, - cx: &Builder<'_, 'tcx>, + tcx: TyCtxt<'tcx>, + typeck_results: &'a ty::TypeckResults<'tcx>, ) -> Result<PlaceBuilder<'tcx>, PlaceBuilder<'tcx>> { - to_upvars_resolved_place_builder(self, cx) + to_upvars_resolved_place_builder(self, tcx, typeck_results) } pub(crate) fn base(&self) -> PlaceBase { @@ -428,7 +411,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expr: &Expr<'tcx>, ) -> BlockAnd<Place<'tcx>> { let place_builder = unpack!(block = self.as_place_builder(block, expr)); - block.and(place_builder.into_place(self)) + block.and(place_builder.into_place(self.tcx, self.typeck_results)) } /// This is used when constructing a compound `Place`, so that we can avoid creating @@ -452,7 +435,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expr: &Expr<'tcx>, ) -> BlockAnd<Place<'tcx>> { let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr)); - block.and(place_builder.into_place(self)) + block.and(place_builder.into_place(self.tcx, self.typeck_results)) } /// This is used when constructing a compound `Place`, so that we can avoid creating @@ -547,7 +530,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { inferred_ty: expr.ty, }); - let place = place_builder.clone().into_place(this); + let place = place_builder.clone().into_place(this.tcx, this.typeck_results); this.cfg.push( block, Statement { @@ -699,7 +682,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if is_outermost_index { self.read_fake_borrows(block, fake_borrow_temps, source_info) } else { - base_place = base_place.expect_upvars_resolved(self); + base_place = base_place.expect_upvars_resolved(self.tcx, self.typeck_results); self.add_fake_borrows_of_base( &base_place, block, @@ -727,7 +710,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let lt = self.temp(bool_ty, expr_span); // len = len(slice) - self.cfg.push_assign(block, source_info, len, Rvalue::Len(slice.into_place(self))); + self.cfg.push_assign( + block, + source_info, + len, + Rvalue::Len(slice.into_place(self.tcx, self.typeck_results)), + ); // lt = idx < len self.cfg.push_assign( block, @@ -807,7 +795,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } ProjectionElem::Field(..) | ProjectionElem::Downcast(..) - | ProjectionElem::OpaqueCast(..) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => (), } 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 93f76333165..15f2d17c4e0 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -321,8 +321,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let place_builder = unpack!(block = this.as_place_builder(block, &this.thir[*thir_place])); - if let Ok(place_builder_resolved) = place_builder.try_upvars_resolved(this) { - let mir_place = place_builder_resolved.into_place(this); + if let Ok(place_builder_resolved) = + place_builder.try_upvars_resolved(this.tcx, this.typeck_results) + { + let mir_place = + place_builder_resolved.into_place(this.tcx, this.typeck_results); this.cfg.push_fake_read( block, this.source_info(this.tcx.hir().span(*hir_id)), @@ -613,7 +616,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // by the parent itself. The mutability of the current capture // is same as that of the capture in the parent closure. PlaceBase::Upvar { .. } => { - let enclosing_upvars_resolved = arg_place_builder.clone().into_place(this); + let enclosing_upvars_resolved = + arg_place_builder.clone().into_place(this.tcx, this.typeck_results); match enclosing_upvars_resolved.as_ref() { PlaceRef { @@ -650,7 +654,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false }, }; - let arg_place = arg_place_builder.into_place(this); + let arg_place = arg_place_builder.into_place(this.tcx, this.typeck_results); this.cfg.push_assign( block, diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs index dac8862647a..724b72f8769 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs @@ -23,7 +23,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ensure_sufficient_stack(|| self.as_temp_inner(block, temp_lifetime, expr, mutability)) } - #[instrument(skip(self), level = "debug")] fn as_temp_inner( &mut self, mut block: BasicBlock, @@ -31,6 +30,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expr: &Expr<'tcx>, mutability: Mutability, ) -> BlockAnd<Local> { + debug!( + "as_temp(block={:?}, temp_lifetime={:?}, expr={:?}, mutability={:?})", + block, temp_lifetime, expr, mutability + ); let this = self; let expr_span = expr.span; diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index d1ef515b3d2..017d43d10a9 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -15,13 +15,14 @@ use std::iter; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Compile `expr`, storing the result into `destination`, which /// is assumed to be uninitialized. - #[instrument(level = "debug", skip(self))] pub(crate) fn expr_into_dest( &mut self, destination: Place<'tcx>, mut block: BasicBlock, expr: &Expr<'tcx>, ) -> BlockAnd<()> { + debug!("expr_into_dest(destination={:?}, block={:?}, expr={:?})", destination, block, expr); + // since we frequently have to reference `self` from within a // closure, where `self` would be shadowed, it's easier to // just use the name `this` uniformly @@ -365,7 +366,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None => { let place_builder = place_builder.clone(); this.consume_by_copy_or_move( - place_builder.field(n, *ty).into_place(this), + place_builder + .field(n, *ty) + .into_place(this.tcx, this.typeck_results), ) } }) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 86ef666eac8..7067a48b783 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -220,8 +220,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let cause_matched_place = FakeReadCause::ForMatchedPlace(None); let source_info = self.source_info(scrutinee_span); - if let Ok(scrutinee_builder) = scrutinee_place_builder.clone().try_upvars_resolved(self) { - let scrutinee_place = scrutinee_builder.into_place(self); + if let Ok(scrutinee_builder) = + scrutinee_place_builder.clone().try_upvars_resolved(self.tcx, self.typeck_results) + { + let scrutinee_place = scrutinee_builder.into_place(self.tcx, self.typeck_results); self.cfg.push_fake_read(block, source_info, cause_matched_place, scrutinee_place); } @@ -346,10 +348,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // ``` let mut opt_scrutinee_place: Option<(Option<&Place<'tcx>>, Span)> = None; let scrutinee_place: Place<'tcx>; - if let Ok(scrutinee_builder) = - scrutinee_place_builder.clone().try_upvars_resolved(this) + if let Ok(scrutinee_builder) = scrutinee_place_builder + .clone() + .try_upvars_resolved(this.tcx, this.typeck_results) { - scrutinee_place = scrutinee_builder.into_place(this); + scrutinee_place = + scrutinee_builder.into_place(this.tcx, this.typeck_results); opt_scrutinee_place = Some((Some(&scrutinee_place), scrutinee_span)); } let scope = this.declare_bindings( @@ -598,6 +602,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { while let Some(next) = { for binding in &candidate_ref.bindings { let local = self.var_local_id(binding.var_id, OutsideGuard); + + let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( + VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. }, + )))) = self.local_decls[local].local_info else { + bug!("Let binding to non-user variable.") + }; // `try_upvars_resolved` may fail if it is unable to resolve the given // `PlaceBuilder` inside a closure. In this case, we don't want to include // a scrutinee place. `scrutinee_place_builder` will fail for destructured @@ -612,15 +622,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // let (v1, v2) = foo; // }; // ``` - if let Ok(match_pair_resolved) = initializer.clone().try_upvars_resolved(self) { - let place = match_pair_resolved.into_place(self); - - let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( - VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. }, - )))) = self.local_decls[local].local_info else { - bug!("Let binding to non-user variable.") - }; - + if let Ok(match_pair_resolved) = + initializer.clone().try_upvars_resolved(self.tcx, self.typeck_results) + { + let place = match_pair_resolved.into_place(self.tcx, self.typeck_results); *match_place = Some(place); } } @@ -649,7 +654,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// scope for the bindings in these patterns, if such a scope had to be /// created. NOTE: Declaring the bindings should always be done in their /// drop scope. - #[instrument(skip(self), level = "debug")] pub(crate) fn declare_bindings( &mut self, mut visibility_scope: Option<SourceScope>, @@ -658,6 +662,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { has_guard: ArmHasGuard, opt_match_place: Option<(Option<&Place<'tcx>>, Span)>, ) -> Option<SourceScope> { + debug!("declare_bindings: pattern={:?}", pattern); self.visit_primary_bindings( &pattern, UserTypeProjections::none(), @@ -867,7 +872,7 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> { Candidate { span: pattern.span, has_guard, - match_pairs: smallvec![MatchPair::new(place, pattern)], + match_pairs: smallvec![MatchPair { place, pattern }], bindings: Vec::new(), ascriptions: Vec::new(), subcandidates: Vec::new(), @@ -1043,7 +1048,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// if `x.0` matches `false` (for the third arm). In the (impossible at /// runtime) case when `x.0` is now `true`, we branch to /// `otherwise_block`. - #[instrument(skip(self, fake_borrows), level = "debug")] fn match_candidates<'pat>( &mut self, span: Span, @@ -1053,6 +1057,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { candidates: &mut [&mut Candidate<'pat, 'tcx>], fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>, ) { + debug!( + "matched_candidate(span={:?}, candidates={:?}, start_block={:?}, otherwise_block={:?})", + span, candidates, start_block, otherwise_block, + ); + // Start by simplifying candidates. Once this process is complete, all // the match pairs which remain require some form of test, whether it // be a switch or pattern comparison. @@ -1371,10 +1380,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) } - #[instrument( - skip(self, otherwise, or_span, place, fake_borrows, candidate, pats), - level = "debug" - )] fn test_or_pattern<'pat>( &mut self, candidate: &mut Candidate<'pat, 'tcx>, @@ -1384,7 +1389,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { place: PlaceBuilder<'tcx>, fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>, ) { - debug!("candidate={:#?}\npats={:#?}", candidate, pats); + debug!("test_or_pattern:\ncandidate={:#?}\npats={:#?}", candidate, pats); let mut or_candidates: Vec<_> = pats .iter() .map(|pat| Candidate::new(place.clone(), pat, candidate.has_guard)) @@ -1600,9 +1605,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Insert a Shallow borrow of any places that is switched on. if let Some(fb) = fake_borrows && let Ok(match_place_resolved) = - match_place.clone().try_upvars_resolved(self) + match_place.clone().try_upvars_resolved(self.tcx, self.typeck_results) { - let resolved_place = match_place_resolved.into_place(self); + let resolved_place = match_place_resolved.into_place(self.tcx, self.typeck_results); fb.insert(resolved_place); } @@ -1629,14 +1634,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { candidates = rest; } // at least the first candidate ought to be tested - assert!( - total_candidate_count > candidates.len(), - "{}, {:#?}", - total_candidate_count, - candidates - ); - debug!("tested_candidates: {}", total_candidate_count - candidates.len()); - debug!("untested_candidates: {}", candidates.len()); + assert!(total_candidate_count > candidates.len()); + debug!("test_candidates: tested_candidates: {}", total_candidate_count - candidates.len()); + debug!("test_candidates: untested_candidates: {}", candidates.len()); // HACK(matthewjasper) This is a closure so that we can let the test // create its blocks before the rest of the match. This currently @@ -1794,8 +1794,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); let mut opt_expr_place: Option<(Option<&Place<'tcx>>, Span)> = None; let expr_place: Place<'tcx>; - if let Ok(expr_builder) = expr_place_builder.try_upvars_resolved(self) { - expr_place = expr_builder.into_place(self); + if let Ok(expr_builder) = + expr_place_builder.try_upvars_resolved(self.tcx, self.typeck_results) + { + expr_place = expr_builder.into_place(self.tcx, self.typeck_results); opt_expr_place = Some((Some(&expr_place), expr_span)); } let otherwise_post_guard_block = otherwise_candidate.pre_binding_block.unwrap(); @@ -2193,7 +2195,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// first local is a binding for occurrences of `var` in the guard, which /// will have type `&T`. The second local is a binding for occurrences of /// `var` in the arm body, which will have type `T`. - #[instrument(skip(self), level = "debug")] fn declare_binding( &mut self, source_info: SourceInfo, @@ -2208,12 +2209,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { opt_match_place: Option<(Option<Place<'tcx>>, Span)>, pat_span: Span, ) { + debug!( + "declare_binding(var_id={:?}, name={:?}, mode={:?}, var_ty={:?}, \ + visibility_scope={:?}, source_info={:?})", + var_id, name, mode, var_ty, visibility_scope, source_info + ); + let tcx = self.tcx; let debug_source_info = SourceInfo { span: source_info.span, scope: visibility_scope }; let binding_mode = match mode { BindingMode::ByValue => ty::BindingMode::BindByValue(mutability), BindingMode::ByRef(_) => ty::BindingMode::BindByReference(mutability), }; + debug!("declare_binding: user_ty={:?}", user_ty); let local = LocalDecl::<'tcx> { mutability, ty: var_ty, @@ -2263,7 +2271,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } else { LocalsForNode::One(for_arm_body) }; - debug!(?locals); + debug!("declare_binding: vars={:?}", locals); self.var_indices.insert(var_id, locals); } diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index 6fa817da28a..c6298904140 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -37,13 +37,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// /// only generates a single switch. If this happens this method returns /// `true`. - #[instrument(skip(self, candidate), level = "debug")] pub(super) fn simplify_candidate<'pat>( &mut self, candidate: &mut Candidate<'pat, 'tcx>, ) -> bool { // repeatedly simplify match pairs until fixed point is reached - debug!("{:#?}", candidate); + debug!(?candidate, "simplify_candidate"); // existing_bindings and new_bindings exists to keep the semantics in order. // Reversing the binding order for bindings after `@` changes the binding order in places @@ -156,10 +155,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ascription: thir::Ascription { ref annotation, variance }, } => { // Apply the type ascription to the value at `match_pair.place`, which is the - if let Ok(place_resolved) = match_pair.place.clone().try_upvars_resolved(self) { + if let Ok(place_resolved) = + match_pair.place.clone().try_upvars_resolved(self.tcx, self.typeck_results) + { candidate.ascriptions.push(Ascription { annotation: annotation.clone(), - source: place_resolved.into_place(self), + source: place_resolved.into_place(self.tcx, self.typeck_results), variance, }); } @@ -183,10 +184,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ref subpattern, is_primary: _, } => { - if let Ok(place_resolved) = match_pair.place.clone().try_upvars_resolved(self) { + if let Ok(place_resolved) = + match_pair.place.clone().try_upvars_resolved(self.tcx, self.typeck_results) + { candidate.bindings.push(Binding { span: match_pair.pattern.span, - source: place_resolved.into_place(self), + source: place_resolved.into_place(self.tcx, self.typeck_results), var_id: var, binding_mode: mode, }); diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 63acd731db7..598da80c574 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -144,7 +144,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - #[instrument(skip(self, make_target_blocks, place_builder), level = "debug")] pub(super) fn perform_test( &mut self, match_start_span: Span, @@ -154,9 +153,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { test: &Test<'tcx>, make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>, ) { - let place = place_builder.into_place(self); - let place_ty = place.ty(&self.local_decls, self.tcx); - debug!(?place, ?place_ty,); + let place: Place<'tcx>; + if let Ok(test_place_builder) = + place_builder.try_upvars_resolved(self.tcx, self.typeck_results) + { + place = test_place_builder.into_place(self.tcx, self.typeck_results); + } else { + return; + } + debug!( + "perform_test({:?}, {:?}: {:?}, {:?})", + block, + place, + place.ty(&self.local_decls, self.tcx), + test + ); let source_info = self.source_info(test.span); match test.kind { @@ -724,7 +735,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // So, if we have a match-pattern like `x @ Enum::Variant(P1, P2)`, // we want to create a set of derived match-patterns like // `(x as Variant).0 @ P1` and `(x as Variant).1 @ P1`. - let downcast_place = match_pair.place.downcast(adt_def, variant_index); // `(x as Variant)` + let elem = + ProjectionElem::Downcast(Some(adt_def.variant(variant_index).name), variant_index); + let downcast_place = match_pair.place.project(elem); // `(x as Variant)` let consequent_match_pairs = subpatterns.iter().map(|subpattern| { // e.g., `(x as Variant).0` let place = downcast_place.clone().field(subpattern.field, subpattern.pattern.ty); diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index 4a7edc517f4..9a1e98d3bb1 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -31,15 +31,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { suffix: &'pat [Pat<'tcx>], ) { let tcx = self.tcx; - let (min_length, exact_size) = - if let Ok(place_resolved) = place.clone().try_upvars_resolved(self) { - match place_resolved.into_place(self).ty(&self.local_decls, tcx).ty.kind() { - ty::Array(_, length) => (length.eval_usize(tcx, self.param_env), true), - _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false), - } - } else { - ((prefix.len() + suffix.len()).try_into().unwrap(), false) - }; + let (min_length, exact_size) = if let Ok(place_resolved) = + place.clone().try_upvars_resolved(tcx, self.typeck_results) + { + match place_resolved + .into_place(tcx, self.typeck_results) + .ty(&self.local_decls, tcx) + .ty + .kind() + { + ty::Array(_, length) => (length.eval_usize(tcx, self.param_env), true), + _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false), + } + } else { + ((prefix.len() + suffix.len()).try_into().unwrap(), false) + }; match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| { let elem = @@ -94,14 +100,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { - pub(in crate::build) fn new( + pub(crate) fn new( place: PlaceBuilder<'tcx>, pattern: &'pat Pat<'tcx>, ) -> MatchPair<'pat, 'tcx> { - // Force the place type to the pattern's type. - // FIXME(oli-obk): only do this when we don't already know the place type. - // FIXME(oli-obk): can we use this to simplify slice/array pattern hacks? - let place = place.project(ProjectionElem::OpaqueCast(pattern.ty)); MatchPair { place, pattern } } } diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index ab37c480285..b9fd8c50e6a 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -553,7 +553,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// Convenience wrapper that pushes a scope and then executes `f` /// to build its contents, popping the scope afterwards. - #[instrument(skip(self, f), level = "debug")] pub(crate) fn in_scope<F, R>( &mut self, region_scope: (region::Scope, SourceInfo), @@ -563,6 +562,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { where F: FnOnce(&mut Builder<'a, 'tcx>) -> BlockAnd<R>, { + debug!("in_scope(region_scope={:?})", region_scope); let source_scope = self.source_scope; let tcx = self.tcx; if let LintLevel::Explicit(current_hir_id) = lint_level { @@ -589,7 +589,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let rv = unpack!(block = f(self)); unpack!(block = self.pop_scope(region_scope, block)); self.source_scope = source_scope; - debug!(?block); + debug!("in_scope: exiting region_scope={:?} block={:?}", region_scope, block); block.and(rv) } diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 89f60902cf9..1f0d0ce04aa 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -431,9 +431,9 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { let lhs = &self.thir[lhs]; if let ty::Adt(adt_def, _) = lhs.ty.kind() && adt_def.is_union() { if let Some((assigned_ty, assignment_span)) = self.assignment_info { - if assigned_ty.needs_drop(self.tcx, self.tcx.param_env(adt_def.did())) { + if assigned_ty.needs_drop(self.tcx, self.param_env) { // This would be unsafe, but should be outright impossible since we reject such unions. - self.tcx.sess.delay_span_bug(assignment_span, "union fields that need dropping should be impossible"); + self.tcx.sess.delay_span_bug(assignment_span, format!("union fields that need dropping should be impossible: {assigned_ty}")); } } else { self.requires_unsafe(expr.span, AccessToUnionField); diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 05da33caa91..4eb3607e9cc 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -48,8 +48,6 @@ impl<'tcx> Cx<'tcx> { _ => None, }; - trace!(?expr.ty); - // Now apply adjustments, if any. for adjustment in self.typeck_results.expr_adjustments(hir_expr) { trace!(?expr, ?adjustment); @@ -58,8 +56,6 @@ impl<'tcx> Cx<'tcx> { self.apply_adjustment(hir_expr, expr, adjustment, adjustment_span.unwrap_or(span)); } - trace!(?expr.ty, "after adjustments"); - // Next, wrap this up in the expr's scope. expr = Expr { temp_lifetime, diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index c0fd19cf71c..60db98073a3 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -1202,32 +1202,35 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { /// Creates a new list of wildcard fields for a given constructor. The result must have a /// length of `constructor.arity()`. - #[instrument(level = "trace")] - pub(super) fn wildcards(pcx: PatCtxt<'_, 'p, 'tcx>, constructor: &Constructor<'tcx>) -> Self { + pub(super) fn wildcards( + cx: &MatchCheckCtxt<'p, 'tcx>, + ty: Ty<'tcx>, + constructor: &Constructor<'tcx>, + ) -> Self { let ret = match constructor { - Single | Variant(_) => match pcx.ty.kind() { - ty::Tuple(fs) => Fields::wildcards_from_tys(pcx.cx, fs.iter()), - ty::Ref(_, rty, _) => Fields::wildcards_from_tys(pcx.cx, once(*rty)), + Single | Variant(_) => match ty.kind() { + ty::Tuple(fs) => Fields::wildcards_from_tys(cx, fs.iter()), + ty::Ref(_, rty, _) => Fields::wildcards_from_tys(cx, once(*rty)), ty::Adt(adt, substs) => { if adt.is_box() { // The only legal patterns of type `Box` (outside `std`) are `_` and box // patterns. If we're here we can assume this is a box pattern. - Fields::wildcards_from_tys(pcx.cx, once(substs.type_at(0))) + Fields::wildcards_from_tys(cx, once(substs.type_at(0))) } else { let variant = &adt.variant(constructor.variant_index_for_adt(*adt)); - let tys = Fields::list_variant_nonhidden_fields(pcx.cx, pcx.ty, variant) + let tys = Fields::list_variant_nonhidden_fields(cx, ty, variant) .map(|(_, ty)| ty); - Fields::wildcards_from_tys(pcx.cx, tys) + Fields::wildcards_from_tys(cx, tys) } } - _ => bug!("Unexpected type for `Single` constructor: {:?}", pcx), + _ => bug!("Unexpected type for `Single` constructor: {:?}", ty), }, - Slice(slice) => match *pcx.ty.kind() { + Slice(slice) => match *ty.kind() { ty::Slice(ty) | ty::Array(ty, _) => { let arity = slice.arity(); - Fields::wildcards_from_tys(pcx.cx, (0..arity).map(|_| ty)) + Fields::wildcards_from_tys(cx, (0..arity).map(|_| ty)) } - _ => bug!("bad slice pattern {:?} {:?}", constructor, pcx), + _ => bug!("bad slice pattern {:?} {:?}", constructor, ty), }, Str(..) | FloatRange(..) @@ -1240,7 +1243,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { bug!("called `Fields::wildcards` on an `Or` ctor") } }; - debug!(?ret); + debug!("Fields::wildcards({:?}, {:?}) = {:#?}", constructor, ty, ret); ret } @@ -1283,7 +1286,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { /// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern /// `Some(_)`. pub(super) fn wild_from_ctor(pcx: PatCtxt<'_, 'p, 'tcx>, ctor: Constructor<'tcx>) -> Self { - let fields = Fields::wildcards(pcx, &ctor); + let fields = Fields::wildcards(pcx.cx, pcx.ty, &ctor); DeconstructedPat::new(ctor, fields, pcx.ty, DUMMY_SP) } @@ -1550,13 +1553,13 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { /// `other_ctor` can be different from `self.ctor`, but must be covered by it. pub(super) fn specialize<'a>( &'a self, - pcx: PatCtxt<'_, 'p, 'tcx>, + cx: &MatchCheckCtxt<'p, 'tcx>, other_ctor: &Constructor<'tcx>, ) -> SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]> { match (&self.ctor, other_ctor) { (Wildcard, _) => { // We return a wildcard for each field of `other_ctor`. - Fields::wildcards(pcx, other_ctor).iter_patterns().collect() + Fields::wildcards(cx, self.ty, other_ctor).iter_patterns().collect() } (Slice(self_slice), Slice(other_slice)) if self_slice.arity() != other_slice.arity() => @@ -1575,7 +1578,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { let prefix = &self.fields.fields[..prefix]; let suffix = &self.fields.fields[self_slice.arity() - suffix..]; let wildcard: &_ = - pcx.cx.pattern_arena.alloc(DeconstructedPat::wildcard(inner_ty)); + cx.pattern_arena.alloc(DeconstructedPat::wildcard(inner_ty)); let extra_wildcards = other_slice.arity() - self_slice.arity(); let extra_wildcards = (0..extra_wildcards).map(|_| wildcard); prefix.iter().chain(extra_wildcards).chain(suffix).collect() diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 7d22f7b69d8..a13748a2d47 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -196,7 +196,6 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } } - #[instrument(skip(self), level = "debug")] fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> { let mut ty = self.typeck_results.node_type(pat.hir_id); diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index f27ec22a8de..9e7a267ecbd 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -411,12 +411,12 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> { /// This is roughly the inverse of `Constructor::apply`. fn pop_head_constructor( &self, - pcx: PatCtxt<'_, 'p, 'tcx>, + cx: &MatchCheckCtxt<'p, 'tcx>, ctor: &Constructor<'tcx>, ) -> PatStack<'p, 'tcx> { // We pop the head pattern and push the new fields extracted from the arguments of // `self.head()`. - let mut new_fields: SmallVec<[_; 2]> = self.head().specialize(pcx, ctor); + let mut new_fields: SmallVec<[_; 2]> = self.head().specialize(cx, ctor); new_fields.extend_from_slice(&self.pats[1..]); PatStack::from_vec(new_fields) } @@ -475,7 +475,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { let mut matrix = Matrix::empty(); for row in &self.patterns { if ctor.is_covered_by(pcx, row.head().ctor()) { - let new_row = row.pop_head_constructor(pcx, ctor); + let new_row = row.pop_head_constructor(pcx.cx, ctor); matrix.push(new_row); } } @@ -786,7 +786,7 @@ fn is_useful<'p, 'tcx>( is_under_guard: bool, is_top_level: bool, ) -> Usefulness<'p, 'tcx> { - debug!(?matrix, ?v); + debug!("matrix,v={:?}{:?}", matrix, v); let Matrix { patterns: rows, .. } = matrix; // The base case. We are pattern-matching on () and the return value is @@ -806,6 +806,11 @@ fn is_useful<'p, 'tcx>( debug_assert!(rows.iter().all(|r| r.len() == v.len())); + let ty = v.head().ty(); + let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty); + debug!("v.head: {:?}, v.span: {:?}", v.head(), v.head().span()); + let pcx = PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive }; + // If the first pattern is an or-pattern, expand it. let mut ret = Usefulness::new_not_useful(witness_preference); if v.head().is_or_pat() { @@ -827,19 +832,6 @@ fn is_useful<'p, 'tcx>( } } } else { - let mut ty = v.head().ty(); - - // Opaque types can't get destructured/split, but the patterns can - // actually hint at hidden types, so we use the patterns' types instead. - if let ty::Opaque(..) = v.head().ty().kind() { - if let Some(row) = rows.first() { - ty = row.head().ty(); - } - } - let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty); - debug!("v.head: {:?}, v.span: {:?}", v.head(), v.head().span()); - let pcx = PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive }; - let v_ctor = v.head().ctor(); debug!(?v_ctor); if let Constructor::IntRange(ctor_range) = &v_ctor { @@ -861,7 +853,7 @@ fn is_useful<'p, 'tcx>( debug!("specialize({:?})", ctor); // We cache the result of `Fields::wildcards` because it is used a lot. let spec_matrix = start_matrix.specialize_constructor(pcx, &ctor); - let v = v.pop_head_constructor(pcx, &ctor); + let v = v.pop_head_constructor(cx, &ctor); let usefulness = ensure_sufficient_stack(|| { is_useful(cx, &spec_matrix, &v, witness_preference, hir_id, is_under_guard, false) }); diff --git a/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs b/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs index 7806e8f45d3..28936274baa 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs @@ -48,7 +48,6 @@ impl<'tcx> Lift for PlaceElem<'tcx> { match *self { ProjectionElem::Deref => ProjectionElem::Deref, ProjectionElem::Field(f, ty) => ProjectionElem::Field(f, ty.lift()), - ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty.lift()), ProjectionElem::Index(ref i) => ProjectionElem::Index(i.lift()), ProjectionElem::Subslice { from, to, from_end } => { ProjectionElem::Subslice { from, to, from_end } diff --git a/compiler/rustc_mir_dataflow/src/un_derefer.rs b/compiler/rustc_mir_dataflow/src/un_derefer.rs index ec2e516f7ac..2ab7eddcac9 100644 --- a/compiler/rustc_mir_dataflow/src/un_derefer.rs +++ b/compiler/rustc_mir_dataflow/src/un_derefer.rs @@ -1,4 +1,4 @@ -use rustc_data_structures::stable_map::FxHashMap; +use rustc_data_structures::fx::FxHashMap; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs index 86327ade94b..b91ae083cf5 100644 --- a/compiler/rustc_mir_transform/src/add_retag.rs +++ b/compiler/rustc_mir_transform/src/add_retag.rs @@ -28,7 +28,6 @@ fn is_stable(place: PlaceRef<'_>) -> bool { ProjectionElem::Field { .. } | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } | - ProjectionElem::OpaqueCast { .. } | ProjectionElem::Downcast { .. } => true, } }) diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index ded1f0462cb..a2ad96cfc16 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -219,14 +219,11 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> { // We have to check the actual type of the assignment, as that determines if the // old value is being dropped. let assigned_ty = place.ty(&self.body.local_decls, self.tcx).ty; - if assigned_ty.needs_drop( - self.tcx, - self.tcx.param_env(base_ty.ty_adt_def().unwrap().did()), - ) { + if assigned_ty.needs_drop(self.tcx, self.param_env) { // This would be unsafe, but should be outright impossible since we reject such unions. self.tcx.sess.delay_span_bug( self.source_info.span, - "union fields that need dropping should be impossible", + format!("union fields that need dropping should be impossible: {assigned_ty}") ); } } else { diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index acd9e605353..f6484a9b54d 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -234,9 +234,9 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> } fn access_local<'a>( - frame: &'a Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>, + frame: &'a Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>, local: Local, - ) -> InterpResult<'tcx, &'a interpret::Operand<Self::PointerTag>> { + ) -> InterpResult<'tcx, &'a interpret::Operand<Self::Provenance>> { let l = &frame.locals[local]; if matches!( @@ -255,7 +255,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> ecx: &'a mut InterpCx<'mir, 'tcx, Self>, frame: usize, local: Local, - ) -> InterpResult<'tcx, &'a mut interpret::Operand<Self::PointerTag>> { + ) -> InterpResult<'tcx, &'a mut interpret::Operand<Self::Provenance>> { if ecx.machine.can_const_prop[local] == ConstPropMode::NoPropagation { throw_machine_stop_str!("tried to write to a local that is marked as not propagatable") } @@ -274,7 +274,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> _tcx: TyCtxt<'tcx>, _machine: &Self, _alloc_id: AllocId, - alloc: ConstAllocation<'tcx, Self::PointerTag, Self::AllocExtra>, + alloc: ConstAllocation<'tcx, Self::Provenance, Self::AllocExtra>, _static_def_id: Option<DefId>, is_write: bool, ) -> InterpResult<'tcx> { @@ -309,14 +309,14 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> #[inline(always)] fn stack<'a>( ecx: &'a InterpCx<'mir, 'tcx, Self>, - ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] { + ) -> &'a [Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>] { &ecx.machine.stack } #[inline(always)] fn stack_mut<'a>( ecx: &'a mut InterpCx<'mir, 'tcx, Self>, - ) -> &'a mut Vec<Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>> { + ) -> &'a mut Vec<Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>> { &mut ecx.machine.stack } } @@ -516,7 +516,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let l = self.use_ecx(|this| this.ecx.read_immediate(&this.ecx.eval_operand(left, None)?)); // Check for exceeding shifts *even if* we cannot evaluate the LHS. if op == BinOp::Shr || op == BinOp::Shl { - let r = r?; + let r = r.clone()?; // We need the type of the LHS. We cannot use `place_layout` as that is the type // of the result, which for checked binops is not the same! let left_ty = left.ty(self.local_decls, self.tcx); diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index 49db140c474..97b1433f5d2 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -230,9 +230,9 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> } fn access_local<'a>( - frame: &'a Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>, + frame: &'a Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>, local: Local, - ) -> InterpResult<'tcx, &'a interpret::Operand<Self::PointerTag>> { + ) -> InterpResult<'tcx, &'a interpret::Operand<Self::Provenance>> { let l = &frame.locals[local]; if matches!( @@ -251,7 +251,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> ecx: &'a mut InterpCx<'mir, 'tcx, Self>, frame: usize, local: Local, - ) -> InterpResult<'tcx, &'a mut interpret::Operand<Self::PointerTag>> { + ) -> InterpResult<'tcx, &'a mut interpret::Operand<Self::Provenance>> { if ecx.machine.can_const_prop[local] == ConstPropMode::NoPropagation { throw_machine_stop_str!("tried to write to a local that is marked as not propagatable") } @@ -270,7 +270,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> _tcx: TyCtxt<'tcx>, _machine: &Self, _alloc_id: AllocId, - alloc: ConstAllocation<'tcx, Self::PointerTag, Self::AllocExtra>, + alloc: ConstAllocation<'tcx, Self::Provenance, Self::AllocExtra>, _static_def_id: Option<DefId>, is_write: bool, ) -> InterpResult<'tcx> { @@ -305,14 +305,14 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> #[inline(always)] fn stack<'a>( ecx: &'a InterpCx<'mir, 'tcx, Self>, - ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] { + ) -> &'a [Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>] { &ecx.machine.stack } #[inline(always)] fn stack_mut<'a>( ecx: &'a mut InterpCx<'mir, 'tcx, Self>, - ) -> &'a mut Vec<Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>> { + ) -> &'a mut Vec<Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>> { &mut ecx.machine.stack } } @@ -584,7 +584,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { }); // Check for exceeding shifts *even if* we cannot evaluate the LHS. if op == BinOp::Shr || op == BinOp::Shl { - let r = r?; + let r = r.clone()?; // We need the type of the LHS. We cannot use `place_layout` as that is the type // of the result, which for checked binops is not the same! let left_ty = left.ty(self.local_decls, self.tcx); @@ -616,10 +616,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } } - if let (Some(l), Some(r)) = (&l, &r) { + if let (Some(l), Some(r)) = (l, r) { // The remaining operators are handled through `overflowing_binary_op`. if self.use_ecx(source_info, |this| { - let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, l, r)?; + let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, &l, &r)?; Ok(overflow) })? { self.report_assert_as_lint( diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index dc5d5cee879..1e46b0a0e81 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -246,7 +246,7 @@ impl<'tcx> Inliner<'tcx> { // not get any optimizations run on it. Any subsequent inlining may cause cycles, but we // do not need to catch this here, we can wait until the inliner decides to continue // inlining a second time. - InstanceDef::VtableShim(_) + InstanceDef::VTableShim(_) | InstanceDef::ReifyShim(_) | InstanceDef::FnPtrShim(..) | InstanceDef::ClosureOnceShim { .. } diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index a3a35f95071..7810218fd67 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -79,7 +79,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( // These have MIR and if that MIR is inlined, substituted and then inlining is run // again, a function item can end up getting inlined. Thus we'll be able to cause // a cycle that way - InstanceDef::VtableShim(_) + InstanceDef::VTableShim(_) | InstanceDef::ReifyShim(_) | InstanceDef::FnPtrShim(..) | InstanceDef::ClosureOnceShim { .. } diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index eaa61d8614d..3620e94bec7 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -32,7 +32,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' let mut result = match instance { ty::InstanceDef::Item(..) => bug!("item {:?} passed to make_shim", instance), - ty::InstanceDef::VtableShim(def_id) => { + ty::InstanceDef::VTableShim(def_id) => { build_call_shim(tcx, instance, Some(Adjustment::Deref), CallKind::Direct(def_id)) } ty::InstanceDef::FnPtrShim(def_id, ty) => { @@ -113,7 +113,7 @@ enum Adjustment { /// We get passed `&[mut] self` and call the target with `*self`. /// /// This either copies `self` (if `Self: Copy`, eg. for function items), or moves out of it - /// (for `VtableShim`, which effectively is passed `&own Self`). + /// (for `VTableShim`, which effectively is passed `&own Self`). Deref, /// We get passed `self: Self` and call the target with `&mut self`. @@ -569,7 +569,7 @@ fn build_call_shim<'tcx>( // FIXME(eddyb) avoid having this snippet both here and in // `Instance::fn_sig` (introduce `InstanceDef::fn_sig`?). - if let ty::InstanceDef::VtableShim(..) = instance { + if let ty::InstanceDef::VTableShim(..) = instance { // Modify fn(self, ...) to fn(self: *mut Self, ...) let mut inputs_and_output = sig.inputs_and_output.to_vec(); let self_arg = &mut inputs_and_output[0]; diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index 980af984362..d305960b485 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -28,6 +28,7 @@ //! return. use crate::MirPass; +use rustc_data_structures::fx::FxHashSet; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::mir::coverage::*; use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; @@ -267,7 +268,8 @@ pub fn remove_dead_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { return; } - let basic_blocks = body.basic_blocks_mut(); + let basic_blocks = body.basic_blocks.as_mut(); + let source_scopes = &body.source_scopes; let mut replacements: Vec<_> = (0..num_blocks).map(BasicBlock::new).collect(); let mut used_blocks = 0; for alive_index in reachable.iter() { @@ -282,7 +284,7 @@ pub fn remove_dead_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { } if tcx.sess.instrument_coverage() { - save_unreachable_coverage(basic_blocks, used_blocks); + save_unreachable_coverage(basic_blocks, source_scopes, used_blocks); } basic_blocks.raw.truncate(used_blocks); @@ -311,56 +313,62 @@ pub fn remove_dead_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { /// `Unreachable` coverage statements. These are non-executable statements whose /// code regions are still recorded in the coverage map, representing regions /// with `0` executions. +/// +/// If there are no live `Counter` `Coverage` statements remaining, we remove +/// dead `Coverage` statements along with the dead blocks. Since at least one +/// counter per function is required by LLVM (and necessary, to add the +/// `function_hash` to the counter's call to the LLVM intrinsic +/// `instrprof.increment()`). +/// +/// The `generator::StateTransform` MIR pass and MIR inlining can create +/// atypical conditions, where all live `Counter`s are dropped from the MIR. +/// +/// With MIR inlining we can have coverage counters belonging to different +/// instances in a single body, so the strategy described above is applied to +/// coverage counters from each instance individually. fn save_unreachable_coverage( basic_blocks: &mut IndexVec<BasicBlock, BasicBlockData<'_>>, + source_scopes: &IndexVec<SourceScope, SourceScopeData<'_>>, first_dead_block: usize, ) { - let has_live_counters = basic_blocks.raw[0..first_dead_block].iter().any(|live_block| { - live_block.statements.iter().any(|statement| { - if let StatementKind::Coverage(coverage) = &statement.kind { - matches!(coverage.kind, CoverageKind::Counter { .. }) - } else { - false - } - }) - }); - if !has_live_counters { - // If there are no live `Counter` `Coverage` statements anymore, don't - // move dead coverage to the `START_BLOCK`. Just allow the dead - // `Coverage` statements to be dropped with the dead blocks. - // - // The `generator::StateTransform` MIR pass can create atypical - // conditions, where all live `Counter`s are dropped from the MIR. - // - // At least one Counter per function is required by LLVM (and necessary, - // to add the `function_hash` to the counter's call to the LLVM - // intrinsic `instrprof.increment()`). + // Identify instances that still have some live coverage counters left. + let mut live = FxHashSet::default(); + for basic_block in &basic_blocks.raw[0..first_dead_block] { + for statement in &basic_block.statements { + let StatementKind::Coverage(coverage) = &statement.kind else { continue }; + let CoverageKind::Counter { .. } = coverage.kind else { continue }; + let instance = statement.source_info.scope.inlined_instance(source_scopes); + live.insert(instance); + } + } + + if live.is_empty() { return; } - // Retain coverage info for dead blocks, so coverage reports will still - // report `0` executions for the uncovered code regions. - let mut dropped_coverage = Vec::new(); - for dead_block in basic_blocks.raw[first_dead_block..].iter() { - for statement in dead_block.statements.iter() { - if let StatementKind::Coverage(coverage) = &statement.kind { - if let Some(code_region) = &coverage.code_region { - dropped_coverage.push((statement.source_info, code_region.clone())); - } + // Retain coverage for instances that still have some live counters left. + let mut retained_coverage = Vec::new(); + for dead_block in &basic_blocks.raw[first_dead_block..] { + for statement in &dead_block.statements { + let StatementKind::Coverage(coverage) = &statement.kind else { continue }; + let Some(code_region) = &coverage.code_region else { continue }; + let instance = statement.source_info.scope.inlined_instance(source_scopes); + if live.contains(&instance) { + retained_coverage.push((statement.source_info, code_region.clone())); } } } let start_block = &mut basic_blocks[START_BLOCK]; - for (source_info, code_region) in dropped_coverage { - start_block.statements.push(Statement { + start_block.statements.extend(retained_coverage.into_iter().map( + |(source_info, code_region)| Statement { source_info, kind: StatementKind::Coverage(Box::new(Coverage { kind: CoverageKind::Unreachable, code_region: Some(code_region), })), - }) - } + }, + )); } pub struct SimplifyLocals; diff --git a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs index bd196f11879..30be64f5b2f 100644 --- a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs +++ b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs @@ -1,7 +1,7 @@ //! A pass that eliminates branches on uninhabited enum variants. use crate::MirPass; -use rustc_data_structures::stable_set::FxHashSet; +use rustc_data_structures::fx::FxHashSet; use rustc_middle::mir::{ BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, SwitchTargets, Terminator, TerminatorKind, diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index d9fa4d65b3a..68b65658c72 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -25,7 +25,7 @@ //! codegen unit: //! //! - Constants -//! - Vtables +//! - VTables //! - Object Shims //! //! @@ -180,7 +180,7 @@ //! regardless of whether it is actually needed or not. use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::sync::{par_iter, MTLock, MTRef, ParallelIterator}; +use rustc_data_structures::sync::{par_for_each_in, MTLock, MTRef}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; @@ -346,7 +346,7 @@ pub fn collect_crate_mono_items( let inlining_map: MTRef<'_, _> = &mut inlining_map; tcx.sess.time("monomorphization_collector_graph_walk", || { - par_iter(roots).for_each(|root| { + par_for_each_in(roots, |root| { let mut recursion_depths = DefIdMap::default(); collect_items_rec( tcx, @@ -992,7 +992,7 @@ fn visit_instance_use<'tcx>( } } ty::InstanceDef::DropGlue(_, Some(_)) - | ty::InstanceDef::VtableShim(..) + | ty::InstanceDef::VTableShim(..) | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::ClosureOnceShim { .. } | ty::InstanceDef::Item(..) @@ -1427,6 +1427,10 @@ fn collect_miri<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIte output.push(create_fn_mono_item(tcx, fn_instance, DUMMY_SP)); } } + GlobalAlloc::VTable(ty, trait_ref) => { + let alloc_id = tcx.vtable_allocation((ty, trait_ref)); + collect_miri(tcx, alloc_id, output) + } } } diff --git a/compiler/rustc_monomorphize/src/partitioning/default.rs b/compiler/rustc_monomorphize/src/partitioning/default.rs index d18b1c26c17..15276569c32 100644 --- a/compiler/rustc_monomorphize/src/partitioning/default.rs +++ b/compiler/rustc_monomorphize/src/partitioning/default.rs @@ -271,7 +271,7 @@ fn characteristic_def_id_of_mono_item<'tcx>( MonoItem::Fn(instance) => { let def_id = match instance.def { ty::InstanceDef::Item(def) => def.did, - ty::InstanceDef::VtableShim(..) + ty::InstanceDef::VTableShim(..) | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::FnPtrShim(..) | ty::InstanceDef::ClosureOnceShim { .. } @@ -425,7 +425,7 @@ fn mono_item_visibility<'tcx>( InstanceDef::DropGlue(def_id, Some(_)) => def_id, // These are all compiler glue and such, never exported, always hidden. - InstanceDef::VtableShim(..) + InstanceDef::VTableShim(..) | InstanceDef::ReifyShim(..) | InstanceDef::FnPtrShim(..) | InstanceDef::Virtual(..) diff --git a/compiler/rustc_monomorphize/src/partitioning/mod.rs b/compiler/rustc_monomorphize/src/partitioning/mod.rs index 36243803f99..ff2d3869328 100644 --- a/compiler/rustc_monomorphize/src/partitioning/mod.rs +++ b/compiler/rustc_monomorphize/src/partitioning/mod.rs @@ -98,6 +98,7 @@ mod merging; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync; use rustc_hir::def_id::DefIdSet; +use rustc_middle::mir; use rustc_middle::mir::mono::MonoItem; use rustc_middle::mir::mono::{CodegenUnit, Linkage}; use rustc_middle::ty::print::with_no_trimmed_paths; @@ -479,9 +480,14 @@ fn codegened_and_inlined_items<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> &'tcx DefIdSe if !visited.insert(did) { continue; } - for scope in &tcx.instance_mir(instance.def).source_scopes { - if let Some((ref inlined, _)) = scope.inlined { - result.insert(inlined.def_id()); + let body = tcx.instance_mir(instance.def); + for block in body.basic_blocks() { + for statement in &block.statements { + let mir::StatementKind::Coverage(_) = statement.kind else { continue }; + let scope = statement.source_info.scope; + if let Some(inlined) = scope.inlined_instance(&body.source_scopes) { + result.insert(inlined.def_id()); + } } } } diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index f6fa19030ac..6e7553f5e49 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -572,9 +572,10 @@ impl<'a> Parser<'a> { // '0' flag and then an ill-formatted format string with just a '$' // and no count, but this is better if we instead interpret this as // no '0' flag and '0$' as the width instead. - if self.consume('$') { + if let Some(end) = self.consume_pos('$') { spec.width = CountIsParam(0); havewidth = true; + spec.width_span = Some(self.to_span_index(end - 1).to(self.to_span_index(end + 1))); } else { spec.flags |= 1 << (FlagSignAwareZeroPad as u32); } diff --git a/compiler/rustc_parse_format/src/tests.rs b/compiler/rustc_parse_format/src/tests.rs index c9667922ee7..9c305b4996a 100644 --- a/compiler/rustc_parse_format/src/tests.rs +++ b/compiler/rustc_parse_format/src/tests.rs @@ -179,6 +179,23 @@ fn format_counts() { })], ); same( + "{1:0$.10x}", + &[NextArgument(Argument { + position: ArgumentIs(1), + format: FormatSpec { + fill: None, + align: AlignUnknown, + flags: 0, + precision: CountIs(10), + width: CountIsParam(0), + precision_span: None, + width_span: Some(InnerSpan::new(4, 6)), + ty: "x", + ty_span: None, + }, + })], + ); + same( "{:.*x}", &[NextArgument(Argument { position: ArgumentImplicitlyIs(1), diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index d96e7d3efe8..f88997f884a 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -706,14 +706,20 @@ impl CheckAttrVisitor<'_> { true } - fn check_doc_tuple_variadic(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool { + fn check_doc_fake_variadic(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool { match self.tcx.hir().find(hir_id).and_then(|node| match node { hir::Node::Item(item) => Some(&item.kind), _ => None, }) { Some(ItemKind::Impl(ref i)) => { - if !matches!(&i.self_ty.kind, hir::TyKind::Tup([_])) { - self.tcx.sess.emit_err(errors::DocTupleVariadicNotFirst { span: meta.span() }); + let is_valid = matches!(&i.self_ty.kind, hir::TyKind::Tup([_])) + || if let hir::TyKind::BareFn(bare_fn_ty) = &i.self_ty.kind { + bare_fn_ty.decl.inputs.len() == 1 + } else { + false + }; + if !is_valid { + self.tcx.sess.emit_err(errors::DocFakeVariadicNotValid { span: meta.span() }); return false; } } @@ -887,9 +893,9 @@ impl CheckAttrVisitor<'_> { is_valid = false } - sym::tuple_variadic - if !self.check_attr_not_crate_level(meta, hir_id, "tuple_variadic") - || !self.check_doc_tuple_variadic(meta, hir_id) => + sym::fake_variadic + if !self.check_attr_not_crate_level(meta, hir_id, "fake_variadic") + || !self.check_doc_fake_variadic(meta, hir_id) => { is_valid = false } @@ -939,7 +945,7 @@ impl CheckAttrVisitor<'_> { | sym::notable_trait | sym::passes | sym::plugins - | sym::tuple_variadic => {} + | sym::fake_variadic => {} sym::test => { if !self.check_test_attr(meta, hir_id) { diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index 1add91fc9c5..7381019a620 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -77,7 +77,7 @@ fn err_if_attr_found(ctxt: &EntryContext<'_>, attrs: &[Attribute], sym: Symbol) .sess .struct_span_err( attr.span, - &format!("`{}` attribute can only be used on functions", sym.as_str()), + &format!("`{}` attribute can only be used on functions", sym), ) .emit(); } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index f8e8720ab54..fcd1e9363b1 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -212,8 +212,8 @@ pub struct DocKeywordInvalidIdent { } #[derive(SessionDiagnostic)] -#[error(passes::doc_tuple_variadic_not_first)] -pub struct DocTupleVariadicNotFirst { +#[error(passes::doc_fake_variadic_not_valid)] +pub struct DocFakeVariadicNotValid { #[primary_span] pub span: Span, } diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs index 26bfa4737a7..e05994f13e4 100644 --- a/compiler/rustc_passes/src/lib_features.rs +++ b/compiler/rustc_passes/src/lib_features.rs @@ -1,8 +1,8 @@ -// Detecting lib features (i.e., features that are not lang features). -// -// These are declared using stability attributes (e.g., `#[stable (..)]` -// and `#[unstable (..)]`), but are not declared in one single location -// (unlike lang features), which means we need to collect them instead. +//! Detecting lib features (i.e., features that are not lang features). +//! +//! These are declared using stability attributes (e.g., `#[stable (..)]` and `#[unstable (..)]`), +//! but are not declared in one single location (unlike lang features), which means we need to +//! collect them instead. use rustc_ast::{Attribute, MetaItemKind}; use rustc_errors::struct_span_err; @@ -71,11 +71,11 @@ impl<'tcx> LibFeatureCollector<'tcx> { fn collect_feature(&mut self, feature: Symbol, since: Option<Symbol>, span: Span) { let already_in_stable = self.lib_features.stable.contains_key(&feature); - let already_in_unstable = self.lib_features.unstable.contains(&feature); + let already_in_unstable = self.lib_features.unstable.contains_key(&feature); match (since, already_in_stable, already_in_unstable) { (Some(since), _, false) => { - if let Some(prev_since) = self.lib_features.stable.get(&feature) { + if let Some((prev_since, _)) = self.lib_features.stable.get(&feature) { if *prev_since != since { self.span_feature_error( span, @@ -89,10 +89,10 @@ impl<'tcx> LibFeatureCollector<'tcx> { } } - self.lib_features.stable.insert(feature, since); + self.lib_features.stable.insert(feature, (since, span)); } (None, false, _) => { - self.lib_features.unstable.insert(feature); + self.lib_features.unstable.insert(feature, span); } (Some(_), _, true) | (None, true, _) => { self.span_feature_error( diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 4e091c5b70d..81b04c414ed 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -2,9 +2,9 @@ //! propagating default levels lexically from parent to children ast nodes. use attr::StabilityLevel; -use rustc_attr::{self as attr, ConstStability, Stability}; -use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; -use rustc_errors::struct_span_err; +use rustc_attr::{self as attr, ConstStability, Stability, Unstable}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; +use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; @@ -29,13 +29,13 @@ use std::num::NonZeroU32; #[derive(PartialEq)] enum AnnotationKind { - // Annotation is required if not inherited from unstable parents + /// Annotation is required if not inherited from unstable parents. Required, - // Annotation is useless, reject it + /// Annotation is useless, reject it. Prohibited, - // Deprecation annotation is useless, reject it. (Stability attribute is still required.) + /// Deprecation annotation is useless, reject it. (Stability attribute is still required.) DeprecationProhibited, - // Annotation itself is useless, but it can be propagated to children + /// Annotation itself is useless, but it can be propagated to children. Container, } @@ -83,7 +83,7 @@ impl InheritStability { } } -// A private tree-walker for producing an Index. +/// A private tree-walker for producing an `Index`. struct Annotator<'a, 'tcx> { tcx: TyCtxt<'tcx>, index: &'a mut Index, @@ -94,9 +94,9 @@ struct Annotator<'a, 'tcx> { } impl<'a, 'tcx> Annotator<'a, 'tcx> { - // Determine the stability for a node based on its attributes and inherited - // stability. The stability is recorded in the index and used as the parent. - // If the node is a function, `fn_sig` is its signature + /// Determine the stability for a node based on its attributes and inherited stability. The + /// stability is recorded in the index and used as the parent. If the node is a function, + /// `fn_sig` is its signature. fn annotate<F>( &mut self, def_id: LocalDefId, @@ -265,6 +265,10 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } } + if let Stability { level: Unstable { implied_by: Some(implied_by), .. }, feature } = stab { + self.index.implications.insert(implied_by, feature); + } + self.index.stab_map.insert(def_id, stab); stab }); @@ -610,6 +614,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { stab_map: Default::default(), const_stab_map: Default::default(), depr_map: Default::default(), + implications: Default::default(), }; { @@ -637,6 +642,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { reason: Some(Symbol::intern(reason)), issue: NonZeroU32::new(27812), is_soft: false, + implied_by: None, }, feature: sym::rustc_private, }; @@ -667,6 +673,7 @@ pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { check_mod_unstable_api_usage, stability_index, + stability_implications: |tcx, _| tcx.stability().implications.clone(), lookup_stability: |tcx, id| tcx.stability().local_stability(id.expect_local()), lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id.expect_local()), lookup_deprecation_entry: |tcx, id| { @@ -945,32 +952,51 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { remaining_lib_features.remove(&sym::libc); remaining_lib_features.remove(&sym::test); - let check_features = |remaining_lib_features: &mut FxIndexMap<_, _>, defined_features: &[_]| { - for &(feature, since) in defined_features { - if let Some(since) = since { - if let Some(span) = remaining_lib_features.get(&feature) { - // Warn if the user has enabled an already-stable lib feature. - unnecessary_stable_feature_lint(tcx, *span, feature, since); - } - } - remaining_lib_features.remove(&feature); - if remaining_lib_features.is_empty() { - break; - } - } - }; - // We always collect the lib features declared in the current crate, even if there are // no unknown features, because the collection also does feature attribute validation. - let local_defined_features = tcx.lib_features(()).to_vec(); - if !remaining_lib_features.is_empty() { - check_features(&mut remaining_lib_features, &local_defined_features); + let local_defined_features = tcx.lib_features(()); + let mut all_lib_features: FxHashMap<_, _> = + local_defined_features.to_vec().iter().map(|el| *el).collect(); + let mut implications = tcx.stability_implications(rustc_hir::def_id::LOCAL_CRATE).clone(); + for &cnum in tcx.crates(()) { + implications.extend(tcx.stability_implications(cnum)); + all_lib_features.extend(tcx.defined_lib_features(cnum).iter().map(|el| *el)); + } - for &cnum in tcx.crates(()) { + // Check that every feature referenced by an `implied_by` exists (for features defined in the + // local crate). + for (implied_by, feature) in tcx.stability_implications(rustc_hir::def_id::LOCAL_CRATE) { + // Only `implied_by` needs to be checked, `feature` is guaranteed to exist. + if !all_lib_features.contains_key(implied_by) { + let span = local_defined_features + .stable + .get(feature) + .map(|(_, span)| span) + .or_else(|| local_defined_features.unstable.get(feature)) + .expect("feature that implied another does not exist"); + tcx.sess + .struct_span_err( + *span, + format!("feature `{implied_by}` implying `{feature}` does not exist"), + ) + .emit(); + } + } + + if !remaining_lib_features.is_empty() { + for (feature, since) in all_lib_features.iter() { + if let Some(since) = since && let Some(span) = remaining_lib_features.get(&feature) { + // Warn if the user has enabled an already-stable lib feature. + if let Some(implies) = implications.get(&feature) { + unnecessary_partially_stable_feature_lint(tcx, *span, *feature, *implies, *since); + } else { + unnecessary_stable_feature_lint(tcx, *span, *feature, *since); + } + } + remaining_lib_features.remove(&feature); if remaining_lib_features.is_empty() { break; } - check_features(&mut remaining_lib_features, tcx.defined_lib_features(cnum)); } } @@ -982,12 +1008,41 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { // don't lint about unused features. We should re-enable this one day! } +fn unnecessary_partially_stable_feature_lint( + tcx: TyCtxt<'_>, + span: Span, + feature: Symbol, + implies: Symbol, + since: Symbol, +) { + tcx.struct_span_lint_hir(lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, |lint| { + lint.build(&format!( + "the feature `{feature}` has been partially stabilized since {since} and is succeeded \ + by the feature `{implies}`" + )) + .span_suggestion( + span, + &format!( + "if you are using features which are still unstable, change to using `{implies}`" + ), + implies, + Applicability::MaybeIncorrect, + ) + .span_suggestion( + tcx.sess.source_map().span_extend_to_line(span), + "if you are using features which are now stable, remove this line", + "", + Applicability::MaybeIncorrect, + ) + .emit(); + }); +} + fn unnecessary_stable_feature_lint(tcx: TyCtxt<'_>, span: Span, feature: Symbol, since: Symbol) { tcx.struct_span_lint_hir(lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, |lint| { lint.build(&format!( - "the feature `{}` has been stable since {} and no longer requires \ - an attribute to enable", - feature, since + "the feature `{feature}` has been stable since {since} and no longer requires an \ + attribute to enable", )) .emit(); }); diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs index 3291be05807..c48b4ecf87a 100644 --- a/compiler/rustc_passes/src/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -68,7 +68,7 @@ fn verify<'tcx>(tcx: TyCtxt<'tcx>, items: &lang_items::LanguageItems) { } } - for (name, item) in WEAK_ITEMS_REFS.clone().into_sorted_vector().into_iter() { + for (name, &item) in WEAK_ITEMS_REFS.iter() { if missing.contains(&item) && required(tcx, item) && items.require(item).is_err() { if item == LangItem::PanicImpl { tcx.sess.err("`#[panic_handler]` function required, but not found"); diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 9a835808d49..390d6f5a856 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1754,7 +1754,6 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { || self.in_assoc_ty || self.tcx.resolutions(()).has_pub_restricted { - let descr = descr.to_string(); let vis_span = self.tcx.sess.source_map().guess_head_span(self.tcx.def_span(def_id)); if kind == "trait" { diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 7c1fdc4e306..eda61df7700 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -37,7 +37,7 @@ mod values; use self::values::Value; pub use rustc_query_system::query::QueryConfig; -pub(crate) use rustc_query_system::query::{QueryDescription, QueryVtable}; +pub(crate) use rustc_query_system::query::{QueryDescription, QueryVTable}; mod on_disk_cache; pub use on_disk_cache::OnDiskCache; diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 333dc5aa668..eda4401c81d 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -340,11 +340,11 @@ macro_rules! define_queries { #[inline] fn make_vtable(tcx: QueryCtxt<'tcx>, key: &Self::Key) -> - QueryVtable<QueryCtxt<$tcx>, Self::Key, Self::Value> + QueryVTable<QueryCtxt<$tcx>, Self::Key, Self::Value> { let compute = get_provider!([$($modifiers)*][tcx, $name, key]); let cache_on_disk = Self::cache_on_disk(tcx.tcx, key); - QueryVtable { + QueryVTable { anon: is_anon!([$($modifiers)*]), eval_always: is_eval_always!([$($modifiers)*]), dep_kind: dep_graph::DepKind::$name, diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs index 7ca668f8a1f..964914a1326 100644 --- a/compiler/rustc_query_system/src/query/config.rs +++ b/compiler/rustc_query_system/src/query/config.rs @@ -19,7 +19,7 @@ pub trait QueryConfig { type Stored: Clone; } -pub struct QueryVtable<CTX: QueryContext, K, V> { +pub struct QueryVTable<CTX: QueryContext, K, V> { pub anon: bool, pub dep_kind: CTX::DepKind, pub eval_always: bool, @@ -31,7 +31,7 @@ pub struct QueryVtable<CTX: QueryContext, K, V> { pub try_load_from_disk: Option<fn(CTX, SerializedDepNodeIndex) -> Option<V>>, } -impl<CTX: QueryContext, K, V> QueryVtable<CTX, K, V> { +impl<CTX: QueryContext, K, V> QueryVTable<CTX, K, V> { pub(crate) fn to_dep_node(&self, tcx: CTX::DepContext, key: &K) -> DepNode<CTX::DepKind> where K: crate::dep_graph::DepNodeParams<CTX::DepContext>, @@ -69,7 +69,7 @@ pub trait QueryDescription<CTX: QueryContext>: QueryConfig { CTX: 'a; // Don't use this method to compute query results, instead use the methods on TyCtxt - fn make_vtable(tcx: CTX, key: &Self::Key) -> QueryVtable<CTX, Self::Key, Self::Value>; + fn make_vtable(tcx: CTX, key: &Self::Key) -> QueryVTable<CTX, Self::Key, Self::Value>; fn cache_on_disk(tcx: CTX::DepContext, key: &Self::Key) -> bool; } diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index f698a853d1e..fb2258434f4 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -12,7 +12,7 @@ pub use self::caches::{ }; mod config; -pub use self::config::{QueryConfig, QueryDescription, QueryVtable}; +pub use self::config::{QueryConfig, QueryDescription, QueryVTable}; use crate::dep_graph::{DepNodeIndex, HasDepContext, SerializedDepNodeIndex}; diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 792f2b03173..5e8ea07d00f 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -4,7 +4,7 @@ use crate::dep_graph::{DepContext, DepNode, DepNodeIndex, DepNodeParams}; use crate::query::caches::QueryCache; -use crate::query::config::{QueryDescription, QueryVtable}; +use crate::query::config::{QueryDescription, QueryVTable}; use crate::query::job::{report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo}; use crate::query::{QueryContext, QueryMap, QuerySideEffects, QueryStackFrame}; use rustc_data_structures::fingerprint::Fingerprint; @@ -331,7 +331,7 @@ fn try_execute_query<CTX, C>( span: Span, key: C::Key, dep_node: Option<DepNode<CTX::DepKind>>, - query: &QueryVtable<CTX, C::Key, C::Value>, + query: &QueryVTable<CTX, C::Key, C::Value>, ) -> (C::Stored, Option<DepNodeIndex>) where C: QueryCache, @@ -368,7 +368,7 @@ fn execute_job<CTX, K, V>( tcx: CTX, key: K, mut dep_node_opt: Option<DepNode<CTX::DepKind>>, - query: &QueryVtable<CTX, K, V>, + query: &QueryVTable<CTX, K, V>, job_id: QueryJobId, ) -> (V, DepNodeIndex) where @@ -437,7 +437,7 @@ fn try_load_from_disk_and_cache_in_memory<CTX, K, V>( tcx: CTX, key: &K, dep_node: &DepNode<CTX::DepKind>, - query: &QueryVtable<CTX, K, V>, + query: &QueryVTable<CTX, K, V>, ) -> Option<(V, DepNodeIndex)> where K: Clone, @@ -530,7 +530,7 @@ fn incremental_verify_ich<CTX, K, V: Debug>( tcx: CTX::DepContext, result: &V, dep_node: &DepNode<CTX::DepKind>, - query: &QueryVtable<CTX, K, V>, + query: &QueryVTable<CTX, K, V>, ) where CTX: QueryContext, { @@ -642,7 +642,7 @@ fn incremental_verify_ich_cold(sess: &Session, dep_node: DebugArg<'_>, result: D fn ensure_must_run<CTX, K, V>( tcx: CTX, key: &K, - query: &QueryVtable<CTX, K, V>, + query: &QueryVTable<CTX, K, V>, ) -> (bool, Option<DepNode<CTX::DepKind>>) where K: crate::dep_graph::DepNodeParams<CTX::DepContext>, diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index a820f700869..d74e26fc844 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1627,7 +1627,7 @@ impl<'a> Resolver<'a> { "{}{} `{}` defined here", prefix, suggestion.res.descr(), - suggestion.candidate.as_str(), + suggestion.candidate, ), ); } @@ -2603,12 +2603,12 @@ fn show_candidates( .skip(1) .all(|(_, descr, _, _)| descr == descr_first) { - descr_first.to_string() + descr_first } else { - "item".to_string() + "item" }; let plural_descr = - if descr.ends_with("s") { format!("{}es", descr) } else { format!("{}s", descr) }; + if descr.ends_with('s') { format!("{}es", descr) } else { format!("{}s", descr) }; let mut msg = format!("{}these {} exist but are inaccessible", prefix, plural_descr); let mut has_colon = false; diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 3ea285b723b..49761023ec3 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -544,7 +544,7 @@ struct LateResolutionVisitor<'a, 'b, 'ast> { current_trait_ref: Option<(Module<'a>, TraitRef)>, /// Fields used to add information to diagnostic errors. - diagnostic_metadata: DiagnosticMetadata<'ast>, + diagnostic_metadata: Box<DiagnosticMetadata<'ast>>, /// State used to know whether to ignore resolution errors for function bodies. /// @@ -1157,7 +1157,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { label_ribs: Vec::new(), lifetime_ribs: Vec::new(), current_trait_ref: None, - diagnostic_metadata: DiagnosticMetadata::default(), + diagnostic_metadata: Box::new(DiagnosticMetadata::default()), // errors at module scope should always be reported in_func_body: false, lifetime_uses: Default::default(), diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 1e53c73620a..e428bae479b 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -83,7 +83,7 @@ impl ForLifetimeSpanType { } } - pub(crate) fn suggestion(&self, sugg: &str) -> String { + pub(crate) fn suggestion(&self, sugg: impl std::fmt::Display) -> String { match self { Self::BoundEmpty | Self::TypeEmpty => format!("for<{}> ", sugg), Self::ClosureEmpty => format!("for<{}>", sugg), @@ -2313,8 +2313,8 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { let suggest_existing = |err: &mut Diagnostic, - name: &str, - formatters: Vec<Option<Box<dyn Fn(&str) -> String>>>| { + name: Symbol, + formatters: Vec<Option<Box<dyn Fn(Symbol) -> String>>>| { if let Some(MissingLifetimeSpot::HigherRanked { span: for_span, span_type }) = self.missing_named_lifetime_spots.iter().rev().next() { @@ -2334,7 +2334,8 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { // If all single char lifetime names are present, we wrap around and double the chars. let lt_name = (1..) .flat_map(a_to_z_repeat_n) - .find(|lt| !lifetime_names.contains(&Symbol::intern(<))) + .map(|lt| Symbol::intern(<)) + .find(|lt| !lifetime_names.contains(lt)) .unwrap(); let msg = format!( "consider making the {} lifetime-generic with a new `{}` lifetime", @@ -2361,7 +2362,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { introduce_suggestion.push((*for_span, for_sugg)); for ((span, _), formatter) in spans_with_counts.iter().zip(formatters.iter()) { if let Some(formatter) = formatter { - introduce_suggestion.push((*span, formatter(<_name))); + introduce_suggestion.push((*span, formatter(lt_name))); } } err.multipart_suggestion_verbose( @@ -2584,7 +2585,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { let lifetime_names: Vec<_> = lifetime_names.iter().collect(); match &lifetime_names[..] { [name] => { - let mut suggs: Vec<Option<Box<dyn Fn(&str) -> String>>> = Vec::new(); + let mut suggs: Vec<Option<Box<dyn Fn(Symbol) -> String>>> = Vec::new(); for (snippet, (_, count)) in snippets.iter().zip(spans_with_counts.iter().copied()) { suggs.push(match snippet.as_deref() { @@ -2592,7 +2593,11 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { Some("'_") => Some(Box::new(|n| n.to_string())), Some("") => Some(Box::new(move |n| format!("{}, ", n).repeat(count))), Some("<") => Some(Box::new(move |n| { - std::iter::repeat(n).take(count).collect::<Vec<_>>().join(", ") + std::iter::repeat(n) + .take(count) + .map(|n| n.to_string()) + .collect::<Vec<_>>() + .join(", ") })), Some(snippet) if !snippet.ends_with('>') => Some(Box::new(move |name| { format!( @@ -2607,7 +2612,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { _ => None, }); } - suggest_existing(err, name.as_str(), suggs); + suggest_existing(err, **name, suggs); } [] => { let mut suggs = Vec::new(); diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 4210560f531..2b5eb12a8a8 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -325,7 +325,7 @@ impl<'a> ResolverExpand for Resolver<'a> { UNUSED_MACROS, node_id, ident.span, - &format!("unused macro definition: `{}`", ident.as_str()), + &format!("unused macro definition: `{}`", ident.name), ); } for (&(def_id, arm_i), &(ident, rule_span)) in self.unused_macro_rules.iter() { @@ -341,7 +341,7 @@ impl<'a> ResolverExpand for Resolver<'a> { &format!( "{} rule of macro `{}` is never used", crate::diagnostics::ordinalize(arm_i + 1), - ident.as_str() + ident.name ), ); } @@ -796,9 +796,16 @@ impl<'a> Resolver<'a> { ) { let span = path.span; if let Some(stability) = &ext.stability { - if let StabilityLevel::Unstable { reason, issue, is_soft } = stability.level { + if let StabilityLevel::Unstable { reason, issue, is_soft, implied_by } = stability.level + { let feature = stability.feature; - if !self.active_features.contains(&feature) && !span.allows_unstable(feature) { + + let is_allowed = |feature| { + self.active_features.contains(&feature) || span.allows_unstable(feature) + }; + let allowed_by_implication = + implied_by.map(|feature| is_allowed(feature)).unwrap_or(false); + if !is_allowed(feature) && !allowed_by_implication { let lint_buffer = &mut self.lint_buffer; let soft_handler = |lint, span, msg: &_| lint_buffer.buffer_lint(lint, node_id, span, msg); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 0e52bf34661..55307b9cebb 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2707,6 +2707,14 @@ impl PpMode { | MirCFG => true, } } + pub fn needs_hir(&self) -> bool { + use PpMode::*; + match *self { + Source(_) | AstTree(_) => false, + + Hir(_) | HirTree | ThirTree | Mir | MirCFG => true, + } + } pub fn needs_analysis(&self) -> bool { use PpMode::*; diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 01ff9e254f7..21b1b0b4ebf 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -535,7 +535,7 @@ mod parse { ) -> bool { match v { Some(s) => { - for s in s.split(",") { + for s in s.split(',') { let Some(pass_name) = s.strip_prefix(&['+', '-'][..]) else { return false }; slot.push((pass_name.to_string(), &s[..1] == "+")); } @@ -1209,6 +1209,8 @@ options! { binary_dep_depinfo: bool = (false, parse_bool, [TRACKED], "include artifacts (sysroot, crate dependencies) used during compilation in dep-info \ (default: no)"), + box_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED], + "emit noalias metadata for box (default: yes)"), branch_protection: Option<BranchProtection> = (None, parse_branch_protection, [TRACKED], "set options for branch target identification and pointer authentication on AArch64"), cf_protection: CFProtection = (CFProtection::None, parse_cfprotection, [TRACKED], @@ -1277,6 +1279,8 @@ options! { "version of DWARF debug information to emit (default: 2 or 4, depending on platform)"), emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED], "emit a section containing stack size metadata (default: no)"), + emit_thin_lto: bool = (true, parse_bool, [TRACKED], + "emit the bc module with thin LTO info (default: yes)"), fewer_names: Option<bool> = (None, parse_opt_bool, [TRACKED], "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \ (default: no)"), diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index afbb88e9233..b4a4424e876 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -718,6 +718,11 @@ impl SourceMap { sp } + /// Extends the given `Span` to contain the entire line it is on. + pub fn span_extend_to_line(&self, sp: Span) -> Span { + self.span_extend_to_prev_char(self.span_extend_to_next_char(sp, '\n', true), '\n', true) + } + /// Given a `Span`, tries to get a shorter span ending before the first occurrence of `char` /// `c`. pub fn span_until_char(&self, sp: Span, c: char) -> Span { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index d5e65c0b442..d15b15f75dd 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -223,6 +223,16 @@ symbols! { LintPass, Mutex, N, + NonZeroI128, + NonZeroI16, + NonZeroI32, + NonZeroI64, + NonZeroI8, + NonZeroU128, + NonZeroU16, + NonZeroU32, + NonZeroU64, + NonZeroU8, None, Ok, Option, @@ -257,6 +267,7 @@ symbols! { Result, Return, Right, + Rust, RustcDecodable, RustcEncodable, Send, @@ -685,6 +696,7 @@ symbols! { fabsf32, fabsf64, fadd_fast, + fake_variadic, fdiv_fast, feature, fence, @@ -788,6 +800,7 @@ symbols! { impl_lint_pass, impl_macros, impl_trait_in_bindings, + implied_by, import, import_shadowing, imported_main, @@ -1460,7 +1473,6 @@ symbols! { tuple, tuple_from_req, tuple_indexing, - tuple_variadic, two_phase, ty, type_alias_enum_variants, @@ -1553,6 +1565,8 @@ symbols! { volatile_store, vreg, vreg_low16, + vtable_align, + vtable_size, warn, wasm_abi, wasm_import_module, diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index e3045c9321d..9241fd82c74 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -67,7 +67,7 @@ pub(super) fn mangle<'tcx>( ) .unwrap(); - if let ty::InstanceDef::VtableShim(..) = instance.def { + if let ty::InstanceDef::VTableShim(..) = instance.def { let _ = printer.write_str("{{vtable-shim}}"); } @@ -129,7 +129,7 @@ fn get_symbol_hash<'tcx>( } // We want to avoid accidental collision between different types of instances. - // Especially, `VtableShim`s and `ReifyShim`s may overlap with their original + // Especially, `VTableShim`s and `ReifyShim`s may overlap with their original // instances without this. discriminant(&instance.def).hash_stable(hcx, &mut hasher); }); diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 13229a3995c..79e3f10526c 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -42,7 +42,7 @@ pub(super) fn mangle<'tcx>( // Append `::{shim:...#0}` to shims that can coexist with a non-shim instance. let shim_kind = match instance.def { - ty::InstanceDef::VtableShim(_) => Some("vtable"), + ty::InstanceDef::VTableShim(_) => Some("vtable"), ty::InstanceDef::ReifyShim(_) => Some("reify"), _ => None, diff --git a/compiler/rustc_target/src/asm/aarch64.rs b/compiler/rustc_target/src/asm/aarch64.rs index 25842049413..62a0f9fb034 100644 --- a/compiler/rustc_target/src/asm/aarch64.rs +++ b/compiler/rustc_target/src/asm/aarch64.rs @@ -1,6 +1,6 @@ use super::{InlineAsmArch, InlineAsmType}; use crate::spec::{RelocModel, Target}; -use rustc_data_structures::stable_set::FxHashSet; +use rustc_data_structures::fx::FxHashSet; use rustc_macros::HashStable_Generic; use rustc_span::Symbol; use std::fmt; diff --git a/compiler/rustc_target/src/asm/arm.rs b/compiler/rustc_target/src/asm/arm.rs index aaa632333db..0db3eb6fcac 100644 --- a/compiler/rustc_target/src/asm/arm.rs +++ b/compiler/rustc_target/src/asm/arm.rs @@ -1,6 +1,6 @@ use super::{InlineAsmArch, InlineAsmType}; use crate::spec::{RelocModel, Target}; -use rustc_data_structures::stable_set::FxHashSet; +use rustc_data_structures::fx::FxHashSet; use rustc_macros::HashStable_Generic; use rustc_span::{sym, Symbol}; use std::fmt; diff --git a/compiler/rustc_target/src/asm/riscv.rs b/compiler/rustc_target/src/asm/riscv.rs index 987bf970529..e41bdc9a58c 100644 --- a/compiler/rustc_target/src/asm/riscv.rs +++ b/compiler/rustc_target/src/asm/riscv.rs @@ -1,6 +1,6 @@ use super::{InlineAsmArch, InlineAsmType}; use crate::spec::{RelocModel, Target}; -use rustc_data_structures::stable_set::FxHashSet; +use rustc_data_structures::fx::FxHashSet; use rustc_macros::HashStable_Generic; use rustc_span::{sym, Symbol}; use std::fmt; diff --git a/compiler/rustc_target/src/asm/x86.rs b/compiler/rustc_target/src/asm/x86.rs index e35035fd25a..238c365093f 100644 --- a/compiler/rustc_target/src/asm/x86.rs +++ b/compiler/rustc_target/src/asm/x86.rs @@ -1,6 +1,6 @@ use super::{InlineAsmArch, InlineAsmType}; use crate::spec::{RelocModel, Target}; -use rustc_data_structures::stable_set::FxHashSet; +use rustc_data_structures::fx::FxHashSet; use rustc_macros::HashStable_Generic; use rustc_span::Symbol; use std::fmt; diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 65ff9ceb67e..5763e6d1b55 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -793,9 +793,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { } ty::PredicateKind::RegionOutlives(binder) => { let binder = bound_predicate.rebind(binder); - if select.infcx().region_outlives_predicate(&dummy_cause, binder).is_err() { - return false; - } + select.infcx().region_outlives_predicate(&dummy_cause, binder) } ty::PredicateKind::TypeOutlives(binder) => { let binder = bound_predicate.rebind(binder); diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs index 6ca630b74cc..5fcaa52d417 100644 --- a/compiler/rustc_trait_selection/src/traits/codegen.rs +++ b/compiler/rustc_trait_selection/src/traits/codegen.rs @@ -3,7 +3,7 @@ // seems likely that they should eventually be merged into more // general routines. -use crate::infer::TyCtxtInferExt; +use crate::infer::{DefiningAnchor, TyCtxtInferExt}; use crate::traits::{ FulfillmentContext, ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine, Unimplemented, @@ -30,7 +30,11 @@ pub fn codegen_fulfill_obligation<'tcx>( // Do the initial selection for the obligation. This yields the // shallow result we are looking for -- that is, what specific impl. - tcx.infer_ctxt().enter(|infcx| { + let mut infcx_builder = + tcx.infer_ctxt().ignoring_regions().with_opaque_type_inference(DefiningAnchor::Bubble); + infcx_builder.enter(|infcx| { + //~^ HACK `Bubble` is required for + // this test to pass: type-alias-impl-trait/assoc-projection-ice.rs let mut selcx = SelectionContext::new(&infcx); let obligation_cause = ObligationCause::dummy(); @@ -69,7 +73,8 @@ pub fn codegen_fulfill_obligation<'tcx>( // Opaque types may have gotten their hidden types constrained, but we can ignore them safely // as they will get constrained elsewhere, too. - let _opaque_types = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); + // (ouz-a) This is required for `type-alias-impl-trait/assoc-projection-ice.rs` to pass + let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); debug!("Cache miss: {trait_ref:?} => {impl_source:?}"); Ok(&*tcx.arena.alloc(impl_source)) diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 52ca23c4b30..9983438233e 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -22,11 +22,12 @@ use rustc_middle::traits::specialization_graph::OverlapMode; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::visit::TypeVisitable; -use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt}; +use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt, TypeVisitor}; use rustc_span::symbol::sym; use rustc_span::DUMMY_SP; use std::fmt::Debug; use std::iter; +use std::ops::ControlFlow; /// Whether we do the orphan check relative to this crate or /// to some remote crate. @@ -578,220 +579,146 @@ fn orphan_check_trait_ref<'tcx>( ); } - // Given impl<P1..=Pn> Trait<T1..=Tn> for T0, an impl is valid only - // if at least one of the following is true: - // - // - Trait is a local trait - // (already checked in orphan_check prior to calling this function) - // - All of - // - At least one of the types T0..=Tn must be a local type. - // Let Ti be the first such type. - // - No uncovered type parameters P1..=Pn may appear in T0..Ti (excluding Ti) - // - fn uncover_fundamental_ty<'tcx>( - tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, - in_crate: InCrate, - ) -> Vec<Ty<'tcx>> { - // FIXME: this is currently somewhat overly complicated, - // but fixing this requires a more complicated refactor. - if !contained_non_local_types(tcx, ty, in_crate).is_empty() { - if let Some(inner_tys) = fundamental_ty_inner_tys(tcx, ty) { - return inner_tys - .flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate)) - .collect(); + let mut checker = OrphanChecker::new(tcx, in_crate); + match trait_ref.visit_with(&mut checker) { + ControlFlow::Continue(()) => Err(OrphanCheckErr::NonLocalInputType(checker.non_local_tys)), + ControlFlow::Break(OrphanCheckEarlyExit::ParamTy(ty)) => { + // Does there exist some local type after the `ParamTy`. + checker.search_first_local_ty = true; + if let Some(OrphanCheckEarlyExit::LocalTy(local_ty)) = + trait_ref.visit_with(&mut checker).break_value() + { + Err(OrphanCheckErr::UncoveredTy(ty, Some(local_ty))) + } else { + Err(OrphanCheckErr::UncoveredTy(ty, None)) } } - - vec![ty] - } - - let mut non_local_spans = vec![]; - for (i, input_ty) in trait_ref - .substs - .types() - .flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate)) - .enumerate() - { - debug!("orphan_check_trait_ref: check ty `{:?}`", input_ty); - let non_local_tys = contained_non_local_types(tcx, input_ty, in_crate); - if non_local_tys.is_empty() { - debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty); - return Ok(()); - } else if let ty::Param(_) = input_ty.kind() { - debug!("orphan_check_trait_ref: uncovered ty: `{:?}`", input_ty); - let local_type = trait_ref - .substs - .types() - .flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate)) - .find(|&ty| ty_is_local_constructor(tcx, ty, in_crate)); - - debug!("orphan_check_trait_ref: uncovered ty local_type: `{:?}`", local_type); - - return Err(OrphanCheckErr::UncoveredTy(input_ty, local_type)); - } - - non_local_spans.extend(non_local_tys.into_iter().map(|input_ty| (input_ty, i == 0))); + ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(_)) => Ok(()), } - // If we exit above loop, never found a local type. - debug!("orphan_check_trait_ref: no local type"); - Err(OrphanCheckErr::NonLocalInputType(non_local_spans)) } -/// Returns a list of relevant non-local types for `ty`. -/// -/// This is just `ty` itself unless `ty` is `#[fundamental]`, -/// in which case we recursively look into this type. -/// -/// If `ty` is local itself, this method returns an empty `Vec`. -/// -/// # Examples -/// -/// - `u32` is not local, so this returns `[u32]`. -/// - for `Foo<u32>`, where `Foo` is a local type, this returns `[]`. -/// - `&mut u32` returns `[u32]`, as `&mut` is a fundamental type, similar to `Box`. -/// - `Box<Foo<u32>>` returns `[]`, as `Box` is a fundamental type and `Foo` is local. -fn contained_non_local_types<'tcx>( +struct OrphanChecker<'tcx> { tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, in_crate: InCrate, -) -> Vec<Ty<'tcx>> { - if ty_is_local_constructor(tcx, ty, in_crate) { - Vec::new() - } else { - match fundamental_ty_inner_tys(tcx, ty) { - Some(inner_tys) => { - inner_tys.flat_map(|ty| contained_non_local_types(tcx, ty, in_crate)).collect() - } - None => vec![ty], + in_self_ty: bool, + /// Ignore orphan check failures and exclusively search for the first + /// local type. + search_first_local_ty: bool, + non_local_tys: Vec<(Ty<'tcx>, bool)>, +} + +impl<'tcx> OrphanChecker<'tcx> { + fn new(tcx: TyCtxt<'tcx>, in_crate: InCrate) -> Self { + OrphanChecker { + tcx, + in_crate, + in_self_ty: true, + search_first_local_ty: false, + non_local_tys: Vec::new(), } } -} -/// For `#[fundamental]` ADTs and `&T` / `&mut T`, returns `Some` with the -/// type parameters of the ADT, or `T`, respectively. For non-fundamental -/// types, returns `None`. -fn fundamental_ty_inner_tys<'tcx>( - tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, -) -> Option<impl Iterator<Item = Ty<'tcx>>> { - let (first_ty, rest_tys) = match *ty.kind() { - ty::Ref(_, ty, _) => (ty, ty::subst::InternalSubsts::empty().types()), - ty::Adt(def, substs) if def.is_fundamental() => { - let mut types = substs.types(); - - // FIXME(eddyb) actually validate `#[fundamental]` up-front. - match types.next() { - None => { - tcx.sess.span_err( - tcx.def_span(def.did()), - "`#[fundamental]` requires at least one type parameter", - ); - - return None; - } + fn found_non_local_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<OrphanCheckEarlyExit<'tcx>> { + self.non_local_tys.push((t, self.in_self_ty)); + ControlFlow::CONTINUE + } - Some(first_ty) => (first_ty, types), - } + fn found_param_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<OrphanCheckEarlyExit<'tcx>> { + if self.search_first_local_ty { + ControlFlow::CONTINUE + } else { + ControlFlow::Break(OrphanCheckEarlyExit::ParamTy(t)) } - _ => return None, - }; + } - Some(iter::once(first_ty).chain(rest_tys)) + fn def_id_is_local(&mut self, def_id: DefId) -> bool { + match self.in_crate { + InCrate::Local => def_id.is_local(), + InCrate::Remote => false, + } + } } -fn def_id_is_local(def_id: DefId, in_crate: InCrate) -> bool { - match in_crate { - // The type is local to *this* crate - it will not be - // local in any other crate. - InCrate::Remote => false, - InCrate::Local => def_id.is_local(), - } +enum OrphanCheckEarlyExit<'tcx> { + ParamTy(Ty<'tcx>), + LocalTy(Ty<'tcx>), } -fn ty_is_local_constructor(tcx: TyCtxt<'_>, ty: Ty<'_>, in_crate: InCrate) -> bool { - debug!("ty_is_local_constructor({:?})", ty); - - match *ty.kind() { - ty::Bool - | ty::Char - | ty::Int(..) - | ty::Uint(..) - | ty::Float(..) - | ty::Str - | ty::FnDef(..) - | ty::FnPtr(_) - | ty::Array(..) - | ty::Slice(..) - | ty::RawPtr(..) - | ty::Ref(..) - | ty::Never - | ty::Tuple(..) - | ty::Param(..) - | ty::Projection(..) => false, - - ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) => match in_crate { - InCrate::Local => false, - // The inference variable might be unified with a local - // type in that remote crate. - InCrate::Remote => true, - }, - - ty::Adt(def, _) => def_id_is_local(def.did(), in_crate), - ty::Foreign(did) => def_id_is_local(did, in_crate), - ty::Opaque(..) => { - // This merits some explanation. - // Normally, opaque types are not involved when performing - // coherence checking, since it is illegal to directly - // implement a trait on an opaque type. However, we might - // end up looking at an opaque type during coherence checking - // if an opaque type gets used within another type (e.g. as - // a type parameter). This requires us to decide whether or - // not an opaque type should be considered 'local' or not. - // - // We choose to treat all opaque types as non-local, even - // those that appear within the same crate. This seems - // somewhat surprising at first, but makes sense when - // you consider that opaque types are supposed to hide - // the underlying type *within the same crate*. When an - // opaque type is used from outside the module - // where it is declared, it should be impossible to observe - // anything about it other than the traits that it implements. - // - // The alternative would be to look at the underlying type - // to determine whether or not the opaque type itself should - // be considered local. However, this could make it a breaking change - // to switch the underlying ('defining') type from a local type - // to a remote type. This would violate the rule that opaque - // types should be completely opaque apart from the traits - // that they implement, so we don't use this behavior. - false - } +impl<'tcx> TypeVisitor<'tcx> for OrphanChecker<'tcx> { + type BreakTy = OrphanCheckEarlyExit<'tcx>; + fn visit_region(&mut self, _r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { + ControlFlow::CONTINUE + } - ty::Dynamic(ref tt, ..) => { - if let Some(principal) = tt.principal() { - def_id_is_local(principal.def_id(), in_crate) - } else { - false + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { + let result = match *ty.kind() { + ty::Bool + | ty::Char + | ty::Int(..) + | ty::Uint(..) + | ty::Float(..) + | ty::Str + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::Array(..) + | ty::Slice(..) + | ty::RawPtr(..) + | ty::Never + | ty::Tuple(..) + | ty::Projection(..) => self.found_non_local_ty(ty), + + ty::Param(..) => self.found_param_ty(ty), + + ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) => match self.in_crate { + InCrate::Local => self.found_non_local_ty(ty), + // The inference variable might be unified with a local + // type in that remote crate. + InCrate::Remote => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)), + }, + + // For fundamental types, we just look inside of them. + ty::Ref(_, ty, _) => ty.visit_with(self), + ty::Adt(def, substs) => { + if self.def_id_is_local(def.did()) { + ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)) + } else if def.is_fundamental() { + substs.visit_with(self) + } else { + self.found_non_local_ty(ty) + } } - } + ty::Foreign(def_id) => { + if self.def_id_is_local(def_id) { + ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)) + } else { + self.found_non_local_ty(ty) + } + } + ty::Dynamic(tt, ..) => { + let principal = tt.principal().map(|p| p.def_id()); + if principal.map_or(false, |p| self.def_id_is_local(p)) { + ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)) + } else { + self.found_non_local_ty(ty) + } + } + ty::Error(_) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)), + ty::Opaque(..) | ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) => { + self.tcx.sess.delay_span_bug( + DUMMY_SP, + format!("ty_is_local invoked on closure or generator: {:?}", ty), + ); + ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)) + } + }; + // A bit of a hack, the `OrphanChecker` is only used to visit a `TraitRef`, so + // the first type we visit is always the self type. + self.in_self_ty = false; + result + } - ty::Error(_) => true, - - // These variants should never appear during coherence checking because they - // cannot be named directly. - // - // They could be indirectly used through an opaque type. While using opaque types - // in impls causes an error, this path can still be hit afterwards. - // - // See `test/ui/coherence/coherence-with-closure.rs` for an example where this - // could happens. - ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) => { - tcx.sess.delay_span_bug( - DUMMY_SP, - format!("ty_is_local invoked on closure or generator: {:?}", ty), - ); - true - } + // FIXME: Constants should participate in orphan checking. + fn visit_const(&mut self, _c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { + ControlFlow::CONTINUE } } diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 0f7dc6a1257..6c177f63887 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -15,8 +15,6 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; pub trait TraitEngineExt<'tcx> { fn new(tcx: TyCtxt<'tcx>) -> Box<Self>; - - fn new_ignoring_regions(tcx: TyCtxt<'tcx>) -> Box<Self>; } impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> { @@ -27,14 +25,6 @@ impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> { Box::new(FulfillmentContext::new()) } } - - fn new_ignoring_regions(tcx: TyCtxt<'tcx>) -> Box<Self> { - if tcx.sess.opts.unstable_opts.chalk { - Box::new(ChalkFulfillmentContext::new()) - } else { - Box::new(FulfillmentContext::new_ignoring_regions()) - } - } } /// Used if you want to have pleasant experience when dealing 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 8a679ca005f..2f92a77a795 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -22,7 +22,6 @@ use rustc_hir::intravisit::Visitor; use rustc_hir::GenericParam; use rustc_hir::Item; use rustc_hir::Node; -use rustc_infer::infer::error_reporting::same_type_modulo_infer; use rustc_infer::traits::TraitEngine; use rustc_middle::traits::select::OverflowError; use rustc_middle::ty::abstract_const::NotConstEvaluatable; @@ -474,7 +473,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if let Some(ref s) = label { // If it has a custom `#[rustc_on_unimplemented]` // error message, let's display it as the label! - err.span_label(span, s.as_str()); + err.span_label(span, s); if !matches!(trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) { // When the self type is a type param We don't need to "the trait // `std::marker::Sized` is not implemented for `T`" as we will point @@ -531,7 +530,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let enclosing_scope_span = tcx.hir().span_with_body(tcx.hir().local_def_id_to_hir_id(body)); - err.span_label(enclosing_scope_span, s.as_str()); + err.span_label(enclosing_scope_span, s); } self.suggest_floating_point_literal(&obligation, &mut err, &trait_ref); @@ -640,7 +639,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if expected.len() == 1 { "" } else { "s" }, ) ); - } else if !same_type_modulo_infer(given_ty, expected_ty) { + } else if !self.same_type_modulo_infer(given_ty, expected_ty) { // Print type mismatch let (expected_args, given_args) = self.cmp(given_ty, expected_ty); @@ -789,24 +788,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { span_bug!(span, "coerce requirement gave wrong error: `{:?}`", predicate) } - ty::PredicateKind::RegionOutlives(predicate) => { - let predicate = bound_predicate.rebind(predicate); - let predicate = self.resolve_vars_if_possible(predicate); - let err = self - .region_outlives_predicate(&obligation.cause, predicate) - .err() - .unwrap(); - struct_span_err!( - self.tcx.sess, - span, - E0279, - "the requirement `{}` is not satisfied (`{}`)", - predicate, - err, - ) - } - - ty::PredicateKind::Projection(..) | ty::PredicateKind::TypeOutlives(..) => { + ty::PredicateKind::RegionOutlives(..) + | ty::PredicateKind::Projection(..) + | ty::PredicateKind::TypeOutlives(..) => { let predicate = self.resolve_vars_if_possible(obligation.predicate); struct_span_err!( self.tcx.sess, @@ -2104,6 +2088,98 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { ); } } + + if let (Some(body_id), Some(ty::subst::GenericArgKind::Type(_))) = + (body_id, subst.map(|subst| subst.unpack())) + { + struct FindExprBySpan<'hir> { + span: Span, + result: Option<&'hir hir::Expr<'hir>>, + } + + impl<'v> hir::intravisit::Visitor<'v> for FindExprBySpan<'v> { + fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { + if self.span == ex.span { + self.result = Some(ex); + } else { + hir::intravisit::walk_expr(self, ex); + } + } + } + + let mut expr_finder = FindExprBySpan { span, result: None }; + + expr_finder.visit_expr(&self.tcx.hir().body(body_id).value); + + if let Some(hir::Expr { + kind: hir::ExprKind::Path(hir::QPath::Resolved(None, path)), .. } + ) = expr_finder.result + && let [ + .., + trait_path_segment @ hir::PathSegment { + res: Some(rustc_hir::def::Res::Def(rustc_hir::def::DefKind::Trait, trait_id)), + .. + }, + hir::PathSegment { + ident: assoc_item_name, + res: Some(rustc_hir::def::Res::Def(_, item_id)), + .. + } + ] = path.segments + && data.trait_ref.def_id == *trait_id + && self.tcx.trait_of_item(item_id) == Some(*trait_id) + && !self.is_tainted_by_errors() + { + let (verb, noun) = match self.tcx.associated_item(item_id).kind { + ty::AssocKind::Const => ("refer to the", "constant"), + ty::AssocKind::Fn => ("call", "function"), + ty::AssocKind::Type => ("refer to the", "type"), // this is already covered by E0223, but this single match arm doesn't hurt here + }; + + // Replace the more general E0283 with a more specific error + err.cancel(); + err = self.tcx.sess.struct_span_err_with_code( + span, + &format!( + "cannot {verb} associated {noun} on trait without specifying the corresponding `impl` type", + ), + rustc_errors::error_code!(E0790), + ); + + if let Some(local_def_id) = data.trait_ref.def_id.as_local() + && let Some(hir::Node::Item(hir::Item { ident: trait_name, kind: hir::ItemKind::Trait(_, _, _, _, trait_item_refs), .. })) = self.tcx.hir().find_by_def_id(local_def_id) + && let Some(method_ref) = trait_item_refs.iter().find(|item_ref| item_ref.ident == *assoc_item_name) { + err.span_label(method_ref.span, format!("`{}::{}` defined here", trait_name, assoc_item_name)); + } + + err.span_label(span, format!("cannot {verb} associated {noun} of trait")); + + let trait_impls = self.tcx.trait_impls_of(data.trait_ref.def_id); + + if trait_impls.blanket_impls().is_empty() + && let Some((impl_ty, _)) = trait_impls.non_blanket_impls().iter().next() + && let Some(impl_def_id) = impl_ty.def() { + let message = if trait_impls.non_blanket_impls().len() == 1 { + "use the fully-qualified path to the only available implementation".to_string() + } else { + format!( + "use a fully-qualified path to a specific available implementation ({} found)", + trait_impls.non_blanket_impls().len() + ) + }; + + err.multipart_suggestion( + message, + vec![ + (trait_path_segment.ident.span.shrink_to_lo(), format!("<{} as ", self.tcx.def_path(impl_def_id).to_string_no_crate_verbose())), + (trait_path_segment.ident.span.shrink_to_hi(), format!(">")) + ], + Applicability::MaybeIncorrect + ); + } + } + }; + err } 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 bca80e7ab8a..5636c74452c 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -607,10 +607,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { "{}, {}={}>", &constraint[..constraint.len() - 1], item.name, - term.to_string() + term ); } else { - constraint.push_str(&format!("<{}={}>", item.name, term.to_string())); + constraint.push_str(&format!("<{}={}>", item.name, term)); } } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 81f5dcc45b9..556ef466cd1 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -58,19 +58,6 @@ pub struct FulfillmentContext<'tcx> { relationships: FxHashMap<ty::TyVid, ty::FoundRelationships>, - // Should this fulfillment context register type-lives-for-region - // obligations on its parent infcx? In some cases, region - // obligations are either already known to hold (normalization) or - // hopefully verified elsewhere (type-impls-bound), and therefore - // should not be checked. - // - // Note that if we are normalizing a type that we already - // know is well-formed, there should be no harm setting this - // to true - all the region variables should be determinable - // using the RFC 447 rules, which don't depend on - // type-lives-for-region constraints, and because the type - // is well-formed, the constraints should hold. - register_region_obligations: bool, // Is it OK to register obligations into this infcx inside // an infcx snapshot? // @@ -103,7 +90,6 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> { FulfillmentContext { predicates: ObligationForest::new(), relationships: FxHashMap::default(), - register_region_obligations: true, usable_in_snapshot: false, } } @@ -112,30 +98,18 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> { FulfillmentContext { predicates: ObligationForest::new(), relationships: FxHashMap::default(), - register_region_obligations: true, usable_in_snapshot: true, } } - pub fn new_ignoring_regions() -> FulfillmentContext<'tcx> { - FulfillmentContext { - predicates: ObligationForest::new(), - relationships: FxHashMap::default(), - register_region_obligations: false, - usable_in_snapshot: false, - } - } - /// Attempts to select obligations using `selcx`. fn select(&mut self, selcx: &mut SelectionContext<'a, 'tcx>) -> Vec<FulfillmentError<'tcx>> { let span = debug_span!("select", obligation_forest_size = ?self.predicates.len()); let _enter = span.enter(); // Process pending obligations. - let outcome: Outcome<_, _> = self.predicates.process_obligations(&mut FulfillProcessor { - selcx, - register_region_obligations: self.register_region_obligations, - }); + let outcome: Outcome<_, _> = + self.predicates.process_obligations(&mut FulfillProcessor { selcx }); // FIXME: if we kept the original cache key, we could mark projection // obligations as complete for the projection cache here. @@ -239,7 +213,6 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { struct FulfillProcessor<'a, 'b, 'tcx> { selcx: &'a mut SelectionContext<'b, 'tcx>, - register_region_obligations: bool, } fn mk_pending(os: Vec<PredicateObligation<'_>>) -> Vec<PendingPredicateObligation<'_>> { @@ -295,6 +268,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { /// This is called much less often than `needs_process_obligation`, so we /// never inline it. #[inline(never)] + #[instrument(level = "debug", skip(self, pending_obligation))] fn process_obligation( &mut self, pending_obligation: &mut PendingPredicateObligation<'tcx>, @@ -303,7 +277,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { let obligation = &mut pending_obligation.obligation; - debug!(?obligation, "process_obligation pre-resolve"); + debug!(?obligation, "pre-resolve"); if obligation.predicate.has_infer_types_or_consts() { obligation.predicate = @@ -312,8 +286,6 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { let obligation = &pending_obligation.obligation; - debug!(?obligation, ?obligation.cause, "process_obligation"); - let infcx = self.selcx.infcx(); if obligation.predicate.has_projections() { @@ -386,19 +358,16 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } ty::PredicateKind::RegionOutlives(data) => { - match infcx.region_outlives_predicate(&obligation.cause, Binder::dummy(data)) { - Ok(()) => ProcessResult::Changed(vec![]), - Err(_) => ProcessResult::Error(CodeSelectionError(Unimplemented)), + if infcx.considering_regions || data.has_placeholders() { + infcx.region_outlives_predicate(&obligation.cause, Binder::dummy(data)); } + + ProcessResult::Changed(vec![]) } ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(t_a, r_b)) => { - if self.register_region_obligations { - self.selcx.infcx().register_region_obligation_with_cause( - t_a, - r_b, - &obligation.cause, - ); + if infcx.considering_regions { + infcx.register_region_obligation_with_cause(t_a, r_b, &obligation.cause); } ProcessResult::Changed(vec![]) } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index a14bf72242b..3ef51b0c27a 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -163,7 +163,7 @@ pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>( // The handling of regions in this area of the code is terrible, // see issue #29149. We should be able to improve on this with // NLL. - let mut fulfill_cx = FulfillmentContext::new_ignoring_regions(); + let mut fulfill_cx = FulfillmentContext::new(); // We can use a dummy node-id here because we won't pay any mind // to region obligations that arise (there shouldn't really be any @@ -207,21 +207,21 @@ fn do_normalize_predicates<'tcx>( predicates: Vec<ty::Predicate<'tcx>>, ) -> Result<Vec<ty::Predicate<'tcx>>, ErrorGuaranteed> { let span = cause.span; - tcx.infer_ctxt().enter(|infcx| { - // FIXME. We should really... do something with these region - // obligations. But this call just continues the older - // behavior (i.e., doesn't cause any new bugs), and it would - // take some further refactoring to actually solve them. In - // particular, we would have to handle implied bounds - // properly, and that code is currently largely confined to - // regionck (though I made some efforts to extract it - // out). -nmatsakis - // - // @arielby: In any case, these obligations are checked - // by wfcheck anyway, so I'm not sure we have to check - // them here too, and we will remove this function when - // we move over to lazy normalization *anyway*. - let fulfill_cx = FulfillmentContext::new_ignoring_regions(); + // FIXME. We should really... do something with these region + // obligations. But this call just continues the older + // behavior (i.e., doesn't cause any new bugs), and it would + // take some further refactoring to actually solve them. In + // particular, we would have to handle implied bounds + // properly, and that code is currently largely confined to + // regionck (though I made some efforts to extract it + // out). -nmatsakis + // + // @arielby: In any case, these obligations are checked + // by wfcheck anyway, so I'm not sure we have to check + // them here too, and we will remove this function when + // we move over to lazy normalization *anyway*. + tcx.infer_ctxt().ignoring_regions().enter(|infcx| { + let fulfill_cx = FulfillmentContext::new(); let predicates = match fully_normalize(&infcx, fulfill_cx, cause, elaborated_env, predicates) { Ok(predicates) => predicates, diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index b3e7fbb3578..9de4d3a646c 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -753,10 +753,13 @@ impl<'tcx> TypeFolder<'tcx> for BoundVarReplacer<'_, 'tcx> { .tcx .mk_const(ty::ConstS { kind: ty::ConstKind::Placeholder(p), ty: ct.ty() }) } - _ if ct.has_vars_bound_at_or_above(self.current_index) => ct.super_fold_with(self), - _ => ct, + _ => ct.super_fold_with(self), } } + + fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p } + } } // The inverse of `BoundVarReplacer`: replaces placeholders with the bound vars from which they came. diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs index c9d46b2810d..c99564936aa 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs @@ -9,7 +9,6 @@ use rustc_infer::traits::TraitEngineExt as _; use rustc_span::source_map::DUMMY_SP; use std::fmt; -use std::rc::Rc; pub struct CustomTypeOp<F, G> { closure: F, @@ -109,7 +108,7 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>( Ok(( TypeOpOutput { output: value, - constraints: Some(Rc::new(region_constraints)), + constraints: Some(infcx.tcx.arena.alloc(region_constraints)), error_info: None, }, region_constraint_data, diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs index 1e72dd69339..578e1d00cf9 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs @@ -10,7 +10,6 @@ use rustc_infer::traits::PredicateObligations; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; use std::fmt; -use std::rc::Rc; pub mod ascribe_user_type; pub mod custom; @@ -41,7 +40,7 @@ pub struct TypeOpOutput<'tcx, Op: TypeOp<'tcx>> { /// The output from the type op. pub output: Op::Output, /// Any region constraints from performing the type op. - pub constraints: Option<Rc<QueryRegionConstraints<'tcx>>>, + pub constraints: Option<&'tcx QueryRegionConstraints<'tcx>>, /// Used for error reporting to be able to rerun the query pub error_info: Option<Op::ErrorInfo>, } @@ -156,11 +155,14 @@ where } } - // Promote the final query-region-constraints into a - // (optional) ref-counted vector: - let region_constraints = - if region_constraints.is_empty() { None } else { Some(Rc::new(region_constraints)) }; - - Ok(TypeOpOutput { output, constraints: region_constraints, error_info }) + Ok(TypeOpOutput { + output, + constraints: if region_constraints.is_empty() { + None + } else { + Some(infcx.tcx.arena.alloc(region_constraints)) + }, + error_info, + }) } } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index fa2d2c751d9..17f34012d1d 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -789,7 +789,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let mut param_env = obligation.param_env; fresh_trait_pred = fresh_trait_pred.map_bound(|mut pred| { - pred.remap_constness(self.tcx(), &mut param_env); + pred.remap_constness(&mut param_env); pred }); @@ -1321,7 +1321,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } let tcx = self.tcx(); let mut pred = cache_fresh_trait_pred.skip_binder(); - pred.remap_constness(tcx, &mut param_env); + pred.remap_constness(&mut param_env); if self.can_use_global_caches(param_env) { if let Some(res) = tcx.selection_cache.get(&(param_env, pred), tcx) { @@ -1375,7 +1375,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let tcx = self.tcx(); let mut pred = cache_fresh_trait_pred.skip_binder(); - pred.remap_constness(tcx, &mut param_env); + pred.remap_constness(&mut param_env); if !self.can_cache_candidate(&candidate) { debug!(?pred, ?candidate, "insert_candidate_cache - candidate is not cacheable"); diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 2c4a453aefc..5f77aae6f22 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -207,18 +207,7 @@ fn fulfill_implication<'a, 'tcx>( // (which are packed up in penv) infcx.save_and_restore_in_snapshot_flag(|infcx| { - // If we came from `translate_substs`, we already know that the - // predicates for our impl hold (after all, we know that a more - // specialized impl holds, so our impl must hold too), and - // we only want to process the projections to determine the - // the types in our substs using RFC 447, so we can safely - // ignore region obligations, which allows us to avoid threading - // a node-id to assign them with. - // - // If we came from specialization graph construction, then - // we already make a mockery out of the region system, so - // why not ignore them a bit earlier? - let mut fulfill_cx = FulfillmentContext::new_ignoring_regions(); + let mut fulfill_cx = FulfillmentContext::new(); for oblig in obligations.chain(more_obligations) { fulfill_cx.register_predicate_obligation(&infcx, oblig); } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 7b5e1498f26..6b758ba63cd 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -60,12 +60,19 @@ pub fn obligations<'a, 'tcx>( GenericArgKind::Lifetime(..) => return Some(Vec::new()), }; - let mut wf = - WfPredicates { infcx, param_env, body_id, span, out: vec![], recursion_depth, item: None }; + let mut wf = WfPredicates { + tcx: infcx.tcx, + param_env, + body_id, + span, + out: vec![], + recursion_depth, + item: None, + }; wf.compute(arg); debug!("wf::obligations({:?}, body_id={:?}) = {:?}", arg, body_id, wf.out); - let result = wf.normalize(); + let result = wf.normalize(infcx); debug!("wf::obligations({:?}, body_id={:?}) ~~> {:?}", arg, body_id, result); Some(result) } @@ -83,7 +90,7 @@ pub fn trait_obligations<'a, 'tcx>( item: &'tcx hir::Item<'tcx>, ) -> Vec<traits::PredicateObligation<'tcx>> { let mut wf = WfPredicates { - infcx, + tcx: infcx.tcx, param_env, body_id, span, @@ -93,7 +100,7 @@ pub fn trait_obligations<'a, 'tcx>( }; wf.compute_trait_ref(trait_ref, Elaborate::All); debug!(obligations = ?wf.out); - wf.normalize() + wf.normalize(infcx) } pub fn predicate_obligations<'a, 'tcx>( @@ -104,7 +111,7 @@ pub fn predicate_obligations<'a, 'tcx>( span: Span, ) -> Vec<traits::PredicateObligation<'tcx>> { let mut wf = WfPredicates { - infcx, + tcx: infcx.tcx, param_env, body_id, span, @@ -159,11 +166,11 @@ pub fn predicate_obligations<'a, 'tcx>( } } - wf.normalize() + wf.normalize(infcx) } -struct WfPredicates<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, +struct WfPredicates<'tcx> { + tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, body_id: hir::HirId, span: Span, @@ -260,18 +267,17 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>( } } -impl<'a, 'tcx> WfPredicates<'a, 'tcx> { +impl<'tcx> WfPredicates<'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx + self.tcx } fn cause(&self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> { traits::ObligationCause::new(self.span, self.body_id, code) } - fn normalize(mut self) -> Vec<traits::PredicateObligation<'tcx>> { + fn normalize(self, infcx: &InferCtxt<'_, 'tcx>) -> Vec<traits::PredicateObligation<'tcx>> { let cause = self.cause(traits::WellFormed(None)); - let infcx = &mut self.infcx; let param_env = self.param_env; let mut obligations = Vec::with_capacity(self.out.len()); for mut obligation in self.out { @@ -296,7 +302,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { /// Pushes the obligations required for `trait_ref` to be WF into `self.out`. fn compute_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>, elaborate: Elaborate) { - let tcx = self.infcx.tcx; + let tcx = self.tcx; let obligations = self.nominal_obligations(trait_ref.def_id, trait_ref.substs); debug!("compute_trait_ref obligations {:?}", obligations); @@ -410,14 +416,14 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { if !subty.has_escaping_bound_vars() { let cause = self.cause(cause); let trait_ref = ty::TraitRef { - def_id: self.infcx.tcx.require_lang_item(LangItem::Sized, None), - substs: self.infcx.tcx.mk_substs_trait(subty, &[]), + def_id: self.tcx.require_lang_item(LangItem::Sized, None), + substs: self.tcx.mk_substs_trait(subty, &[]), }; self.out.push(traits::Obligation::with_depth( cause, self.recursion_depth, self.param_env, - ty::Binder::dummy(trait_ref).without_const().to_predicate(self.infcx.tcx), + ty::Binder::dummy(trait_ref).without_const().to_predicate(self.tcx), )); } } @@ -452,26 +458,16 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { predicate, )); } - ty::ConstKind::Infer(infer) => { - let resolved = self.infcx.shallow_resolve(infer); - // the `InferConst` changed, meaning that we made progress. - if resolved != infer { - let cause = self.cause(traits::WellFormed(None)); - - let resolved_constant = self.infcx.tcx.mk_const(ty::ConstS { - kind: ty::ConstKind::Infer(resolved), - ty: constant.ty(), - }); - self.out.push(traits::Obligation::with_depth( - cause, - self.recursion_depth, - self.param_env, - ty::Binder::dummy(ty::PredicateKind::WellFormed( - resolved_constant.into(), - )) + ty::ConstKind::Infer(_) => { + let cause = self.cause(traits::WellFormed(None)); + + self.out.push(traits::Obligation::with_depth( + cause, + self.recursion_depth, + self.param_env, + ty::Binder::dummy(ty::PredicateKind::WellFormed(constant.into())) .to_predicate(self.tcx()), - )); - } + )); } ty::ConstKind::Error(_) | ty::ConstKind::Param(_) @@ -563,7 +559,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { } } - ty::Generator(..) => { + ty::Generator(did, substs, ..) => { // Walk ALL the types in the generator: this will // include the upvar types as well as the yield // type. Note that this is mildly distinct from @@ -571,6 +567,8 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // about the signature of the closure. We don't // have the problem of implied bounds here since // generators don't take arguments. + let obligations = self.nominal_obligations(did, substs); + self.out.extend(obligations); } ty::Closure(did, substs) => { @@ -622,12 +620,10 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { } ty::Opaque(did, substs) => { - // all of the requirements on type parameters - // should've been checked by the instantiation - // of whatever returned this exact `impl Trait`. - - // for named opaque `impl Trait` types we still need to check them - if ty::is_impl_trait_defn(self.infcx.tcx, did).is_none() { + // All of the requirements on type parameters + // have already been checked for `impl Trait` in + // return position. We do need to check type-alias-impl-trait though. + if ty::is_impl_trait_defn(self.tcx, did).is_none() { let obligations = self.nominal_obligations(did, substs); self.out.extend(obligations); } @@ -675,41 +671,35 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // See also the comment on `fn obligations`, describing "livelock" // prevention, which happens before this can be reached. ty::Infer(_) => { - let ty = self.infcx.shallow_resolve(ty); - if let ty::Infer(ty::TyVar(_)) = ty.kind() { - // Not yet resolved, but we've made progress. - let cause = self.cause(traits::WellFormed(None)); - self.out.push(traits::Obligation::with_depth( - cause, - self.recursion_depth, - param_env, - ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())) - .to_predicate(self.tcx()), - )); - } else { - // Yes, resolved, proceed with the result. - // FIXME(eddyb) add the type to `walker` instead of recursing. - self.compute(ty.into()); - } + let cause = self.cause(traits::WellFormed(None)); + self.out.push(traits::Obligation::with_depth( + cause, + self.recursion_depth, + param_env, + ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())) + .to_predicate(self.tcx()), + )); } } } } + #[instrument(level = "debug", skip(self))] fn nominal_obligations( &mut self, def_id: DefId, substs: SubstsRef<'tcx>, ) -> Vec<traits::PredicateObligation<'tcx>> { - let predicates = self.infcx.tcx.predicates_of(def_id); + let predicates = self.tcx.predicates_of(def_id); let mut origins = vec![def_id; predicates.predicates.len()]; let mut head = predicates; while let Some(parent) = head.parent { - head = self.infcx.tcx.predicates_of(parent); + head = self.tcx.predicates_of(parent); origins.extend(iter::repeat(parent).take(head.predicates.len())); } - let predicates = predicates.instantiate(self.infcx.tcx, substs); + let predicates = predicates.instantiate(self.tcx, substs); + trace!("{:#?}", predicates); debug_assert_eq!(predicates.predicates.len(), origins.len()); iter::zip(iter::zip(predicates.predicates, predicates.spans), origins.into_iter().rev()) @@ -764,7 +754,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // Note: in fact we only permit builtin traits, not `Bar<'d>`, I // am looking forward to the future here. if !data.has_escaping_bound_vars() && !region.has_escaping_bound_vars() { - let implicit_bounds = object_region_bounds(self.infcx.tcx, data); + let implicit_bounds = object_region_bounds(self.tcx, data); let explicit_bound = region; @@ -777,7 +767,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { cause, self.recursion_depth, self.param_env, - outlives.to_predicate(self.infcx.tcx), + outlives.to_predicate(self.tcx), )); } } diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index c7cac8fca89..4d4d55de5f4 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -47,7 +47,7 @@ fn compute_implied_outlives_bounds<'tcx>( // process it next. Because the resulting predicates aren't always // guaranteed to be a subset of the original type, so we need to store the // WF args we've computed in a set. - let mut checked_wf_args = rustc_data_structures::stable_set::FxHashSet::default(); + let mut checked_wf_args = rustc_data_structures::fx::FxHashSet::default(); let mut wf_args = vec![ty.into()]; let mut implied_bounds = vec![]; diff --git a/compiler/rustc_ty_utils/src/representability.rs b/compiler/rustc_ty_utils/src/representability.rs index 7efc82efd15..eded7891682 100644 --- a/compiler/rustc_ty_utils/src/representability.rs +++ b/compiler/rustc_ty_utils/src/representability.rs @@ -1,5 +1,5 @@ //! Check whether a type is representable. -use rustc_data_structures::stable_map::FxHashMap; +use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::Span; diff --git a/compiler/rustc_type_ir/src/codec.rs b/compiler/rustc_type_ir/src/codec.rs index 6a9ea790a30..ee249050cc6 100644 --- a/compiler/rustc_type_ir/src/codec.rs +++ b/compiler/rustc_type_ir/src/codec.rs @@ -1,6 +1,6 @@ use crate::Interner; -use rustc_data_structures::stable_map::FxHashMap; +use rustc_data_structures::fx::FxHashMap; use rustc_serialize::{Decoder, Encoder}; /// The shorthand encoding uses an enum's variant index `usize` diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs index 7795e65132f..f629f6a0099 100644 --- a/compiler/rustc_typeck/src/check/_match.rs +++ b/compiler/rustc_typeck/src/check/_match.rs @@ -9,7 +9,6 @@ use rustc_span::Span; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::{ IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, - StatementAsExpression, }; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -75,8 +74,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let mut other_arms = vec![]; // Used only for diagnostics. - let mut prior_arm_ty = None; - for (i, arm) in arms.iter().enumerate() { + let mut prior_arm = None; + for arm in arms { if let Some(g) = &arm.guard { self.diverges.set(Diverges::Maybe); match g { @@ -96,21 +95,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let opt_suggest_box_span = self.opt_suggest_box_span(arm_ty, orig_expected); - let (arm_span, semi_span) = - self.get_appropriate_arm_semicolon_removal_span(&arms, i, prior_arm_ty, arm_ty); - let (span, code) = match i { + let (arm_block_id, arm_span) = if let hir::ExprKind::Block(blk, _) = arm.body.kind { + (Some(blk.hir_id), self.find_block_span(blk)) + } else { + (None, arm.body.span) + }; + + let (span, code) = match prior_arm { // The reason for the first arm to fail is not that the match arms diverge, // but rather that there's a prior obligation that doesn't hold. - 0 => (arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id)), - _ => ( + None => (arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id)), + Some((prior_arm_block_id, prior_arm_ty, prior_arm_span)) => ( expr.span, ObligationCauseCode::MatchExpressionArm(Box::new(MatchExpressionArmCause { + arm_block_id, arm_span, + arm_ty, + prior_arm_block_id, + prior_arm_ty, + prior_arm_span, scrut_span: scrut.span, - semi_span, source: match_src, prior_arms: other_arms.clone(), - last_ty: prior_arm_ty.unwrap(), scrut_hir_id: scrut.hir_id, opt_suggest_box_span, })), @@ -139,7 +145,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ret_ty = ret_coercion.borrow().expected_ty(); let ret_ty = self.inh.infcx.shallow_resolve(ret_ty); self.can_coerce(arm_ty, ret_ty) - && prior_arm_ty.map_or(true, |t| self.can_coerce(t, ret_ty)) + && prior_arm.map_or(true, |(_, t, _)| self.can_coerce(t, ret_ty)) // The match arms need to unify for the case of `impl Trait`. && !matches!(ret_ty.kind(), ty::Opaque(..)) } @@ -181,7 +187,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if other_arms.len() > 5 { other_arms.remove(0); } - prior_arm_ty = Some(arm_ty); + + prior_arm = Some((arm_block_id, arm_ty, arm_span)); } // If all of the arms in the `match` diverge, @@ -207,28 +214,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match_ty } - fn get_appropriate_arm_semicolon_removal_span( - &self, - arms: &'tcx [hir::Arm<'tcx>], - i: usize, - prior_arm_ty: Option<Ty<'tcx>>, - arm_ty: Ty<'tcx>, - ) -> (Span, Option<(Span, StatementAsExpression)>) { - let arm = &arms[i]; - let (arm_span, mut semi_span) = if let hir::ExprKind::Block(blk, _) = &arm.body.kind { - self.find_block_span(blk, prior_arm_ty) - } else { - (arm.body.span, None) - }; - if semi_span.is_none() && i > 0 { - if let hir::ExprKind::Block(blk, _) = &arms[i - 1].body.kind { - let (_, semi_span_prev) = self.find_block_span(blk, Some(arm_ty)); - semi_span = semi_span_prev; - } - } - (arm_span, semi_span) - } - /// When the previously checked expression (the scrutinee) diverges, /// warn the user about the match arms being unreachable. fn warn_arms_when_scrutinee_diverges(&self, arms: &'tcx [hir::Arm<'tcx>]) { @@ -259,7 +244,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &cause, &mut |err| { if let Some((span, msg)) = &ret_reason { - err.span_label(*span, msg.as_str()); + err.span_label(*span, msg); } else if let ExprKind::Block(block, _) = &then_expr.kind && let Some(expr) = &block.expr { @@ -313,7 +298,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { else_ty: Ty<'tcx>, opt_suggest_box_span: Option<Span>, ) -> ObligationCause<'tcx> { - let mut outer_sp = if self.tcx.sess.source_map().is_multiline(span) { + let mut outer_span = if self.tcx.sess.source_map().is_multiline(span) { // The `if`/`else` isn't in one line in the output, include some context to make it // clear it is an if/else expression: // ``` @@ -339,69 +324,67 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None }; - let mut remove_semicolon = None; - let error_sp = if let ExprKind::Block(block, _) = &else_expr.kind { - let (error_sp, semi_sp) = self.find_block_span(block, Some(then_ty)); - remove_semicolon = semi_sp; - if block.expr.is_none() && block.stmts.is_empty() { - // Avoid overlapping spans that aren't as readable: - // ``` - // 2 | let x = if true { - // | _____________- - // 3 | | 3 - // | | - expected because of this - // 4 | | } else { - // | |____________^ - // 5 | || - // 6 | || }; - // | || ^ - // | ||_____| - // | |______if and else have incompatible types - // | expected integer, found `()` - // ``` - // by not pointing at the entire expression: - // ``` - // 2 | let x = if true { - // | ------- `if` and `else` have incompatible types - // 3 | 3 - // | - expected because of this - // 4 | } else { - // | ____________^ - // 5 | | - // 6 | | }; - // | |_____^ expected integer, found `()` - // ``` - if outer_sp.is_some() { - outer_sp = Some(self.tcx.sess.source_map().guess_head_span(span)); - } + let (error_sp, else_id) = if let ExprKind::Block(block, _) = &else_expr.kind { + let block = block.innermost_block(); + + // Avoid overlapping spans that aren't as readable: + // ``` + // 2 | let x = if true { + // | _____________- + // 3 | | 3 + // | | - expected because of this + // 4 | | } else { + // | |____________^ + // 5 | || + // 6 | || }; + // | || ^ + // | ||_____| + // | |______if and else have incompatible types + // | expected integer, found `()` + // ``` + // by not pointing at the entire expression: + // ``` + // 2 | let x = if true { + // | ------- `if` and `else` have incompatible types + // 3 | 3 + // | - expected because of this + // 4 | } else { + // | ____________^ + // 5 | | + // 6 | | }; + // | |_____^ expected integer, found `()` + // ``` + if block.expr.is_none() && block.stmts.is_empty() + && let Some(outer_span) = &mut outer_span + { + *outer_span = self.tcx.sess.source_map().guess_head_span(*outer_span); } - error_sp + + (self.find_block_span(block), block.hir_id) } else { - // shouldn't happen unless the parser has done something weird - else_expr.span + (else_expr.span, else_expr.hir_id) }; - // Compute `Span` of `then` part of `if`-expression. - let then_sp = if let ExprKind::Block(block, _) = &then_expr.kind { - let (then_sp, semi_sp) = self.find_block_span(block, Some(else_ty)); - remove_semicolon = remove_semicolon.or(semi_sp); + let then_id = if let ExprKind::Block(block, _) = &then_expr.kind { + let block = block.innermost_block(); + // Exclude overlapping spans if block.expr.is_none() && block.stmts.is_empty() { - outer_sp = None; // same as in `error_sp`; cleanup output + outer_span = None; } - then_sp + block.hir_id } else { - // shouldn't happen unless the parser has done something weird - then_expr.span + then_expr.hir_id }; // Finally construct the cause: self.cause( error_sp, ObligationCauseCode::IfExpression(Box::new(IfExpressionCause { - then: then_sp, - else_sp: error_sp, - outer: outer_sp, - semicolon: remove_semicolon, + else_id, + then_id, + then_ty, + else_ty, + outer_span, opt_suggest_box_span, })), ) @@ -482,22 +465,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn find_block_span( - &self, - block: &'tcx hir::Block<'tcx>, - expected_ty: Option<Ty<'tcx>>, - ) -> (Span, Option<(Span, StatementAsExpression)>) { - if let Some(expr) = &block.expr { - (expr.span, None) - } else if let Some(stmt) = block.stmts.last() { - // possibly incorrect trailing `;` in the else arm - (stmt.span, expected_ty.and_then(|ty| self.could_remove_semicolon(block, ty))) - } else { - // empty block; point at its entirety - (block.span, None) - } - } - // When we have a `match` as a tail expression in a `fn` with a returned `impl Trait` // we check if the different arms would work with boxed trait objects instead and // provide a structured suggestion in that case. diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs index d14d06237be..00c8aa3a1bb 100644 --- a/compiler/rustc_typeck/src/check/callee.rs +++ b/compiler/rustc_typeck/src/check/callee.rs @@ -4,7 +4,7 @@ use crate::type_error_struct; use rustc_errors::{struct_span_err, Applicability, Diagnostic}; use rustc_hir as hir; -use rustc_hir::def::{Namespace, Res}; +use rustc_hir::def::{self, Namespace, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_infer::{ infer, @@ -390,17 +390,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (fn_sig, Some(def_id)) } ty::FnPtr(sig) => (sig, None), - ref t => { + _ => { let mut unit_variant = None; - let mut removal_span = call_expr.span; - if let ty::Adt(adt_def, ..) = t - && adt_def.is_enum() - && let hir::ExprKind::Call(expr, _) = call_expr.kind + if let hir::ExprKind::Path(qpath) = &callee_expr.kind + && let Res::Def(def::DefKind::Ctor(kind, def::CtorKind::Const), _) + = self.typeck_results.borrow().qpath_res(qpath, callee_expr.hir_id) + // Only suggest removing parens if there are no arguments + && arg_exprs.is_empty() { - removal_span = - expr.span.shrink_to_hi().to(call_expr.span.shrink_to_hi()); + let descr = match kind { + def::CtorOf::Struct => "struct", + def::CtorOf::Variant => "enum variant", + }; + let removal_span = + callee_expr.span.shrink_to_hi().to(call_expr.span.shrink_to_hi()); unit_variant = - self.tcx.sess.source_map().span_to_snippet(expr.span).ok(); + Some((removal_span, descr, rustc_hir_pretty::qpath_to_string(qpath))); } let callee_ty = self.resolve_vars_if_possible(callee_ty); @@ -410,8 +415,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { callee_ty, E0618, "expected function, found {}", - match unit_variant { - Some(ref path) => format!("enum variant `{path}`"), + match &unit_variant { + Some((_, kind, path)) => format!("{kind} `{path}`"), None => format!("`{callee_ty}`"), } ); @@ -423,11 +428,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { callee_expr.span, ); - if let Some(ref path) = unit_variant { + if let Some((removal_span, kind, path)) = &unit_variant { err.span_suggestion_verbose( - removal_span, + *removal_span, &format!( - "`{path}` is a unit variant, you need to write it without the parentheses", + "`{path}` is a unit {kind}, and does not take parentheses to be constructed", ), "", Applicability::MachineApplicable, @@ -470,7 +475,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(span) = self.tcx.hir().res_span(def) { let callee_ty = callee_ty.to_string(); let label = match (unit_variant, inner_callee_path) { - (Some(path), _) => Some(format!("`{path}` defined here")), + (Some((_, kind, path)), _) => Some(format!("{kind} `{path}` defined here")), (_, Some(hir::QPath::Resolved(_, path))) => self .tcx .sess diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index 66dd5582490..7aaddc2bd7a 100644 --- a/compiler/rustc_typeck/src/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -69,7 +69,7 @@ enum PointerKind<'tcx> { /// No metadata attached, ie pointer to sized type or foreign type Thin, /// A trait object - Vtable(Option<DefId>), + VTable(Option<DefId>), /// Slice Length, /// The unsize info of this projection @@ -102,7 +102,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(match *t.kind() { ty::Slice(_) | ty::Str => Some(PointerKind::Length), - ty::Dynamic(ref tty, ..) => Some(PointerKind::Vtable(tty.principal_def_id())), + ty::Dynamic(ref tty, ..) => Some(PointerKind::VTable(tty.principal_def_id())), ty::Adt(def, substs) if def.is_struct() => match def.non_enum_variant().fields.last() { None => Some(PointerKind::Thin), Some(f) => { @@ -951,7 +951,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { match fcx.pointer_kind(m_cast.ty, self.span)? { None => Err(CastError::UnknownCastPtrKind), Some(PointerKind::Thin) => Ok(CastKind::AddrPtrCast), - Some(PointerKind::Vtable(_)) => Err(CastError::IntToFatCast(Some("a vtable"))), + Some(PointerKind::VTable(_)) => Err(CastError::IntToFatCast(Some("a vtable"))), Some(PointerKind::Length) => Err(CastError::IntToFatCast(Some("a length"))), Some( PointerKind::OfProjection(_) diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 69f3f03cfa9..9497d5c4528 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -14,7 +14,7 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::{ItemKind, Node, PathSegment}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt}; +use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt}; use rustc_infer::traits::Obligation; use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS; use rustc_middle::hir::nested_filter; @@ -731,52 +731,52 @@ fn check_opaque_meets_bounds<'tcx>( }; let param_env = tcx.param_env(defining_use_anchor); - tcx.infer_ctxt().with_opaque_type_inference(defining_use_anchor).enter(move |infcx| { - let ocx = ObligationCtxt::new(&infcx); - let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs); + tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(defining_use_anchor)).enter( + move |infcx| { + let ocx = ObligationCtxt::new(&infcx); + let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs); - let misc_cause = traits::ObligationCause::misc(span, hir_id); + let misc_cause = traits::ObligationCause::misc(span, hir_id); - match infcx.at(&misc_cause, param_env).eq(opaque_ty, hidden_type) { - Ok(infer_ok) => ocx.register_infer_ok_obligations(infer_ok), - Err(ty_err) => { - tcx.sess.delay_span_bug( - span, - &format!("could not unify `{hidden_type}` with revealed type:\n{ty_err}"), - ); + match infcx.at(&misc_cause, param_env).eq(opaque_ty, hidden_type) { + Ok(infer_ok) => ocx.register_infer_ok_obligations(infer_ok), + Err(ty_err) => { + tcx.sess.delay_span_bug( + span, + &format!("could not unify `{hidden_type}` with revealed type:\n{ty_err}"), + ); + } } - } - // Additionally require the hidden type to be well-formed with only the generics of the opaque type. - // Defining use functions may have more bounds than the opaque type, which is ok, as long as the - // hidden type is well formed even without those bounds. - let predicate = - ty::Binder::dummy(ty::PredicateKind::WellFormed(hidden_type.into())).to_predicate(tcx); - ocx.register_obligation(Obligation::new(misc_cause, param_env, predicate)); - - // Check that all obligations are satisfied by the implementation's - // version. - let errors = ocx.select_all_or_error(); - if !errors.is_empty() { - infcx.report_fulfillment_errors(&errors, None, false); - } - - match origin { - // Checked when type checking the function containing them. - hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {} - // Can have different predicates to their defining use - hir::OpaqueTyOrigin::TyAlias => { - let outlives_environment = OutlivesEnvironment::new(param_env); - infcx.check_region_obligations_and_report_errors( - defining_use_anchor, - &outlives_environment, - ); + // Additionally require the hidden type to be well-formed with only the generics of the opaque type. + // Defining use functions may have more bounds than the opaque type, which is ok, as long as the + // hidden type is well formed even without those bounds. + let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(hidden_type.into())) + .to_predicate(tcx); + ocx.register_obligation(Obligation::new(misc_cause, param_env, predicate)); + + // Check that all obligations are satisfied by the implementation's + // version. + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { + infcx.report_fulfillment_errors(&errors, None, false); } - } - - // Clean up after ourselves - let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); - }); + match origin { + // Checked when type checking the function containing them. + hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {} + // Can have different predicates to their defining use + hir::OpaqueTyOrigin::TyAlias => { + let outlives_environment = OutlivesEnvironment::new(param_env); + infcx.check_region_obligations_and_report_errors( + defining_use_anchor, + &outlives_environment, + ); + } + } + // Clean up after ourselves + let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); + }, + ); } fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) { diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index a53217ef818..1a9354f5d20 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -2,7 +2,7 @@ use super::potentially_plural_count; use crate::check::regionck::OutlivesEnvironmentExt; use crate::check::wfcheck; use crate::errors::LifetimesOrBoundsMismatchOnTrait; -use rustc_data_structures::stable_set::FxHashSet; +use rustc_data_structures::fx::FxHashSet; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -1460,6 +1460,7 @@ pub fn check_type_bounds<'tcx>( .map(|e| e.map_bound(|e| *e).transpose_tuple2()) .map(|(bound, span)| { debug!(?bound); + // this is where opaque type is found let concrete_ty_bound = bound.subst(tcx, rebased_substs); debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound); @@ -1481,7 +1482,6 @@ pub fn check_type_bounds<'tcx>( ocx.register_obligations(obligations); ocx.register_obligation(obligation); } - // Check that all obligations are satisfied by the implementation's // version. let errors = ocx.select_all_or_error(); @@ -1505,6 +1505,21 @@ pub fn check_type_bounds<'tcx>( &outlives_environment, ); + let constraints = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); + for (key, value) in constraints { + infcx + .report_mismatched_types( + &ObligationCause::misc( + value.hidden_type.span, + tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local()), + ), + tcx.mk_opaque(key.def_id.to_def_id(), key.substs), + value.hidden_type.ty, + TypeError::Mismatch, + ) + .emit(); + } + Ok(()) }) } diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index 740261cfe74..a2d8765289c 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -33,6 +33,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.annotate_expected_due_to_let_ty(err, expr, error); self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr); self.suggest_compatible_variants(err, expr, expected, expr_ty); + self.suggest_non_zero_new_unwrap(err, expr, expected, expr_ty); if self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) { return; } @@ -347,7 +348,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - let compatible_variants: Vec<String> = expected_adt + let compatible_variants: Vec<(String, Option<String>)> = expected_adt .variants() .iter() .filter(|variant| { @@ -355,6 +356,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) .filter_map(|variant| { let sole_field = &variant.fields[0]; + + let field_is_local = sole_field.did.is_local(); + let field_is_accessible = + sole_field.vis.is_accessible_from(expr.hir_id.owner.to_def_id(), self.tcx); + + if !field_is_local && !field_is_accessible { + return None; + } + + let note_about_variant_field_privacy = (field_is_local && !field_is_accessible) + .then(|| format!(" (its field is private, but it's local to this crate and its privacy can be changed)")); + let sole_field_ty = sole_field.ty(self.tcx, substs); if self.can_coerce(expr_ty, sole_field_ty) { let variant_path = @@ -363,9 +376,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(path) = variant_path.strip_prefix("std::prelude::") && let Some((_, path)) = path.split_once("::") { - return Some(path.to_string()); + return Some((path.to_string(), note_about_variant_field_privacy)); } - Some(variant_path) + Some((variant_path, note_about_variant_field_privacy)) } else { None } @@ -379,10 +392,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match &compatible_variants[..] { [] => { /* No variants to format */ } - [variant] => { + [(variant, note)] => { // Just a single matching variant. err.multipart_suggestion_verbose( - &format!("try wrapping the expression in `{variant}`"), + &format!( + "try wrapping the expression in `{variant}`{note}", + note = note.as_deref().unwrap_or("") + ), vec![ (expr.span.shrink_to_lo(), format!("{prefix}{variant}(")), (expr.span.shrink_to_hi(), ")".to_string()), @@ -397,7 +413,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "try wrapping the expression in a variant of `{}`", self.tcx.def_path_str(expected_adt.did()) ), - compatible_variants.into_iter().map(|variant| { + compatible_variants.into_iter().map(|(variant, _)| { vec![ (expr.span.shrink_to_lo(), format!("{prefix}{variant}(")), (expr.span.shrink_to_hi(), ")".to_string()), @@ -410,6 +426,57 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + fn suggest_non_zero_new_unwrap( + &self, + err: &mut Diagnostic, + expr: &hir::Expr<'_>, + expected: Ty<'tcx>, + expr_ty: Ty<'tcx>, + ) { + let tcx = self.tcx; + let (adt, unwrap) = match expected.kind() { + // In case Option<NonZero*> is wanted, but * is provided, suggest calling new + ty::Adt(adt, substs) if tcx.is_diagnostic_item(sym::Option, adt.did()) => { + // Unwrap option + let ty::Adt(adt, _) = substs.type_at(0).kind() else { return }; + + (adt, "") + } + // In case NonZero* is wanted, but * is provided also add `.unwrap()` to satisfy types + ty::Adt(adt, _) => (adt, ".unwrap()"), + _ => return, + }; + + let map = [ + (sym::NonZeroU8, tcx.types.u8), + (sym::NonZeroU16, tcx.types.u16), + (sym::NonZeroU32, tcx.types.u32), + (sym::NonZeroU64, tcx.types.u64), + (sym::NonZeroU128, tcx.types.u128), + (sym::NonZeroI8, tcx.types.i8), + (sym::NonZeroI16, tcx.types.i16), + (sym::NonZeroI32, tcx.types.i32), + (sym::NonZeroI64, tcx.types.i64), + (sym::NonZeroI128, tcx.types.i128), + ]; + + let Some((s, _)) = map + .iter() + .find(|&&(s, t)| self.tcx.is_diagnostic_item(s, adt.did()) && self.can_coerce(expr_ty, t)) + else { return }; + + let path = self.tcx.def_path_str(adt.non_enum_variant().def_id); + + err.multipart_suggestion( + format!("consider calling `{s}::new`"), + vec![ + (expr.span.shrink_to_lo(), format!("{path}::new(")), + (expr.span.shrink_to_hi(), format!("){unwrap}")), + ], + Applicability::MaybeIncorrect, + ); + } + pub fn get_conversion_methods( &self, span: Span, diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 02e493f7258..8e4cd2392e0 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -531,7 +531,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tcx.ty_error() } Res::Def(DefKind::Ctor(_, CtorKind::Fictive), _) => { - report_unexpected_variant_res(tcx, res, expr.span); + report_unexpected_variant_res(tcx, res, qpath, expr.span); tcx.ty_error() } _ => self.instantiate_value_path(segs, opt_ty, res, expr.span, expr.hir_id).0, @@ -1803,7 +1803,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .source_map() .span_to_snippet(range_end.expr.span) .map(|s| format!(" from `{s}`")) - .unwrap_or(String::new()); + .unwrap_or_default(); err.span_suggestion( range_start.span.shrink_to_hi(), &format!("to set the remaining fields{instead}, separate the last named field with a comma"), @@ -2362,7 +2362,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false }; let expr_snippet = - self.tcx.sess.source_map().span_to_snippet(expr.span).unwrap_or(String::new()); + self.tcx.sess.source_map().span_to_snippet(expr.span).unwrap_or_default(); let is_wrapped = expr_snippet.starts_with('(') && expr_snippet.ends_with(')'); let after_open = expr.span.lo() + rustc_span::BytePos(1); let before_close = expr.span.hi() - rustc_span::BytePos(1); diff --git a/compiler/rustc_typeck/src/check/fallback.rs b/compiler/rustc_typeck/src/check/fallback.rs index 15788f410f1..67a89a69f65 100644 --- a/compiler/rustc_typeck/src/check/fallback.rs +++ b/compiler/rustc_typeck/src/check/fallback.rs @@ -1,9 +1,8 @@ use crate::check::FnCtxt; use rustc_data_structures::{ - fx::FxHashMap, + fx::{FxHashMap, FxHashSet}, graph::WithSuccessors, graph::{iterate::DepthFirstSearch, vec_graph::VecGraph}, - stable_set::FxHashSet, }; use rustc_middle::ty::{self, Ty}; diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index d33b5b21403..21b3c9063a7 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -30,17 +30,15 @@ use rustc_middle::ty::{ }; use rustc_session::lint; use rustc_span::hygiene::DesugaringKind; -use rustc_span::source_map::{original_sp, DUMMY_SP}; use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::{self, BytePos, Span}; +use rustc_span::{Span, DUMMY_SP}; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; use rustc_trait_selection::traits::{ - self, ObligationCause, ObligationCauseCode, StatementAsExpression, TraitEngine, TraitEngineExt, + self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt, }; use std::collections::hash_map::Entry; -use std::iter; use std::slice; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -763,12 +761,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // src/test/ui/impl-trait/hidden-type-is-opaque-2.rs for examples that hit this path. if formal_ret.has_infer_types() { for ty in ret_ty.walk() { - if let ty::subst::GenericArgKind::Type(ty) = ty.unpack() { - if let ty::Opaque(def_id, _) = *ty.kind() { - if self.infcx.opaque_type_origin(def_id, DUMMY_SP).is_some() { - return None; - } - } + if let ty::subst::GenericArgKind::Type(ty) = ty.unpack() + && let ty::Opaque(def_id, _) = *ty.kind() + && let Some(def_id) = def_id.as_local() + && self.infcx.opaque_type_origin(def_id, DUMMY_SP).is_some() { + return None; } } } @@ -1060,84 +1057,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )); } - pub(in super::super) fn could_remove_semicolon( - &self, - blk: &'tcx hir::Block<'tcx>, - expected_ty: Ty<'tcx>, - ) -> Option<(Span, StatementAsExpression)> { - // Be helpful when the user wrote `{... expr;}` and - // taking the `;` off is enough to fix the error. - let last_stmt = blk.stmts.last()?; - let hir::StmtKind::Semi(ref last_expr) = last_stmt.kind else { - return None; - }; - let last_expr_ty = self.node_ty(last_expr.hir_id); - let needs_box = match (last_expr_ty.kind(), expected_ty.kind()) { - (ty::Opaque(last_def_id, _), ty::Opaque(exp_def_id, _)) - if last_def_id == exp_def_id => - { - StatementAsExpression::CorrectType - } - (ty::Opaque(last_def_id, last_bounds), ty::Opaque(exp_def_id, exp_bounds)) => { - debug!( - "both opaque, likely future {:?} {:?} {:?} {:?}", - last_def_id, last_bounds, exp_def_id, exp_bounds - ); - - let last_local_id = last_def_id.as_local()?; - let exp_local_id = exp_def_id.as_local()?; - - match ( - &self.tcx.hir().expect_item(last_local_id).kind, - &self.tcx.hir().expect_item(exp_local_id).kind, - ) { - ( - hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: last_bounds, .. }), - hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: exp_bounds, .. }), - ) if iter::zip(*last_bounds, *exp_bounds).all(|(left, right)| { - match (left, right) { - ( - hir::GenericBound::Trait(tl, ml), - hir::GenericBound::Trait(tr, mr), - ) if tl.trait_ref.trait_def_id() == tr.trait_ref.trait_def_id() - && ml == mr => - { - true - } - ( - hir::GenericBound::LangItemTrait(langl, _, _, argsl), - hir::GenericBound::LangItemTrait(langr, _, _, argsr), - ) if langl == langr => { - // FIXME: consider the bounds! - debug!("{:?} {:?}", argsl, argsr); - true - } - _ => false, - } - }) => - { - StatementAsExpression::NeedsBoxing - } - _ => StatementAsExpression::CorrectType, - } - } - _ => StatementAsExpression::CorrectType, - }; - if (matches!(last_expr_ty.kind(), ty::Error(_)) - || self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err()) - && matches!(needs_box, StatementAsExpression::CorrectType) - { - return None; - } - let span = if last_stmt.span.from_expansion() { - let mac_call = original_sp(last_stmt.span, blk.span); - self.tcx.sess.source_map().mac_call_stmt_semi_span(mac_call)? - } else { - last_stmt.span.with_lo(last_stmt.span.hi() - BytePos(1)) - }; - Some((span, needs_box)) - } - // Instantiates the given path, which must refer to an item with the given // number of type parameters and type. #[instrument(skip(self, span), level = "debug")] diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 89b376442a8..1555f4f3fd6 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -31,9 +31,7 @@ use rustc_middle::ty::{self, DefIdTree, IsSuggestable, Ty}; use rustc_session::Session; use rustc_span::symbol::Ident; use rustc_span::{self, Span}; -use rustc_trait_selection::traits::{ - self, ObligationCauseCode, SelectionContext, StatementAsExpression, -}; +use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext}; use std::iter; use std::slice; @@ -443,17 +441,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Next, let's construct the error let (error_span, full_call_span, ctor_of) = match &call_expr.kind { hir::ExprKind::Call( - hir::Expr { - span, - kind: - hir::ExprKind::Path(hir::QPath::Resolved( - _, - hir::Path { res: Res::Def(DefKind::Ctor(of, _), _), .. }, - )), - .. - }, + hir::Expr { hir_id, span, kind: hir::ExprKind::Path(qpath), .. }, _, - ) => (call_span, *span, Some(of)), + ) => { + if let Res::Def(DefKind::Ctor(of, _), _) = + self.typeck_results.borrow().qpath_res(qpath, *hir_id) + { + (call_span, *span, Some(of)) + } else { + (call_span, *span, None) + } + } hir::ExprKind::Call(hir::Expr { span, .. }, _) => (call_span, *span, None), hir::ExprKind::MethodCall(path_segment, _, span) => { let ident_span = path_segment.ident.span; @@ -483,6 +481,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.set_tainted_by_errors(); let tcx = self.tcx; + // Get the argument span in the context of the call span so that + // suggestions and labels are (more) correct when an arg is a + // macro invocation. + let normalize_span = |span: Span| -> Span { + let normalized_span = span.find_ancestor_inside(error_span).unwrap_or(span); + // Sometimes macros mess up the spans, so do not normalize the + // arg span to equal the error span, because that's less useful + // than pointing out the arg expr in the wrong context. + if normalized_span.source_equal(error_span) { span } else { normalized_span } + }; + // Precompute the provided types and spans, since that's all we typically need for below let provided_arg_tys: IndexVec<ProvidedIdx, (Ty<'tcx>, Span)> = provided_args .iter() @@ -492,7 +501,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .borrow() .expr_ty_adjusted_opt(*expr) .unwrap_or_else(|| tcx.ty_error()); - (self.resolve_vars_if_possible(ty), expr.span) + (self.resolve_vars_if_possible(ty), normalize_span(expr.span)) }) .collect(); let callee_expr = match &call_expr.peel_blocks().kind { @@ -575,6 +584,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If so, we might have just forgotten to wrap some args in a tuple. if let Some(ty::Tuple(tys)) = formal_and_expected_inputs.get(mismatch_idx.into()).map(|tys| tys.1.kind()) + // If the tuple is unit, we're not actually wrapping any arguments. + && !tys.is_empty() && provided_arg_tys.len() == formal_and_expected_inputs.len() - 1 + tys.len() { // Wrap up the N provided arguments starting at this position in a tuple. @@ -600,11 +611,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Take some care with spans, so we don't suggest wrapping a macro's // innards in parenthesis, for example. if satisfied - && let Some(lo) = - provided_args[mismatch_idx.into()].span.find_ancestor_inside(error_span) - && let Some(hi) = provided_args[(mismatch_idx + tys.len() - 1).into()] - .span - .find_ancestor_inside(error_span) + && let Some((_, lo)) = + provided_arg_tys.get(ProvidedIdx::from_usize(mismatch_idx)) + && let Some((_, hi)) = + provided_arg_tys.get(ProvidedIdx::from_usize(mismatch_idx + tys.len() - 1)) { let mut err; if tys.len() == 1 { @@ -612,7 +622,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // so don't do anything special here. err = self.report_and_explain_type_error( TypeTrace::types( - &self.misc(lo), + &self.misc(*lo), true, formal_and_expected_inputs[mismatch_idx.into()].1, provided_arg_tys[mismatch_idx.into()].0, @@ -1052,7 +1062,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let suggestion_text = if let Some(provided_idx) = provided_idx && let (_, provided_span) = provided_arg_tys[*provided_idx] && let Ok(arg_text) = - source_map.span_to_snippet(provided_span.source_callsite()) + source_map.span_to_snippet(provided_span) { arg_text } else { @@ -1410,7 +1420,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self.misc(sp), &mut |err| { if let Some(expected_ty) = expected.only_has_type(self) { - self.consider_hint_about_removing_semicolon(blk, expected_ty, err); + if !self.consider_removing_semicolon(blk, expected_ty, err) { + self.consider_returning_binding(blk, expected_ty, err); + } if expected_ty == self.tcx.types.bool { // If this is caused by a missing `let` in a `while let`, // silence this redundant error, as we already emit E0070. @@ -1478,42 +1490,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty } - /// A common error is to add an extra semicolon: - /// - /// ```compile_fail,E0308 - /// fn foo() -> usize { - /// 22; - /// } - /// ``` - /// - /// This routine checks if the final statement in a block is an - /// expression with an explicit semicolon whose type is compatible - /// with `expected_ty`. If so, it suggests removing the semicolon. - fn consider_hint_about_removing_semicolon( - &self, - blk: &'tcx hir::Block<'tcx>, - expected_ty: Ty<'tcx>, - err: &mut Diagnostic, - ) { - if let Some((span_semi, boxed)) = self.could_remove_semicolon(blk, expected_ty) { - if let StatementAsExpression::NeedsBoxing = boxed { - err.span_suggestion_verbose( - span_semi, - "consider removing this semicolon and boxing the expression", - "", - Applicability::HasPlaceholders, - ); - } else { - err.span_suggestion_short( - span_semi, - "remove this semicolon", - "", - Applicability::MachineApplicable, - ); - } - } - } - fn parent_item_span(&self, id: hir::HirId) -> Option<Span> { let node = self.tcx.hir().get_by_def_id(self.tcx.hir().get_parent_item(id)); match node { @@ -1791,19 +1767,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .flat_map(|a| a.args.iter()) { if let hir::GenericArg::Type(hir_ty) = &arg { - if let hir::TyKind::Path(hir::QPath::TypeRelative(..)) = - &hir_ty.kind - { - // Avoid ICE with associated types. As this is best - // effort only, it's ok to ignore the case. It - // would trigger in `is_send::<T::AssocType>();` - // from `typeck-default-trait-impl-assoc-type.rs`. - } else { - let ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, hir_ty); - let ty = self.resolve_vars_if_possible(ty); - if ty == predicate.self_ty() { - error.obligation.cause.span = hir_ty.span; - } + let ty = self.resolve_vars_if_possible( + self.typeck_results.borrow().node_type(hir_ty.hir_id), + ); + if ty == predicate.self_ty() { + error.obligation.cause.span = hir_ty.span; } } } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index 80feac18412..3e6ff72204f 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -11,12 +11,12 @@ use rustc_hir::{ Expr, ExprKind, GenericBound, Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate, }; use rustc_infer::infer::{self, TyCtxtInferExt}; -use rustc_infer::traits; +use rustc_infer::traits::{self, StatementAsExpression}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Binder, IsSuggestable, Subst, ToPredicate, Ty}; use rustc_span::symbol::sym; use rustc_span::Span; -use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(in super::super) fn suggest_semicolon_at_end(&self, span: Span, err: &mut Diagnostic) { @@ -864,4 +864,43 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } } + + /// A common error is to add an extra semicolon: + /// + /// ```compile_fail,E0308 + /// fn foo() -> usize { + /// 22; + /// } + /// ``` + /// + /// This routine checks if the final statement in a block is an + /// expression with an explicit semicolon whose type is compatible + /// with `expected_ty`. If so, it suggests removing the semicolon. + pub(crate) fn consider_removing_semicolon( + &self, + blk: &'tcx hir::Block<'tcx>, + expected_ty: Ty<'tcx>, + err: &mut Diagnostic, + ) -> bool { + if let Some((span_semi, boxed)) = self.could_remove_semicolon(blk, expected_ty) { + if let StatementAsExpression::NeedsBoxing = boxed { + err.span_suggestion_verbose( + span_semi, + "consider removing this semicolon and boxing the expression", + "", + Applicability::HasPlaceholders, + ); + } else { + err.span_suggestion_short( + span_semi, + "remove this semicolon", + "", + Applicability::MachineApplicable, + ); + } + true + } else { + false + } + } } diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs index 14b226d91cb..518cd734236 100644 --- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs +++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs @@ -17,8 +17,7 @@ use self::record_consumed_borrow::find_consumed_and_borrowed; use crate::check::FnCtxt; use hir::def_id::DefId; use hir::{Body, HirId, HirIdMap, Node}; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::stable_set::FxHashSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs index da2db3f2e30..a2c23db162b 100644 --- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs +++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs @@ -6,7 +6,7 @@ use hir::{ intravisit::{self, Visitor}, Body, Expr, ExprKind, Guard, HirId, LoopIdError, }; -use rustc_data_structures::{fx::FxHashMap, stable_set::FxHashSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_index::vec::IndexVec; use rustc_middle::{ diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs index 67cc46f21f0..ded0888c33e 100644 --- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs +++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs @@ -4,7 +4,7 @@ use crate::{ expr_use_visitor::{self, ExprUseVisitor}, }; use hir::{def_id::DefId, Body, HirId, HirIdMap}; -use rustc_data_structures::stable_set::FxHashSet; +use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_middle::hir::place::{PlaceBase, Projection, ProjectionKind}; use rustc_middle::ty::{ParamEnv, TyCtxt}; @@ -72,9 +72,8 @@ impl<'tcx> ExprUseDelegate<'tcx> { } fn mark_consumed(&mut self, consumer: HirId, target: TrackedValue) { - if !self.places.consumed.contains_key(&consumer) { - self.places.consumed.insert(consumer, <_>::default()); - } + self.places.consumed.entry(consumer).or_insert_with(|| <_>::default()); + debug!(?consumer, ?target, "mark_consumed"); self.places.consumed.get_mut(&consumer).map(|places| places.insert(target)); } diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs index 4afbc00b37c..2f841fc277d 100644 --- a/compiler/rustc_typeck/src/check/inherited.rs +++ b/compiler/rustc_typeck/src/check/inherited.rs @@ -86,7 +86,10 @@ impl<'tcx> Inherited<'_, 'tcx> { let hir_owner = tcx.hir().local_def_id_to_hir_id(def_id).owner; InheritedBuilder { - infcx: tcx.infer_ctxt().with_fresh_in_progress_typeck_results(hir_owner), + infcx: tcx + .infer_ctxt() + .ignoring_regions() + .with_fresh_in_progress_typeck_results(hir_owner), def_id, } } @@ -113,7 +116,7 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> { maybe_typeck_results: infcx.in_progress_typeck_results, }, infcx, - fulfillment_cx: RefCell::new(<dyn TraitEngine<'_>>::new_ignoring_regions(tcx)), + fulfillment_cx: RefCell::new(<dyn TraitEngine<'_>>::new(tcx)), locals: RefCell::new(Default::default()), deferred_sized_obligations: RefCell::new(Vec::new()), deferred_call_resolutions: RefCell::new(Default::default()), diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs index 7fe710cf8f4..3f2a0da8d65 100644 --- a/compiler/rustc_typeck/src/check/intrinsic.rs +++ b/compiler/rustc_typeck/src/check/intrinsic.rs @@ -400,6 +400,10 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { sym::const_eval_select => (4, vec![param(0), param(1), param(2)], param(3)), + sym::vtable_size | sym::vtable_align => { + (0, vec![tcx.mk_imm_ptr(tcx.mk_unit())], tcx.types.usize) + } + other => { tcx.sess.emit_err(UnrecognizedIntrinsicFunction { span: it.span, name: other }); return; diff --git a/compiler/rustc_typeck/src/check/intrinsicck.rs b/compiler/rustc_typeck/src/check/intrinsicck.rs index 0adf0d28aae..df94abbafb1 100644 --- a/compiler/rustc_typeck/src/check/intrinsicck.rs +++ b/compiler/rustc_typeck/src/check/intrinsicck.rs @@ -1,5 +1,5 @@ use rustc_ast::InlineAsmTemplatePiece; -use rustc_data_structures::stable_set::FxHashSet; +use rustc_data_structures::fx::FxHashSet; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_index::vec::Idx; diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 849e96445d3..b088fc9eddb 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -87,10 +87,10 @@ mod op; mod pat; mod place_op; mod region; -mod regionck; +pub mod regionck; pub mod rvalue_scopes; mod upvar; -mod wfcheck; +pub mod wfcheck; pub mod writeback; use check::{check_abi, check_fn, check_mod_item_types}; @@ -863,17 +863,14 @@ fn bad_non_zero_sized_fields<'tcx>( err.emit(); } -fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, span: Span) { +fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, qpath: &hir::QPath<'_>, span: Span) { struct_span_err!( tcx.sess, span, E0533, - "expected unit struct, unit variant or constant, found {}{}", + "expected unit struct, unit variant or constant, found {} `{}`", res.descr(), - tcx.sess - .source_map() - .span_to_snippet(span) - .map_or_else(|_| String::new(), |s| format!(" `{s}`",)), + rustc_hir_pretty::qpath_to_string(qpath), ) .emit(); } diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index d4bb3d43eff..9858cd8fa19 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -408,8 +408,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false, ), }; - let mut err = - struct_span_err!(self.tcx.sess, op.span, E0369, "{}", message.as_str()); + let mut err = struct_span_err!(self.tcx.sess, op.span, E0369, "{message}"); if !lhs_expr.span.eq(&rhs_expr.span) { self.add_type_neq_err_label( &mut err, @@ -631,18 +630,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let rm_borrow_msg = "remove the borrow to obtain an owned `String`"; let to_owned_msg = "create an owned `String` from a string reference"; - let string_type = self.tcx.get_diagnostic_item(sym::String); - let is_std_string = |ty: Ty<'tcx>| match ty.ty_adt_def() { - Some(ty_def) => Some(ty_def.did()) == string_type, - None => false, + let is_std_string = |ty: Ty<'tcx>| { + ty.ty_adt_def() + .map_or(false, |ty_def| self.tcx.is_diagnostic_item(sym::String, ty_def.did())) }; match (lhs_ty.kind(), rhs_ty.kind()) { (&Ref(_, l_ty, _), &Ref(_, r_ty, _)) // &str or &String + &str, &String or &&str - if (*l_ty.kind() == Str || is_std_string(l_ty)) && ( - *r_ty.kind() == Str || is_std_string(r_ty) || - &format!("{:?}", rhs_ty) == "&&str" - ) => + if (*l_ty.kind() == Str || is_std_string(l_ty)) + && (*r_ty.kind() == Str + || is_std_string(r_ty) + || matches!( + r_ty.kind(), Ref(_, inner_ty, _) if *inner_ty.kind() == Str + )) => { if let IsAssign::No = is_assign { // Do not supply this message if `&str += &str` err.span_label(op.span, "`+` cannot be used to concatenate two `&str` strings"); diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index fbfbfba5c2a..c7318cd6e53 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -183,7 +183,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { PatKind::TupleStruct(ref qpath, subpats, ddpos) => { self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, def_bm, ti) } - PatKind::Path(_) => self.check_pat_path(pat, path_res.unwrap(), expected, ti), + PatKind::Path(ref qpath) => { + self.check_pat_path(pat, qpath, path_res.unwrap(), expected, ti) + } PatKind::Struct(ref qpath, fields, has_rest_pat) => { self.check_pat_struct(pat, qpath, fields, has_rest_pat, expected, def_bm, ti) } @@ -800,6 +802,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn check_pat_path<'b>( &self, pat: &Pat<'_>, + qpath: &hir::QPath<'_>, path_resolution: (Res, Option<Ty<'tcx>>, &'b [hir::PathSegment<'b>]), expected: Ty<'tcx>, ti: TopInfo<'tcx>, @@ -814,7 +817,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return tcx.ty_error(); } Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fictive | CtorKind::Fn), _) => { - report_unexpected_variant_res(tcx, res, pat.span); + report_unexpected_variant_res(tcx, res, qpath, pat.span); return tcx.ty_error(); } Res::SelfCtor(..) diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs index 1c3c5f999bc..d49a6138f7a 100644 --- a/compiler/rustc_typeck/src/check/regionck.rs +++ b/compiler/rustc_typeck/src/check/regionck.rs @@ -1,5 +1,5 @@ use crate::outlives::outlives_bounds::InferCtxtExt as _; -use rustc_data_structures::stable_set::FxHashSet; +use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::InferCtxt; diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 3bd3e2d8091..d175d7e0695 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -49,8 +49,7 @@ use rustc_span::sym; use rustc_span::{BytePos, Pos, Span, Symbol}; use rustc_trait_selection::infer::InferCtxtExt; -use rustc_data_structures::stable_map::FxHashMap; -use rustc_data_structures::stable_set::FxHashSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_index::vec::Idx; use rustc_target::abi::VariantIdx; diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 6df59ea1096..1b80e4edca9 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -1913,7 +1913,7 @@ impl<'a, 'tcx> WfCheckingCtxt<'a, 'tcx> { } } -pub(super) fn impl_implied_bounds<'tcx>( +pub fn impl_implied_bounds<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, impl_def_id: LocalDefId, diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index 0cbb0e25d0d..d102fb45a8c 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -4,7 +4,8 @@ use crate::check::FnCtxt; -use rustc_data_structures::stable_map::FxHashMap; +use hir::def_id::LocalDefId; +use rustc_data_structures::fx::FxHashMap; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -509,13 +510,13 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_) => { let ty = self.resolve(decl.hidden_type.ty, &decl.hidden_type.span); struct RecursionChecker { - def_id: DefId, + def_id: LocalDefId, } impl<'tcx> ty::TypeVisitor<'tcx> for RecursionChecker { type BreakTy = (); fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { if let ty::Opaque(def_id, _) = *t.kind() { - if def_id == self.def_id { + if def_id == self.def_id.to_def_id() { return ControlFlow::Break(()); } } diff --git a/compiler/rustc_typeck/src/coherence/builtin.rs b/compiler/rustc_typeck/src/coherence/builtin.rs index a92c37ff143..d8e42729ff3 100644 --- a/compiler/rustc_typeck/src/coherence/builtin.rs +++ b/compiler/rustc_typeck/src/coherence/builtin.rs @@ -116,8 +116,8 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) { // why this field does not implement Copy. This is useful because sometimes // it is not immediately clear why Copy is not implemented for a field, since // all we point at is the field itself. - tcx.infer_ctxt().enter(|infcx| { - let mut fulfill_cx = traits::FulfillmentContext::new_ignoring_regions(); + tcx.infer_ctxt().ignoring_regions().enter(|infcx| { + let mut fulfill_cx = traits::FulfillmentContext::new(); fulfill_cx.register_bound( &infcx, param_env, diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls.rs b/compiler/rustc_typeck/src/coherence/inherent_impls.rs index 7a9b874b5e4..52aad636fd8 100644 --- a/compiler/rustc_typeck/src/coherence/inherent_impls.rs +++ b/compiler/rustc_typeck/src/coherence/inherent_impls.rs @@ -219,8 +219,9 @@ impl<'tcx> InherentCollect<'tcx> { | ty::RawPtr(_) | ty::Ref(..) | ty::Never + | ty::FnPtr(_) | ty::Tuple(..) => self.check_primitive_impl(item.def_id, self_ty, items, ty.span), - ty::FnPtr(_) | ty::Projection(..) | ty::Opaque(..) | ty::Param(_) => { + ty::Projection(..) | ty::Opaque(..) | ty::Param(_) => { let mut err = struct_span_err!( self.tcx.sess, ty.span, diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 6ec741269e8..24e6a5d3047 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -2813,7 +2813,37 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { ) .emit(); } - None => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED, + 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 + // of unintentional ecosystem breakage -- particularly on + // Mach-O targets. + // + // As a result, we emit `llvm.compiler.used` only on ELF + // targets. This is somewhat ad-hoc, but actually follows + // our pre-LLVM 13 behavior (prior to the ecosystem + // breakage), and seems to match `clang`'s behavior as well + // (both before and after LLVM 13), possibly because they + // have similar compatibility concerns to us. See + // https://github.com/rust-lang/rust/issues/47384#issuecomment-1019080146 + // and following comments for some discussion of this, as + // well as the comments in `rustc_codegen_llvm` where these + // flags are handled. + // + // Anyway, to be clear: this is still up in the air + // somewhat, and is subject to change in the future (which + // is a good thing, because this would ideally be a bit + // more firmed up). + let is_like_elf = !(tcx.sess.target.is_like_osx + || tcx.sess.target.is_like_windows + || tcx.sess.target.is_like_wasm); + codegen_fn_attrs.flags = if is_like_elf { + CodegenFnAttrFlags::USED + } else { + CodegenFnAttrFlags::USED_LINKER + }; + } } } else if attr.has_name(sym::cmse_nonsecure_entry) { if !matches!(tcx.fn_sig(did).abi(), abi::Abi::C { .. }) { diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index f942a4fb53a..faa4f3700bb 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -342,7 +342,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { let concrete_ty = tcx .mir_borrowck(owner) .concrete_opaque_types - .get(&def_id.to_def_id()) + .get(&def_id) .copied() .map(|concrete| concrete.ty) .unwrap_or_else(|| { @@ -353,7 +353,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { // the `concrete_opaque_types` table. tcx.ty_error() } else { - table.concrete_opaque_types.get(&def_id.to_def_id()).copied().unwrap_or_else(|| { + table.concrete_opaque_types.get(&def_id).copied().unwrap_or_else(|| { // We failed to resolve the opaque type or it // resolves to itself. We interpret this as the // no values of the hidden type ever being constructed, @@ -526,7 +526,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { tcx: TyCtxt<'tcx>, /// def_id of the opaque type whose defining uses are being checked - def_id: DefId, + def_id: LocalDefId, /// as we walk the defining uses, we are checking that all of them /// define the same hidden type. This variable is set to `Some` @@ -602,7 +602,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { fn visit_item(&mut self, it: &'tcx Item<'tcx>) { trace!(?it.def_id); // The opaque type itself or its children are not within its reveal scope. - if it.def_id.to_def_id() != self.def_id { + if it.def_id != self.def_id { self.check(it.def_id); intravisit::walk_item(self, it); } @@ -610,7 +610,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) { trace!(?it.def_id); // The opaque type itself or its children are not within its reveal scope. - if it.def_id.to_def_id() != self.def_id { + if it.def_id != self.def_id { self.check(it.def_id); intravisit::walk_impl_item(self, it); } @@ -624,7 +624,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let scope = tcx.hir().get_defining_scope(hir_id); - let mut locator = ConstraintLocator { def_id: def_id.to_def_id(), tcx, found: None }; + let mut locator = ConstraintLocator { def_id: def_id, tcx, found: None }; debug!(?scope); diff --git a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs index 6ece955de64..f16888345e9 100644 --- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs @@ -65,6 +65,8 @@ //! cause use after frees with purely safe code in the same way as specializing //! on traits with methods can. +use crate::check::regionck::OutlivesEnvironmentExt; +use crate::check::wfcheck::impl_implied_bounds; use crate::constrained_generic_params as cgp; use crate::errors::SubstsOnOverriddenImpl; @@ -148,8 +150,15 @@ fn get_impl_substs<'tcx>( let impl2_substs = translate_substs(infcx, param_env, impl1_def_id.to_def_id(), impl1_substs, impl2_node); - // Conservatively use an empty `ParamEnv`. - let outlives_env = OutlivesEnvironment::new(ty::ParamEnv::empty()); + let mut outlives_env = OutlivesEnvironment::new(param_env); + let implied_bounds = + impl_implied_bounds(infcx.tcx, param_env, impl1_def_id, tcx.def_span(impl1_def_id)); + outlives_env.add_implied_bounds( + infcx, + implied_bounds, + tcx.hir().local_def_id_to_hir_id(impl1_def_id), + ); + infcx.process_registered_region_obligations(outlives_env.region_bound_pairs(), param_env); infcx.resolve_regions_and_report_errors(impl1_def_id, &outlives_env); let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else { let span = tcx.def_span(impl1_def_id); |
