diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:50 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:50 +0000 |
commit | 9835e2ae736235810b4ea1c162ca5e65c547e770 (patch) | |
tree | 3fcebf40ed70e581d776a8a4c65923e8ec20e026 /compiler/rustc_hir_analysis/src/check | |
parent | Releasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff) | |
download | rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip |
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_hir_analysis/src/check')
-rw-r--r-- | compiler/rustc_hir_analysis/src/check/check.rs | 72 | ||||
-rw-r--r-- | compiler/rustc_hir_analysis/src/check/compare_impl_item.rs | 60 | ||||
-rw-r--r-- | compiler/rustc_hir_analysis/src/check/dropck.rs | 351 | ||||
-rw-r--r-- | compiler/rustc_hir_analysis/src/check/intrinsic.rs | 10 | ||||
-rw-r--r-- | compiler/rustc_hir_analysis/src/check/intrinsicck.rs | 68 | ||||
-rw-r--r-- | compiler/rustc_hir_analysis/src/check/mod.rs | 201 | ||||
-rw-r--r-- | compiler/rustc_hir_analysis/src/check/region.rs | 4 | ||||
-rw-r--r-- | compiler/rustc_hir_analysis/src/check/wfcheck.rs | 61 |
8 files changed, 370 insertions, 457 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 0bb98fdf2..3b2c052e8 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -13,11 +13,12 @@ use rustc_hir::intravisit::Visitor; use rustc_hir::{ItemKind, Node, PathSegment}; use rustc_infer::infer::opaque_types::ConstrainOpaqueTypeRegionVisitor; use rustc_infer::infer::outlives::env::OutlivesEnvironment; -use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt}; +use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt}; use rustc_infer::traits::{Obligation, TraitEngineExt as _}; -use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS; +use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS; use rustc_middle::hir::nested_filter; use rustc_middle::middle::stability::EvalResult; +use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES}; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::util::{Discr, IntTypeExt}; @@ -31,6 +32,7 @@ use rustc_target::abi::FieldIdx; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedDirective; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; +use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::{self, ObligationCtxt, TraitEngine, TraitEngineExt as _}; use std::ops::ControlFlow; @@ -170,14 +172,12 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) { if matches!(tcx.def_kind(def_id), DefKind::Static(_) if tcx.def_kind(tcx.local_parent(def_id)) == DefKind::ForeignMod) => { - tcx.sess - .struct_span_err(span, "extern static is too large for the current architecture") - .emit(); + tcx.sess.emit_err(errors::TooLargeStatic { span }); return; } // Generic statics are rejected, but we still reach this case. Err(e) => { - tcx.sess.delay_span_bug(span, &e.to_string()); + tcx.sess.delay_span_bug(span, e.to_string()); return; } }; @@ -224,7 +224,7 @@ fn check_opaque(tcx: TyCtxt<'_>, id: hir::ItemId) { if check_opaque_for_cycles(tcx, item.owner_id.def_id, substs, span, &origin).is_err() { return; } - check_opaque_meets_bounds(tcx, item.owner_id.def_id, substs, span, &origin); + check_opaque_meets_bounds(tcx, item.owner_id.def_id, span, &origin); } /// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result @@ -320,7 +320,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( }; let prohibit_opaque = tcx .explicit_item_bounds(def_id) - .iter() + .subst_identity_iter_copied() .try_for_each(|(predicate, _)| predicate.visit_with(&mut visitor)); if let Some(ty) = prohibit_opaque.break_value() { @@ -336,7 +336,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( &tcx.sess.parse_sess, sym::impl_trait_projections, span, - &format!( + format!( "`{}` return type cannot contain a projection or `Self` that references \ lifetimes from a parent scope", if is_async { "async fn" } else { "impl Trait" }, @@ -393,13 +393,12 @@ pub(super) fn check_opaque_for_cycles<'tcx>( fn check_opaque_meets_bounds<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, - substs: SubstsRef<'tcx>, span: Span, origin: &hir::OpaqueTyOrigin, ) { let defining_use_anchor = match *origin { hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did, - hir::OpaqueTyOrigin::TyAlias => def_id, + hir::OpaqueTyOrigin::TyAlias { .. } => tcx.impl_trait_parent(def_id), }; let param_env = tcx.param_env(defining_use_anchor); @@ -408,6 +407,8 @@ fn check_opaque_meets_bounds<'tcx>( .with_opaque_type_inference(DefiningAnchor::Bind(defining_use_anchor)) .build(); let ocx = ObligationCtxt::new(&infcx); + + let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs); // `ReErased` regions appear in the "parent_substs" of closures/generators. @@ -430,7 +431,7 @@ fn check_opaque_meets_bounds<'tcx>( let ty_err = ty_err.to_string(tcx); tcx.sess.delay_span_bug( span, - &format!("could not unify `{hidden_ty}` with revealed type:\n{ty_err}"), + format!("could not unify `{hidden_ty}` with revealed type:\n{ty_err}"), ); } } @@ -450,9 +451,18 @@ fn check_opaque_meets_bounds<'tcx>( match origin { // Checked when type checking the function containing them. hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {} + // Nested opaque types occur only in associated types: + // ` type Opaque<T> = impl Trait<&'static T, AssocTy = impl Nested>; ` + // They can only be referenced as `<Opaque<T> as Trait<&'static T>>::AssocTy`. + // We don't have to check them here because their well-formedness follows from the WF of + // the projection input types in the defining- and use-sites. + hir::OpaqueTyOrigin::TyAlias { .. } + if tcx.def_kind(tcx.parent(def_id.to_def_id())) == DefKind::OpaqueTy => {} // Can have different predicates to their defining use - hir::OpaqueTyOrigin::TyAlias => { - let outlives_env = OutlivesEnvironment::new(param_env); + hir::OpaqueTyOrigin::TyAlias { .. } => { + let wf_tys = ocx.assumed_wf_types(param_env, span, def_id); + let implied_bounds = infcx.implied_bounds_tys(param_env, def_id, wf_tys); + let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds); let _ = ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env); } } @@ -494,7 +504,7 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { debug!( "check_item_type(it.def_id={:?}, it.name={})", id.owner_id, - tcx.def_path_str(id.owner_id.to_def_id()) + tcx.def_path_str(id.owner_id) ); let _indenter = indenter(); match tcx.def_kind(id.owner_id) { @@ -538,7 +548,7 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { tcx, assoc_item, assoc_item, - tcx.mk_trait_ref(id.owner_id.to_def_id(), trait_substs), + ty::TraitRef::new(tcx, id.owner_id.to_def_id(), trait_substs), ); } _ => {} @@ -620,11 +630,11 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { E0044, "foreign items may not have {kinds} parameters", ) - .span_label(item.span, &format!("can't have {kinds} parameters")) + .span_label(item.span, format!("can't have {kinds} parameters")) .help( // FIXME: once we start storing spans for type arguments, turn this // into a suggestion. - &format!( + format!( "replace the {} parameters with concrete {}{}", kinds, kinds_pl, @@ -791,16 +801,15 @@ fn check_impl_items_against_trait<'tcx>( let is_implemented = leaf_def .as_ref() - .map_or(false, |node_item| node_item.item.defaultness(tcx).has_value()); + .is_some_and(|node_item| node_item.item.defaultness(tcx).has_value()); if !is_implemented && tcx.impl_defaultness(impl_id).is_final() { missing_items.push(tcx.associated_item(trait_item_id)); } // true if this item is specifically implemented in this impl - let is_implemented_here = leaf_def - .as_ref() - .map_or(false, |node_item| !node_item.defining_node.is_from_trait()); + let is_implemented_here = + leaf_def.as_ref().is_some_and(|node_item| !node_item.defining_node.is_from_trait()); if !is_implemented_here { let full_impl_span = @@ -863,7 +872,7 @@ fn check_impl_items_against_trait<'tcx>( if !missing_items.is_empty() { let full_impl_span = tcx.hir().span_with_body(tcx.hir().local_def_id_to_hir_id(impl_id)); - missing_items_err(tcx, tcx.def_span(impl_id), &missing_items, full_impl_span); + missing_items_err(tcx, impl_id, &missing_items, full_impl_span); } if let Some(missing_items) = must_implement_one_of { @@ -987,10 +996,7 @@ pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) { err.span_note( tcx.def_span(def_spans[0].0), - &format!( - "`{}` has a `#[repr(align)]` attribute", - tcx.item_name(def_spans[0].0) - ), + format!("`{}` has a `#[repr(align)]` attribute", tcx.item_name(def_spans[0].0)), ); if def_spans.len() > 2 { @@ -999,7 +1005,7 @@ pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) { let ident = tcx.item_name(*adt_def); err.span_note( *span, - &if first { + if first { format!( "`{}` contains a field of type `{}`", tcx.type_of(def.did()).subst_identity(), @@ -1076,8 +1082,8 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) let layout = tcx.layout_of(param_env.and(ty)); // We are currently checking the type this field came from, so it must be local let span = tcx.hir().span_if_local(field.did).unwrap(); - let zst = layout.map_or(false, |layout| layout.is_zst()); - let align1 = layout.map_or(false, |layout| layout.align.abi.bytes() == 1); + let zst = layout.is_ok_and(|layout| layout.is_zst()); + let align1 = layout.is_ok_and(|layout| layout.align.abi.bytes() == 1); if !zst { return (span, zst, align1, None); } @@ -1468,10 +1474,10 @@ fn opaque_type_cycle_error( let ty_span = tcx.def_span(def_id); if !seen.contains(&ty_span) { let descr = if ty.is_impl_trait() { "opaque " } else { "" }; - err.span_label(ty_span, &format!("returning this {descr}type `{ty}`")); + err.span_label(ty_span, format!("returning this {descr}type `{ty}`")); seen.insert(ty_span); } - err.span_label(sp, &format!("returning here with type `{ty}`")); + err.span_label(sp, format!("returning here with type `{ty}`")); } for closure_def_id in visitor.closures { @@ -1508,8 +1514,8 @@ fn opaque_type_cycle_error( } if tcx.sess.opts.unstable_opts.drop_tracking_mir && let DefKind::Generator = tcx.def_kind(closure_def_id) + && let Some(generator_layout) = tcx.mir_generator_witnesses(closure_def_id) { - let generator_layout = tcx.mir_generator_witnesses(closure_def_id); for interior_ty in &generator_layout.field_tys { label_match(interior_ty.ty, interior_ty.source_info.span); } diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 5d119a773..8bf1e0e84 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -60,19 +60,21 @@ pub(super) fn compare_impl_method<'tcx>( }; } -/// This function is best explained by example. Consider a trait: +/// This function is best explained by example. Consider a trait with it's implementation: /// -/// trait Trait<'t, T> { -/// // `trait_m` -/// fn method<'a, M>(t: &'t T, m: &'a M) -> Self; -/// } +/// ```rust +/// trait Trait<'t, T> { +/// // `trait_m` +/// fn method<'a, M>(t: &'t T, m: &'a M) -> Self; +/// } /// -/// And an impl: +/// struct Foo; /// -/// impl<'i, 'j, U> Trait<'j, &'i U> for Foo { -/// // `impl_m` -/// fn method<'b, N>(t: &'j &'i U, m: &'b N) -> Foo; -/// } +/// impl<'i, 'j, U> Trait<'j, &'i U> for Foo { +/// // `impl_m` +/// fn method<'b, N>(t: &'j &'i U, m: &'b N) -> Foo { Foo } +/// } +/// ``` /// /// We wish to decide if those two method types are compatible. /// For this we have to show that, assuming the bounds of the impl hold, the @@ -82,7 +84,9 @@ pub(super) fn compare_impl_method<'tcx>( /// type parameters to impl type parameters. This is taken from the /// impl trait reference: /// -/// trait_to_impl_substs = {'t => 'j, T => &'i U, Self => Foo} +/// ```rust,ignore (pseudo-Rust) +/// trait_to_impl_substs = {'t => 'j, T => &'i U, Self => Foo} +/// ``` /// /// We create a mapping `dummy_substs` that maps from the impl type /// parameters to fresh types and regions. For type parameters, @@ -91,13 +95,17 @@ pub(super) fn compare_impl_method<'tcx>( /// regions (Note: but only early-bound regions, i.e., those /// declared on the impl or used in type parameter bounds). /// -/// impl_to_placeholder_substs = {'i => 'i0, U => U0, N => N0 } +/// ```rust,ignore (pseudo-Rust) +/// impl_to_placeholder_substs = {'i => 'i0, U => U0, N => N0 } +/// ``` /// /// Now we can apply `placeholder_substs` to the type of the impl method /// to yield a new function type in terms of our fresh, placeholder /// types: /// -/// <'b> fn(t: &'i0 U0, m: &'b) -> Foo +/// ```rust,ignore (pseudo-Rust) +/// <'b> fn(t: &'i0 U0, m: &'b) -> Foo +/// ``` /// /// We now want to extract and substitute the type of the *trait* /// method and compare it. To do so, we must create a compound @@ -106,11 +114,15 @@ pub(super) fn compare_impl_method<'tcx>( /// type parameters. We extend the mapping to also include /// the method parameters. /// -/// trait_to_placeholder_substs = { T => &'i0 U0, Self => Foo, M => N0 } +/// ```rust,ignore (pseudo-Rust) +/// trait_to_placeholder_substs = { T => &'i0 U0, Self => Foo, M => N0 } +/// ``` /// /// Applying this to the trait method type yields: /// -/// <'a> fn(t: &'i0 U0, m: &'a) -> Foo +/// ```rust,ignore (pseudo-Rust) +/// <'a> fn(t: &'i0 U0, m: &'a) -> Foo +/// ``` /// /// This type is also the same but the name of the bound region (`'a` /// vs `'b`). However, the normal subtyping rules on fn types handle @@ -579,7 +591,7 @@ fn compare_asyncness<'tcx>( pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( tcx: TyCtxt<'tcx>, impl_m_def_id: LocalDefId, -) -> Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed> { +) -> Result<&'tcx FxHashMap<DefId, ty::EarlyBinder<Ty<'tcx>>>, ErrorGuaranteed> { let impl_m = tcx.opt_associated_item(impl_m_def_id.to_def_id()).unwrap(); let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap(); let impl_trait_ref = @@ -782,14 +794,14 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( }) }); debug!(%ty); - collected_tys.insert(def_id, ty); + collected_tys.insert(def_id, ty::EarlyBinder(ty)); } Err(err) => { let reported = tcx.sess.delay_span_bug( return_span, format!("could not fully resolve: {ty} => {err:?}"), ); - collected_tys.insert(def_id, tcx.ty_error(reported)); + collected_tys.insert(def_id, ty::EarlyBinder(tcx.ty_error(reported))); } } } @@ -839,7 +851,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ImplTraitInTraitCollector<'_, 'tcx> { }); self.types.insert(proj.def_id, (infer_ty, proj.substs)); // Recurse into bounds - for (pred, pred_span) in self.interner().bound_explicit_item_bounds(proj.def_id).subst_iter_copied(self.interner(), proj.substs) { + for (pred, pred_span) in self.interner().explicit_item_bounds(proj.def_id).subst_iter_copied(self.interner(), proj.substs) { let pred = pred.fold_with(self); let pred = self.ocx.normalize( &ObligationCause::misc(self.span, self.body_id), @@ -1163,7 +1175,7 @@ fn compare_self_type<'tcx>( /// as the number of generics on the respective assoc item in the trait definition. /// /// For example this code emits the errors in the following code: -/// ``` +/// ```rust,compile_fail /// trait Trait { /// fn foo(); /// type Assoc<T>; @@ -1273,7 +1285,7 @@ fn compare_number_of_generics<'tcx>( let mut err = tcx.sess.struct_span_err_with_code( spans, - &format!( + format!( "{} `{}` has {} {kind} parameter{} but its trait \ declaration has {} {kind} parameter{}", item_kind, @@ -1317,7 +1329,7 @@ fn compare_number_of_generics<'tcx>( impl_count, kind, pluralize!(impl_count), - suffix.unwrap_or_else(String::new), + suffix.unwrap_or_default(), ), ); } @@ -1547,7 +1559,7 @@ fn compare_synthetic_generics<'tcx>( /// the same kind as the respective generic parameter in the trait def. /// /// For example all 4 errors in the following code are emitted here: -/// ``` +/// ```rust,ignore (pseudo-Rust) /// trait Foo { /// fn foo<const N: u8>(); /// type bar<const N: u8>; @@ -2023,7 +2035,7 @@ pub(super) fn check_type_bounds<'tcx>( }; let obligations: Vec<_> = tcx - .bound_explicit_item_bounds(trait_ty.def_id) + .explicit_item_bounds(trait_ty.def_id) .subst_iter_copied(tcx, rebased_substs) .map(|(concrete_ty_bound, span)| { debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound); diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index 111bf5e54..e0ba255cc 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -1,13 +1,17 @@ // FIXME(@lcnr): Move this module out of `rustc_hir_analysis`. // // We don't do any drop checking during hir typeck. -use crate::hir::def_id::{DefId, LocalDefId}; +use rustc_data_structures::fx::FxHashSet; use rustc_errors::{struct_span_err, ErrorGuaranteed}; -use rustc_middle::ty::error::TypeError; -use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; +use rustc_infer::infer::outlives::env::OutlivesEnvironment; +use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::util::IgnoreRegions; -use rustc_middle::ty::{self, Predicate, Ty, TyCtxt}; +use rustc_middle::ty::util::CheckRegions; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_trait_selection::traits::{self, ObligationCtxt}; + +use crate::errors; +use crate::hir::def_id::{DefId, LocalDefId}; /// This function confirms that the `Drop` implementation identified by /// `drop_impl_did` is not any more specialized than the type it is @@ -27,22 +31,34 @@ use rustc_middle::ty::{self, Predicate, Ty, TyCtxt}; /// cannot do `struct S<T>; impl<T:Clone> Drop for S<T> { ... }`). /// pub fn check_drop_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<(), ErrorGuaranteed> { + match tcx.impl_polarity(drop_impl_did) { + ty::ImplPolarity::Positive => {} + ty::ImplPolarity::Negative => { + return Err(tcx.sess.emit_err(errors::DropImplPolarity::Negative { + span: tcx.def_span(drop_impl_did), + })); + } + ty::ImplPolarity::Reservation => { + return Err(tcx.sess.emit_err(errors::DropImplPolarity::Reservation { + span: tcx.def_span(drop_impl_did), + })); + } + } let dtor_self_type = tcx.type_of(drop_impl_did).subst_identity(); - let dtor_predicates = tcx.predicates_of(drop_impl_did); match dtor_self_type.kind() { - ty::Adt(adt_def, self_to_impl_substs) => { + ty::Adt(adt_def, adt_to_impl_substs) => { ensure_drop_params_and_item_params_correspond( tcx, drop_impl_did.expect_local(), adt_def.did(), - self_to_impl_substs, + adt_to_impl_substs, )?; ensure_drop_predicates_are_implied_by_item_defn( tcx, - dtor_predicates, + drop_impl_did.expect_local(), adt_def.did().expect_local(), - self_to_impl_substs, + adt_to_impl_substs, ) } _ => { @@ -52,7 +68,7 @@ pub fn check_drop_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<(), Erro let span = tcx.def_span(drop_impl_did); let reported = tcx.sess.delay_span_bug( span, - &format!("should have been rejected by coherence check: {dtor_self_type}"), + format!("should have been rejected by coherence check: {dtor_self_type}"), ); Err(reported) } @@ -63,9 +79,9 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>( tcx: TyCtxt<'tcx>, drop_impl_did: LocalDefId, self_type_did: DefId, - drop_impl_substs: SubstsRef<'tcx>, + adt_to_impl_substs: SubstsRef<'tcx>, ) -> Result<(), ErrorGuaranteed> { - let Err(arg) = tcx.uses_unique_generic_params(drop_impl_substs, IgnoreRegions::No) else { + let Err(arg) = tcx.uses_unique_generic_params(adt_to_impl_substs, CheckRegions::OnlyEarlyBound) else { return Ok(()) }; @@ -76,15 +92,15 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>( struct_span_err!(tcx.sess, drop_impl_span, E0366, "`Drop` impls cannot be specialized"); match arg { ty::util::NotUniqueParam::DuplicateParam(arg) => { - err.note(&format!("`{arg}` is mentioned multiple times")) + err.note(format!("`{arg}` is mentioned multiple times")) } ty::util::NotUniqueParam::NotParam(arg) => { - err.note(&format!("`{arg}` is not a generic parameter")) + err.note(format!("`{arg}` is not a generic parameter")) } }; err.span_note( item_span, - &format!( + format!( "use the same sequence of generic lifetime, type and const parameters \ as the {self_descr} definition", ), @@ -96,237 +112,94 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>( /// implied by assuming the predicates attached to self_type_did. fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( tcx: TyCtxt<'tcx>, - dtor_predicates: ty::GenericPredicates<'tcx>, - self_type_did: LocalDefId, - self_to_impl_substs: SubstsRef<'tcx>, + drop_impl_def_id: LocalDefId, + adt_def_id: LocalDefId, + adt_to_impl_substs: SubstsRef<'tcx>, ) -> Result<(), ErrorGuaranteed> { - let mut result = Ok(()); - - // Here is an example, analogous to that from - // `compare_impl_method`. - // - // Consider a struct type: - // - // struct Type<'c, 'b:'c, 'a> { - // x: &'a Contents // (contents are irrelevant; - // y: &'c Cell<&'b Contents>, // only the bounds matter for our purposes.) - // } - // - // and a Drop impl: - // - // impl<'z, 'y:'z, 'x:'y> Drop for P<'z, 'y, 'x> { - // fn drop(&mut self) { self.y.set(self.x); } // (only legal if 'x: 'y) - // } - // - // We start out with self_to_impl_substs, that maps the generic - // parameters of Type to that of the Drop impl. - // - // self_to_impl_substs = {'c => 'z, 'b => 'y, 'a => 'x} - // - // Applying this to the predicates (i.e., assumptions) provided by the item - // definition yields the instantiated assumptions: - // - // ['y : 'z] + let infcx = tcx.infer_ctxt().build(); + let ocx = ObligationCtxt::new(&infcx); + + // Take the param-env of the adt and substitute the substs that show up in + // the implementation's self type. This gives us the assumptions that the + // self ty of the implementation is allowed to know just from it being a + // well-formed adt, since that's all we're allowed to assume while proving + // the Drop implementation is not specialized. // - // We then check all of the predicates of the Drop impl: - // - // ['y:'z, 'x:'y] - // - // and ensure each is in the list of instantiated - // assumptions. Here, `'y:'z` is present, but `'x:'y` is - // absent. So we report an error that the Drop impl injected a - // predicate that is not present on the struct definition. - - // We can assume the predicates attached to struct/enum definition - // hold. - let generic_assumptions = tcx.predicates_of(self_type_did); - - let assumptions_in_impl_context = generic_assumptions.instantiate(tcx, &self_to_impl_substs); - let assumptions_in_impl_context = assumptions_in_impl_context.predicates; - - debug!(?assumptions_in_impl_context, ?dtor_predicates.predicates); - - let self_param_env = tcx.param_env(self_type_did); - - // An earlier version of this code attempted to do this checking - // via the traits::fulfill machinery. However, it ran into trouble - // since the fulfill machinery merely turns outlives-predicates - // 'a:'b and T:'b into region inference constraints. It is simpler - // just to look for all the predicates directly. - - assert_eq!(dtor_predicates.parent, None); - for &(predicate, predicate_sp) in dtor_predicates.predicates { - // (We do not need to worry about deep analysis of type - // expressions etc because the Drop impls are already forced - // to take on a structure that is roughly an alpha-renaming of - // the generic parameters of the item definition.) - - // This path now just checks *all* predicates via an instantiation of - // the `SimpleEqRelation`, which simply forwards to the `relate` machinery - // after taking care of anonymizing late bound regions. - // - // However, it may be more efficient in the future to batch - // the analysis together via the fulfill (see comment above regarding - // the usage of the fulfill machinery), rather than the - // repeated `.iter().any(..)` calls. + // We don't need to normalize this param-env or anything, since we're only + // substituting it with free params, so no additional param-env normalization + // can occur on top of what has been done in the param_env query itself. + let param_env = ty::EarlyBinder(tcx.param_env(adt_def_id)) + .subst(tcx, adt_to_impl_substs) + .with_constness(tcx.constness(drop_impl_def_id)); + + for (pred, span) in tcx.predicates_of(drop_impl_def_id).instantiate_identity(tcx) { + let normalize_cause = traits::ObligationCause::misc(span, adt_def_id); + let pred = ocx.normalize(&normalize_cause, param_env, pred); + let cause = traits::ObligationCause::new(span, adt_def_id, traits::DropImpl); + ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, pred)); + } - // This closure is a more robust way to check `Predicate` equality - // than simple `==` checks (which were the previous implementation). - // It relies on `ty::relate` for `TraitPredicate`, `ProjectionPredicate`, - // `ConstEvaluatable` and `TypeOutlives` (which implement the Relate trait), - // while delegating on simple equality for the other `Predicate`. - // This implementation solves (Issue #59497) and (Issue #58311). - // It is unclear to me at the moment whether the approach based on `relate` - // could be extended easily also to the other `Predicate`. - let predicate_matches_closure = |p: Predicate<'tcx>| { - let mut relator: SimpleEqRelation<'tcx> = SimpleEqRelation::new(tcx, self_param_env); - let predicate = predicate.kind(); - let p = p.kind(); - match (predicate.skip_binder(), p.skip_binder()) { - ( - ty::PredicateKind::Clause(ty::Clause::Trait(a)), - ty::PredicateKind::Clause(ty::Clause::Trait(b)), - ) => relator.relate(predicate.rebind(a), p.rebind(b)).is_ok(), - ( - ty::PredicateKind::Clause(ty::Clause::Projection(a)), - ty::PredicateKind::Clause(ty::Clause::Projection(b)), - ) => relator.relate(predicate.rebind(a), p.rebind(b)).is_ok(), - ( - ty::PredicateKind::ConstEvaluatable(a), - ty::PredicateKind::ConstEvaluatable(b), - ) => relator.relate(predicate.rebind(a), predicate.rebind(b)).is_ok(), - ( - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate( - ty_a, - lt_a, - ))), - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate( - ty_b, - lt_b, - ))), - ) => { - relator.relate(predicate.rebind(ty_a), p.rebind(ty_b)).is_ok() - && relator.relate(predicate.rebind(lt_a), p.rebind(lt_b)).is_ok() - } - (ty::PredicateKind::WellFormed(arg_a), ty::PredicateKind::WellFormed(arg_b)) => { - relator.relate(predicate.rebind(arg_a), p.rebind(arg_b)).is_ok() - } - _ => predicate == p, + // All of the custom error reporting logic is to preserve parity with the old + // error messages. + // + // They can probably get removed with better treatment of the new `DropImpl` + // obligation cause code, and perhaps some custom logic in `report_region_errors`. + + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { + let mut guar = None; + let mut root_predicates = FxHashSet::default(); + for error in errors { + let root_predicate = error.root_obligation.predicate; + if root_predicates.insert(root_predicate) { + let item_span = tcx.def_span(adt_def_id); + let self_descr = tcx.def_descr(adt_def_id.to_def_id()); + guar = Some( + struct_span_err!( + tcx.sess, + error.root_obligation.cause.span, + E0367, + "`Drop` impl requires `{root_predicate}` \ + but the {self_descr} it is implemented for does not", + ) + .span_note(item_span, "the implementor must specify the same requirement") + .emit(), + ); } - }; - - if !assumptions_in_impl_context.iter().copied().any(predicate_matches_closure) { - let item_span = tcx.def_span(self_type_did); - let self_descr = tcx.def_descr(self_type_did.to_def_id()); - let reported = struct_span_err!( - tcx.sess, - predicate_sp, - E0367, - "`Drop` impl requires `{predicate}` but the {self_descr} it is implemented for does not", - ) - .span_note(item_span, "the implementor must specify the same requirement") - .emit(); - result = Err(reported); } + return Err(guar.unwrap()); } - result -} - -/// This is an implementation of the [`TypeRelation`] trait with the -/// aim of simply comparing for equality (without side-effects). -/// -/// It is not intended to be used anywhere else other than here. -pub(crate) struct SimpleEqRelation<'tcx> { - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, -} - -impl<'tcx> SimpleEqRelation<'tcx> { - fn new(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> SimpleEqRelation<'tcx> { - SimpleEqRelation { tcx, param_env } - } -} - -impl<'tcx> TypeRelation<'tcx> for SimpleEqRelation<'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.param_env - } - - fn tag(&self) -> &'static str { - "dropck::SimpleEqRelation" - } - - fn a_is_expected(&self) -> bool { - true - } - - fn relate_with_variance<T: Relate<'tcx>>( - &mut self, - _: ty::Variance, - _info: ty::VarianceDiagInfo<'tcx>, - a: T, - b: T, - ) -> RelateResult<'tcx, T> { - // Here we ignore variance because we require drop impl's types - // to be *exactly* the same as to the ones in the struct definition. - self.relate(a, b) - } - - fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - debug!("SimpleEqRelation::tys(a={:?}, b={:?})", a, b); - ty::relate::super_relate_tys(self, a, b) - } - - fn regions( - &mut self, - a: ty::Region<'tcx>, - b: ty::Region<'tcx>, - ) -> RelateResult<'tcx, ty::Region<'tcx>> { - debug!("SimpleEqRelation::regions(a={:?}, b={:?})", a, b); - - // We can just equate the regions because LBRs have been - // already anonymized. - if a == b { - Ok(a) - } else { - // I'm not sure is this `TypeError` is the right one, but - // it should not matter as it won't be checked (the dropck - // will emit its own, more informative and higher-level errors - // in case anything goes wrong). - Err(TypeError::RegionsPlaceholderMismatch) + let errors = ocx.infcx.resolve_regions(&OutlivesEnvironment::new(param_env)); + if !errors.is_empty() { + let mut guar = None; + for error in errors { + let item_span = tcx.def_span(adt_def_id); + let self_descr = tcx.def_descr(adt_def_id.to_def_id()); + let outlives = match error { + RegionResolutionError::ConcreteFailure(_, a, b) => format!("{b}: {a}"), + RegionResolutionError::GenericBoundFailure(_, generic, r) => { + format!("{generic}: {r}") + } + RegionResolutionError::SubSupConflict(_, _, _, a, _, b, _) => format!("{b}: {a}"), + RegionResolutionError::UpperBoundUniverseConflict(a, _, _, _, b) => { + format!("{b}: {a}", a = tcx.mk_re_var(a)) + } + }; + guar = Some( + struct_span_err!( + tcx.sess, + error.origin().span(), + E0367, + "`Drop` impl requires `{outlives}` \ + but the {self_descr} it is implemented for does not", + ) + .span_note(item_span, "the implementor must specify the same requirement") + .emit(), + ); } + return Err(guar.unwrap()); } - fn consts( - &mut self, - a: ty::Const<'tcx>, - b: ty::Const<'tcx>, - ) -> RelateResult<'tcx, ty::Const<'tcx>> { - debug!("SimpleEqRelation::consts(a={:?}, b={:?})", a, b); - ty::relate::super_relate_consts(self, a, b) - } - - fn binders<T>( - &mut self, - a: ty::Binder<'tcx, T>, - b: ty::Binder<'tcx, T>, - ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> - where - T: Relate<'tcx>, - { - debug!("SimpleEqRelation::binders({:?}: {:?}", a, b); - - // Anonymizing the LBRs is necessary to solve (Issue #59497). - // After we do so, it should be totally fine to skip the binders. - let anon_a = self.tcx.anonymize_bound_vars(a); - let anon_b = self.tcx.anonymize_bound_vars(b); - self.relate(anon_a.skip_binder(), anon_b.skip_binder())?; - - Ok(a) - } + Ok(()) } diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 854974d16..e8785235c 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -198,7 +198,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { | sym::assert_zero_valid | sym::assert_mem_uninitialized_valid => (1, Vec::new(), tcx.mk_unit()), sym::forget => (1, vec![param(0)], tcx.mk_unit()), - sym::transmute => (2, vec![param(0)], param(1)), + sym::transmute | sym::transmute_unchecked => (2, vec![param(0)], param(1)), sym::prefetch_read_data | sym::prefetch_write_data | sym::prefetch_read_instruction @@ -215,7 +215,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { sym::type_name => (1, Vec::new(), tcx.mk_static_str()), sym::type_id => (1, Vec::new(), tcx.types.u64), - sym::offset | sym::arith_offset => ( + sym::offset => (2, vec![param(0), param(1)], param(0)), + sym::arith_offset => ( 1, vec![ tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), @@ -380,6 +381,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { sym::unlikely => (0, vec![tcx.types.bool], tcx.types.bool), sym::read_via_copy => (1, vec![tcx.mk_imm_ptr(param(0))], param(0)), + sym::write_via_move => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()), sym::discriminant_value => { let assoc_items = tcx.associated_item_def_ids( @@ -545,14 +547,14 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) Err(_) => { let msg = format!("unrecognized platform-specific intrinsic function: `{name}`"); - tcx.sess.struct_span_err(it.span, &msg).emit(); + tcx.sess.struct_span_err(it.span, msg).emit(); return; } } } _ => { let msg = format!("unrecognized platform-specific intrinsic function: `{name}`"); - tcx.sess.struct_span_err(it.span, &msg).emit(); + tcx.sess.struct_span_err(it.span, msg).emit(); return; } }; diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index 0d482b53a..0bb1467ef 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -84,33 +84,45 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { ty::Adt(adt, substs) if adt.repr().simd() => { let fields = &adt.non_enum_variant().fields; let elem_ty = fields[FieldIdx::from_u32(0)].ty(self.tcx, substs); - match elem_ty.kind() { - ty::Never | ty::Error(_) => return None, - ty::Int(IntTy::I8) | ty::Uint(UintTy::U8) => { - Some(InlineAsmType::VecI8(fields.len() as u64)) + + let (size, ty) = match elem_ty.kind() { + ty::Array(ty, len) => { + if let Some(len) = + len.try_eval_target_usize(self.tcx, self.tcx.param_env(adt.did())) + { + (len, *ty) + } else { + return None; + } } + _ => (fields.len() as u64, elem_ty), + }; + + match ty.kind() { + ty::Never | ty::Error(_) => return None, + ty::Int(IntTy::I8) | ty::Uint(UintTy::U8) => Some(InlineAsmType::VecI8(size)), ty::Int(IntTy::I16) | ty::Uint(UintTy::U16) => { - Some(InlineAsmType::VecI16(fields.len() as u64)) + Some(InlineAsmType::VecI16(size)) } ty::Int(IntTy::I32) | ty::Uint(UintTy::U32) => { - Some(InlineAsmType::VecI32(fields.len() as u64)) + Some(InlineAsmType::VecI32(size)) } ty::Int(IntTy::I64) | ty::Uint(UintTy::U64) => { - Some(InlineAsmType::VecI64(fields.len() as u64)) + Some(InlineAsmType::VecI64(size)) } ty::Int(IntTy::I128) | ty::Uint(UintTy::U128) => { - Some(InlineAsmType::VecI128(fields.len() as u64)) + Some(InlineAsmType::VecI128(size)) } ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => { Some(match self.tcx.sess.target.pointer_width { - 16 => InlineAsmType::VecI16(fields.len() as u64), - 32 => InlineAsmType::VecI32(fields.len() as u64), - 64 => InlineAsmType::VecI64(fields.len() as u64), + 16 => InlineAsmType::VecI16(size), + 32 => InlineAsmType::VecI32(size), + 64 => InlineAsmType::VecI64(size), _ => unreachable!(), }) } - ty::Float(FloatTy::F32) => Some(InlineAsmType::VecF32(fields.len() as u64)), - ty::Float(FloatTy::F64) => Some(InlineAsmType::VecF64(fields.len() as u64)), + ty::Float(FloatTy::F32) => Some(InlineAsmType::VecF32(size)), + ty::Float(FloatTy::F64) => Some(InlineAsmType::VecF64(size)), _ => None, } } @@ -118,7 +130,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { _ => None, }; let Some(asm_ty) = asm_ty else { - let msg = &format!("cannot use value of type `{ty}` for inline assembly"); + let msg = format!("cannot use value of type `{ty}` for inline assembly"); let mut err = self.tcx.sess.struct_span_err(expr.span, msg); err.note( "only integers, floats, SIMD vectors, pointers and function pointers \ @@ -133,7 +145,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { if !ty.is_copy_modulo_regions(self.tcx, self.param_env) { let msg = "arguments for inline assembly must be copyable"; let mut err = self.tcx.sess.struct_span_err(expr.span, msg); - err.note(&format!("`{ty}` does not implement the Copy trait")); + err.note(format!("`{ty}` does not implement the Copy trait")); err.emit(); } @@ -152,8 +164,8 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { let mut err = self.tcx.sess.struct_span_err(vec![in_expr.span, expr.span], msg); let in_expr_ty = (self.get_operand_ty)(in_expr); - err.span_label(in_expr.span, &format!("type `{in_expr_ty}`")); - err.span_label(expr.span, &format!("type `{ty}`")); + err.span_label(in_expr.span, format!("type `{in_expr_ty}`")); + err.span_label(expr.span, format!("type `{ty}`")); err.note( "asm inout arguments must have the same type, \ unless they are both pointers or integers of the same size", @@ -172,17 +184,17 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { let reg_class = reg.reg_class(); let supported_tys = reg_class.supported_types(asm_arch); let Some((_, feature)) = supported_tys.iter().find(|&&(t, _)| t == asm_ty) else { - let msg = &format!("type `{ty}` cannot be used with this register class"); + let msg = format!("type `{ty}` cannot be used with this register class"); let mut err = self.tcx.sess.struct_span_err(expr.span, msg); let supported_tys: Vec<_> = supported_tys.iter().map(|(t, _)| t.to_string()).collect(); - err.note(&format!( + err.note(format!( "register class `{}` supports these types: {}", reg_class.name(), supported_tys.join(", "), )); if let Some(suggest) = reg_class.suggest_class(asm_arch, asm_ty) { - err.help(&format!( + err.help(format!( "consider using the `{}` register class instead", suggest.name() )); @@ -203,9 +215,9 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { // register class is usable at all. if let Some(feature) = feature { if !target_features.contains(feature) { - let msg = &format!("`{}` target feature is not enabled", feature); + let msg = format!("`{}` target feature is not enabled", feature); let mut err = self.tcx.sess.struct_span_err(expr.span, msg); - err.note(&format!( + err.note(format!( "this is required to use type `{}` with register class `{}`", ty, reg_class.name(), @@ -240,10 +252,10 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { "formatting may not be suitable for sub-register argument", |lint| { lint.span_label(expr.span, "for this argument"); - lint.help(&format!( + lint.help(format!( "use `{{{idx}:{suggested_modifier}}}` to have the register formatted as `{suggested_result}`", )); - lint.help(&format!( + lint.help(format!( "or use `{{{idx}:{default_modifier}}}` to keep the default formatting of `{default_result}`", )); lint @@ -289,7 +301,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { op.is_clobber(), ) { let msg = format!("cannot use register `{}`: {}", reg.name(), msg); - self.tcx.sess.struct_span_err(*op_sp, &msg).emit(); + self.tcx.sess.struct_span_err(*op_sp, msg).emit(); continue; } } @@ -328,7 +340,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { reg_class.name(), feature ); - self.tcx.sess.struct_span_err(*op_sp, &msg).emit(); + self.tcx.sess.struct_span_err(*op_sp, msg).emit(); // register isn't enabled, don't do more checks continue; } @@ -342,7 +354,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { .intersperse(", ") .collect::<String>(), ); - self.tcx.sess.struct_span_err(*op_sp, &msg).emit(); + self.tcx.sess.struct_span_err(*op_sp, msg).emit(); // register isn't enabled, don't do more checks continue; } @@ -424,7 +436,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { self.tcx.sess.struct_span_err(*op_sp, "invalid `sym` operand"); err.span_label( self.tcx.def_span(anon_const.def_id), - &format!("is {} `{}`", ty.kind().article(), ty), + format!("is {} `{}`", ty.kind().article(), ty), ); err.help("`sym` operands must refer to either a function or a static"); err.emit(); diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 8fe4c44fc..3971a4c01 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -74,11 +74,11 @@ pub use check::check_abi; use check::check_mod_item_types; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder}; +use rustc_errors::{pluralize, struct_span_err, Diagnostic, DiagnosticBuilder}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_index::bit_set::BitSet; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{InternalSubsts, SubstsRef}; use rustc_session::parse::feature_err; @@ -90,6 +90,7 @@ use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor; use std::num::NonZeroU32; +use crate::errors; use crate::require_c_abi_if_c_variadic; use crate::util::common::indenter; @@ -171,34 +172,18 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) { fn report_forbidden_specialization(tcx: TyCtxt<'_>, impl_item: DefId, parent_impl: DefId) { let span = tcx.def_span(impl_item); let ident = tcx.item_name(impl_item); - let mut err = struct_span_err!( - tcx.sess, - span, - E0520, - "`{}` specializes an item from a parent `impl`, but that item is not marked `default`", - ident, - ); - err.span_label(span, format!("cannot specialize default item `{}`", ident)); - - match tcx.span_of_impl(parent_impl) { - Ok(span) => { - err.span_label(span, "parent `impl` is here"); - err.note(&format!( - "to specialize, `{}` in the parent `impl` must be marked `default`", - ident - )); - } - Err(cname) => { - err.note(&format!("parent implementation is in crate `{cname}`")); - } - } - err.emit(); + let err = match tcx.span_of_impl(parent_impl) { + Ok(sp) => errors::ImplNotMarkedDefault::Ok { span, ident, ok_label: sp }, + Err(cname) => errors::ImplNotMarkedDefault::Err { span, ident, cname }, + }; + + tcx.sess.emit_err(err); } fn missing_items_err( tcx: TyCtxt<'_>, - impl_span: Span, + impl_def_id: LocalDefId, missing_items: &[ty::AssocItem], full_impl_span: Span, ) { @@ -211,14 +196,6 @@ fn missing_items_err( .collect::<Vec<_>>() .join("`, `"); - let mut err = struct_span_err!( - tcx.sess, - impl_span, - E0046, - "not all trait items implemented, missing: `{missing_items_msg}`", - ); - err.span_label(impl_span, format!("missing `{missing_items_msg}` in implementation")); - // `Span` before impl block closing brace. let hi = full_impl_span.hi() - BytePos(1); // Point at the place right before the closing brace of the relevant `impl` to suggest @@ -227,20 +204,40 @@ fn missing_items_err( // Obtain the level of indentation ending in `sugg_sp`. let padding = tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(|| String::new()); + let (mut missing_trait_item, mut missing_trait_item_none, mut missing_trait_item_label) = + (Vec::new(), Vec::new(), Vec::new()); for &trait_item in missing_items { - let snippet = suggestion_signature(trait_item, tcx); + let snippet = suggestion_signature( + tcx, + trait_item, + tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity(), + ); let code = format!("{}{}\n{}", padding, snippet, padding); - let msg = format!("implement the missing item: `{snippet}`"); - let appl = Applicability::HasPlaceholders; if let Some(span) = tcx.hir().span_if_local(trait_item.def_id) { - err.span_label(span, format!("`{}` from trait", trait_item.name)); - err.tool_only_span_suggestion(sugg_sp, &msg, code, appl); + missing_trait_item_label + .push(errors::MissingTraitItemLabel { span, item: trait_item.name }); + missing_trait_item.push(errors::MissingTraitItemSuggestion { + span: sugg_sp, + code, + snippet, + }); } else { - err.span_suggestion_hidden(sugg_sp, &msg, code, appl); + missing_trait_item_none.push(errors::MissingTraitItemSuggestionNone { + span: sugg_sp, + code, + snippet, + }) } } - err.emit(); + + tcx.sess.emit_err(errors::MissingTraitItem { + span: tcx.span_of_impl(impl_def_id.to_def_id()).unwrap(), + missing_items_msg, + missing_trait_item_label, + missing_trait_item, + missing_trait_item_none, + }); } fn missing_items_must_implement_one_of_err( @@ -252,19 +249,11 @@ fn missing_items_must_implement_one_of_err( let missing_items_msg = missing_items.iter().map(Ident::to_string).collect::<Vec<_>>().join("`, `"); - let mut err = struct_span_err!( - tcx.sess, - impl_span, - E0046, - "not all trait items implemented, missing one of: `{missing_items_msg}`", - ); - err.span_label(impl_span, format!("missing one of `{missing_items_msg}` in implementation")); - - if let Some(annotation_span) = annotation_span { - err.span_note(annotation_span, "required because of this annotation"); - } - - err.emit(); + tcx.sess.emit_err(errors::MissingOneOfTraitItem { + span: impl_span, + note: annotation_span, + missing_items_msg, + }); } fn default_body_is_unstable( @@ -276,36 +265,42 @@ fn default_body_is_unstable( issue: Option<NonZeroU32>, ) { let missing_item_name = tcx.associated_item(item_did).name; - let use_of_unstable_library_feature_note = match reason { - Some(r) => format!("use of unstable library feature '{feature}': {r}"), - None => format!("use of unstable library feature '{feature}'"), + let (mut some_note, mut none_note, mut reason_str) = (false, false, String::new()); + match reason { + Some(r) => { + some_note = true; + reason_str = r.to_string(); + } + None => none_note = true, }; - let mut err = struct_span_err!( - tcx.sess, - impl_span, - E0046, - "not all trait items implemented, missing: `{missing_item_name}`", - ); - err.note(format!("default implementation of `{missing_item_name}` is unstable")); - err.note(use_of_unstable_library_feature_note); + let mut err = tcx.sess.create_err(errors::MissingTraitItemUnstable { + span: impl_span, + some_note, + none_note, + missing_item_name, + feature, + reason: reason_str, + }); + rustc_session::parse::add_feature_diagnostics_for_issue( &mut err, &tcx.sess.parse_sess, feature, rustc_feature::GateIssue::Library(issue), ); + err.emit(); } /// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions. fn bounds_from_generic_predicates<'tcx>( tcx: TyCtxt<'tcx>, - predicates: ty::GenericPredicates<'tcx>, + predicates: impl IntoIterator<Item = (ty::Predicate<'tcx>, Span)>, ) -> (String, String) { let mut types: FxHashMap<Ty<'tcx>, Vec<DefId>> = FxHashMap::default(); let mut projections = vec![]; - for (predicate, _) in predicates.predicates { + for (predicate, _) in predicates { debug!("predicate {:?}", predicate); let bound_predicate = predicate.kind(); match bound_predicate.skip_binder() { @@ -367,7 +362,7 @@ fn fn_sig_suggestion<'tcx>( tcx: TyCtxt<'tcx>, sig: ty::FnSig<'tcx>, ident: Ident, - predicates: ty::GenericPredicates<'tcx>, + predicates: impl IntoIterator<Item = (ty::Predicate<'tcx>, Span)>, assoc: ty::AssocItem, ) -> String { let args = sig @@ -436,7 +431,17 @@ pub fn ty_kind_suggestion(ty: Ty<'_>) -> Option<&'static str> { /// Return placeholder code for the given associated item. /// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a /// structured suggestion. -fn suggestion_signature(assoc: ty::AssocItem, tcx: TyCtxt<'_>) -> String { +fn suggestion_signature<'tcx>( + tcx: TyCtxt<'tcx>, + assoc: ty::AssocItem, + impl_trait_ref: ty::TraitRef<'tcx>, +) -> String { + let substs = ty::InternalSubsts::identity_for_item(tcx, assoc.def_id).rebase_onto( + tcx, + assoc.container_id(tcx), + impl_trait_ref.with_self_ty(tcx, tcx.types.self_param).substs, + ); + match assoc.kind { ty::AssocKind::Fn => { // We skip the binder here because the binder would deanonymize all @@ -445,16 +450,22 @@ fn suggestion_signature(assoc: ty::AssocItem, tcx: TyCtxt<'_>) -> String { // regions just fine, showing `fn(&MyType)`. fn_sig_suggestion( tcx, - tcx.fn_sig(assoc.def_id).subst_identity().skip_binder(), + tcx.fn_sig(assoc.def_id).subst(tcx, substs).skip_binder(), assoc.ident(tcx), - tcx.predicates_of(assoc.def_id), + tcx.predicates_of(assoc.def_id).instantiate_own(tcx, substs), assoc, ) } - ty::AssocKind::Type => format!("type {} = Type;", assoc.name), + ty::AssocKind::Type => { + let (generics, where_clauses) = bounds_from_generic_predicates( + tcx, + tcx.predicates_of(assoc.def_id).instantiate_own(tcx, substs), + ); + format!("type {}{generics} = /* Type */{where_clauses};", assoc.name) + } ty::AssocKind::Const => { let ty = tcx.type_of(assoc.def_id).subst_identity(); - let val = ty_kind_suggestion(ty).unwrap_or("value"); + let val = ty_kind_suggestion(ty).unwrap_or("todo!()"); format!("const {}: {} = {};", assoc.name, ty, val) } } @@ -467,16 +478,18 @@ fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>, sp: Span, d .iter() .map(|variant| tcx.hir().span_if_local(variant.def_id).unwrap()) .collect(); - let msg = format!("needs exactly one variant, but has {}", adt.variants().len(),); - let mut err = struct_span_err!(tcx.sess, sp, E0731, "transparent enum {msg}"); - err.span_label(sp, &msg); + let (mut spans, mut many) = (Vec::new(), None); if let [start @ .., end] = &*variant_spans { - for variant_span in start { - err.span_label(*variant_span, ""); - } - err.span_label(*end, &format!("too many variants in `{}`", tcx.def_path_str(did))); + spans = start.to_vec(); + many = Some(*end); } - err.emit(); + tcx.sess.emit_err(errors::TransparentEnumVariant { + span: sp, + spans, + many, + number: adt.variants().len(), + path: tcx.def_path_str(did), + }); } /// Emit an error when encountering two or more non-zero-sized fields in a transparent @@ -488,21 +501,21 @@ fn bad_non_zero_sized_fields<'tcx>( field_spans: impl Iterator<Item = Span>, sp: Span, ) { - let msg = format!("needs at most one non-zero-sized field, but has {field_count}"); - let mut err = struct_span_err!( - tcx.sess, - sp, - E0690, - "{}transparent {} {}", - if adt.is_enum() { "the variant of a " } else { "" }, - adt.descr(), - msg, - ); - err.span_label(sp, &msg); - for sp in field_spans { - err.span_label(sp, "this field is non-zero-sized"); + if adt.is_enum() { + tcx.sess.emit_err(errors::TransparentNonZeroSizedEnum { + span: sp, + spans: field_spans.collect(), + field_count, + desc: adt.descr(), + }); + } else { + tcx.sess.emit_err(errors::TransparentNonZeroSized { + span: sp, + spans: field_spans.collect(), + field_count, + desc: adt.descr(), + }); } - err.emit(); } // FIXME: Consider moving this method to a more fitting place. diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index b28bfb1d5..6ab5556e9 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -12,7 +12,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Arm, Block, Expr, Local, Pat, PatKind, Stmt}; -use rustc_index::vec::Idx; +use rustc_index::Idx; use rustc_middle::middle::region::*; use rustc_middle::ty::TyCtxt; use rustc_span::source_map; @@ -421,7 +421,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h let target_scopes = visitor.fixup_scopes.drain(start_point..); for scope in target_scopes { - let mut yield_data = + let yield_data = visitor.scope_tree.yield_in_scope.get_mut(&scope).unwrap().last_mut().unwrap(); let count = yield_data.expr_and_pat_count; let span = yield_data.span; diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 53197bc84..b403ee96b 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -12,7 +12,7 @@ use rustc_infer::infer::outlives::env::{OutlivesEnvironment, RegionBoundPairs}; use rustc_infer::infer::outlives::obligations::TypeOutlives; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; use rustc_middle::mir::ConstraintCategory; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::trait_def::TraitSpecializationKind; use rustc_middle::ty::{ self, AdtKind, GenericParamDefKind, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, @@ -155,7 +155,7 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) { debug!( ?item.owner_id, - item.name = ? tcx.def_path_str(def_id.to_def_id()) + item.name = ? tcx.def_path_str(def_id) ); match item.kind { @@ -179,7 +179,7 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) { hir::ItemKind::Impl(impl_) => { let is_auto = tcx .impl_trait_ref(def_id) - .map_or(false, |trait_ref| tcx.trait_is_auto(trait_ref.skip_binder().def_id)); + .is_some_and(|trait_ref| tcx.trait_is_auto(trait_ref.skip_binder().def_id)); if let (hir::Defaultness::Default { .. }, true) = (impl_.defaultness, is_auto) { let sp = impl_.of_trait.as_ref().map_or(item.span, |t| t.path.span); let mut err = @@ -251,7 +251,7 @@ fn check_foreign_item(tcx: TyCtxt<'_>, item: &hir::ForeignItem<'_>) { debug!( ?item.owner_id, - item.name = ? tcx.def_path_str(def_id.to_def_id()) + item.name = ? tcx.def_path_str(def_id) ); match item.kind { @@ -360,7 +360,9 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe tcx, param_env, item_def_id, - tcx.explicit_item_bounds(item_def_id).to_vec(), + tcx.explicit_item_bounds(item_def_id) + .subst_identity_iter_copied() + .collect::<Vec<_>>(), &FxIndexSet::default(), gat_def_id.def_id, gat_generics, @@ -443,7 +445,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe let plural = pluralize!(unsatisfied_bounds.len()); let mut err = tcx.sess.struct_span_err( gat_item_hir.span, - &format!("missing required bound{} on `{}`", plural, gat_item_hir.ident), + format!("missing required bound{} on `{}`", plural, gat_item_hir.ident), ); let suggestion = format!( @@ -453,14 +455,14 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe ); err.span_suggestion( gat_item_hir.generics.tail_span_for_predicate_suggestion(), - &format!("add the required where clause{plural}"), + format!("add the required where clause{plural}"), suggestion, Applicability::MachineApplicable, ); let bound = if unsatisfied_bounds.len() > 1 { "these bounds are" } else { "this bound is" }; - err.note(&format!( + err.note(format!( "{} currently required to ensure that impls have maximum flexibility", bound )); @@ -914,14 +916,14 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { if is_ptr { tcx.sess.span_err( hir_ty.span, - &format!( + format!( "using {unsupported_type} as const generic parameters is forbidden", ), ); } else { let mut err = tcx.sess.struct_span_err( hir_ty.span, - &format!( + format!( "{unsupported_type} is forbidden as the type of a const generic parameter", ), ); @@ -1025,9 +1027,9 @@ fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: b packed && { let ty = tcx.type_of(variant.fields.raw.last().unwrap().did).subst_identity(); let ty = tcx.erase_regions(ty); - if ty.needs_infer() { + if ty.has_infer() { tcx.sess - .delay_span_bug(item.span, &format!("inference variables in {:?}", ty)); + .delay_span_bug(item.span, format!("inference variables in {:?}", ty)); // Just treat unresolved type expression as if it needs drop. true } else { @@ -1125,7 +1127,7 @@ fn check_associated_type_bounds(wfcx: &WfCheckingCtxt<'_, '_>, item: ty::AssocIt let bounds = wfcx.tcx().explicit_item_bounds(item.def_id); debug!("check_associated_type_bounds: bounds={:?}", bounds); - let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| { + let wf_obligations = bounds.subst_identity_iter_copied().flat_map(|(bound, bound_span)| { let normalized_bound = wfcx.normalize(span, None, bound); traits::wf::predicate_obligations( wfcx.infcx, @@ -1290,7 +1292,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id // Ignore dependent defaults -- that is, where the default of one type // parameter includes another (e.g., `<T, U = T>`). In those cases, we can't // be sure if it will error or not as user might always specify the other. - if !ty.needs_subst() { + if !ty.has_param() { wfcx.register_wf_obligation( tcx.def_span(param.def_id), Some(WellFormedLoc::Ty(param.def_id.expect_local())), @@ -1306,7 +1308,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id // for `struct Foo<const N: usize, const M: usize = { 1 - 2 }>` // we should eagerly error. let default_ct = tcx.const_param_default(param.def_id).subst_identity(); - if !default_ct.needs_subst() { + if !default_ct.has_param() { wfcx.register_wf_obligation( tcx.def_span(param.def_id), None, @@ -1340,7 +1342,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id if is_our_default(param) { let default_ty = tcx.type_of(param.def_id).subst_identity(); // ... and it's not a dependent default, ... - if !default_ty.needs_subst() { + if !default_ty.has_param() { // ... then substitute it with the default. return default_ty.into(); } @@ -1353,7 +1355,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id if is_our_default(param) { let default_ct = tcx.const_param_default(param.def_id).subst_identity(); // ... and it's not a dependent default, ... - if !default_ct.needs_subst() { + if !default_ct.has_param() { // ... then substitute it with the default. return default_ct.into(); } @@ -1574,21 +1576,14 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> { && let hir::OpaqueTyOrigin::FnReturn(source) | hir::OpaqueTyOrigin::AsyncFn(source) = opaque.origin && source == self.fn_def_id { - let opaque_ty = tcx.fold_regions(unshifted_opaque_ty, |re, depth| { - if let ty::ReLateBound(index, bv) = re.kind() { - if depth != ty::INNERMOST { - return tcx.mk_re_error_with_message( - DUMMY_SP, - "we shouldn't walk non-predicate binders with `impl Trait`...", - ); - } - tcx.mk_re_late_bound(index.shifted_out_to_binder(self.depth), bv) - } else { - re + let opaque_ty = tcx.fold_regions(unshifted_opaque_ty, |re, _depth| { + match re.kind() { + ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReError(_) => re, + r => bug!("unexpected region: {r:?}"), } }); for (bound, bound_span) in tcx - .bound_explicit_item_bounds(opaque_ty.def_id) + .explicit_item_bounds(opaque_ty.def_id) .subst_iter_copied(tcx, opaque_ty.substs) { let bound = self.wfcx.normalize(bound_span, None, bound); @@ -1656,7 +1651,7 @@ fn check_method_receiver<'tcx>( &tcx.sess.parse_sess, sym::arbitrary_self_types, span, - &format!( + format!( "`{receiver_ty}` cannot be used as the type of `self` without \ the `arbitrary_self_types` feature", ), @@ -1784,7 +1779,7 @@ fn receiver_is_implemented<'tcx>( receiver_ty: Ty<'tcx>, ) -> bool { let tcx = wfcx.tcx(); - let trait_ref = ty::Binder::dummy(tcx.mk_trait_ref(receiver_trait_def_id, [receiver_ty])); + let trait_ref = ty::TraitRef::new(tcx, receiver_trait_def_id, [receiver_ty]); let obligation = traits::Obligation::new(tcx, cause, wfcx.param_env, trait_ref); @@ -1879,10 +1874,10 @@ fn report_bivariance( } else { format!("consider removing `{param_name}` or referring to it in a field") }; - err.help(&msg); + err.help(msg); if matches!(param.kind, hir::GenericParamKind::Type { .. }) && !has_explicit_bounds { - err.help(&format!( + err.help(format!( "if you intended `{0}` to be a const parameter, use `const {0}: usize` instead", param_name )); |