summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_analysis/src/check
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_hir_analysis/src/check')
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs72
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs60
-rw-r--r--compiler/rustc_hir_analysis/src/check/dropck.rs351
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsicck.rs68
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs201
-rw-r--r--compiler/rustc_hir_analysis/src/check/region.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs61
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
));