>),
/// An anonymous struct type i.e. `struct { foo: Type }`
- AnonStruct(ThinVec),
+ AnonStruct(NodeId, ThinVec),
/// An anonymous union type i.e. `union { bar: Type }`
- AnonUnion(ThinVec),
+ AnonUnion(NodeId, ThinVec),
/// A path (`module::module::...::Type`), optionally
/// "qualified", e.g., ` as SomeTrait>::SomeType`.
///
@@ -2161,6 +2161,10 @@ impl TyKind {
None
}
}
+
+ pub fn is_anon_adt(&self) -> bool {
+ matches!(self, TyKind::AnonStruct(..) | TyKind::AnonUnion(..))
+ }
}
/// Syntax used to declare a trait object.
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 90677151d250..d482ada170ee 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -514,7 +514,8 @@ pub fn noop_visit_ty(ty: &mut P, vis: &mut T) {
visit_vec(bounds, |bound| vis.visit_param_bound(bound));
}
TyKind::MacCall(mac) => vis.visit_mac_call(mac),
- TyKind::AnonStruct(fields) | TyKind::AnonUnion(fields) => {
+ TyKind::AnonStruct(id, fields) | TyKind::AnonUnion(id, fields) => {
+ vis.visit_id(id);
fields.flat_map_in_place(|field| vis.flat_map_field_def(field));
}
}
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 8d084ee29a7d..4aaaa0ba4245 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -450,7 +450,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {}
TyKind::MacCall(mac) => visitor.visit_mac_call(mac),
TyKind::Never | TyKind::CVarArgs => {}
- TyKind::AnonStruct(ref fields, ..) | TyKind::AnonUnion(ref fields, ..) => {
+ TyKind::AnonStruct(_, ref fields) | TyKind::AnonUnion(_, ref fields) => {
walk_list!(visitor, visit_field_def, fields)
}
}
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index fb52f9cf58f2..933372fae4eb 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -720,7 +720,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
}
- fn lower_field_def(&mut self, (index, f): (usize, &FieldDef)) -> hir::FieldDef<'hir> {
+ pub(super) fn lower_field_def(
+ &mut self,
+ (index, f): (usize, &FieldDef),
+ ) -> hir::FieldDef<'hir> {
let ty = if let TyKind::Path(qself, path) = &f.ty.kind {
let t = self.lower_path_ty(
&f.ty,
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 5f7439060b3c..480072ce705a 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1288,17 +1288,44 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
TyKind::Err => {
hir::TyKind::Err(self.dcx().span_delayed_bug(t.span, "TyKind::Err lowered"))
}
- // FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS
- #[allow(rustc::untranslatable_diagnostic)]
- #[allow(rustc::diagnostic_outside_of_impl)]
- TyKind::AnonStruct(ref _fields) => {
- hir::TyKind::Err(self.dcx().span_err(t.span, "anonymous structs are unimplemented"))
- }
- // FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS
- #[allow(rustc::untranslatable_diagnostic)]
- #[allow(rustc::diagnostic_outside_of_impl)]
- TyKind::AnonUnion(ref _fields) => {
- hir::TyKind::Err(self.dcx().span_err(t.span, "anonymous unions are unimplemented"))
+ // Lower the anonymous structs or unions in a nested lowering context.
+ //
+ // ```
+ // struct Foo {
+ // _: union {
+ // // ^__________________ <-- within the nested lowering context,
+ // /* fields */ // | we lower all fields defined into an
+ // } // | owner node of struct or union item
+ // // ^_____________________|
+ // }
+ // ```
+ TyKind::AnonStruct(node_id, fields) | TyKind::AnonUnion(node_id, fields) => {
+ // Here its `def_id` is created in `build_reduced_graph`.
+ let def_id = self.local_def_id(*node_id);
+ debug!(?def_id);
+ let owner_id = hir::OwnerId { def_id };
+ self.with_hir_id_owner(*node_id, |this| {
+ let fields = this.arena.alloc_from_iter(
+ fields.iter().enumerate().map(|f| this.lower_field_def(f)),
+ );
+ let span = t.span;
+ let variant_data = hir::VariantData::Struct { fields, recovered: false };
+ // FIXME: capture the generics from the outer adt.
+ let generics = hir::Generics::empty();
+ let kind = match t.kind {
+ TyKind::AnonStruct(..) => hir::ItemKind::Struct(variant_data, generics),
+ TyKind::AnonUnion(..) => hir::ItemKind::Union(variant_data, generics),
+ _ => unreachable!(),
+ };
+ hir::OwnerNode::Item(this.arena.alloc(hir::Item {
+ ident: Ident::new(kw::Empty, span),
+ owner_id,
+ kind,
+ span: this.lower_span(span),
+ vis_span: this.lower_span(span.shrink_to_lo()),
+ }))
+ });
+ hir::TyKind::AnonAdt(hir::ItemId { owner_id })
}
TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 9ea5d1ed5fa2..d24dc44d2c52 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -219,8 +219,8 @@ impl<'a> AstValidator<'a> {
}
}
}
- TyKind::AnonStruct(ref fields, ..) | TyKind::AnonUnion(ref fields, ..) => {
- walk_list!(self, visit_field_def, fields)
+ TyKind::AnonStruct(_, ref fields) | TyKind::AnonUnion(_, ref fields) => {
+ walk_list!(self, visit_struct_field_def, fields)
}
_ => visit::walk_ty(self, t),
}
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 731232bce65c..cda746894e86 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -1003,11 +1003,11 @@ impl<'a> State<'a> {
}
self.pclose();
}
- ast::TyKind::AnonStruct(fields) => {
+ ast::TyKind::AnonStruct(_, fields) => {
self.head("struct");
self.print_record_struct_body(fields, ty.span);
}
- ast::TyKind::AnonUnion(fields) => {
+ ast::TyKind::AnonUnion(_, fields) => {
self.head("union");
self.print_record_struct_body(fields, ty.span);
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 44e4dea34817..18cf6f64fbc0 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -691,7 +691,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// If the type is opaque/param/closure, and it is Fn or FnMut, let's suggest (mutably)
// borrowing the type, since `&mut F: FnMut` iff `F: FnMut` and similarly for `Fn`.
- // These types seem reasonably opaque enough that they could be substituted with their
+ // These types seem reasonably opaque enough that they could be instantiated with their
// borrowed variants in a function body when we see a move error.
let borrow_level = match *ty.kind() {
ty::Param(_) => tcx
@@ -3018,7 +3018,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
/// assignment to `x.f`).
pub(crate) fn report_illegal_reassignment(
&mut self,
- _location: Location,
(place, span): (Place<'tcx>, Span),
assigned_span: Span,
err_place: Place<'tcx>,
@@ -3159,7 +3158,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
) -> Option> {
// Define a fallback for when we can't match a closure.
let fallback = || {
- let is_closure = self.infcx.tcx.is_closure_or_coroutine(self.mir_def_id().to_def_id());
+ let is_closure = self.infcx.tcx.is_closure_like(self.mir_def_id().to_def_id());
if is_closure {
None
} else {
@@ -3370,7 +3369,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
sig: ty::PolyFnSig<'tcx>,
) -> Option> {
debug!("annotate_fn_sig: did={:?} sig={:?}", did, sig);
- let is_closure = self.infcx.tcx.is_closure_or_coroutine(did.to_def_id());
+ let is_closure = self.infcx.tcx.is_closure_like(did.to_def_id());
let fn_hir_id = self.infcx.tcx.local_def_id_to_hir_id(did);
let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(fn_hir_id)?;
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 5aed18ca4563..b3d684086c28 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -67,7 +67,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
local,
projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
} => {
- debug_assert!(is_closure_or_coroutine(
+ debug_assert!(is_closure_like(
Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty
));
@@ -126,9 +126,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
{
item_msg = access_place_desc;
debug_assert!(self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_ref());
- debug_assert!(is_closure_or_coroutine(
- the_place_err.ty(self.body, self.infcx.tcx).ty
- ));
+ debug_assert!(is_closure_like(the_place_err.ty(self.body, self.infcx.tcx).ty));
reason = if self.is_upvar_field_projection(access_place.as_ref()).is_some() {
", as it is a captured variable in a `Fn` closure".to_string()
@@ -389,7 +387,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
local,
projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
} => {
- debug_assert!(is_closure_or_coroutine(
+ debug_assert!(is_closure_like(
Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty
));
@@ -1474,7 +1472,8 @@ fn suggest_ampmut<'tcx>(
}
}
-fn is_closure_or_coroutine(ty: Ty<'_>) -> bool {
+/// If the type is a `Coroutine`, `Closure`, or `CoroutineClosure`
+fn is_closure_like(ty: Ty<'_>) -> bool {
ty.is_closure() || ty.is_coroutine() || ty.is_coroutine_closure()
}
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 4dba34c11f94..e8ffab9307eb 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -1036,7 +1036,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
self,
self.infcx.tcx,
self.body,
- location,
(sd, place_span.0),
&borrow_set,
|borrow_index| borrows_in_scope.contains(borrow_index),
@@ -2174,7 +2173,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// report the error as an illegal reassignment
let init = &self.move_data.inits[init_index];
let assigned_span = init.span(self.body);
- self.report_illegal_reassignment(location, (place, span), assigned_span, place);
+ self.report_illegal_reassignment((place, span), assigned_span, place);
} else {
self.report_mutability_error(place, span, the_place_err, error_access, location)
}
diff --git a/compiler/rustc_borrowck/src/path_utils.rs b/compiler/rustc_borrowck/src/path_utils.rs
index adafad7fa2fd..88b20bba9fb0 100644
--- a/compiler/rustc_borrowck/src/path_utils.rs
+++ b/compiler/rustc_borrowck/src/path_utils.rs
@@ -27,7 +27,6 @@ pub(super) fn each_borrow_involving_path<'tcx, F, I, S>(
s: &mut S,
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
- _location: Location,
access_place: (AccessDepth, Place<'tcx>),
borrow_set: &BorrowSet<'tcx>,
is_candidate: I,
diff --git a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
index 93aae1a7f976..10941cadcbb2 100644
--- a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
+++ b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
@@ -340,7 +340,6 @@ impl<'cx, 'tcx> LoanInvalidationsGenerator<'cx, 'tcx> {
self,
self.tcx,
self.body,
- location,
(sd, place),
self.borrow_set,
|_| true,
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 3153b709ffe3..34d60fc8f6e1 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -662,7 +662,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
polonius_output: Option>,
) -> (Option>, RegionErrors<'tcx>) {
let mir_def_id = body.source.def_id();
- self.propagate_constraints(body);
+ self.propagate_constraints();
let mut errors_buffer = RegionErrors::new(infcx.tcx);
@@ -716,8 +716,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// for each region variable until all the constraints are
/// satisfied. Note that some values may grow **too** large to be
/// feasible, but we check this later.
- #[instrument(skip(self, _body), level = "debug")]
- fn propagate_constraints(&mut self, _body: &Body<'tcx>) {
+ #[instrument(skip(self), level = "debug")]
+ fn propagate_constraints(&mut self) {
debug!("constraints={:#?}", {
let mut constraints: Vec<_> = self.outlives_constraints().collect();
constraints.sort_by_key(|c| (c.sup, c.sub));
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index 636c174e002d..cd2fe56ca491 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -45,7 +45,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// be allowed:
/// `fn f<'a: 'b, 'b: 'a>(x: *mut &'b i32) -> impl Sized + 'a { x }`
///
- /// Then we map the regions in both the type and the subst to their
+ /// Then we map the regions in both the type and the generic parameters to their
/// `external_name` giving `concrete_type = &'a i32`,
/// `args = ['static, 'a]`. This will then allow
/// `infer_opaque_definition_from_instantiation` to determine that
@@ -77,9 +77,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let args = opaque_type_key.args;
debug!(?concrete_type, ?args);
- let mut subst_regions = vec![self.universal_regions.fr_static];
+ let mut arg_regions = vec![self.universal_regions.fr_static];
- let to_universal_region = |vid, subst_regions: &mut Vec<_>| {
+ let to_universal_region = |vid, arg_regions: &mut Vec<_>| {
trace!(?vid);
let scc = self.constraint_sccs.scc(vid);
trace!(?scc);
@@ -88,11 +88,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
}) {
Some(region) => {
let vid = self.universal_regions.to_region_vid(region);
- subst_regions.push(vid);
+ arg_regions.push(vid);
region
}
None => {
- subst_regions.push(vid);
+ arg_regions.push(vid);
ty::Region::new_error_with_message(
infcx.tcx,
concrete_type.span,
@@ -106,10 +106,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// This will ensure they get precedence when folding the regions in the concrete type.
if let Some(&ci) = member_constraints.get(&opaque_type_key) {
for &vid in self.member_constraints.choice_regions(ci) {
- to_universal_region(vid, &mut subst_regions);
+ to_universal_region(vid, &mut arg_regions);
}
}
- debug!(?subst_regions);
+ debug!(?arg_regions);
// Next, insert universal regions from args, so we can translate regions that appear
// in them but are not subject to member constraints, for instance closure args.
@@ -119,18 +119,18 @@ impl<'tcx> RegionInferenceContext<'tcx> {
return region;
}
let vid = self.to_region_vid(region);
- to_universal_region(vid, &mut subst_regions)
+ to_universal_region(vid, &mut arg_regions)
});
debug!(?universal_args);
- debug!(?subst_regions);
+ debug!(?arg_regions);
// Deduplicate the set of regions while keeping the chosen order.
- let subst_regions = subst_regions.into_iter().collect::>();
- debug!(?subst_regions);
+ let arg_regions = arg_regions.into_iter().collect::>();
+ debug!(?arg_regions);
let universal_concrete_type =
infcx.tcx.fold_regions(concrete_type, |region, _| match *region {
- ty::ReVar(vid) => subst_regions
+ ty::ReVar(vid) => arg_regions
.iter()
.find(|ur_vid| self.eval_equal(vid, **ur_vid))
.and_then(|ur_vid| self.definitions[*ur_vid].external_name)
diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs
index a5a7ce4ea3e8..af5b635ae668 100644
--- a/compiler/rustc_borrowck/src/type_check/input_output.rs
+++ b/compiler/rustc_borrowck/src/type_check/input_output.rs
@@ -29,7 +29,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
pub(super) fn check_signature_annotation(&mut self, body: &Body<'tcx>) {
let mir_def_id = body.source.def_id().expect_local();
- if !self.tcx().is_closure_or_coroutine(mir_def_id.to_def_id()) {
+ if !self.tcx().is_closure_like(mir_def_id.to_def_id()) {
return;
}
diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs
index 7bf19f611668..267405ac32e2 100644
--- a/compiler/rustc_builtin_macros/src/deriving/clone.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs
@@ -110,7 +110,9 @@ fn cs_clone_simple(
&& !seen_type_names.insert(name)
{
// Already produced an assertion for this type.
- } else {
+ // Anonymous structs or unions must be eliminated as they cannot be
+ // type parameters.
+ } else if !field.ty.kind.is_anon_adt() {
// let _: AssertParamIsClone;
super::assert_ty_bounds(
cx,
diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs
index a6f3252e7be1..8a3375cba9dc 100644
--- a/compiler/rustc_builtin_macros/src/deriving/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs
@@ -123,6 +123,8 @@ fn assert_ty_bounds(
span: Span,
assert_path: &[Symbol],
) {
+ // Deny anonymous structs or unions to avoid wierd errors.
+ assert!(!ty.kind.is_anon_adt(), "Anonymous structs or unions cannot be type parameters");
// Generate statement `let _: assert_path;`.
let span = cx.with_def_site_ctxt(span);
let assert_path = cx.path_all(span, true, cx.std_path(assert_path), vec![GenericArg::Type(ty)]);
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index 07c83f1aa089..f9eaa0d94cbb 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -479,7 +479,7 @@ pub fn from_fn_attrs<'ll, 'tcx>(
// `+multivalue` feature because the purpose of the wasm abi is to match
// the WebAssembly specification, which has this feature. This won't be
// needed when LLVM enables this `multivalue` feature by default.
- if !cx.tcx.is_closure_or_coroutine(instance.def_id()) {
+ if !cx.tcx.is_closure_like(instance.def_id()) {
let abi = cx.tcx.fn_sig(instance.def_id()).skip_binder().abi();
if abi == Abi::Wasm {
function_features.push("+multivalue".to_string());
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 4bb400b18798..e48479c8da27 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -213,6 +213,7 @@ pub fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> LLVMFeature<'a> {
("x86", "rdrand") => LLVMFeature::new("rdrnd"),
("x86", "bmi1") => LLVMFeature::new("bmi"),
("x86", "cmpxchg16b") => LLVMFeature::new("cx16"),
+ ("x86", "lahfsahf") => LLVMFeature::new("sahf"),
("aarch64", "rcpc2") => LLVMFeature::new("rcpc-immo"),
("aarch64", "dpb") => LLVMFeature::new("ccpp"),
("aarch64", "dpb2") => LLVMFeature::new("ccdp"),
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index b387d0b2258b..9e23757fceef 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -229,7 +229,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
}
sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL,
sym::track_caller => {
- let is_closure = tcx.is_closure_or_coroutine(did.to_def_id());
+ let is_closure = tcx.is_closure_like(did.to_def_id());
if !is_closure
&& let Some(fn_sig) = fn_sig()
@@ -274,7 +274,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
}
}
sym::target_feature => {
- if !tcx.is_closure_or_coroutine(did.to_def_id())
+ if !tcx.is_closure_like(did.to_def_id())
&& let Some(fn_sig) = fn_sig()
&& fn_sig.skip_binder().unsafety() == hir::Unsafety::Normal
{
@@ -529,7 +529,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
// would result in this closure being compiled without the inherited target features, but this
// is probably a poor usage of `#[inline(always)]` and easily avoided by not using the attribute.
if tcx.features().target_feature_11
- && tcx.is_closure_or_coroutine(did.to_def_id())
+ && tcx.is_closure_like(did.to_def_id())
&& codegen_fn_attrs.inline != InlineAttr::Always
{
let owner_id = tcx.parent(did.to_def_id());
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index 3694e41a0e08..ee1d548b2319 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -77,6 +77,8 @@ pub fn from_target_feature(
Some(sym::aarch64_ver_target_feature) => rust_features.aarch64_ver_target_feature,
Some(sym::csky_target_feature) => rust_features.csky_target_feature,
Some(sym::loongarch_target_feature) => rust_features.loongarch_target_feature,
+ Some(sym::lahfsahf_target_feature) => rust_features.lahfsahf_target_feature,
+ Some(sym::prfchw_target_feature) => rust_features.prfchw_target_feature,
Some(name) => bug!("unknown target feature gate {}", name),
None => true,
};
diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs
index 71085c2b2a5c..80d02589900f 100644
--- a/compiler/rustc_const_eval/src/const_eval/error.rs
+++ b/compiler/rustc_const_eval/src/const_eval/error.rs
@@ -151,7 +151,7 @@ where
let mut err = tcx.dcx().create_err(err);
let msg = error.diagnostic_message();
- error.add_args(tcx.dcx(), &mut err);
+ error.add_args(&mut err);
// Use *our* span to label the interp error
err.span_label(our_span, msg);
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index 0844cdbe99b8..c55d899e4d5a 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -356,22 +356,13 @@ pub fn const_validate_mplace<'mir, 'tcx>(
let mut inner = false;
while let Some((mplace, path)) = ref_tracking.todo.pop() {
let mode = match ecx.tcx.static_mutability(cid.instance.def_id()) {
- Some(_) if cid.promoted.is_some() => {
- // Promoteds in statics are consts that re allowed to point to statics.
- CtfeValidationMode::Const {
- allow_immutable_unsafe_cell: false,
- allow_extern_static_ptrs: true,
- }
- }
+ _ if cid.promoted.is_some() => CtfeValidationMode::Promoted,
Some(mutbl) => CtfeValidationMode::Static { mutbl }, // a `static`
None => {
// In normal `const` (not promoted), the outermost allocation is always only copied,
// so having `UnsafeCell` in there is okay despite them being in immutable memory.
let allow_immutable_unsafe_cell = cid.promoted.is_none() && !inner;
- CtfeValidationMode::Const {
- allow_immutable_unsafe_cell,
- allow_extern_static_ptrs: false,
- }
+ CtfeValidationMode::Const { allow_immutable_unsafe_cell }
}
};
ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode)?;
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index a649526c1964..11679ab77e35 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -426,7 +426,7 @@ pub struct UndefinedBehavior {
pub trait ReportErrorExt {
/// Returns the diagnostic message for this error.
fn diagnostic_message(&self) -> DiagnosticMessage;
- fn add_args(self, dcx: &DiagCtxt, builder: &mut DiagnosticBuilder<'_, G>);
+ fn add_args(self, diag: &mut DiagnosticBuilder<'_, G>);
fn debug(self) -> String
where
@@ -434,11 +434,11 @@ pub trait ReportErrorExt {
{
ty::tls::with(move |tcx| {
let dcx = tcx.dcx();
- let mut builder = dcx.struct_allow(DiagnosticMessage::Str(String::new().into()));
+ let mut diag = dcx.struct_allow(DiagnosticMessage::Str(String::new().into()));
let message = self.diagnostic_message();
- self.add_args(dcx, &mut builder);
- let s = dcx.eagerly_translate_to_string(message, builder.args());
- builder.cancel();
+ self.add_args(&mut diag);
+ let s = dcx.eagerly_translate_to_string(message, diag.args());
+ diag.cancel();
s
})
}
@@ -505,20 +505,17 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
}
}
- fn add_args(
- self,
- dcx: &DiagCtxt,
- builder: &mut DiagnosticBuilder<'_, G>,
- ) {
+ fn add_args(self, diag: &mut DiagnosticBuilder<'_, G>) {
use UndefinedBehaviorInfo::*;
+ let dcx = diag.dcx;
match self {
Ub(_) => {}
Custom(custom) => {
(custom.add_args)(&mut |name, value| {
- builder.arg(name, value);
+ diag.arg(name, value);
});
}
- ValidationError(e) => e.add_args(dcx, builder),
+ ValidationError(e) => e.add_args(diag),
Unreachable
| DivisionByZero
@@ -533,20 +530,18 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
| UninhabitedEnumVariantWritten(_)
| UninhabitedEnumVariantRead(_) => {}
BoundsCheckFailed { len, index } => {
- builder.arg("len", len);
- builder.arg("index", index);
+ diag.arg("len", len);
+ diag.arg("index", index);
}
UnterminatedCString(ptr) | InvalidFunctionPointer(ptr) | InvalidVTablePointer(ptr) => {
- builder.arg("pointer", ptr);
+ diag.arg("pointer", ptr);
}
PointerUseAfterFree(alloc_id, msg) => {
- builder
- .arg("alloc_id", alloc_id)
+ diag.arg("alloc_id", alloc_id)
.arg("bad_pointer_message", bad_pointer_message(msg, dcx));
}
PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size, msg } => {
- builder
- .arg("alloc_id", alloc_id)
+ diag.arg("alloc_id", alloc_id)
.arg("alloc_size", alloc_size.bytes())
.arg("ptr_offset", ptr_offset)
.arg("ptr_size", ptr_size.bytes())
@@ -554,47 +549,47 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
}
DanglingIntPointer(ptr, msg) => {
if ptr != 0 {
- builder.arg("pointer", format!("{ptr:#x}[noalloc]"));
+ diag.arg("pointer", format!("{ptr:#x}[noalloc]"));
}
- builder.arg("bad_pointer_message", bad_pointer_message(msg, dcx));
+ diag.arg("bad_pointer_message", bad_pointer_message(msg, dcx));
}
AlignmentCheckFailed(Misalignment { required, has }, msg) => {
- builder.arg("required", required.bytes());
- builder.arg("has", has.bytes());
- builder.arg("msg", format!("{msg:?}"));
+ diag.arg("required", required.bytes());
+ diag.arg("has", has.bytes());
+ diag.arg("msg", format!("{msg:?}"));
}
WriteToReadOnly(alloc) | DerefFunctionPointer(alloc) | DerefVTablePointer(alloc) => {
- builder.arg("allocation", alloc);
+ diag.arg("allocation", alloc);
}
InvalidBool(b) => {
- builder.arg("value", format!("{b:02x}"));
+ diag.arg("value", format!("{b:02x}"));
}
InvalidChar(c) => {
- builder.arg("value", format!("{c:08x}"));
+ diag.arg("value", format!("{c:08x}"));
}
InvalidTag(tag) => {
- builder.arg("tag", format!("{tag:x}"));
+ diag.arg("tag", format!("{tag:x}"));
}
InvalidStr(err) => {
- builder.arg("err", format!("{err}"));
+ diag.arg("err", format!("{err}"));
}
InvalidUninitBytes(Some((alloc, info))) => {
- builder.arg("alloc", alloc);
- builder.arg("access", info.access);
- builder.arg("uninit", info.bad);
+ diag.arg("alloc", alloc);
+ diag.arg("access", info.access);
+ diag.arg("uninit", info.bad);
}
ScalarSizeMismatch(info) => {
- builder.arg("target_size", info.target_size);
- builder.arg("data_size", info.data_size);
+ diag.arg("target_size", info.target_size);
+ diag.arg("data_size", info.data_size);
}
InvalidNichedEnumVariantWritten { enum_ty } => {
- builder.arg("ty", enum_ty.to_string());
+ diag.arg("ty", enum_ty.to_string());
}
AbiMismatchArgument { caller_ty, callee_ty }
| AbiMismatchReturn { caller_ty, callee_ty } => {
- builder.arg("caller_ty", caller_ty.to_string());
- builder.arg("callee_ty", callee_ty.to_string());
+ diag.arg("caller_ty", caller_ty.to_string());
+ diag.arg("callee_ty", callee_ty.to_string());
}
}
}
@@ -674,7 +669,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
}
}
- fn add_args(self, dcx: &DiagCtxt, err: &mut DiagnosticBuilder<'_, G>) {
+ fn add_args(self, err: &mut DiagnosticBuilder<'_, G>) {
use crate::fluent_generated as fluent;
use rustc_middle::mir::interpret::ValidationErrorKind::*;
@@ -684,12 +679,12 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
}
let message = if let Some(path) = self.path {
- dcx.eagerly_translate_to_string(
+ err.dcx.eagerly_translate_to_string(
fluent::const_eval_validation_front_matter_invalid_value_with_path,
[("path".into(), DiagnosticArgValue::Str(path.into()))].iter().map(|(a, b)| (a, b)),
)
} else {
- dcx.eagerly_translate_to_string(
+ err.dcx.eagerly_translate_to_string(
fluent::const_eval_validation_front_matter_invalid_value,
[].into_iter(),
)
@@ -700,7 +695,6 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
fn add_range_arg(
r: WrappingRange,
max_hi: u128,
- dcx: &DiagCtxt,
err: &mut DiagnosticBuilder<'_, G>,
) {
let WrappingRange { start: lo, end: hi } = r;
@@ -724,7 +718,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
("hi".into(), DiagnosticArgValue::Str(hi.to_string().into())),
];
let args = args.iter().map(|(a, b)| (a, b));
- let message = dcx.eagerly_translate_to_string(msg, args);
+ let message = err.dcx.eagerly_translate_to_string(msg, args);
err.arg("in_range", message);
}
@@ -746,7 +740,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
ExpectedKind::EnumTag => fluent::const_eval_validation_expected_enum_tag,
ExpectedKind::Str => fluent::const_eval_validation_expected_str,
};
- let msg = dcx.eagerly_translate_to_string(msg, [].into_iter());
+ let msg = err.dcx.eagerly_translate_to_string(msg, [].into_iter());
err.arg("expected", msg);
}
InvalidEnumTag { value }
@@ -757,11 +751,11 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
err.arg("value", value);
}
NullablePtrOutOfRange { range, max_value } | PtrOutOfRange { range, max_value } => {
- add_range_arg(range, max_value, dcx, err)
+ add_range_arg(range, max_value, err)
}
OutOfRange { range, max_value, value } => {
err.arg("value", value);
- add_range_arg(range, max_value, dcx, err);
+ add_range_arg(range, max_value, err);
}
UnalignedPtr { required_bytes, found_bytes, .. } => {
err.arg("required_bytes", required_bytes);
@@ -802,13 +796,13 @@ impl ReportErrorExt for UnsupportedOpInfo {
UnsupportedOpInfo::ExternStatic(_) => const_eval_extern_static,
}
}
- fn add_args(self, _: &DiagCtxt, builder: &mut DiagnosticBuilder<'_, G>) {
+ fn add_args(self, diag: &mut DiagnosticBuilder<'_, G>) {
use crate::fluent_generated::*;
use UnsupportedOpInfo::*;
if let ReadPointerAsInt(_) | OverwritePartialPointer(_) | ReadPartialPointer(_) = self {
- builder.help(const_eval_ptr_as_bytes_1);
- builder.help(const_eval_ptr_as_bytes_2);
+ diag.help(const_eval_ptr_as_bytes_1);
+ diag.help(const_eval_ptr_as_bytes_2);
}
match self {
// `ReadPointerAsInt(Some(info))` is never printed anyway, it only serves as an error to
@@ -816,10 +810,10 @@ impl ReportErrorExt for UnsupportedOpInfo {
// print. So it's not worth the effort of having diagnostics that can print the `info`.
UnsizedLocal | Unsupported(_) | ReadPointerAsInt(_) => {}
OverwritePartialPointer(ptr) | ReadPartialPointer(ptr) => {
- builder.arg("ptr", ptr);
+ diag.arg("ptr", ptr);
}
ThreadLocalStatic(did) | ExternStatic(did) => {
- builder.arg("did", format!("{did:?}"));
+ diag.arg("did", format!("{did:?}"));
}
}
}
@@ -835,18 +829,14 @@ impl<'tcx> ReportErrorExt for InterpError<'tcx> {
InterpError::MachineStop(e) => e.diagnostic_message(),
}
}
- fn add_args(
- self,
- dcx: &DiagCtxt,
- builder: &mut DiagnosticBuilder<'_, G>,
- ) {
+ fn add_args(self, diag: &mut DiagnosticBuilder<'_, G>) {
match self {
- InterpError::UndefinedBehavior(ub) => ub.add_args(dcx, builder),
- InterpError::Unsupported(e) => e.add_args(dcx, builder),
- InterpError::InvalidProgram(e) => e.add_args(dcx, builder),
- InterpError::ResourceExhaustion(e) => e.add_args(dcx, builder),
+ InterpError::UndefinedBehavior(ub) => ub.add_args(diag),
+ InterpError::Unsupported(e) => e.add_args(diag),
+ InterpError::InvalidProgram(e) => e.add_args(diag),
+ InterpError::ResourceExhaustion(e) => e.add_args(diag),
InterpError::MachineStop(e) => e.add_args(&mut |name, value| {
- builder.arg(name, value);
+ diag.arg(name, value);
}),
}
}
@@ -864,28 +854,24 @@ impl<'tcx> ReportErrorExt for InvalidProgramInfo<'tcx> {
}
}
}
- fn add_args(
- self,
- dcx: &DiagCtxt,
- builder: &mut DiagnosticBuilder<'_, G>,
- ) {
+ fn add_args(self, diag: &mut DiagnosticBuilder<'_, G>) {
match self {
InvalidProgramInfo::TooGeneric | InvalidProgramInfo::AlreadyReported(_) => {}
InvalidProgramInfo::Layout(e) => {
- // The level doesn't matter, `diag` is consumed without it being used.
+ // The level doesn't matter, `dummy_diag` is consumed without it being used.
let dummy_level = Level::Bug;
- let diag: DiagnosticBuilder<'_, ()> =
- e.into_diagnostic().into_diagnostic(dcx, dummy_level);
- for (name, val) in diag.args() {
- builder.arg(name.clone(), val.clone());
+ let dummy_diag: DiagnosticBuilder<'_, ()> =
+ e.into_diagnostic().into_diagnostic(diag.dcx, dummy_level);
+ for (name, val) in dummy_diag.args() {
+ diag.arg(name.clone(), val.clone());
}
- diag.cancel();
+ dummy_diag.cancel();
}
InvalidProgramInfo::FnAbiAdjustForForeignAbi(
AdjustForForeignAbiError::Unsupported { arch, abi },
) => {
- builder.arg("arch", arch);
- builder.arg("abi", abi.name());
+ diag.arg("arch", arch);
+ diag.arg("abi", abi.name());
}
}
}
@@ -900,7 +886,7 @@ impl ReportErrorExt for ResourceExhaustionInfo {
ResourceExhaustionInfo::AddressSpaceFull => const_eval_address_space_full,
}
}
- fn add_args(self, _: &DiagCtxt, _: &mut DiagnosticBuilder<'_, G>) {}
+ fn add_args(self, _: &mut DiagnosticBuilder<'_, G>) {}
}
impl rustc_errors::IntoDiagnosticArg for InternKind {
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index dd9dfe3fe798..33e96e7faa8d 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -445,7 +445,7 @@ pub fn format_interp_error<'tcx>(dcx: &DiagCtxt, e: InterpErrorInfo<'tcx>) -> St
#[allow(rustc::untranslatable_diagnostic)]
let mut diag = dcx.struct_allow("");
let msg = e.diagnostic_message();
- e.add_args(dcx, &mut diag);
+ e.add_args(&mut diag);
let s = dcx.eagerly_translate_to_string(msg, diag.args());
diag.cancel();
s
@@ -554,18 +554,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
/// Call this on things you got out of the MIR (so it is as generic as the current
/// stack frame), to bring it into the proper environment for this interpreter.
- pub(super) fn subst_from_current_frame_and_normalize_erasing_regions<
+ pub(super) fn instantiate_from_current_frame_and_normalize_erasing_regions<
T: TypeFoldable>,
>(
&self,
value: T,
) -> Result {
- self.subst_from_frame_and_normalize_erasing_regions(self.frame(), value)
+ self.instantiate_from_frame_and_normalize_erasing_regions(self.frame(), value)
}
/// Call this on things you got out of the MIR (so it is as generic as the provided
/// stack frame), to bring it into the proper environment for this interpreter.
- pub(super) fn subst_from_frame_and_normalize_erasing_regions>>(
+ pub(super) fn instantiate_from_frame_and_normalize_erasing_regions<
+ T: TypeFoldable>,
+ >(
&self,
frame: &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>,
value: T,
@@ -656,7 +658,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let layout = from_known_layout(self.tcx, self.param_env, layout, || {
let local_ty = frame.body.local_decls[local].ty;
- let local_ty = self.subst_from_frame_and_normalize_erasing_regions(frame, local_ty)?;
+ let local_ty =
+ self.instantiate_from_frame_and_normalize_erasing_regions(frame, local_ty)?;
self.layout_of(local_ty)
})?;
@@ -791,8 +794,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// Make sure all the constants required by this frame evaluate successfully (post-monomorphization check).
if M::POST_MONO_CHECKS {
for &const_ in &body.required_consts {
- let c =
- self.subst_from_current_frame_and_normalize_erasing_regions(const_.const_)?;
+ let c = self
+ .instantiate_from_current_frame_and_normalize_erasing_regions(const_.const_)?;
c.eval(*self.tcx, self.param_env, Some(const_.span)).map_err(|err| {
err.emit_note(*self.tcx);
err
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index 4653c9016c69..317e5673b51b 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -696,9 +696,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
trace!("eval_place_to_op: got {:?}", op);
// Sanity-check the type we ended up with.
if cfg!(debug_assertions) {
- let normalized_place_ty = self.subst_from_current_frame_and_normalize_erasing_regions(
- mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty,
- )?;
+ let normalized_place_ty = self
+ .instantiate_from_current_frame_and_normalize_erasing_regions(
+ mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty,
+ )?;
if !mir_assign_valid_types(
*self.tcx,
self.param_env,
@@ -731,8 +732,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
&Copy(place) | &Move(place) => self.eval_place_to_op(place, layout)?,
Constant(constant) => {
- let c =
- self.subst_from_current_frame_and_normalize_erasing_regions(constant.const_)?;
+ let c = self.instantiate_from_current_frame_and_normalize_erasing_regions(
+ constant.const_,
+ )?;
// This can still fail:
// * During ConstProp, with `TooGeneric` or since the `required_consts` were not all
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index 772445f4f622..03d1dc9fd3d6 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -542,9 +542,10 @@ where
trace!("{:?}", self.dump_place(&place));
// Sanity-check the type we ended up with.
if cfg!(debug_assertions) {
- let normalized_place_ty = self.subst_from_current_frame_and_normalize_erasing_regions(
- mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty,
- )?;
+ let normalized_place_ty = self
+ .instantiate_from_current_frame_and_normalize_erasing_regions(
+ mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty,
+ )?;
if !mir_assign_valid_types(
*self.tcx,
self.param_env,
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index f0f1008aba80..23f3d7eb67da 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -235,7 +235,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
NullaryOp(ref null_op, ty) => {
- let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty)?;
+ let ty = self.instantiate_from_current_frame_and_normalize_erasing_regions(ty)?;
let layout = self.layout_of(ty)?;
if let mir::NullOp::SizeOf | mir::NullOp::AlignOf = null_op
&& layout.is_unsized()
@@ -276,7 +276,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Cast(cast_kind, ref operand, cast_ty) => {
let src = self.eval_operand(operand, None)?;
let cast_ty =
- self.subst_from_current_frame_and_normalize_erasing_regions(cast_ty)?;
+ self.instantiate_from_current_frame_and_normalize_erasing_regions(cast_ty)?;
self.cast(&src, cast_kind, cast_ty, &dest)?;
}
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index ff20fc5092c6..4037220e5ed4 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -173,7 +173,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Drop { place, target, unwind, replace: _ } => {
let frame = self.frame();
let ty = place.ty(&frame.body.local_decls, *self.tcx).ty;
- let ty = self.subst_from_frame_and_normalize_erasing_regions(frame, ty)?;
+ let ty = self.instantiate_from_frame_and_normalize_erasing_regions(frame, ty)?;
let instance = Instance::resolve_drop_in_place(*self.tcx, ty);
if let ty::InstanceDef::DropGlue(_, None) = instance.def {
// This is the branch we enter if and only if the dropped type has no drop glue
@@ -672,8 +672,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// Construct the destination place for this argument. At this point all
// locals are still dead, so we cannot construct a `PlaceTy`.
let dest = mir::Place::from(local);
- // `layout_of_local` does more than just the substitution we need to get the
- // type, but the result gets cached so this avoids calling the substitution
+ // `layout_of_local` does more than just the instantiation we need to get the
+ // type, but the result gets cached so this avoids calling the instantiation
// query *again* the next time this local is accessed.
let ty = self.layout_of_local(self.frame(), local, None)?.ty;
if Some(local) == body.spread_arg {
diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs
index 416443f5f4d2..3a9ee9047340 100644
--- a/compiler/rustc_const_eval/src/interpret/util.rs
+++ b/compiler/rustc_const_eval/src/interpret/util.rs
@@ -19,11 +19,11 @@ where
}
struct FoundParam;
- struct UsedParamsNeedSubstVisitor<'tcx> {
+ struct UsedParamsNeedInstantiationVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
}
- impl<'tcx> TypeVisitor> for UsedParamsNeedSubstVisitor<'tcx> {
+ impl<'tcx> TypeVisitor> for UsedParamsNeedInstantiationVisitor<'tcx> {
type BreakTy = FoundParam;
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow {
@@ -34,21 +34,22 @@ where
match *ty.kind() {
ty::Param(_) => ControlFlow::Break(FoundParam),
ty::Closure(def_id, args)
+ | ty::CoroutineClosure(def_id, args, ..)
| ty::Coroutine(def_id, args, ..)
| ty::FnDef(def_id, args) => {
let instance = ty::InstanceDef::Item(def_id);
let unused_params = self.tcx.unused_generic_params(instance);
- for (index, subst) in args.into_iter().enumerate() {
+ for (index, arg) in args.into_iter().enumerate() {
let index = index
.try_into()
.expect("more generic parameters than can fit into a `u32`");
// Only recurse when generic parameters in fns, closures and coroutines
// are used and have to be instantiated.
//
- // Just in case there are closures or coroutines within this subst,
+ // Just in case there are closures or coroutines within this arg,
// recurse.
- if unused_params.is_used(index) && subst.has_param() {
- return subst.visit_with(self);
+ if unused_params.is_used(index) && arg.has_param() {
+ return arg.visit_with(self);
}
}
ControlFlow::Continue(())
@@ -65,7 +66,7 @@ where
}
}
- let mut vis = UsedParamsNeedSubstVisitor { tcx };
+ let mut vis = UsedParamsNeedInstantiationVisitor { tcx };
if matches!(ty.visit_with(&mut vis), ControlFlow::Break(FoundParam)) {
throw_inval!(TooGeneric);
} else {
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 38aeace02ba4..eb9f3fee1650 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -129,17 +129,20 @@ pub enum PathElem {
pub enum CtfeValidationMode {
/// Validation of a `static`
Static { mutbl: Mutability },
- /// Validation of a `const` (including promoteds).
+ /// Validation of a promoted.
+ Promoted,
+ /// Validation of a `const`.
/// `allow_immutable_unsafe_cell` says whether we allow `UnsafeCell` in immutable memory (which is the
/// case for the top-level allocation of a `const`, where this is fine because the allocation will be
/// copied at each use site).
- Const { allow_immutable_unsafe_cell: bool, allow_extern_static_ptrs: bool },
+ Const { allow_immutable_unsafe_cell: bool },
}
impl CtfeValidationMode {
fn allow_immutable_unsafe_cell(self) -> bool {
match self {
CtfeValidationMode::Static { .. } => false,
+ CtfeValidationMode::Promoted { .. } => false,
CtfeValidationMode::Const { allow_immutable_unsafe_cell, .. } => {
allow_immutable_unsafe_cell
}
@@ -149,6 +152,7 @@ impl CtfeValidationMode {
fn may_contain_mutable_ref(self) -> bool {
match self {
CtfeValidationMode::Static { mutbl } => mutbl == Mutability::Mut,
+ CtfeValidationMode::Promoted { .. } => false,
CtfeValidationMode::Const { .. } => false,
}
}
@@ -236,8 +240,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
// Now we know we are projecting to a field, so figure out which one.
match layout.ty.kind() {
- // coroutines and closures.
- ty::Closure(def_id, _) | ty::Coroutine(def_id, _) => {
+ // coroutines, closures, and coroutine-closures all have upvars that may be named.
+ ty::Closure(def_id, _) | ty::Coroutine(def_id, _) | ty::CoroutineClosure(def_id, _) => {
let mut name = None;
// FIXME this should be more descriptive i.e. CapturePlace instead of CapturedVar
// https://github.com/rust-lang/project-rfc-2229/issues/46
@@ -476,34 +480,32 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
throw_validation_failure!(self.path, MutableRefToImmutable);
}
}
+ // Mode-specific checks
match self.ctfe_mode {
- Some(CtfeValidationMode::Static { .. }) => {
+ Some(
+ CtfeValidationMode::Static { .. }
+ | CtfeValidationMode::Promoted { .. },
+ ) => {
// We skip recursively checking other statics. These statics must be sound by
// themselves, and the only way to get broken statics here is by using
// unsafe code.
// The reasons we don't check other statics is twofold. For one, in all
// sound cases, the static was already validated on its own, and second, we
// trigger cycle errors if we try to compute the value of the other static
- // and that static refers back to us.
+ // and that static refers back to us (potentially through a promoted).
// This could miss some UB, but that's fine.
return Ok(());
}
- Some(CtfeValidationMode::Const {
- allow_extern_static_ptrs, ..
- }) => {
+ Some(CtfeValidationMode::Const { .. }) => {
// For consts on the other hand we have to recursively check;
// pattern matching assumes a valid value. However we better make
// sure this is not mutable.
if is_mut {
throw_validation_failure!(self.path, ConstRefToMutable);
}
+ // We can't recursively validate `extern static`, so we better reject them.
if self.ecx.tcx.is_foreign_item(did) {
- if !allow_extern_static_ptrs {
- throw_validation_failure!(self.path, ConstRefToExtern);
- } else {
- // We can't validate this...
- return Ok(());
- }
+ throw_validation_failure!(self.path, ConstRefToExtern);
}
}
None => {}
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index 28dc69859fd7..43048dc41d3c 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -619,9 +619,11 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
if base_ty.is_unsafe_ptr() {
if place_ref.projection.is_empty() {
let decl = &self.body.local_decls[place_ref.local];
- if let LocalInfo::StaticRef { def_id, .. } = *decl.local_info() {
- let span = decl.source_info.span;
- self.check_static(def_id, span);
+ // If this is a static, then this is not really dereferencing a pointer,
+ // just directly accessing a static. That is not subject to any feature
+ // gates (except for the one about whether statics can even be used, but
+ // that is checked already by `visit_operand`).
+ if let LocalInfo::StaticRef { .. } = *decl.local_info() {
return;
}
}
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
index 1be2a2bc1f3c..12e7ec15e329 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
@@ -72,7 +72,7 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> {
pub fn fn_sig(&self) -> PolyFnSig<'tcx> {
let did = self.def_id().to_def_id();
- if self.tcx.is_closure_or_coroutine(did) {
+ if self.tcx.is_closure_like(did) {
let ty = self.tcx.type_of(did).instantiate_identity();
let ty::Closure(_, args) = ty.kind() else { bug!("type_of closure not ty::Closure") };
args.as_closure().sig()
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
index a9d472d377cd..0c93cfaa5464 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
@@ -409,11 +409,6 @@ impl<'tcx> NonConstOp<'tcx> for TransientCellBorrow {
fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
Status::Unstable(sym::const_refs_to_cell)
}
- fn importance(&self) -> DiagnosticImportance {
- // The cases that cannot possibly work will already emit a `CellBorrow`, so we should
- // not additionally emit a feature gate error if activating the feature gate won't work.
- DiagnosticImportance::Secondary
- }
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
ccx.tcx
.sess
@@ -427,6 +422,11 @@ impl<'tcx> NonConstOp<'tcx> for TransientCellBorrow {
/// it in the future for static items.
pub struct CellBorrow;
impl<'tcx> NonConstOp<'tcx> for CellBorrow {
+ fn importance(&self) -> DiagnosticImportance {
+ // Most likely the code will try to do mutation with these borrows, which
+ // triggers its own errors. Only show this one if that does not happen.
+ DiagnosticImportance::Secondary
+ }
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
// FIXME: Maybe a more elegant solution to this if else case
if let hir::ConstContext::Static(_) = ccx.const_kind() {
@@ -459,8 +459,8 @@ impl<'tcx> NonConstOp<'tcx> for MutBorrow {
}
fn importance(&self) -> DiagnosticImportance {
- // If there were primary errors (like non-const function calls), do not emit further
- // errors about mutable references.
+ // Most likely the code will try to do mutation with these borrows, which
+ // triggers its own errors. Only show this one if that does not happen.
DiagnosticImportance::Secondary
}
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
index a23922c778ff..2c835f6750f7 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
@@ -96,7 +96,7 @@ where
});
}
- fn address_of_allows_mutation(&self, _mt: mir::Mutability, _place: mir::Place<'tcx>) -> bool {
+ fn address_of_allows_mutation(&self) -> bool {
// Exact set of permissions granted by AddressOf is undecided. Conservatively assume that
// it might allow mutation until resolution of #56604.
true
@@ -171,10 +171,8 @@ where
self.super_rvalue(rvalue, location);
match rvalue {
- mir::Rvalue::AddressOf(mt, borrowed_place) => {
- if !borrowed_place.is_indirect()
- && self.address_of_allows_mutation(*mt, *borrowed_place)
- {
+ mir::Rvalue::AddressOf(_mt, borrowed_place) => {
+ if !borrowed_place.is_indirect() && self.address_of_allows_mutation() {
let place_ty = borrowed_place.ty(self.ccx.body, self.ccx.tcx).ty;
if Q::in_any_value_of_ty(self.ccx, place_ty) {
self.state.qualif.insert(borrowed_place.local);
diff --git a/compiler/rustc_error_codes/src/error_codes/E0139.md b/compiler/rustc_error_codes/src/error_codes/E0139.md
index a116cf29395f..4f7f65689c63 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0139.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0139.md
@@ -22,9 +22,9 @@ fn foo(x: Vec) {
In this specific case there's a good chance that the transmute is harmless (but
this is not guaranteed by Rust). However, when alignment and enum optimizations
come into the picture, it's quite likely that the sizes may or may not match
-with different type parameter substitutions. It's not possible to check this for
-_all_ possible types, so `transmute()` simply only accepts types without any
-unsubstituted type parameters.
+with different type parameter instantiations. It's not possible to check this
+for _all_ possible types, so `transmute()` simply only accepts types without any
+uninstantiated type parameters.
If you need this, there's a good chance you're doing something wrong. Keep in
mind that Rust doesn't guarantee much about the layout of different structs
@@ -32,7 +32,7 @@ mind that Rust doesn't guarantee much about the layout of different structs
there is a solution that avoids the transmute entirely, try it instead.
If it's possible, hand-monomorphize the code by writing the function for each
-possible type substitution. It's possible to use traits to do this cleanly,
+possible type instantiation. It's possible to use traits to do this cleanly,
for example:
```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0230.md b/compiler/rustc_error_codes/src/error_codes/E0230.md
index 87ea90e73c90..c30a7e38e9c4 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0230.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0230.md
@@ -15,9 +15,9 @@ There will be an error about `bool` not implementing `Index`, followed by a
note saying "the type `bool` cannot be indexed by `u8`".
As you can see, you can specify type parameters in curly braces for
-substitution with the actual types (using the regular format string syntax) in
-a given situation. Furthermore, `{Self}` will substitute to the type (in this
-case, `bool`) that we tried to use.
+instantiation with the actual types (using the regular format string syntax) in
+a given situation. Furthermore, `{Self}` will be instantiated to the type (in
+this case, `bool`) that we tried to use.
This error appears when the curly braces contain an identifier which doesn't
match with any of the type parameters or the string `Self`. This might happen
diff --git a/compiler/rustc_error_codes/src/error_codes/E0231.md b/compiler/rustc_error_codes/src/error_codes/E0231.md
index a1aaf90df496..b22e3c7082a8 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0231.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0231.md
@@ -15,9 +15,9 @@ there will be an error about `bool` not implementing `Index`, followed by a
note saying "the type `bool` cannot be indexed by `u8`".
As you can see, you can specify type parameters in curly braces for
-substitution with the actual types (using the regular format string syntax) in
-a given situation. Furthermore, `{Self}` will substitute to the type (in this
-case, `bool`) that we tried to use.
+instantiation with the actual types (using the regular format string syntax) in
+a given situation. Furthermore, `{Self}` will be instantiated to the type (in
+this case, `bool`) that we tried to use.
This error appears when the curly braces do not contain an identifier. Please
add one of the same name as a type parameter. If you intended to use literal
diff --git a/compiler/rustc_error_codes/src/error_codes/E0393.md b/compiler/rustc_error_codes/src/error_codes/E0393.md
index 3e853cf1b8a3..50225b25163f 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0393.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0393.md
@@ -12,12 +12,12 @@ fn together_we_will_rule_the_galaxy(son: &A) {}
```
A trait object is defined over a single, fully-defined trait. With a regular
-default parameter, this parameter can just be substituted in. However, if the
+default parameter, this parameter can just be instantiated in. However, if the
default parameter is `Self`, the trait changes for each concrete type; i.e.
`i32` will be expected to implement `A`, `bool` will be expected to
implement `A`, etc... These types will not share an implementation of a
fully-defined trait; instead they share implementations of a trait with
-different parameters substituted in for each implementation. This is
+different parameters instantiated in for each implementation. This is
irreconcilable with what we need to make a trait object work, and is thus
disallowed. Making the trait concrete by explicitly specifying the value of the
defaulted parameter will fix this issue. Fixed example:
diff --git a/compiler/rustc_error_codes/src/error_codes/E0794.md b/compiler/rustc_error_codes/src/error_codes/E0794.md
index c8f73de95a21..dcbe2b97c852 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0794.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0794.md
@@ -14,7 +14,7 @@ let _ = foo::<'static>;
The type of a concrete instance of a generic function is universally quantified
over late-bound lifetime parameters. This is because we want the function to
-work for any lifetime substituted for the late-bound lifetime parameter, no
+work for any lifetime instantiated for the late-bound lifetime parameter, no
matter where the function is called. Consequently, it doesn't make sense to
specify arguments for late-bound lifetime parameters, since they are not
resolved until the function's call site(s).
@@ -56,7 +56,7 @@ let bar_fn3 = bar::; // OK
In the definition of `bar`, the lifetime parameter `'a` is late-bound, while
`'b` is early-bound. This is reflected in the type annotation for `bar_fn`,
-where `'a` is universally quantified and `'b` is substituted by a specific
+where `'a` is universally quantified and `'b` is instantiated with a specific
lifetime. It is not allowed to explicitly specify early-bound lifetime
arguments when late-bound lifetime parameters are present (as for `bar_fn2`,
see [issue #42868](https://github.com/rust-lang/rust/issues/42868)), although
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index ab3ad0e9d684..da9ef6627bea 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -411,8 +411,8 @@ impl CodeSuggestion {
/// or `.span_bug` rather than a failed assertion, etc.
pub struct ExplicitBug;
-/// Signifies that the compiler died with an explicit call to `.delay_*_bug`
-/// rather than a failed assertion, etc.
+/// Signifies that the compiler died due to a delayed bug rather than a failed
+/// assertion, etc.
pub struct DelayedBugPanic;
/// A `DiagCtxt` deals with errors and other compiler output.
@@ -428,10 +428,14 @@ pub struct DiagCtxt {
struct DiagCtxtInner {
flags: DiagCtxtFlags,
- /// The number of lint errors that have been emitted, including duplicates.
- lint_err_count: usize,
- /// The number of non-lint errors that have been emitted, including duplicates.
- err_count: usize,
+ /// The error guarantees from all emitted errors. The length gives the error count.
+ err_guars: Vec,
+ /// The error guarantee from all emitted lint errors. The length gives the
+ /// lint error count.
+ lint_err_guars: Vec,
+ /// The delayed bugs and their error guarantees.
+ delayed_bugs: Vec<(DelayedDiagnostic, ErrorGuaranteed)>,
+ good_path_delayed_bugs: Vec,
/// The number of stashed errors. Unlike the other counts, this can go up
/// and down, so it doesn't guarantee anything.
@@ -447,8 +451,6 @@ struct DiagCtxtInner {
has_printed: bool,
emitter: Box,
- delayed_bugs: Vec,
- good_path_delayed_bugs: Vec,
/// This flag indicates that an expected diagnostic was emitted and suppressed.
/// This is used for the `good_path_delayed_bugs` check.
suppressed_expected_diag: bool,
@@ -560,7 +562,7 @@ impl Drop for DiagCtxtInner {
fn drop(&mut self) {
self.emit_stashed_diagnostics();
- if !self.has_errors() {
+ if self.err_guars.is_empty() {
self.flush_delayed(DelayedBugKind::Normal)
}
@@ -604,15 +606,15 @@ impl DiagCtxt {
Self {
inner: Lock::new(DiagCtxtInner {
flags: DiagCtxtFlags { can_emit_warnings: true, ..Default::default() },
- lint_err_count: 0,
- err_count: 0,
+ err_guars: Vec::new(),
+ lint_err_guars: Vec::new(),
+ delayed_bugs: Vec::new(),
+ good_path_delayed_bugs: Vec::new(),
stashed_err_count: 0,
deduplicated_err_count: 0,
deduplicated_warn_count: 0,
has_printed: false,
emitter,
- delayed_bugs: Vec::new(),
- good_path_delayed_bugs: Vec::new(),
suppressed_expected_diag: false,
taught_diagnostics: Default::default(),
emitted_diagnostic_codes: Default::default(),
@@ -661,14 +663,14 @@ impl DiagCtxt {
/// the overall count of emitted error diagnostics.
pub fn reset_err_count(&self) {
let mut inner = self.inner.borrow_mut();
- inner.lint_err_count = 0;
- inner.err_count = 0;
inner.stashed_err_count = 0;
inner.deduplicated_err_count = 0;
inner.deduplicated_warn_count = 0;
inner.has_printed = false;
// actually free the underlying memory (which `clear` would not do)
+ inner.err_guars = Default::default();
+ inner.lint_err_guars = Default::default();
inner.delayed_bugs = Default::default();
inner.good_path_delayed_bugs = Default::default();
inner.taught_diagnostics = Default::default();
@@ -718,221 +720,10 @@ impl DiagCtxt {
self.inner.borrow_mut().emit_stashed_diagnostics()
}
- /// Construct a builder at the `Warning` level at the given `span` and with the `msg`.
- ///
- /// An `emit` call on the builder will only emit if `can_emit_warnings` is `true`.
- #[rustc_lint_diagnostics]
- #[track_caller]
- pub fn struct_span_warn(
- &self,
- span: impl Into,
- msg: impl Into,
- ) -> DiagnosticBuilder<'_, ()> {
- self.struct_warn(msg).with_span(span)
- }
-
- /// Construct a builder at the `Warning` level with the `msg`.
- ///
- /// An `emit` call on the builder will only emit if `can_emit_warnings` is `true`.
- #[rustc_lint_diagnostics]
- #[track_caller]
- pub fn struct_warn(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> {
- DiagnosticBuilder::new(self, Warning, msg)
- }
-
- /// Construct a builder at the `Allow` level with the `msg`.
- #[rustc_lint_diagnostics]
- #[track_caller]
- pub fn struct_allow(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> {
- DiagnosticBuilder::new(self, Allow, msg)
- }
-
- /// Construct a builder at the `Expect` level with the `msg`.
- #[rustc_lint_diagnostics]
- #[track_caller]
- pub fn struct_expect(
- &self,
- msg: impl Into,
- id: LintExpectationId,
- ) -> DiagnosticBuilder<'_, ()> {
- DiagnosticBuilder::new(self, Expect(id), msg)
- }
-
- /// Construct a builder at the `Error` level at the given `span` and with the `msg`.
- #[rustc_lint_diagnostics]
- #[track_caller]
- pub fn struct_span_err(
- &self,
- span: impl Into,
- msg: impl Into,
- ) -> DiagnosticBuilder<'_> {
- self.struct_err(msg).with_span(span)
- }
-
- /// Construct a builder at the `Error` level with the `msg`.
- // FIXME: This method should be removed (every error should have an associated error code).
- #[rustc_lint_diagnostics]
- #[track_caller]
- pub fn struct_err(&self, msg: impl Into) -> DiagnosticBuilder<'_> {
- DiagnosticBuilder::new(self, Error, msg)
- }
-
- /// Construct a builder at the `Fatal` level at the given `span` and with the `msg`.
- #[rustc_lint_diagnostics]
- #[track_caller]
- pub fn struct_span_fatal(
- &self,
- span: impl Into,
- msg: impl Into,
- ) -> DiagnosticBuilder<'_, FatalAbort> {
- self.struct_fatal(msg).with_span(span)
- }
-
- /// Construct a builder at the `Fatal` level with the `msg`.
- #[rustc_lint_diagnostics]
- #[track_caller]
- pub fn struct_fatal(
- &self,
- msg: impl Into,
- ) -> DiagnosticBuilder<'_, FatalAbort> {
- DiagnosticBuilder::new(self, Fatal, msg)
- }
-
- /// Construct a builder at the `Help` level with the `msg`.
- #[rustc_lint_diagnostics]
- pub fn struct_help(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> {
- DiagnosticBuilder::new(self, Help, msg)
- }
-
- /// Construct a builder at the `Note` level with the `msg`.
- #[rustc_lint_diagnostics]
- #[track_caller]
- pub fn struct_note(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> {
- DiagnosticBuilder::new(self, Note, msg)
- }
-
- /// Construct a builder at the `Bug` level with the `msg`.
- #[rustc_lint_diagnostics]
- #[track_caller]
- pub fn struct_bug(&self, msg: impl Into) -> DiagnosticBuilder<'_, BugAbort> {
- DiagnosticBuilder::new(self, Bug, msg)
- }
-
- /// Construct a builder at the `Bug` level at the given `span` with the `msg`.
- #[rustc_lint_diagnostics]
- #[track_caller]
- pub fn struct_span_bug(
- &self,
- span: impl Into,
- msg: impl Into,
- ) -> DiagnosticBuilder<'_, BugAbort> {
- self.struct_bug(msg).with_span(span)
- }
-
- #[rustc_lint_diagnostics]
- #[track_caller]
- pub fn span_fatal(&self, span: impl Into, msg: impl Into) -> ! {
- self.struct_span_fatal(span, msg).emit()
- }
-
- #[rustc_lint_diagnostics]
- #[track_caller]
- pub fn span_err(
- &self,
- span: impl Into,
- msg: impl Into,
- ) -> ErrorGuaranteed {
- self.struct_span_err(span, msg).emit()
- }
-
- #[rustc_lint_diagnostics]
- #[track_caller]
- pub fn span_warn(&self, span: impl Into, msg: impl Into) {
- self.struct_span_warn(span, msg).emit()
- }
-
- #[track_caller]
- pub fn span_bug(&self, span: impl Into, msg: impl Into) -> ! {
- self.struct_span_bug(span, msg).emit()
- }
-
- /// Ensures that compilation cannot succeed.
- ///
- /// If this function has been called but no errors have been emitted and
- /// compilation succeeds, it will cause an internal compiler error (ICE).
- ///
- /// This can be used in code paths that should never run on successful compilations.
- /// For example, it can be used to create an [`ErrorGuaranteed`]
- /// (but you should prefer threading through the [`ErrorGuaranteed`] from an error emission
- /// directly).
- #[track_caller]
- pub fn delayed_bug(&self, msg: impl Into) -> ErrorGuaranteed {
- DiagnosticBuilder::::new(self, DelayedBug, msg).emit()
- }
-
- /// Like `delayed_bug`, but takes an additional span.
- ///
- /// Note: this function used to be called `delay_span_bug`. It was renamed
- /// to match similar functions like `span_err`, `span_warn`, etc.
- #[track_caller]
- pub fn span_delayed_bug(
- &self,
- sp: impl Into,
- msg: impl Into,
- ) -> ErrorGuaranteed {
- DiagnosticBuilder::::new(self, DelayedBug, msg).with_span(sp).emit()
- }
-
- /// Ensures that a diagnostic is printed. See `Level::GoodPathDelayedBug`.
- pub fn good_path_delayed_bug(&self, msg: impl Into) {
- DiagnosticBuilder::<()>::new(self, GoodPathDelayedBug, msg).emit()
- }
-
- #[track_caller]
- #[rustc_lint_diagnostics]
- pub fn span_note(&self, span: impl Into, msg: impl Into) {
- self.struct_span_note(span, msg).emit()
- }
-
- #[track_caller]
- #[rustc_lint_diagnostics]
- pub fn struct_span_note(
- &self,
- span: impl Into,
- msg: impl Into,
- ) -> DiagnosticBuilder<'_, ()> {
- DiagnosticBuilder::new(self, Note, msg).with_span(span)
- }
-
- #[rustc_lint_diagnostics]
- pub fn fatal(&self, msg: impl Into) -> ! {
- self.struct_fatal(msg).emit()
- }
-
- #[rustc_lint_diagnostics]
- pub fn err(&self, msg: impl Into) -> ErrorGuaranteed {
- self.struct_err(msg).emit()
- }
-
- #[rustc_lint_diagnostics]
- pub fn warn(&self, msg: impl Into) {
- self.struct_warn(msg).emit()
- }
-
- #[rustc_lint_diagnostics]
- pub fn note(&self, msg: impl Into) {
- self.struct_note(msg).emit()
- }
-
- #[rustc_lint_diagnostics]
- pub fn bug(&self, msg: impl Into) -> ! {
- self.struct_bug(msg).emit()
- }
-
/// This excludes lint errors, delayed bugs, and stashed errors.
#[inline]
pub fn err_count(&self) -> usize {
- self.inner.borrow().err_count
+ self.inner.borrow().err_guars.len()
}
/// This excludes normal errors, lint errors and delayed bugs. Unless
@@ -946,36 +737,19 @@ impl DiagCtxt {
/// This excludes lint errors, delayed bugs, and stashed errors.
pub fn has_errors(&self) -> Option {
- self.inner.borrow().has_errors().then(|| {
- // FIXME(nnethercote) find a way to store an `ErrorGuaranteed`.
- #[allow(deprecated)]
- ErrorGuaranteed::unchecked_error_guaranteed()
- })
+ self.inner.borrow().has_errors()
}
/// This excludes delayed bugs and stashed errors. Unless absolutely
/// necessary, prefer `has_errors` to this method.
pub fn has_errors_or_lint_errors(&self) -> Option {
- let inner = self.inner.borrow();
- let result = inner.has_errors() || inner.lint_err_count > 0;
- result.then(|| {
- // FIXME(nnethercote) find a way to store an `ErrorGuaranteed`.
- #[allow(deprecated)]
- ErrorGuaranteed::unchecked_error_guaranteed()
- })
+ self.inner.borrow().has_errors_or_lint_errors()
}
/// This excludes stashed errors. Unless absolutely necessary, prefer
/// `has_errors` or `has_errors_or_lint_errors` to this method.
pub fn has_errors_or_lint_errors_or_delayed_bugs(&self) -> Option {
- let inner = self.inner.borrow();
- let result =
- inner.has_errors() || inner.lint_err_count > 0 || !inner.delayed_bugs.is_empty();
- result.then(|| {
- // FIXME(nnethercote) find a way to store an `ErrorGuaranteed`.
- #[allow(deprecated)]
- ErrorGuaranteed::unchecked_error_guaranteed()
- })
+ self.inner.borrow().has_errors_or_lint_errors_or_delayed_bugs()
}
pub fn print_error_count(&self, registry: &Registry) {
@@ -1008,10 +782,10 @@ impl DiagCtxt {
.emit_diagnostic(Diagnostic::new(Warning, DiagnosticMessage::Str(warnings)));
}
(_, 0) => {
- inner.emit_diagnostic(Diagnostic::new(Fatal, errors));
+ inner.emit_diagnostic(Diagnostic::new(Error, errors));
}
(_, _) => {
- inner.emit_diagnostic(Diagnostic::new(Fatal, format!("{errors}; {warnings}")));
+ inner.emit_diagnostic(Diagnostic::new(Error, format!("{errors}; {warnings}")));
}
}
@@ -1055,7 +829,7 @@ impl DiagCtxt {
pub fn abort_if_errors(&self) {
let mut inner = self.inner.borrow_mut();
inner.emit_stashed_diagnostics();
- if inner.has_errors() {
+ if !inner.err_guars.is_empty() {
FatalError.raise();
}
}
@@ -1077,84 +851,6 @@ impl DiagCtxt {
self.inner.borrow_mut().emit_diagnostic(diagnostic)
}
- #[track_caller]
- pub fn emit_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> ErrorGuaranteed {
- self.create_err(err).emit()
- }
-
- #[track_caller]
- pub fn create_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> DiagnosticBuilder<'a> {
- err.into_diagnostic(self, Error)
- }
-
- #[track_caller]
- pub fn create_warn<'a>(
- &'a self,
- warning: impl IntoDiagnostic<'a, ()>,
- ) -> DiagnosticBuilder<'a, ()> {
- warning.into_diagnostic(self, Warning)
- }
-
- #[track_caller]
- pub fn emit_warn<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) {
- self.create_warn(warning).emit()
- }
-
- #[track_caller]
- pub fn create_almost_fatal<'a>(
- &'a self,
- fatal: impl IntoDiagnostic<'a, FatalError>,
- ) -> DiagnosticBuilder<'a, FatalError> {
- fatal.into_diagnostic(self, Fatal)
- }
-
- #[track_caller]
- pub fn emit_almost_fatal<'a>(
- &'a self,
- fatal: impl IntoDiagnostic<'a, FatalError>,
- ) -> FatalError {
- self.create_almost_fatal(fatal).emit()
- }
-
- #[track_caller]
- pub fn create_fatal<'a>(
- &'a self,
- fatal: impl IntoDiagnostic<'a, FatalAbort>,
- ) -> DiagnosticBuilder<'a, FatalAbort> {
- fatal.into_diagnostic(self, Fatal)
- }
-
- #[track_caller]
- pub fn emit_fatal<'a>(&'a self, fatal: impl IntoDiagnostic<'a, FatalAbort>) -> ! {
- self.create_fatal(fatal).emit()
- }
-
- #[track_caller]
- pub fn create_bug<'a>(
- &'a self,
- bug: impl IntoDiagnostic<'a, BugAbort>,
- ) -> DiagnosticBuilder<'a, BugAbort> {
- bug.into_diagnostic(self, Bug)
- }
-
- #[track_caller]
- pub fn emit_bug<'a>(&'a self, bug: impl IntoDiagnostic<'a, diagnostic_builder::BugAbort>) -> ! {
- self.create_bug(bug).emit()
- }
-
- #[track_caller]
- pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, ()>) {
- self.create_note(note).emit()
- }
-
- #[track_caller]
- pub fn create_note<'a>(
- &'a self,
- note: impl IntoDiagnostic<'a, ()>,
- ) -> DiagnosticBuilder<'a, ()> {
- note.into_diagnostic(self, Note)
- }
-
pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) {
self.inner.borrow_mut().emitter.emit_artifact_notification(path, artifact_type);
}
@@ -1175,8 +871,21 @@ impl DiagCtxt {
) {
let mut inner = self.inner.borrow_mut();
+ // This "error" is an odd duck.
+ // - It's only produce with JSON output.
+ // - It's not emitted the usual way, via `emit_diagnostic`.
+ // - The `$message_type` field is "unused_externs" rather than the usual
+ // "diagnosic".
+ //
+ // We count it as a lint error because it has a lint level. The value
+ // of `loud` (which comes from "unused-externs" or
+ // "unused-externs-silent"), also affects whether it's treated like a
+ // hard error or not.
if loud && lint_level.is_error() {
- inner.lint_err_count += 1;
+ // This `unchecked_error_guaranteed` is valid. It is where the
+ // `ErrorGuaranteed` for unused_extern errors originates.
+ #[allow(deprecated)]
+ inner.lint_err_guars.push(ErrorGuaranteed::unchecked_error_guaranteed());
inner.panic_if_treat_err_as_bug();
}
@@ -1229,6 +938,288 @@ impl DiagCtxt {
}
}
+// This `impl` block contains only the public diagnostic creation/emission API.
+//
+// Functions beginning with `struct_`/`create_` create a diagnostic. Other
+// functions create and emit a diagnostic all in one go.
+impl DiagCtxt {
+ // No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing.
+ #[track_caller]
+ pub fn struct_bug(&self, msg: impl Into) -> DiagnosticBuilder<'_, BugAbort> {
+ DiagnosticBuilder::new(self, Bug, msg)
+ }
+
+ // No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing.
+ #[track_caller]
+ pub fn bug(&self, msg: impl Into) -> ! {
+ self.struct_bug(msg).emit()
+ }
+
+ // No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing.
+ #[track_caller]
+ pub fn struct_span_bug(
+ &self,
+ span: impl Into,
+ msg: impl Into,
+ ) -> DiagnosticBuilder<'_, BugAbort> {
+ self.struct_bug(msg).with_span(span)
+ }
+
+ // No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing.
+ #[track_caller]
+ pub fn span_bug(&self, span: impl Into, msg: impl Into) -> ! {
+ self.struct_span_bug(span, msg).emit()
+ }
+
+ #[track_caller]
+ pub fn create_bug<'a>(
+ &'a self,
+ bug: impl IntoDiagnostic<'a, BugAbort>,
+ ) -> DiagnosticBuilder<'a, BugAbort> {
+ bug.into_diagnostic(self, Bug)
+ }
+
+ #[track_caller]
+ pub fn emit_bug<'a>(&'a self, bug: impl IntoDiagnostic<'a, BugAbort>) -> ! {
+ self.create_bug(bug).emit()
+ }
+
+ #[rustc_lint_diagnostics]
+ #[track_caller]
+ pub fn struct_fatal(
+ &self,
+ msg: impl Into,
+ ) -> DiagnosticBuilder<'_, FatalAbort> {
+ DiagnosticBuilder::new(self, Fatal, msg)
+ }
+
+ #[rustc_lint_diagnostics]
+ #[track_caller]
+ pub fn fatal(&self, msg: impl Into) -> ! {
+ self.struct_fatal(msg).emit()
+ }
+
+ #[rustc_lint_diagnostics]
+ #[track_caller]
+ pub fn struct_span_fatal(
+ &self,
+ span: impl Into,
+ msg: impl Into,
+ ) -> DiagnosticBuilder<'_, FatalAbort> {
+ self.struct_fatal(msg).with_span(span)
+ }
+
+ #[rustc_lint_diagnostics]
+ #[track_caller]
+ pub fn span_fatal(&self, span: impl Into, msg: impl Into) -> ! {
+ self.struct_span_fatal(span, msg).emit()
+ }
+
+ #[track_caller]
+ pub fn create_fatal<'a>(
+ &'a self,
+ fatal: impl IntoDiagnostic<'a, FatalAbort>,
+ ) -> DiagnosticBuilder<'a, FatalAbort> {
+ fatal.into_diagnostic(self, Fatal)
+ }
+
+ #[track_caller]
+ pub fn emit_fatal<'a>(&'a self, fatal: impl IntoDiagnostic<'a, FatalAbort>) -> ! {
+ self.create_fatal(fatal).emit()
+ }
+
+ #[track_caller]
+ pub fn create_almost_fatal<'a>(
+ &'a self,
+ fatal: impl IntoDiagnostic<'a, FatalError>,
+ ) -> DiagnosticBuilder<'a, FatalError> {
+ fatal.into_diagnostic(self, Fatal)
+ }
+
+ #[track_caller]
+ pub fn emit_almost_fatal<'a>(
+ &'a self,
+ fatal: impl IntoDiagnostic<'a, FatalError>,
+ ) -> FatalError {
+ self.create_almost_fatal(fatal).emit()
+ }
+
+ // FIXME: This method should be removed (every error should have an associated error code).
+ #[rustc_lint_diagnostics]
+ #[track_caller]
+ pub fn struct_err(&self, msg: impl Into) -> DiagnosticBuilder<'_> {
+ DiagnosticBuilder::new(self, Error, msg)
+ }
+
+ #[rustc_lint_diagnostics]
+ #[track_caller]
+ pub fn err(&self, msg: impl Into) -> ErrorGuaranteed {
+ self.struct_err(msg).emit()
+ }
+
+ #[rustc_lint_diagnostics]
+ #[track_caller]
+ pub fn struct_span_err(
+ &self,
+ span: impl Into,
+ msg: impl Into,
+ ) -> DiagnosticBuilder<'_> {
+ self.struct_err(msg).with_span(span)
+ }
+
+ #[rustc_lint_diagnostics]
+ #[track_caller]
+ pub fn span_err(
+ &self,
+ span: impl Into,
+ msg: impl Into,
+ ) -> ErrorGuaranteed {
+ self.struct_span_err(span, msg).emit()
+ }
+
+ #[track_caller]
+ pub fn create_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> DiagnosticBuilder<'a> {
+ err.into_diagnostic(self, Error)
+ }
+
+ #[track_caller]
+ pub fn emit_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> ErrorGuaranteed {
+ self.create_err(err).emit()
+ }
+
+ /// Ensures that an error is printed. See `Level::DelayedBug`.
+ // No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing.
+ #[track_caller]
+ pub fn delayed_bug(&self, msg: impl Into) -> ErrorGuaranteed {
+ DiagnosticBuilder::::new(self, DelayedBug, msg).emit()
+ }
+
+ /// Ensures that an error is printed. See `Level::DelayedBug`.
+ ///
+ /// Note: this function used to be called `delay_span_bug`. It was renamed
+ /// to match similar functions like `span_err`, `span_warn`, etc.
+ // No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing.
+ #[track_caller]
+ pub fn span_delayed_bug(
+ &self,
+ sp: impl Into,
+ msg: impl Into,
+ ) -> ErrorGuaranteed {
+ DiagnosticBuilder::::new(self, DelayedBug, msg).with_span(sp).emit()
+ }
+
+ /// Ensures that a diagnostic is printed. See `Level::GoodPathDelayedBug`.
+ // No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing.
+ #[track_caller]
+ pub fn good_path_delayed_bug(&self, msg: impl Into) {
+ DiagnosticBuilder::<()>::new(self, GoodPathDelayedBug, msg).emit()
+ }
+
+ #[rustc_lint_diagnostics]
+ #[track_caller]
+ pub fn struct_warn(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> {
+ DiagnosticBuilder::new(self, Warning, msg)
+ }
+
+ #[rustc_lint_diagnostics]
+ #[track_caller]
+ pub fn warn(&self, msg: impl Into) {
+ self.struct_warn(msg).emit()
+ }
+
+ #[rustc_lint_diagnostics]
+ #[track_caller]
+ pub fn struct_span_warn(
+ &self,
+ span: impl Into,
+ msg: impl Into,
+ ) -> DiagnosticBuilder<'_, ()> {
+ self.struct_warn(msg).with_span(span)
+ }
+
+ #[rustc_lint_diagnostics]
+ #[track_caller]
+ pub fn span_warn(&self, span: impl Into, msg: impl Into) {
+ self.struct_span_warn(span, msg).emit()
+ }
+
+ #[track_caller]
+ pub fn create_warn<'a>(
+ &'a self,
+ warning: impl IntoDiagnostic<'a, ()>,
+ ) -> DiagnosticBuilder<'a, ()> {
+ warning.into_diagnostic(self, Warning)
+ }
+
+ #[track_caller]
+ pub fn emit_warn<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) {
+ self.create_warn(warning).emit()
+ }
+
+ #[rustc_lint_diagnostics]
+ #[track_caller]
+ pub fn struct_note(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> {
+ DiagnosticBuilder::new(self, Note, msg)
+ }
+
+ #[rustc_lint_diagnostics]
+ #[track_caller]
+ pub fn note(&self, msg: impl Into) {
+ self.struct_note(msg).emit()
+ }
+
+ #[rustc_lint_diagnostics]
+ #[track_caller]
+ pub fn struct_span_note(
+ &self,
+ span: impl Into,
+ msg: impl Into,
+ ) -> DiagnosticBuilder<'_, ()> {
+ DiagnosticBuilder::new(self, Note, msg).with_span(span)
+ }
+
+ #[rustc_lint_diagnostics]
+ #[track_caller]
+ pub fn span_note(&self, span: impl Into, msg: impl Into) {
+ self.struct_span_note(span, msg).emit()
+ }
+
+ #[track_caller]
+ pub fn create_note<'a>(
+ &'a self,
+ note: impl IntoDiagnostic<'a, ()>,
+ ) -> DiagnosticBuilder<'a, ()> {
+ note.into_diagnostic(self, Note)
+ }
+
+ #[track_caller]
+ pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, ()>) {
+ self.create_note(note).emit()
+ }
+
+ #[rustc_lint_diagnostics]
+ #[track_caller]
+ pub fn struct_help(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> {
+ DiagnosticBuilder::new(self, Help, msg)
+ }
+
+ #[rustc_lint_diagnostics]
+ #[track_caller]
+ pub fn struct_allow(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> {
+ DiagnosticBuilder::new(self, Allow, msg)
+ }
+
+ #[rustc_lint_diagnostics]
+ #[track_caller]
+ pub fn struct_expect(
+ &self,
+ msg: impl Into,
+ id: LintExpectationId,
+ ) -> DiagnosticBuilder<'_, ()> {
+ DiagnosticBuilder::new(self, Expect(id), msg)
+ }
+}
+
// Note: we prefer implementing operations on `DiagCtxt`, rather than
// `DiagCtxtInner`, whenever possible. This minimizes functions where
// `DiagCtxt::foo()` just borrows `inner` and forwards a call to
@@ -1236,7 +1227,7 @@ impl DiagCtxt {
impl DiagCtxtInner {
/// Emit all stashed diagnostics.
fn emit_stashed_diagnostics(&mut self) {
- let has_errors = self.has_errors();
+ let has_errors = !self.err_guars.is_empty();
for (_, diag) in std::mem::take(&mut self.stashed_diagnostics).into_iter() {
// Decrement the count tracking the stash; emitting will increment it.
if diag.is_error() {
@@ -1298,9 +1289,13 @@ impl DiagCtxtInner {
// when an error is first emitted, also), but maybe there's a case
// in which that's not sound? otherwise this is really inefficient.
let backtrace = std::backtrace::Backtrace::capture();
- self.delayed_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace));
+ // This `unchecked_error_guaranteed` is valid. It is where the
+ // `ErrorGuaranteed` for delayed bugs originates.
#[allow(deprecated)]
- return Some(ErrorGuaranteed::unchecked_error_guaranteed());
+ let guar = ErrorGuaranteed::unchecked_error_guaranteed();
+ self.delayed_bugs
+ .push((DelayedDiagnostic::with_backtrace(diagnostic, backtrace), guar));
+ return Some(guar);
}
GoodPathDelayedBug => {
let backtrace = std::backtrace::Backtrace::capture();
@@ -1334,7 +1329,6 @@ impl DiagCtxtInner {
!self.emitted_diagnostics.insert(diagnostic_hash)
};
- let level = diagnostic.level;
let is_error = diagnostic.is_error();
let is_lint = diagnostic.is_lint.is_some();
@@ -1373,36 +1367,47 @@ impl DiagCtxtInner {
}
if is_error {
+ // This `unchecked_error_guaranteed` is valid. It is where the
+ // `ErrorGuaranteed` for errors and lint errors originates.
+ #[allow(deprecated)]
+ let guar = ErrorGuaranteed::unchecked_error_guaranteed();
+ guaranteed = Some(guar);
if is_lint {
- self.lint_err_count += 1;
+ self.lint_err_guars.push(guar);
} else {
- self.err_count += 1;
+ self.err_guars.push(guar);
}
self.panic_if_treat_err_as_bug();
}
-
- #[allow(deprecated)]
- if level == Level::Error {
- guaranteed = Some(ErrorGuaranteed::unchecked_error_guaranteed());
- }
});
guaranteed
}
fn treat_err_as_bug(&self) -> bool {
- self.flags.treat_err_as_bug.is_some_and(|c| self.err_count + self.lint_err_count >= c.get())
+ self.flags
+ .treat_err_as_bug
+ .is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() >= c.get())
}
// Use this one before incrementing `err_count`.
fn treat_next_err_as_bug(&self) -> bool {
self.flags
.treat_err_as_bug
- .is_some_and(|c| self.err_count + self.lint_err_count + 1 >= c.get())
+ .is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() + 1 >= c.get())
}
- fn has_errors(&self) -> bool {
- self.err_count > 0
+ fn has_errors(&self) -> Option {
+ self.err_guars.get(0).copied()
+ }
+
+ fn has_errors_or_lint_errors(&self) -> Option {
+ self.has_errors().or_else(|| self.lint_err_guars.get(0).copied())
+ }
+
+ fn has_errors_or_lint_errors_or_delayed_bugs(&self) -> Option {
+ self.has_errors_or_lint_errors()
+ .or_else(|| self.delayed_bugs.get(0).map(|(_, guar)| guar).copied())
}
fn failure_note(&mut self, msg: impl Into) {
@@ -1412,7 +1417,7 @@ impl DiagCtxtInner {
fn flush_delayed(&mut self, kind: DelayedBugKind) {
let (bugs, note1) = match kind {
DelayedBugKind::Normal => (
- std::mem::take(&mut self.delayed_bugs),
+ std::mem::take(&mut self.delayed_bugs).into_iter().map(|(b, _)| b).collect(),
"no errors encountered even though delayed bugs were created",
),
DelayedBugKind::GoodPath => (
@@ -1434,7 +1439,7 @@ impl DiagCtxtInner {
{
let _ = write!(
&mut out,
- "delayed span bug: {}\n{}\n",
+ "delayed bug: {}\n{}\n",
bug.inner
.messages
.iter()
@@ -1477,7 +1482,7 @@ impl DiagCtxtInner {
fn panic_if_treat_err_as_bug(&self) {
if self.treat_err_as_bug() {
let n = self.flags.treat_err_as_bug.map(|c| c.get()).unwrap();
- assert_eq!(n, self.err_count + self.lint_err_count);
+ assert_eq!(n, self.err_guars.len() + self.lint_err_guars.len());
if n == 1 {
panic!("aborting due to `-Z treat-err-as-bug=1`");
} else {
@@ -1584,6 +1589,7 @@ pub enum Level {
ForceWarning(Option),
/// A warning about the code being compiled. Does not prevent compilation from finishing.
+ /// Will be skipped if `can_emit_warnings` is false.
Warning,
/// A message giving additional context.
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 019cc1c847e9..6aedd2a5e334 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -806,7 +806,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_attr!(TEST, rustc_regions, Normal, template!(Word), WarnFollowing),
rustc_attr!(
TEST, rustc_error, Normal,
- template!(Word, List: "span_delayed_bug_from_inside_query"), WarnFollowingWordOnly
+ template!(Word, List: "delayed_bug_from_inside_query"), WarnFollowingWordOnly
),
rustc_attr!(TEST, rustc_dump_user_args, Normal, template!(Word), WarnFollowing),
rustc_attr!(TEST, rustc_evaluate_where_clauses, Normal, template!(Word), WarnFollowing),
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index efb0b1fbabbc..9012b731a132 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -301,9 +301,11 @@ declare_features! (
(unstable, csky_target_feature, "1.73.0", Some(44839)),
(unstable, ermsb_target_feature, "1.49.0", Some(44839)),
(unstable, hexagon_target_feature, "1.27.0", Some(44839)),
+ (unstable, lahfsahf_target_feature, "CURRENT_RUSTC_VERSION", Some(44839)),
(unstable, loongarch_target_feature, "1.73.0", Some(44839)),
(unstable, mips_target_feature, "1.27.0", Some(44839)),
(unstable, powerpc_target_feature, "1.27.0", Some(44839)),
+ (unstable, prfchw_target_feature, "CURRENT_RUSTC_VERSION", Some(44839)),
(unstable, riscv_target_feature, "1.45.0", Some(44839)),
(unstable, rtm_target_feature, "1.35.0", Some(44839)),
(unstable, sse4a_target_feature, "1.27.0", Some(44839)),
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index 81ec7ddb629e..23943ee28e2e 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -8,6 +8,7 @@ use rustc_data_structures::unord::UnordMap;
use rustc_macros::HashStable_Generic;
use rustc_span::def_id::{DefId, LocalDefId};
use rustc_span::hygiene::MacroKind;
+use rustc_span::symbol::kw;
use rustc_span::Symbol;
use std::array::IntoIter;
@@ -115,6 +116,12 @@ pub enum DefKind {
Impl {
of_trait: bool,
},
+ /// A closure, coroutine, or coroutine-closure.
+ ///
+ /// These are all represented with the same `ExprKind::Closure` in the AST and HIR,
+ /// which makes it difficult to distinguish these during def collection. Therefore,
+ /// we treat them all the same, and code which needs to distinguish them can match
+ /// or `hir::ClosureKind` or `type_of`.
Closure,
}
@@ -225,6 +232,7 @@ impl DefKind {
pub fn def_path_data(self, name: Symbol) -> DefPathData {
match self {
+ DefKind::Struct | DefKind::Union if name == kw::Empty => DefPathData::AnonAdt,
DefKind::Mod
| DefKind::Struct
| DefKind::Union
diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs
index 9fb1fc19bf4e..b81ad8b19462 100644
--- a/compiler/rustc_hir/src/definitions.rs
+++ b/compiler/rustc_hir/src/definitions.rs
@@ -287,6 +287,8 @@ pub enum DefPathData {
/// An existential `impl Trait` type node.
/// Argument position `impl Trait` have a `TypeNs` with their pretty-printed name.
OpaqueTy,
+ /// An anonymous struct or union type i.e. `struct { foo: Type }` or `union { bar: Type }`
+ AnonAdt,
}
impl Definitions {
@@ -409,8 +411,9 @@ impl DefPathData {
match *self {
TypeNs(name) if name == kw::Empty => None,
TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => Some(name),
+
Impl | ForeignMod | CrateRoot | Use | GlobalAsm | Closure | Ctor | AnonConst
- | OpaqueTy => None,
+ | OpaqueTy | AnonAdt => None,
}
}
@@ -431,6 +434,7 @@ impl DefPathData {
Ctor => DefPathDataName::Anon { namespace: sym::constructor },
AnonConst => DefPathDataName::Anon { namespace: sym::constant },
OpaqueTy => DefPathDataName::Anon { namespace: sym::opaque },
+ AnonAdt => DefPathDataName::Anon { namespace: sym::anon_adt },
}
}
}
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index a7a1c69b9bed..77044df9a409 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2536,7 +2536,7 @@ pub struct OpaqueTy<'hir> {
/// lifetimes that are captured from the function signature they originate from.
///
/// This is done by generating a new early-bound lifetime parameter local to the
- /// opaque which is substituted in the function signature with the late-bound
+ /// opaque which is instantiated in the function signature with the late-bound
/// lifetime.
///
/// This mapping associated a captured lifetime (first parameter) with the new
@@ -2587,6 +2587,8 @@ pub enum TyKind<'hir> {
Never,
/// A tuple (`(A, B, C, D, ...)`).
Tup(&'hir [Ty<'hir>]),
+ /// An anonymous struct or union type i.e. `struct { foo: Type }` or `union { foo: Type }`
+ AnonAdt(ItemId),
/// A path to a type definition (`module::module::...::Type`), or an
/// associated type (e.g., ` as Trait>::Type` or `::Target`).
///
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 52e1109ff921..e9337dd3586e 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -852,6 +852,9 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) {
}
TyKind::Typeof(ref expression) => visitor.visit_anon_const(expression),
TyKind::Infer | TyKind::InferDelegation(..) | TyKind::Err(_) => {}
+ TyKind::AnonAdt(item_id) => {
+ visitor.visit_nested_item(item_id);
+ }
}
}
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index d6f604c180bf..a61cfd0e4ce9 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -123,6 +123,28 @@ hir_analysis_field_already_declared =
.label = field already declared
.previous_decl_label = `{$field_name}` first declared here
+hir_analysis_field_already_declared_both_nested =
+ field `{$field_name}` is already declared
+ .label = field `{$field_name}` declared in this unnamed field
+ .nested_field_decl_note = field `{$field_name}` declared here
+ .previous_decl_label = `{$field_name}` first declared here in this unnamed field
+ .previous_nested_field_decl_note = field `{$field_name}` first declared here
+
+hir_analysis_field_already_declared_current_nested =
+ field `{$field_name}` is already declared
+ .label = field `{$field_name}` declared in this unnamed field
+ .nested_field_decl_note = field `{$field_name}` declared here
+ .previous_decl_label = `{$field_name}` first declared here
+
+hir_analysis_field_already_declared_nested_help =
+ fields from the type of this unnamed field are considered fields of the outer type
+
+hir_analysis_field_already_declared_previous_nested =
+ field `{$field_name}` is already declared
+ .label = field already declared
+ .previous_decl_label = `{$field_name}` first declared here in this unnamed field
+ .previous_nested_field_decl_note = field `{$field_name}` first declared here
+
hir_analysis_function_not_found_in_trait = function not found in this trait
hir_analysis_function_not_have_default_implementation = function doesn't have a default implementation
@@ -131,6 +153,8 @@ hir_analysis_function_not_have_default_implementation = function doesn't have a
hir_analysis_functions_names_duplicated = functions names are duplicated
.note = all `#[rustc_must_implement_one_of]` arguments must be unique
+hir_analysis_generic_args_on_overridden_impl = could not resolve generic parameters on overridden impl
+
hir_analysis_impl_not_marked_default = `{$ident}` specializes an item from a parent `impl`, but that item is not marked `default`
.label = cannot specialize default item `{$ident}`
.ok_label = parent `impl` is here
@@ -365,8 +389,6 @@ hir_analysis_static_mut_ref_lint = {$shared}reference of mutable static is disco
hir_analysis_static_specialize = cannot specialize on `'static` lifetime
-hir_analysis_substs_on_overridden_impl = could not resolve substs on overridden impl
-
hir_analysis_tait_forward_compat = item constrains opaque type that is not in its signature
.note = this item must mention the opaque type in its signature in order to be able to register hidden types
@@ -420,6 +442,19 @@ hir_analysis_typeof_reserved_keyword_used =
hir_analysis_unconstrained_opaque_type = unconstrained opaque type
.note = `{$name}` must be used in combination with a concrete type within the same {$what}
+hir_analysis_unnamed_fields_repr_field_defined = unnamed field defined here
+
+hir_analysis_unnamed_fields_repr_field_missing_repr_c =
+ named type of unnamed field must have `#[repr(C)]` representation
+ .label = unnamed field defined here
+ .field_ty_label = `{$field_ty}` defined here
+ .suggestion = add `#[repr(C)]` to this {$field_adt_kind}
+
+hir_analysis_unnamed_fields_repr_missing_repr_c =
+ {$adt_kind} with unnamed fields must have `#[repr(C)]` representation
+ .label = {$adt_kind} `{$adt_name}` defined here
+ .suggestion = add `#[repr(C)]` to this {$adt_kind}
+
hir_analysis_unrecognized_atomic_operation =
unrecognized atomic operation function: `{$op}`
.label = unrecognized atomic operation
diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
index 1ae267d1a405..7157382c883e 100644
--- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
@@ -336,12 +336,12 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
let projection_ty = if let ty::AssocKind::Fn = assoc_kind {
let mut emitted_bad_param_err = None;
- // If we have an method return type bound, then we need to substitute
+ // If we have an method return type bound, then we need to instantiate
// the method's early bound params with suitable late-bound params.
let mut num_bound_vars = candidate.bound_vars().len();
let args =
candidate.skip_binder().args.extend_to(tcx, assoc_item.def_id, |param, _| {
- let subst = match param.kind {
+ let arg = match param.kind {
ty::GenericParamDefKind::Lifetime => ty::Region::new_bound(
tcx,
ty::INNERMOST,
@@ -379,7 +379,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
}
};
num_bound_vars += 1;
- subst
+ arg
});
// Next, we need to check that the return-type notation is being used on
@@ -402,12 +402,13 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
// Finally, move the fn return type's bound vars over to account for the early bound
// params (and trait ref's late bound params). This logic is very similar to
- // `Predicate::subst_supertrait`, and it's no coincidence why.
+ // `rustc_middle::ty::predicate::Clause::instantiate_supertrait`
+ // and it's no coincidence why.
let shifted_output = tcx.shift_bound_var_indices(num_bound_vars, output);
- let subst_output = ty::EarlyBinder::bind(shifted_output).instantiate(tcx, args);
+ let instantiation_output = ty::EarlyBinder::bind(shifted_output).instantiate(tcx, args);
let bound_vars = tcx.late_bound_vars(binding.hir_id);
- ty::Binder::bind_with_vars(subst_output, bound_vars)
+ ty::Binder::bind_with_vars(instantiation_output, bound_vars)
} else {
// Append the generic arguments of the associated type to the `trait_ref`.
candidate.map_bound(|trait_ref| {
diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs
index aa826c1f2680..614e5f9d32b7 100644
--- a/compiler/rustc_hir_analysis/src/astconv/generics.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs
@@ -1,6 +1,6 @@
use super::IsMethodCall;
use crate::astconv::{
- errors::prohibit_assoc_ty_binding, CreateSubstsForGenericArgsCtxt, ExplicitLateBound,
+ errors::prohibit_assoc_ty_binding, CreateInstantiationsForGenericArgsCtxt, ExplicitLateBound,
GenericArgCountMismatch, GenericArgCountResult, GenericArgPosition,
};
use crate::structured_errors::{GenericArgsInfo, StructuredDiagnostic, WrongNumberOfGenericArgs};
@@ -177,9 +177,9 @@ pub fn create_args_for_parent_generic_args<'tcx: 'a, 'a>(
has_self: bool,
self_ty: Option>,
arg_count: &GenericArgCountResult,
- ctx: &mut impl CreateSubstsForGenericArgsCtxt<'a, 'tcx>,
+ ctx: &mut impl CreateInstantiationsForGenericArgsCtxt<'a, 'tcx>,
) -> GenericArgsRef<'tcx> {
- // Collect the segments of the path; we need to substitute arguments
+ // Collect the segments of the path; we need to instantiate arguments
// for parameters throughout the entire path (wherever there are
// generic parameters).
let mut parent_defs = tcx.generics_of(def_id);
@@ -191,7 +191,7 @@ pub fn create_args_for_parent_generic_args<'tcx: 'a, 'a>(
}
// We manually build up the generic arguments, rather than using convenience
- // methods in `subst.rs`, so that we can iterate over the arguments and
+ // methods in `rustc_middle/src/ty/generic_args.rs`, so that we can iterate over the arguments and
// parameters in lock-step linearly, instead of trying to match each pair.
let mut args: SmallVec<[ty::GenericArg<'tcx>; 8]> = SmallVec::with_capacity(count);
// Iterate over each segment of the path.
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 1ae3ebaebbbb..a001044c3e52 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -214,7 +214,7 @@ pub struct GenericArgCountResult {
pub correct: Result<(), GenericArgCountMismatch>,
}
-pub trait CreateSubstsForGenericArgsCtxt<'a, 'tcx> {
+pub trait CreateInstantiationsForGenericArgsCtxt<'a, 'tcx> {
fn args_for_def_id(&mut self, def_id: DefId) -> (Option<&'a GenericArgs<'tcx>>, bool);
fn provided_kind(
@@ -366,8 +366,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
if generics.has_self {
if generics.parent.is_some() {
- // The parent is a trait so it should have at least one subst
- // for the `Self` type.
+ // The parent is a trait so it should have at least one
+ // generic parameter for the `Self` type.
assert!(!parent_args.is_empty())
} else {
// This item (presumably a trait) needs a self-type.
@@ -402,7 +402,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
return (tcx.mk_args(parent_args), arg_count);
}
- struct SubstsForAstPathCtxt<'a, 'tcx> {
+ struct InstantiationsForAstPathCtxt<'a, 'tcx> {
astconv: &'a (dyn AstConv<'tcx> + 'a),
def_id: DefId,
generic_args: &'a GenericArgs<'tcx>,
@@ -411,7 +411,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
infer_args: bool,
}
- impl<'a, 'tcx> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for SubstsForAstPathCtxt<'a, 'tcx> {
+ impl<'a, 'tcx> CreateInstantiationsForGenericArgsCtxt<'a, 'tcx>
+ for InstantiationsForAstPathCtxt<'a, 'tcx>
+ {
fn args_for_def_id(&mut self, did: DefId) -> (Option<&'a GenericArgs<'tcx>>, bool) {
if did == self.def_id {
(Some(self.generic_args), self.infer_args)
@@ -556,7 +558,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
}
- let mut args_ctx = SubstsForAstPathCtxt {
+ let mut args_ctx = InstantiationsForAstPathCtxt {
astconv: self,
def_id,
span,
@@ -1671,9 +1673,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.is_accessible_from(self.item_def_id(), tcx)
&& tcx.all_impls(*trait_def_id)
.any(|impl_def_id| {
- let trait_ref = tcx.impl_trait_ref(impl_def_id);
- trait_ref.is_some_and(|trait_ref| {
- let impl_ = trait_ref.instantiate(
+ let impl_header = tcx.impl_trait_header(impl_def_id);
+ impl_header.is_some_and(|header| {
+ let header = header.instantiate(
tcx,
infcx.fresh_args_for_item(DUMMY_SP, impl_def_id),
);
@@ -1685,11 +1687,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
infcx
.can_eq(
ty::ParamEnv::empty(),
- impl_.self_ty(),
+ header.trait_ref.self_ty(),
value,
- )
+ ) && header.polarity != ty::ImplPolarity::Negative
})
- && tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative
})
})
.map(|trait_def_id| tcx.def_path_str(trait_def_id))
@@ -1735,13 +1736,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
} else {
// Find all the types that have an `impl` for the trait.
tcx.all_impls(trait_def_id)
- .filter(|impl_def_id| {
+ .filter_map(|impl_def_id| tcx.impl_trait_header(impl_def_id))
+ .filter(|header| {
// Consider only accessible traits
tcx.visibility(trait_def_id).is_accessible_from(self.item_def_id(), tcx)
- && tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative
+ && header.skip_binder().polarity != ty::ImplPolarity::Negative
})
- .filter_map(|impl_def_id| tcx.impl_trait_ref(impl_def_id))
- .map(|impl_| impl_.instantiate_identity().self_ty())
+ .map(|header| header.instantiate_identity().trait_ref.self_ty())
// We don't care about blanket impls.
.filter(|self_ty| !self_ty.has_non_region_param())
.map(|self_ty| tcx.erase_regions(self_ty).to_string())
@@ -2412,8 +2413,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let self_ty = self.tcx().type_of(parent).instantiate_identity();
let generic_self_ty = ty::GenericArg::from(self_ty);
- let substs = self.tcx().mk_args_from_iter(std::iter::once(generic_self_ty));
- sig.instantiate(self.tcx(), substs)
+ let args = self.tcx().mk_args_from_iter(std::iter::once(generic_self_ty));
+ sig.instantiate(self.tcx(), args)
} else {
sig.instantiate_identity()
};
@@ -2457,6 +2458,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
hir::TyKind::Tup(fields) => {
Ty::new_tup_from_iter(tcx, fields.iter().map(|t| self.ast_ty_to_ty(t)))
}
+ hir::TyKind::AnonAdt(item_id) => {
+ let did = item_id.owner_id.def_id;
+ let adt_def = tcx.adt_def(did);
+ let generics = tcx.generics_of(did);
+
+ debug!("ast_ty_to_ty_inner(AnonAdt): generics={:?}", generics);
+ let args = ty::GenericArgs::for_item(tcx, did.to_def_id(), |param, _| {
+ tcx.mk_param_from_def(param)
+ });
+ debug!("ast_ty_to_ty_inner(AnonAdt): args={:?}", args);
+
+ Ty::new_adt(tcx, adt_def, tcx.mk_args(args))
+ }
hir::TyKind::BareFn(bf) => {
require_c_abi_if_c_variadic(tcx, bf.decl, bf.abi, ast_ty.span);
diff --git a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs
index 2d85ad5789ec..cbbf560076e2 100644
--- a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs
@@ -175,7 +175,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => {
let pred = bound_predicate.rebind(pred);
- // A `Self` within the original bound will be substituted with a
+ // A `Self` within the original bound will be instantiated with a
// `trait_object_dummy_self`, so check for that.
let references_self = match pred.skip_binder().term.unpack() {
ty::TermKind::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()),
diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs
index 5bc904e5930c..f2ceb4702643 100644
--- a/compiler/rustc_hir_analysis/src/autoderef.rs
+++ b/compiler/rustc_hir_analysis/src/autoderef.rs
@@ -91,10 +91,6 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> {
return None;
};
- if new_ty.references_error() {
- return None;
- }
-
self.state.steps.push((self.state.cur_ty, kind));
debug!(
"autoderef stage #{:?} is {:?} from {:?}",
@@ -137,6 +133,10 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
debug!("overloaded_deref_ty({:?})", ty);
let tcx = self.infcx.tcx;
+ if ty.references_error() {
+ return None;
+ }
+
//
let trait_ref = ty::TraitRef::new(tcx, tcx.lang_items().deref_trait()?, [ty]);
let cause = traits::ObligationCause::misc(self.span, self.body_id);
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 7250dc81faf8..b693d7201c15 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -80,6 +80,7 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {
check_transparent(tcx, def);
check_packed(tcx, span, def);
+ check_unnamed_fields(tcx, def);
}
fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) {
@@ -89,6 +90,58 @@ fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) {
check_transparent(tcx, def);
check_union_fields(tcx, span, def_id);
check_packed(tcx, span, def);
+ check_unnamed_fields(tcx, def);
+}
+
+/// Check the representation of adts with unnamed fields.
+fn check_unnamed_fields(tcx: TyCtxt<'_>, def: ty::AdtDef<'_>) {
+ if def.is_enum() {
+ return;
+ }
+ let variant = def.non_enum_variant();
+ if !variant.has_unnamed_fields() {
+ return;
+ }
+ if !def.is_anonymous() {
+ let adt_kind = def.descr();
+ let span = tcx.def_span(def.did());
+ let unnamed_fields = variant
+ .fields
+ .iter()
+ .filter(|f| f.is_unnamed())
+ .map(|f| {
+ let span = tcx.def_span(f.did);
+ errors::UnnamedFieldsReprFieldDefined { span }
+ })
+ .collect::>();
+ debug_assert_ne!(unnamed_fields.len(), 0, "expect unnamed fields in this adt");
+ let adt_name = tcx.item_name(def.did());
+ if !def.repr().c() {
+ tcx.dcx().emit_err(errors::UnnamedFieldsRepr::MissingReprC {
+ span,
+ adt_kind,
+ adt_name,
+ unnamed_fields,
+ sugg_span: span.shrink_to_lo(),
+ });
+ }
+ }
+ for field in variant.fields.iter().filter(|f| f.is_unnamed()) {
+ let field_ty = tcx.type_of(field.did).instantiate_identity();
+ if let Some(adt) = field_ty.ty_adt_def()
+ && !adt.is_anonymous()
+ && !adt.repr().c()
+ {
+ let field_ty_span = tcx.def_span(adt.did());
+ tcx.dcx().emit_err(errors::UnnamedFieldsRepr::FieldMissingReprC {
+ span: tcx.def_span(field.did),
+ field_ty_span,
+ field_ty,
+ field_adt_kind: adt.descr(),
+ sugg_span: field_ty_span.shrink_to_lo(),
+ });
+ }
+ }
}
/// Check that the fields of the `union` do not need dropping.
@@ -474,8 +527,12 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
}
DefKind::Fn => {} // entirely within check_item_body
DefKind::Impl { of_trait } => {
- if of_trait && let Some(impl_trait_ref) = tcx.impl_trait_ref(def_id) {
- check_impl_items_against_trait(tcx, def_id, impl_trait_ref.instantiate_identity());
+ if of_trait && let Some(impl_trait_header) = tcx.impl_trait_header(def_id) {
+ check_impl_items_against_trait(
+ tcx,
+ def_id,
+ impl_trait_header.instantiate_identity(),
+ );
check_on_unimplemented(tcx, def_id);
}
}
@@ -666,19 +723,19 @@ pub(super) fn check_specialization_validity<'tcx>(
fn check_impl_items_against_trait<'tcx>(
tcx: TyCtxt<'tcx>,
impl_id: LocalDefId,
- impl_trait_ref: ty::TraitRef<'tcx>,
+ impl_trait_header: ty::ImplTraitHeader<'tcx>,
) {
// If the trait reference itself is erroneous (so the compilation is going
// to fail), skip checking the items here -- the `impl_item` table in `tcx`
// isn't populated for such impls.
- if impl_trait_ref.references_error() {
+ if impl_trait_header.references_error() {
return;
}
let impl_item_refs = tcx.associated_item_def_ids(impl_id);
// Negative impls are not expected to have any items
- match tcx.impl_polarity(impl_id) {
+ match impl_trait_header.polarity {
ty::ImplPolarity::Reservation | ty::ImplPolarity::Positive => {}
ty::ImplPolarity::Negative => {
if let [first_item_ref, ..] = impl_item_refs {
@@ -695,7 +752,7 @@ fn check_impl_items_against_trait<'tcx>(
}
}
- let trait_def = tcx.trait_def(impl_trait_ref.def_id);
+ let trait_def = tcx.trait_def(impl_trait_header.trait_ref.def_id);
for &impl_item in impl_item_refs {
let ty_impl_item = tcx.associated_item(impl_item);
@@ -714,10 +771,10 @@ fn check_impl_items_against_trait<'tcx>(
));
}
ty::AssocKind::Fn => {
- compare_impl_method(tcx, ty_impl_item, ty_trait_item, impl_trait_ref);
+ compare_impl_method(tcx, ty_impl_item, ty_trait_item, impl_trait_header.trait_ref);
}
ty::AssocKind::Type => {
- compare_impl_ty(tcx, ty_impl_item, ty_trait_item, impl_trait_ref);
+ compare_impl_ty(tcx, ty_impl_item, ty_trait_item, impl_trait_header.trait_ref);
}
}
@@ -737,7 +794,7 @@ fn check_impl_items_against_trait<'tcx>(
let mut must_implement_one_of: Option<&[Ident]> =
trait_def.must_implement_one_of.as_deref();
- for &trait_item_id in tcx.associated_item_def_ids(impl_trait_ref.def_id) {
+ for &trait_item_id in tcx.associated_item_def_ids(impl_trait_header.trait_ref.def_id) {
let leaf_def = ancestors.leaf_def(tcx, trait_item_id);
let is_implemented = leaf_def
@@ -815,7 +872,7 @@ fn check_impl_items_against_trait<'tcx>(
if let Some(missing_items) = must_implement_one_of {
let attr_span = tcx
- .get_attr(impl_trait_ref.def_id, sym::rustc_must_implement_one_of)
+ .get_attr(impl_trait_header.trait_ref.def_id, sym::rustc_must_implement_one_of)
.map(|attr| attr.span);
missing_items_must_implement_one_of_err(
@@ -1030,7 +1087,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
match t.kind() {
ty::Tuple(list) => list.iter().try_for_each(|t| check_non_exhaustive(tcx, t)),
ty::Array(ty, _) => check_non_exhaustive(tcx, *ty),
- ty::Adt(def, subst) => {
+ ty::Adt(def, args) => {
if !def.did().is_local() {
let non_exhaustive = def.is_variant_list_non_exhaustive()
|| def
@@ -1042,13 +1099,13 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
return ControlFlow::Break((
def.descr(),
def.did(),
- subst,
+ args,
non_exhaustive,
));
}
}
def.all_fields()
- .map(|field| field.ty(tcx, subst))
+ .map(|field| field.ty(tcx, args))
.try_for_each(|t| check_non_exhaustive(tcx, t))
}
_ => ControlFlow::Continue(()),
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 6edd68f1baeb..69a02b73a798 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -125,9 +125,9 @@ fn check_method_is_structurally_compatible<'tcx>(
/// <'b> fn(t: &'i0 U0, m: &'b N0) -> Foo
/// ```
///
-/// We now want to extract and substitute the type of the *trait*
+/// We now want to extract and instantiate the type of the *trait*
/// method and compare it. To do so, we must create a compound
-/// substitution by combining `trait_to_impl_args` and
+/// instantiation by combining `trait_to_impl_args` and
/// `impl_to_placeholder_args`, and also adding a mapping for the method
/// type parameters. We extend the mapping to also include
/// the method parameters.
@@ -146,11 +146,11 @@ fn check_method_is_structurally_compatible<'tcx>(
/// vs `'b`). However, the normal subtyping rules on fn types handle
/// this kind of equivalency just fine.
///
-/// We now use these substitutions to ensure that all declared bounds are
-/// satisfied by the implementation's method.
+/// We now use these generic parameters to ensure that all declared bounds
+/// are satisfied by the implementation's method.
///
/// We do this by creating a parameter environment which contains a
-/// substitution corresponding to `impl_to_placeholder_args`. We then build
+/// generic parameter corresponding to `impl_to_placeholder_args`. We then build
/// `trait_to_placeholder_args` and use it to convert the predicates contained
/// in the `trait_m` generics to the placeholder form.
///
@@ -454,7 +454,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
let impl_trait_ref =
tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap().instantiate_identity();
// First, check a few of the same things as `compare_impl_method`,
- // just so we don't ICE during substitution later.
+ // just so we don't ICE during instantiation later.
check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, true)?;
let trait_to_impl_args = impl_trait_ref.args;
@@ -543,7 +543,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
// }
// ```
// .. to compile. However, since we use both the normalized and unnormalized
- // inputs and outputs from the substituted trait signature, we will end up
+ // inputs and outputs from the instantiated trait signature, we will end up
// seeing the hidden type of an RPIT in the signature itself. Naively, this
// means that we will use the hidden type to imply the hidden type's own
// well-formedness.
@@ -699,7 +699,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
// NOTE(compiler-errors): RPITITs, like all other RPITs, have early-bound
// region args that are synthesized during AST lowering. These are args
// that are appended to the parent args (trait and trait method). However,
- // we're trying to infer the unsubstituted type value of the RPITIT inside
+ // we're trying to infer the uninstantiated type value of the RPITIT inside
// the *impl*, so we can later use the impl's method args to normalize
// an RPITIT to a concrete type (`confirm_impl_trait_in_trait_candidate`).
//
@@ -711,7 +711,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
// guarantee that the indices from the trait args and impl args line up.
// So to fix this, we subtract the number of trait args and add the number of
// impl args to *renumber* these early-bound regions to their corresponding
- // indices in the impl's substitutions list.
+ // indices in the impl's generic parameters list.
//
// Also, we only need to account for a difference in trait and impl args,
// since we previously enforce that the trait method and impl method have the
diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs
index 7b60457affa8..82a6b6b6f2cb 100644
--- a/compiler/rustc_hir_analysis/src/check/dropck.rs
+++ b/compiler/rustc_hir_analysis/src/check/dropck.rs
@@ -124,14 +124,14 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
let infcx = tcx.infer_ctxt().build();
let ocx = ObligationCtxt::new(&infcx);
- // Take the param-env of the adt and substitute the args that show up in
+ // Take the param-env of the adt and instantiate the args 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 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
+ // instantiating 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::bind(tcx.param_env(adt_def_id)).instantiate(tcx, adt_to_impl_args);
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index b74431983113..2f8e065df330 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -56,7 +56,7 @@ type variable is an instance of a type parameter. That is,
given a generic function `fn foo(t: T)`, while checking the
function `foo`, the type `ty_param(0)` refers to the type `T`, which
is treated in abstract. However, when `foo()` is called, `T` will be
-substituted for a fresh type variable `N`. This variable will
+instantiated with a fresh type variable `N`. This variable will
eventually be resolved to some concrete type (which might itself be
a type parameter).
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index 1c0a1a695139..0f5fd7e99b77 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -16,7 +16,6 @@ use rustc_index::Idx;
use rustc_middle::middle::region::*;
use rustc_middle::ty::TyCtxt;
use rustc_span::source_map;
-use rustc_span::Span;
use super::errs::{maybe_expr_static_mut, maybe_stmt_static_mut};
@@ -72,11 +71,7 @@ struct RegionResolutionVisitor<'tcx> {
}
/// Records the lifetime of a local variable as `cx.var_parent`
-fn record_var_lifetime(
- visitor: &mut RegionResolutionVisitor<'_>,
- var_id: hir::ItemLocalId,
- _sp: Span,
-) {
+fn record_var_lifetime(visitor: &mut RegionResolutionVisitor<'_>, var_id: hir::ItemLocalId) {
match visitor.cx.var_parent {
None => {
// this can happen in extern fn declarations like
@@ -210,7 +205,7 @@ fn resolve_pat<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, pat: &'tcx hir
// If this is a binding then record the lifetime of that binding.
if let PatKind::Binding(..) = pat.kind {
- record_var_lifetime(visitor, pat.hir_id.local_id, pat.span);
+ record_var_lifetime(visitor, pat.hir_id.local_id);
}
debug!("resolve_pat - pre-increment {} pat = {:?}", visitor.expr_and_pat_count, pat);
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 646a84b043c8..7f674a1e7e45 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -118,9 +118,9 @@ where
return Err(err);
} else {
// HACK(oli-obk): tests/ui/specialization/min_specialization/specialize_on_type_error.rs
- // causes an error (span_delayed_bug) during normalization, without reporting an error,
- // so we need to act as if no error happened, in order to let our callers continue and
- // report an error later in check_impl_items_against_trait.
+ // causes an delayed bug during normalization, without reporting an error, so we need
+ // to act as if no error happened, in order to let our callers continue and report an
+ // error later in check_impl_items_against_trait.
return Ok(());
}
}
@@ -245,9 +245,9 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<()
// won't be allowed unless there's an *explicit* implementation of `Send`
// for `T`
hir::ItemKind::Impl(impl_) => {
- let is_auto = tcx
- .impl_trait_ref(def_id)
- .is_some_and(|trait_ref| tcx.trait_is_auto(trait_ref.skip_binder().def_id));
+ let header = tcx.impl_trait_header(def_id);
+ let is_auto = header
+ .is_some_and(|header| tcx.trait_is_auto(header.skip_binder().trait_ref.def_id));
let mut res = Ok(());
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);
@@ -259,11 +259,12 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<()
.emit());
}
// We match on both `ty::ImplPolarity` and `ast::ImplPolarity` just to get the `!` span.
- match tcx.impl_polarity(def_id) {
- ty::ImplPolarity::Positive => {
+ match header.map(|h| h.skip_binder().polarity) {
+ // `None` means this is an inherent impl
+ Some(ty::ImplPolarity::Positive) | None => {
res = res.and(check_impl(tcx, item, impl_.self_ty, &impl_.of_trait));
}
- ty::ImplPolarity::Negative => {
+ Some(ty::ImplPolarity::Negative) => {
let ast::ImplPolarity::Negative(span) = impl_.polarity else {
bug!("impl_polarity query disagrees with impl's polarity in AST");
};
@@ -280,7 +281,7 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<()
.emit());
}
}
- ty::ImplPolarity::Reservation => {
+ Some(ty::ImplPolarity::Reservation) => {
// FIXME: what amount of WF checking do we need for reservation impls?
}
}
@@ -618,7 +619,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable>>(
// The bounds we that we would require from `to_check`
let mut bounds = FxHashSet::default();
- let (regions, types) = GATSubstCollector::visit(gat_def_id.to_def_id(), to_check);
+ let (regions, types) = GATArgsCollector::visit(gat_def_id.to_def_id(), to_check);
// If both regions and types are empty, then this GAT isn't in the
// set of types we are checking, and we shouldn't try to do clause analysis
@@ -787,34 +788,34 @@ fn test_region_obligations<'tcx>(
/// `>::GAT` and adds the arguments `P0..Pm` into
/// the two vectors, `regions` and `types` (depending on their kind). For each
/// parameter `Pi` also track the index `i`.
-struct GATSubstCollector<'tcx> {
+struct GATArgsCollector<'tcx> {
gat: DefId,
- // Which region appears and which parameter index its substituted for
+ // Which region appears and which parameter index its instantiated with
regions: FxHashSet<(ty::Region<'tcx>, usize)>,
- // Which params appears and which parameter index its substituted for
+ // Which params appears and which parameter index its instantiated with
types: FxHashSet<(Ty<'tcx>, usize)>,
}
-impl<'tcx> GATSubstCollector<'tcx> {
+impl<'tcx> GATArgsCollector<'tcx> {
fn visit>>(
gat: DefId,
t: T,
) -> (FxHashSet<(ty::Region<'tcx>, usize)>, FxHashSet<(Ty<'tcx>, usize)>) {
let mut visitor =
- GATSubstCollector { gat, regions: FxHashSet::default(), types: FxHashSet::default() };
+ GATArgsCollector { gat, regions: FxHashSet::default(), types: FxHashSet::default() };
t.visit_with(&mut visitor);
(visitor.regions, visitor.types)
}
}
-impl<'tcx> TypeVisitor> for GATSubstCollector<'tcx> {
+impl<'tcx> TypeVisitor> for GATArgsCollector<'tcx> {
type BreakTy = !;
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow {
match t.kind() {
ty::Alias(ty::Projection, p) if p.def_id == self.gat => {
- for (idx, subst) in p.args.iter().enumerate() {
- match subst.unpack() {
+ for (idx, arg) in p.args.iter().enumerate() {
+ match arg.unpack() {
GenericArgKind::Lifetime(lt) if !lt.is_bound() => {
self.regions.insert((lt, idx));
}
@@ -1407,14 +1408,14 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
}
}
- // Check that trait predicates are WF when params are substituted by their defaults.
+ // Check that trait predicates are WF when params are instantiated with their defaults.
// We don't want to overly constrain the predicates that may be written but we want to
// catch cases where a default my never be applied such as `struct Foo`.
// Therefore we check if a predicate which contains a single type param
- // with a concrete default is WF with that default substituted.
+ // with a concrete default is WF with that default instantiated.
// For more examples see tests `defaults-well-formedness.rs` and `type-check-defaults.rs`.
//
- // First we build the defaulted substitution.
+ // First we build the defaulted generic parameters.
let args = GenericArgs::for_item(tcx, def_id.to_def_id(), |param, _| {
match param.kind {
GenericParamDefKind::Lifetime => {
@@ -1428,7 +1429,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
let default_ty = tcx.type_of(param.def_id).instantiate_identity();
// ... and it's not a dependent default, ...
if !default_ty.has_param() {
- // ... then substitute it with the default.
+ // ... then instantiate it with the default.
return default_ty.into();
}
}
@@ -1441,7 +1442,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
let default_ct = tcx.const_param_default(param.def_id).instantiate_identity();
// ... and it's not a dependent default, ...
if !default_ct.has_param() {
- // ... then substitute it with the default.
+ // ... then instantiate it with the default.
return default_ct.into();
}
}
@@ -1451,7 +1452,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
}
});
- // Now we build the substituted predicates.
+ // Now we build the instantiated predicates.
let default_obligations = predicates
.predicates
.iter()
@@ -1483,23 +1484,25 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
}
let mut param_count = CountParams::default();
let has_region = pred.visit_with(&mut param_count).is_break();
- let substituted_pred = ty::EarlyBinder::bind(pred).instantiate(tcx, args);
+ let instantiated_pred = ty::EarlyBinder::bind(pred).instantiate(tcx, args);
// Don't check non-defaulted params, dependent defaults (including lifetimes)
// or preds with multiple params.
- if substituted_pred.has_non_region_param() || param_count.params.len() > 1 || has_region
+ if instantiated_pred.has_non_region_param()
+ || param_count.params.len() > 1
+ || has_region
{
None
- } else if predicates.predicates.iter().any(|&(p, _)| p == substituted_pred) {
+ } else if predicates.predicates.iter().any(|&(p, _)| p == instantiated_pred) {
// Avoid duplication of predicates that contain no parameters, for example.
None
} else {
- Some((substituted_pred, sp))
+ Some((instantiated_pred, sp))
}
})
.map(|(pred, sp)| {
// Convert each of those into an obligation. So if you have
// something like `struct Foo`, we would
- // take that predicate `T: Copy`, substitute to `String: Copy`
+ // take that predicate `T: Copy`, instantiated with `String: Copy`
// (actually that happens in the previous `flat_map` call),
// and then try to prove it (in this case, we'll fail).
//
@@ -1635,6 +1638,12 @@ fn check_method_receiver<'tcx>(
let receiver_ty = sig.inputs()[0];
let receiver_ty = wfcx.normalize(span, None, receiver_ty);
+ // If the receiver already has errors reported, consider it valid to avoid
+ // unnecessary errors (#58712).
+ if receiver_ty.references_error() {
+ return Ok(());
+ }
+
if tcx.features().arbitrary_self_types {
if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, true) {
// Report error; `arbitrary_self_types` was enabled.
@@ -1749,9 +1758,7 @@ fn receiver_is_valid<'tcx>(
}
} else {
debug!("receiver_is_valid: type `{:?}` does not deref to `{:?}`", receiver_ty, self_ty);
- // If the receiver already has errors reported due to it, consider it valid to avoid
- // unnecessary errors (#58712).
- return receiver_ty.references_error();
+ return false;
}
}
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index fc911ecdad2f..370c6c607d7b 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -396,7 +396,7 @@ pub fn coerce_unsized_info<'tcx>(
//
// To check if this impl is legal, we would walk down
// the fields of `Foo` and consider their types with
- // both substitutes. We are looking to find that
+ // both generic parameters. We are looking to find that
// exactly one (non-phantom) field has changed its
// type, which we will expect to be the pointer that
// is becoming fat (we could probably generalize this
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index f458ff01c104..e8787d159ae1 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -31,6 +31,7 @@ use rustc_middle::ty::util::{Discr, IntTypeExt};
use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, ToPredicate, Ty, TyCtxt};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::Span;
+use rustc_target::abi::FieldIdx;
use rustc_target::spec::abi;
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
@@ -78,12 +79,12 @@ pub fn provide(providers: &mut Providers) {
trait_def,
adt_def,
fn_sig,
- impl_trait_ref,
- impl_polarity,
+ impl_trait_header,
coroutine_kind,
coroutine_for_closure,
collect_mod_item_types,
is_type_alias_impl_trait,
+ find_field,
..*providers
};
}
@@ -598,7 +599,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
hir::ItemKind::Impl { .. } => {
tcx.ensure().generics_of(def_id);
tcx.ensure().type_of(def_id);
- tcx.ensure().impl_trait_ref(def_id);
+ tcx.ensure().impl_trait_header(def_id);
tcx.ensure().predicates_of(def_id);
}
hir::ItemKind::Trait(..) => {
@@ -789,6 +790,175 @@ fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
}
}
+fn find_field(tcx: TyCtxt<'_>, (def_id, ident): (DefId, Ident)) -> Option {
+ tcx.adt_def(def_id).non_enum_variant().fields.iter_enumerated().find_map(|(idx, field)| {
+ if field.is_unnamed() {
+ let field_ty = tcx.type_of(field.did).instantiate_identity();
+ let adt_def = field_ty.ty_adt_def().expect("expect Adt for unnamed field");
+ tcx.find_field((adt_def.did(), ident)).map(|_| idx)
+ } else {
+ (field.ident(tcx).normalize_to_macros_2_0() == ident).then_some(idx)
+ }
+ })
+}
+
+#[derive(Clone, Copy)]
+struct NestedSpan {
+ span: Span,
+ nested_field_span: Span,
+}
+
+impl NestedSpan {
+ fn to_field_already_declared_nested_help(&self) -> errors::FieldAlreadyDeclaredNestedHelp {
+ errors::FieldAlreadyDeclaredNestedHelp { span: self.span }
+ }
+}
+
+#[derive(Clone, Copy)]
+enum FieldDeclSpan {
+ NotNested(Span),
+ Nested(NestedSpan),
+}
+
+impl From for FieldDeclSpan {
+ fn from(span: Span) -> Self {
+ Self::NotNested(span)
+ }
+}
+
+impl From for FieldDeclSpan {
+ fn from(span: NestedSpan) -> Self {
+ Self::Nested(span)
+ }
+}
+
+struct FieldUniquenessCheckContext<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ seen_fields: FxHashMap,
+}
+
+impl<'tcx> FieldUniquenessCheckContext<'tcx> {
+ fn new(tcx: TyCtxt<'tcx>) -> Self {
+ Self { tcx, seen_fields: FxHashMap::default() }
+ }
+
+ /// Check if a given field `ident` declared at `field_decl` has been declared elsewhere before.
+ fn check_field_decl(&mut self, ident: Ident, field_decl: FieldDeclSpan) {
+ use FieldDeclSpan::*;
+ let field_name = ident.name;
+ let ident = ident.normalize_to_macros_2_0();
+ match (field_decl, self.seen_fields.get(&ident).copied()) {
+ (NotNested(span), Some(NotNested(prev_span))) => {
+ self.tcx.dcx().emit_err(errors::FieldAlreadyDeclared::NotNested {
+ field_name,
+ span,
+ prev_span,
+ });
+ }
+ (NotNested(span), Some(Nested(prev))) => {
+ self.tcx.dcx().emit_err(errors::FieldAlreadyDeclared::PreviousNested {
+ field_name,
+ span,
+ prev_span: prev.span,
+ prev_nested_field_span: prev.nested_field_span,
+ prev_help: prev.to_field_already_declared_nested_help(),
+ });
+ }
+ (
+ Nested(current @ NestedSpan { span, nested_field_span, .. }),
+ Some(NotNested(prev_span)),
+ ) => {
+ self.tcx.dcx().emit_err(errors::FieldAlreadyDeclared::CurrentNested {
+ field_name,
+ span,
+ nested_field_span,
+ help: current.to_field_already_declared_nested_help(),
+ prev_span,
+ });
+ }
+ (Nested(current @ NestedSpan { span, nested_field_span }), Some(Nested(prev))) => {
+ self.tcx.dcx().emit_err(errors::FieldAlreadyDeclared::BothNested {
+ field_name,
+ span,
+ nested_field_span,
+ help: current.to_field_already_declared_nested_help(),
+ prev_span: prev.span,
+ prev_nested_field_span: prev.nested_field_span,
+ prev_help: prev.to_field_already_declared_nested_help(),
+ });
+ }
+ (field_decl, None) => {
+ self.seen_fields.insert(ident, field_decl);
+ }
+ }
+ }
+
+ /// Check the uniqueness of fields across adt where there are
+ /// nested fields imported from an unnamed field.
+ fn check_field_in_nested_adt(&mut self, adt_def: ty::AdtDef<'_>, unnamed_field_span: Span) {
+ for field in adt_def.all_fields() {
+ if field.is_unnamed() {
+ // Here we don't care about the generic parameters, so `instantiate_identity` is enough.
+ match self.tcx.type_of(field.did).instantiate_identity().kind() {
+ ty::Adt(adt_def, _) => {
+ self.check_field_in_nested_adt(*adt_def, unnamed_field_span);
+ }
+ ty_kind => span_bug!(
+ self.tcx.def_span(field.did),
+ "Unexpected TyKind in FieldUniquenessCheckContext::check_field_in_nested_adt(): {ty_kind:?}"
+ ),
+ }
+ } else {
+ self.check_field_decl(
+ field.ident(self.tcx),
+ NestedSpan {
+ span: unnamed_field_span,
+ nested_field_span: self.tcx.def_span(field.did),
+ }
+ .into(),
+ );
+ }
+ }
+ }
+
+ /// Check the uniqueness of fields in a struct variant, and recursively
+ /// check the nested fields if it is an unnamed field with type of an
+ /// annoymous adt.
+ fn check_field(&mut self, field: &hir::FieldDef<'_>) {
+ if field.ident.name != kw::Underscore {
+ self.check_field_decl(field.ident, field.span.into());
+ return;
+ }
+ match &field.ty.kind {
+ hir::TyKind::AnonAdt(item_id) => {
+ match &self.tcx.hir_node(item_id.hir_id()).expect_item().kind {
+ hir::ItemKind::Struct(variant_data, ..)
+ | hir::ItemKind::Union(variant_data, ..) => {
+ variant_data.fields().iter().for_each(|f| self.check_field(f));
+ }
+ item_kind => span_bug!(
+ field.ty.span,
+ "Unexpected ItemKind in FieldUniquenessCheckContext::check_field(): {item_kind:?}"
+ ),
+ }
+ }
+ hir::TyKind::Path(hir::QPath::Resolved(_, hir::Path { res, .. })) => {
+ self.check_field_in_nested_adt(self.tcx.adt_def(res.def_id()), field.span);
+ }
+ // Abort due to errors (there must be an error if an unnamed field
+ // has any type kind other than an anonymous adt or a named adt)
+ ty_kind => {
+ self.tcx.dcx().span_delayed_bug(
+ field.ty.span,
+ format!("Unexpected TyKind in FieldUniquenessCheckContext::check_field(): {ty_kind:?}"),
+ );
+ // FIXME: errors during AST validation should abort the compilation before reaching here.
+ self.tcx.dcx().abort_if_errors();
+ }
+ }
+ }
+}
+
fn convert_variant(
tcx: TyCtxt<'_>,
variant_did: Option,
@@ -797,29 +967,26 @@ fn convert_variant(
def: &hir::VariantData<'_>,
adt_kind: ty::AdtKind,
parent_did: LocalDefId,
+ is_anonymous: bool,
) -> ty::VariantDef {
- let mut seen_fields: FxHashMap = Default::default();
+ let mut has_unnamed_fields = false;
+ let mut field_uniqueness_check_ctx = FieldUniquenessCheckContext::new(tcx);
let fields = def
.fields()
.iter()
- .map(|f| {
- let dup_span = seen_fields.get(&f.ident.normalize_to_macros_2_0()).cloned();
- if let Some(prev_span) = dup_span {
- tcx.dcx().emit_err(errors::FieldAlreadyDeclared {
- field_name: f.ident,
- span: f.span,
- prev_span,
- });
- } else {
- seen_fields.insert(f.ident.normalize_to_macros_2_0(), f.span);
- }
-
- ty::FieldDef {
- did: f.def_id.to_def_id(),
- name: f.ident.name,
- vis: tcx.visibility(f.def_id),
+ .inspect(|f| {
+ has_unnamed_fields |= f.ident.name == kw::Underscore;
+ // We only check named ADT here because anonymous ADTs are checked inside
+ // the nammed ADT in which they are defined.
+ if !is_anonymous {
+ field_uniqueness_check_ctx.check_field(f);
}
})
+ .map(|f| ty::FieldDef {
+ did: f.def_id.to_def_id(),
+ name: f.ident.name,
+ vis: tcx.visibility(f.def_id),
+ })
.collect();
let recovered = match def {
hir::VariantData::Struct { recovered, .. } => *recovered,
@@ -837,6 +1004,7 @@ fn convert_variant(
adt_kind == AdtKind::Struct && tcx.has_attr(parent_did, sym::non_exhaustive)
|| variant_did
.is_some_and(|variant_did| tcx.has_attr(variant_did, sym::non_exhaustive)),
+ has_unnamed_fields,
)
}
@@ -847,7 +1015,12 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
bug!("expected ADT to be an item");
};
- let repr = tcx.repr_options_of_def(def_id.to_def_id());
+ let is_anonymous = item.ident.name == kw::Empty;
+ let repr = if is_anonymous {
+ tcx.adt_def(tcx.local_parent(def_id)).repr()
+ } else {
+ tcx.repr_options_of_def(def_id.to_def_id())
+ };
let (kind, variants) = match &item.kind {
ItemKind::Enum(def, _) => {
let mut distance_from_explicit = 0;
@@ -871,6 +1044,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
&v.data,
AdtKind::Enum,
def_id,
+ is_anonymous,
)
})
.collect();
@@ -890,6 +1064,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
def,
adt_kind,
def_id,
+ is_anonymous,
))
.collect();
@@ -897,7 +1072,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
}
_ => bug!("{:?} is not an ADT", item.owner_id.def_id),
};
- tcx.mk_adt_def(def_id.to_def_id(), kind, variants, repr)
+ tcx.mk_adt_def(def_id.to_def_id(), kind, variants, repr, is_anonymous)
}
fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
@@ -1323,19 +1498,20 @@ fn suggest_impl_trait<'tcx>(
None
}
-fn impl_trait_ref(
+fn impl_trait_header(
tcx: TyCtxt<'_>,
def_id: LocalDefId,
-) -> Option>> {
+) -> Option>> {
let icx = ItemCtxt::new(tcx, def_id);
- let impl_ = tcx.hir().expect_item(def_id).expect_impl();
+ let item = tcx.hir().expect_item(def_id);
+ let impl_ = item.expect_impl();
impl_
.of_trait
.as_ref()
.map(|ast_trait_ref| {
let selfty = tcx.type_of(def_id).instantiate_identity();
- if let Some(ErrorGuaranteed { .. }) = check_impl_constness(
+ let trait_ref = if let Some(ErrorGuaranteed { .. }) = check_impl_constness(
tcx,
tcx.is_const_trait_impl_raw(def_id.to_def_id()),
ast_trait_ref,
@@ -1360,9 +1536,12 @@ fn impl_trait_ref(
icx.astconv().instantiate_mono_trait_ref(trait_ref, selfty)
} else {
icx.astconv().instantiate_mono_trait_ref(ast_trait_ref, selfty)
- }
+ };
+ ty::EarlyBinder::bind(ty::ImplTraitHeader {
+ trait_ref,
+ polarity: polarity_of_impl(tcx, def_id, impl_, item.span)
+ })
})
- .map(ty::EarlyBinder::bind)
}
fn check_impl_constness(
@@ -1390,43 +1569,34 @@ fn check_impl_constness(
}))
}
-fn impl_polarity(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::ImplPolarity {
+fn polarity_of_impl(
+ tcx: TyCtxt<'_>,
+ def_id: LocalDefId,
+ impl_: &hir::Impl<'_>,
+ span: Span,
+) -> ty::ImplPolarity {
let is_rustc_reservation = tcx.has_attr(def_id, sym::rustc_reservation_impl);
- let item = tcx.hir().expect_item(def_id);
- match &item.kind {
- hir::ItemKind::Impl(hir::Impl {
- polarity: hir::ImplPolarity::Negative(span),
- of_trait,
- ..
- }) => {
+ match &impl_ {
+ hir::Impl { polarity: hir::ImplPolarity::Negative(span), of_trait, .. } => {
if is_rustc_reservation {
let span = span.to(of_trait.as_ref().map_or(*span, |t| t.path.span));
tcx.dcx().span_err(span, "reservation impls can't be negative");
}
ty::ImplPolarity::Negative
}
- hir::ItemKind::Impl(hir::Impl {
- polarity: hir::ImplPolarity::Positive,
- of_trait: None,
- ..
- }) => {
+ hir::Impl { polarity: hir::ImplPolarity::Positive, of_trait: None, .. } => {
if is_rustc_reservation {
- tcx.dcx().span_err(item.span, "reservation impls can't be inherent");
+ tcx.dcx().span_err(span, "reservation impls can't be inherent");
}
ty::ImplPolarity::Positive
}
- hir::ItemKind::Impl(hir::Impl {
- polarity: hir::ImplPolarity::Positive,
- of_trait: Some(_),
- ..
- }) => {
+ hir::Impl { polarity: hir::ImplPolarity::Positive, of_trait: Some(_), .. } => {
if is_rustc_reservation {
ty::ImplPolarity::Reservation
} else {
ty::ImplPolarity::Positive
}
}
- item => bug!("impl_polarity: {:?} not an impl", item),
}
}
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index e5e731bbe8c6..9cc6c16c1263 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -71,7 +71,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
// end up with that const looking like: `ty::ConstKind::Unevaluated(def_id, args: [N#0])`.
//
// This causes ICEs (#86580) when building the args for Foo in `fn foo() -> Foo { .. }` as
- // we substitute the defaults with the partially built args when we build the args. Subst'ing
+ // we instantiate the defaults with the partially built args when we build the args. Instantiating
// the `N#0` on the unevaluated const indexes into the empty args we're in the process of building.
//
// We fix this by having this function return the parent's generics ourselves and truncating the
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index 1aa9c6929f81..c9cf43ddfc88 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -1786,7 +1786,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
let bound_predicate = pred.kind();
match bound_predicate.skip_binder() {
ty::ClauseKind::Trait(data) => {
- // The order here needs to match what we would get from `subst_supertrait`
+ // The order here needs to match what we would get from
+ // `rustc_middle::ty::predicate::Clause::instantiate_supertrait`
let pred_bound_vars = bound_predicate.bound_vars();
let mut all_bound_vars = bound_vars.clone();
all_bound_vars.extend(pred_bound_vars.iter());
diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
index 65d1ffa40e2e..05efad3ccb31 100644
--- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
+++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
@@ -119,7 +119,7 @@ pub fn identify_constrained_generic_params<'tcx>(
/// * `::Item = T` -- a desugared ProjectionPredicate
///
/// When we, for example, try to go over the trait-reference
-/// `IntoIter as Trait`, we substitute the impl parameters with fresh
+/// `IntoIter as Trait`, we instantiate the impl parameters with fresh
/// variables and match them with the impl trait-ref, so we know that
/// `$U = IntoIter`.
///
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index bec53693d6c9..6a505b961974 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -175,14 +175,66 @@ pub struct DropImplOnWrongItem {
}
#[derive(Diagnostic)]
-#[diag(hir_analysis_field_already_declared, code = E0124)]
-pub struct FieldAlreadyDeclared {
- pub field_name: Ident,
+pub enum FieldAlreadyDeclared {
+ #[diag(hir_analysis_field_already_declared, code = E0124)]
+ NotNested {
+ field_name: Symbol,
+ #[primary_span]
+ #[label]
+ span: Span,
+ #[label(hir_analysis_previous_decl_label)]
+ prev_span: Span,
+ },
+ #[diag(hir_analysis_field_already_declared_current_nested)]
+ CurrentNested {
+ field_name: Symbol,
+ #[primary_span]
+ #[label]
+ span: Span,
+ #[note(hir_analysis_nested_field_decl_note)]
+ nested_field_span: Span,
+ #[subdiagnostic]
+ help: FieldAlreadyDeclaredNestedHelp,
+ #[label(hir_analysis_previous_decl_label)]
+ prev_span: Span,
+ },
+ #[diag(hir_analysis_field_already_declared_previous_nested)]
+ PreviousNested {
+ field_name: Symbol,
+ #[primary_span]
+ #[label]
+ span: Span,
+ #[label(hir_analysis_previous_decl_label)]
+ prev_span: Span,
+ #[note(hir_analysis_previous_nested_field_decl_note)]
+ prev_nested_field_span: Span,
+ #[subdiagnostic]
+ prev_help: FieldAlreadyDeclaredNestedHelp,
+ },
+ #[diag(hir_analysis_field_already_declared_both_nested)]
+ BothNested {
+ field_name: Symbol,
+ #[primary_span]
+ #[label]
+ span: Span,
+ #[note(hir_analysis_nested_field_decl_note)]
+ nested_field_span: Span,
+ #[subdiagnostic]
+ help: FieldAlreadyDeclaredNestedHelp,
+ #[label(hir_analysis_previous_decl_label)]
+ prev_span: Span,
+ #[note(hir_analysis_previous_nested_field_decl_note)]
+ prev_nested_field_span: Span,
+ #[subdiagnostic]
+ prev_help: FieldAlreadyDeclaredNestedHelp,
+ },
+}
+
+#[derive(Subdiagnostic)]
+#[help(hir_analysis_field_already_declared_nested_help)]
+pub struct FieldAlreadyDeclaredNestedHelp {
#[primary_span]
- #[label]
pub span: Span,
- #[label(hir_analysis_previous_decl_label)]
- pub prev_span: Span,
}
#[derive(Diagnostic)]
@@ -372,8 +424,8 @@ pub struct ManualImplementation {
}
#[derive(Diagnostic)]
-#[diag(hir_analysis_substs_on_overridden_impl)]
-pub struct SubstsOnOverriddenImpl {
+#[diag(hir_analysis_generic_args_on_overridden_impl)]
+pub struct GenericArgsOnOverriddenImpl {
#[primary_span]
pub span: Span,
}
@@ -1534,3 +1586,38 @@ pub(crate) enum UnusedGenericParameterHelp {
#[help(hir_analysis_unused_generic_parameter_ty_alias_help)]
TyAlias { param_name: Ident },
}
+
+#[derive(Diagnostic)]
+pub enum UnnamedFieldsRepr<'a> {
+ #[diag(hir_analysis_unnamed_fields_repr_missing_repr_c)]
+ MissingReprC {
+ #[primary_span]
+ #[label]
+ span: Span,
+ adt_kind: &'static str,
+ adt_name: Symbol,
+ #[subdiagnostic]
+ unnamed_fields: Vec,
+ #[suggestion(code = "#[repr(C)]\n")]
+ sugg_span: Span,
+ },
+ #[diag(hir_analysis_unnamed_fields_repr_field_missing_repr_c)]
+ FieldMissingReprC {
+ #[primary_span]
+ #[label]
+ span: Span,
+ #[label(hir_analysis_field_ty_label)]
+ field_ty_span: Span,
+ field_ty: Ty<'a>,
+ field_adt_kind: &'static str,
+ #[suggestion(code = "#[repr(C)]\n")]
+ sugg_span: Span,
+ },
+}
+
+#[derive(Subdiagnostic)]
+#[note(hir_analysis_unnamed_fields_repr_field_defined)]
+pub struct UnnamedFieldsReprFieldDefined {
+ #[primary_span]
+ pub span: Span,
+}
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index 1b6a39d8162e..c8dedb0f3719 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -34,8 +34,8 @@
//! impl> SpecExtend for I { /* default impl */ }
//! ```
//!
-//! We get that the subst for `impl2` are `[T, std::vec::IntoIter]`. `T` is
-//! constrained to be `::Item`, so we check only
+//! We get that the generic pamameters for `impl2` are `[T, std::vec::IntoIter]`.
+//! `T` is constrained to be `::Item`, so we check only
//! `std::vec::IntoIter` for repeated parameters, which it doesn't have. The
//! predicates of `impl1` are only `T: Sized`, which is also a predicate of
//! `impl2`. So this specialization is sound.
@@ -65,7 +65,7 @@
//! cause use after frees with purely safe code in the same way as specializing
//! on traits with methods can.
-use crate::errors::SubstsOnOverriddenImpl;
+use crate::errors::GenericArgsOnOverriddenImpl;
use crate::{constrained_generic_params as cgp, errors};
use rustc_data_structures::fx::FxHashSet;
@@ -179,8 +179,8 @@ fn check_constness(
}
/// Given a specializing impl `impl1`, and the base impl `impl2`, returns two
-/// substitutions `(S1, S2)` that equate their trait references. The returned
-/// types are expressed in terms of the generics of `impl1`.
+/// generic parameters `(S1, S2)` that equate their trait references.
+/// The returned types are expressed in terms of the generics of `impl1`.
///
/// Example
///
@@ -228,13 +228,13 @@ fn get_impl_args(
let _ = ocx.resolve_regions_and_report_errors(impl1_def_id, &outlives_env);
let Ok(impl2_args) = infcx.fully_resolve(impl2_args) else {
let span = tcx.def_span(impl1_def_id);
- let guar = tcx.dcx().emit_err(SubstsOnOverriddenImpl { span });
+ let guar = tcx.dcx().emit_err(GenericArgsOnOverriddenImpl { span });
return Err(guar);
};
Ok((impl1_args, impl2_args))
}
-/// Returns a list of all of the unconstrained subst of the given impl.
+/// Returns a list of all of the unconstrained generic parameters of the given impl.
///
/// For example given the impl:
///
@@ -425,9 +425,7 @@ fn check_predicates<'tcx>(
let mut res = Ok(());
for (clause, span) in impl1_predicates {
- if !impl2_predicates
- .iter()
- .any(|pred2| trait_predicates_eq(tcx, clause.as_predicate(), *pred2, span))
+ if !impl2_predicates.iter().any(|pred2| trait_predicates_eq(clause.as_predicate(), *pred2))
{
res = res.and(check_specialization_on(tcx, clause, span))
}
@@ -459,10 +457,8 @@ fn check_predicates<'tcx>(
///
/// So we make that check in this function and try to raise a helpful error message.
fn trait_predicates_eq<'tcx>(
- _tcx: TyCtxt<'tcx>,
predicate1: ty::Predicate<'tcx>,
predicate2: ty::Predicate<'tcx>,
- _span: Span,
) -> bool {
// FIXME(effects)
predicate1 == predicate2
diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
index 0cb38094ceca..0c0dbbe7ad9d 100644
--- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
@@ -229,7 +229,7 @@ fn insert_required_predicates_to_be_wf<'tcx>(
/// Here, we should fetch the explicit predicates, which
/// will give us `U: 'static` and `U: Outer`. The latter we
/// can ignore, but we will want to process `U: 'static`,
-/// applying the substitution as above.
+/// applying the instantiation as above.
fn check_explicit_predicates<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: DefId,
@@ -316,7 +316,7 @@ fn check_explicit_predicates<'tcx>(
/// Here, when processing the type of field `outer`, we would request the
/// set of implicit predicates computed for `Inner` thus far. This will
/// initially come back empty, but in next round we will get `U: 'b`.
-/// We then apply the substitution `['b => 'a, U => T]` and thus get the
+/// We then apply the instantiation `['b => 'a, U => T]` and thus get the
/// requirement that `T: 'a` holds for `Outer`.
fn check_inferred_predicates<'tcx>(
tcx: TyCtxt<'tcx>,
@@ -334,7 +334,7 @@ fn check_inferred_predicates<'tcx>(
for (&predicate, &span) in predicates.as_ref().skip_binder() {
// `predicate` is `U: 'b` in the example above.
- // So apply the substitution to get `T: 'a`.
+ // So apply the instantiation to get `T: 'a`.
let ty::OutlivesPredicate(arg, region) =
predicates.rebind(predicate).instantiate(tcx, args);
insert_outlives_predicate(tcx, arg, region, span, required_predicates);
diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs
index 7d145ea1f23a..4d5dcbadc4a2 100644
--- a/compiler/rustc_hir_analysis/src/variance/mod.rs
+++ b/compiler/rustc_hir_analysis/src/variance/mod.rs
@@ -172,16 +172,16 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc
trait_ref: ty::TraitRef { def_id: _, args, .. },
polarity: _,
}) => {
- for subst in &args[1..] {
- subst.visit_with(&mut collector);
+ for arg in &args[1..] {
+ arg.visit_with(&mut collector);
}
}
ty::ClauseKind::Projection(ty::ProjectionPredicate {
projection_ty: ty::AliasTy { args, .. },
term,
}) => {
- for subst in &args[1..] {
- subst.visit_with(&mut collector);
+ for arg in &args[1..] {
+ arg.visit_with(&mut collector);
}
term.visit_with(&mut collector);
}
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index b90fa03a3dc0..8f8f747339b4 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -328,6 +328,7 @@ impl<'a> State<'a> {
hir::TyKind::Infer | hir::TyKind::InferDelegation(..) => {
self.word("_");
}
+ hir::TyKind::AnonAdt(..) => self.word("/* anonymous adt */"),
}
self.end()
}
@@ -728,26 +729,30 @@ impl<'a> State<'a> {
}
hir::VariantData::Struct { .. } => {
self.print_where_clause(generics);
- self.nbsp();
- self.bopen();
- self.hardbreak_if_not_bol();
-
- for field in struct_def.fields() {
- self.hardbreak_if_not_bol();
- self.maybe_print_comment(field.span.lo());
- self.print_outer_attributes(self.attrs(field.hir_id));
- self.print_ident(field.ident);
- self.word_nbsp(":");
- self.print_type(field.ty);
- self.word(",");
- }
-
- self.bclose(span)
+ self.print_variant_struct(span, struct_def.fields())
}
}
}
- fn print_variant(&mut self, v: &hir::Variant<'_>) {
+ fn print_variant_struct(&mut self, span: rustc_span::Span, fields: &[hir::FieldDef<'_>]) {
+ self.nbsp();
+ self.bopen();
+ self.hardbreak_if_not_bol();
+
+ for field in fields {
+ self.hardbreak_if_not_bol();
+ self.maybe_print_comment(field.span.lo());
+ self.print_outer_attributes(self.attrs(field.hir_id));
+ self.print_ident(field.ident);
+ self.word_nbsp(":");
+ self.print_type(field.ty);
+ self.word(",");
+ }
+
+ self.bclose(span)
+ }
+
+ pub fn print_variant(&mut self, v: &hir::Variant<'_>) {
self.head("");
let generics = hir::Generics::empty();
self.print_struct(&v.data, generics, v.ident.name, v.span, false);
diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs
index aab78465f8c8..5841392dbcf1 100644
--- a/compiler/rustc_hir_typeck/src/check.rs
+++ b/compiler/rustc_hir_typeck/src/check.rs
@@ -90,8 +90,7 @@ pub(super) fn check_fn<'a, 'tcx>(
// ty.span == binding_span iff this is a closure parameter with no type ascription,
// or if it's an implicit `self` parameter
traits::SizedArgumentType(
- if ty_span == Some(param.span) && tcx.is_closure_or_coroutine(fn_def_id.into())
- {
+ if ty_span == Some(param.span) && tcx.is_closure_like(fn_def_id.into()) {
None
} else {
ty.map(|ty| ty.hir_id)
@@ -123,7 +122,7 @@ pub(super) fn check_fn<'a, 'tcx>(
if let ty::Dynamic(..) = declared_ret_ty.kind() {
// We have special-cased the case where the function is declared
// `-> dyn Foo` and we don't actually relate it to the
- // `fcx.ret_coercion`, so just substitute a type variable.
+ // `fcx.ret_coercion`, so just instantiate a type variable.
actual_return_ty =
fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::DynReturnFn, span });
debug!("actual_return_ty replaced with {:?}", actual_return_ty);
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 549ad44d7e34..e98ace948f92 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -752,7 +752,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
let mut obligations: Vec<_> = predicates
.iter()
.map(|predicate| {
- // For each existential predicate (e.g., `?Self: Clone`) substitute
+ // For each existential predicate (e.g., `?Self: Clone`) instantiate
// the type of the expression (e.g., `usize` in our example above)
// and then require that the resulting predicate (e.g., `usize: Clone`)
// holds (it does).
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 31c97aab7fb8..19bdeab409bb 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -346,7 +346,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
ExprKind::DropTemps(e) => self.check_expr_with_expectation(e, expected),
ExprKind::Array(args) => self.check_expr_array(args, expected, expr),
- ExprKind::ConstBlock(ref block) => self.check_expr_const_block(block, expected, expr),
+ ExprKind::ConstBlock(ref block) => self.check_expr_const_block(block, expected),
ExprKind::Repeat(element, ref count) => {
self.check_expr_repeat(element, count, expected, expr)
}
@@ -1487,7 +1487,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self,
block: &'tcx hir::ConstBlock,
expected: Expectation<'tcx>,
- _expr: &'tcx hir::Expr<'tcx>,
) -> Ty<'tcx> {
let body = self.tcx.hir().body(block.body);
@@ -1721,7 +1720,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let ident = tcx.adjust_ident(field.ident, variant.def_id);
let field_type = if let Some((i, v_field)) = remaining_fields.remove(&ident) {
seen_fields.insert(ident, field.span);
- self.write_field_index(field.hir_id, i);
+ // FIXME: handle nested fields
+ self.write_field_index(field.hir_id, i, Vec::new());
// We don't look at stability attributes on
// struct-like enums (yet...), but it's definitely not
@@ -1801,7 +1801,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// consistency. But they should be merged as much as possible.
let fru_tys = if self.tcx.features().type_changing_struct_update {
if adt.is_struct() {
- // Make some fresh substitutions for our ADT type.
+ // Make some fresh generic parameters for our ADT type.
let fresh_args = self.fresh_args_for_item(base_expr.span, adt.did());
// We do subtyping on the FRU fields first, so we can
// learn exactly what types we expect the base expr
@@ -2367,24 +2367,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let body_hir_id = self.tcx.local_def_id_to_hir_id(self.body_id);
let (ident, def_scope) =
self.tcx.adjust_ident_and_get_scope(field, base_def.did(), body_hir_id);
- let fields = &base_def.non_enum_variant().fields;
- if let Some((index, field)) = fields
- .iter_enumerated()
- .find(|(_, f)| f.ident(self.tcx).normalize_to_macros_2_0() == ident)
- {
+ let mut adt_def = *base_def;
+ let mut last_ty = None;
+ let mut nested_fields = Vec::new();
+ let mut index = None;
+ while let Some(idx) = self.tcx.find_field((adt_def.did(), ident)) {
+ let &mut first_idx = index.get_or_insert(idx);
+ let field = &adt_def.non_enum_variant().fields[idx];
let field_ty = self.field_ty(expr.span, field, args);
- // Save the index of all fields regardless of their visibility in case
- // of error recovery.
- self.write_field_index(expr.hir_id, index);
- let adjustments = self.adjust_steps(&autoderef);
- if field.vis.is_accessible_from(def_scope, self.tcx) {
- self.apply_adjustments(base, adjustments);
- self.register_predicates(autoderef.into_obligations());
-
- self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None);
- return field_ty;
+ if let Some(ty) = last_ty {
+ nested_fields.push((ty, idx));
}
- private_candidate = Some((adjustments, base_def.did()));
+ if field.ident(self.tcx).normalize_to_macros_2_0() == ident {
+ // Save the index of all fields regardless of their visibility in case
+ // of error recovery.
+ self.write_field_index(expr.hir_id, first_idx, nested_fields);
+ let adjustments = self.adjust_steps(&autoderef);
+ if field.vis.is_accessible_from(def_scope, self.tcx) {
+ self.apply_adjustments(base, adjustments);
+ self.register_predicates(autoderef.into_obligations());
+
+ self.tcx.check_stability(
+ field.did,
+ Some(expr.hir_id),
+ expr.span,
+ None,
+ );
+ return field_ty;
+ }
+ private_candidate = Some((adjustments, base_def.did()));
+ break;
+ }
+ last_ty = Some(field_ty);
+ adt_def = field_ty.ty_adt_def().expect("expect Adt for unnamed field");
}
}
ty::Tuple(tys) => {
@@ -2395,7 +2410,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.apply_adjustments(base, adjustments);
self.register_predicates(autoderef.into_obligations());
- self.write_field_index(expr.hir_id, FieldIdx::from_usize(index));
+ self.write_field_index(
+ expr.hir_id,
+ FieldIdx::from_usize(index),
+ Vec::new(),
+ );
return field_ty;
}
}
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index 3ecf6c5e428b..04fb7bcf4f3b 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -142,7 +142,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
let param_ty = return_if_err!(self.mc.pat_ty_adjusted(param.pat));
debug!("consume_body: param_ty = {:?}", param_ty);
- let param_place = self.mc.cat_rvalue(param.hir_id, param.pat.span, param_ty);
+ let param_place = self.mc.cat_rvalue(param.hir_id, param_ty);
self.walk_irrefutable_pat(¶m_place, param.pat);
}
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 7eb421ca8f5a..f7ff9f8224a2 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -15,7 +15,7 @@ use rustc_hir_analysis::astconv::generics::{
check_generic_arg_count_for_call, create_args_for_parent_generic_args,
};
use rustc_hir_analysis::astconv::{
- AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
+ AstConv, CreateInstantiationsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
GenericArgCountResult, IsMethodCall, PathSeg,
};
use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
@@ -145,8 +145,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
- pub fn write_field_index(&self, hir_id: hir::HirId, index: FieldIdx) {
+ pub fn write_field_index(
+ &self,
+ hir_id: hir::HirId,
+ index: FieldIdx,
+ nested_fields: Vec<(Ty<'tcx>, FieldIdx)>,
+ ) {
self.typeck_results.borrow_mut().field_indices_mut().insert(hir_id, index);
+ if !nested_fields.is_empty() {
+ self.typeck_results.borrow_mut().nested_fields_mut().insert(hir_id, nested_fields);
+ }
}
#[instrument(level = "debug", skip(self))]
@@ -179,8 +187,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
/// Given the args that we just converted from the HIR, try to
- /// canonicalize them and store them as user-given substitutions
- /// (i.e., substitutions that must be respected by the NLL check).
+ /// canonicalize them and store them as user-given parameters
+ /// (i.e., parameters that must be respected by the NLL check).
///
/// This should be invoked **before any unifications have
/// occurred**, so that annotations like `Vec<_>` are preserved
@@ -733,7 +741,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return Err(TypeError::Mismatch);
}
- // Record all the argument types, with the substitutions
+ // Record all the argument types, with the args
// produced from the above subtyping unification.
Ok(Some(formal_args.iter().map(|&ty| self.resolve_vars_if_possible(ty)).collect()))
})
@@ -1163,7 +1171,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Now we have to compare the types that the user *actually*
// provided against the types that were *expected*. If the user
- // did not provide any types, then we want to substitute inference
+ // did not provide any types, then we want to instantiate inference
// variables. If the user provided some types, we may still need
// to add defaults. If the user provided *too many* types, that's
// a problem.
@@ -1253,14 +1261,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
},
};
- struct CreateCtorSubstsContext<'a, 'tcx> {
+ struct CreateCtorInstantiationsContext<'a, 'tcx> {
fcx: &'a FnCtxt<'a, 'tcx>,
span: Span,
path_segs: &'a [PathSeg],
infer_args_for_err: &'a FxHashSet,
segments: &'tcx [hir::PathSegment<'tcx>],
}
- impl<'tcx, 'a> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for CreateCtorSubstsContext<'a, 'tcx> {
+ impl<'tcx, 'a> CreateInstantiationsForGenericArgsCtxt<'a, 'tcx>
+ for CreateCtorInstantiationsContext<'a, 'tcx>
+ {
fn args_for_def_id(
&mut self,
def_id: DefId,
@@ -1384,7 +1394,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
has_self,
self_ty.map(|s| s.raw),
&arg_count,
- &mut CreateCtorSubstsContext {
+ &mut CreateCtorInstantiationsContext {
fcx: self,
span,
path_segs: &path_segs,
@@ -1402,18 +1412,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.add_required_obligations_for_hir(span, def_id, args, hir_id);
- // Substitute the values for the type parameters into the type of
+ // Instantiate the values for the type parameters into the type of
// the referenced item.
let ty = tcx.type_of(def_id);
assert!(!args.has_escaping_bound_vars());
assert!(!ty.skip_binder().has_escaping_bound_vars());
- let ty_substituted = self.normalize(span, ty.instantiate(tcx, args));
+ let ty_instantiated = self.normalize(span, ty.instantiate(tcx, args));
if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
// In the case of `Foo::method` and `>::method`, if `method`
// is inherent, there is no `Self` parameter; instead, the impl needs
// type parameters, which we can infer by unifying the provided `Self`
- // with the substituted impl type.
+ // with the instantiated impl type.
// This also occurs for an enum variant on a type alias.
let impl_ty = self.normalize(span, tcx.type_of(impl_def_id).instantiate(tcx, args));
let self_ty = self.normalize(span, self_ty);
@@ -1434,13 +1444,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
- debug!("instantiate_value_path: type of {:?} is {:?}", hir_id, ty_substituted);
+ debug!("instantiate_value_path: type of {:?} is {:?}", hir_id, ty_instantiated);
self.write_args(hir_id, args);
- (ty_substituted, res)
+ (ty_instantiated, res)
}
- /// Add all the obligations that are required, substituting and normalized appropriately.
+ /// Add all the obligations that are required, instantiated and normalized appropriately.
pub(crate) fn add_required_obligations_for_hir(
&self,
span: Span,
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
index 6aa986b0df4c..f0631dd4b5fb 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
@@ -21,7 +21,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return false;
};
- let Some(unsubstituted_pred) = self
+ let Some(uninstantiated_pred) = self
.tcx
.predicates_of(def_id)
.instantiate_identity(self.tcx)
@@ -34,7 +34,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let generics = self.tcx.generics_of(def_id);
let (predicate_args, predicate_self_type_to_point_at) =
- match unsubstituted_pred.kind().skip_binder() {
+ match uninstantiated_pred.kind().skip_binder() {
ty::ClauseKind::Trait(pred) => {
(pred.trait_ref.args.to_vec(), Some(pred.self_ty().into()))
}
@@ -343,10 +343,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& let TypeVariableOriginKind::TypeParameterDefinition(_, def_id) = origin.kind
&& let generics = self.0.tcx.generics_of(self.1)
&& let Some(index) = generics.param_def_id_to_index(self.0.tcx, def_id)
- && let Some(subst) =
+ && let Some(arg) =
ty::GenericArgs::identity_for_item(self.0.tcx, self.1).get(index as usize)
{
- ControlFlow::Break(*subst)
+ ControlFlow::Break(*arg)
} else {
ty.super_visit_with(self)
}
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 193c9a4b9087..d68e20541ef0 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -2133,17 +2133,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr_ty: Ty<'tcx>,
) -> bool {
let tcx = self.tcx;
- let (adt, substs, unwrap) = match expected.kind() {
+ let (adt, args, unwrap) = match expected.kind() {
// In case Option is wanted, but * is provided, suggest calling new
- ty::Adt(adt, substs) if tcx.is_diagnostic_item(sym::Option, adt.did()) => {
- let nonzero_type = substs.type_at(0); // Unwrap option type.
- let ty::Adt(adt, substs) = nonzero_type.kind() else {
+ ty::Adt(adt, args) if tcx.is_diagnostic_item(sym::Option, adt.did()) => {
+ let nonzero_type = args.type_at(0); // Unwrap option type.
+ let ty::Adt(adt, args) = nonzero_type.kind() else {
return false;
};
- (adt, substs, "")
+ (adt, args, "")
}
// In case `NonZero<*>` is wanted but `*` is provided, also add `.unwrap()` to satisfy types.
- ty::Adt(adt, substs) => (adt, substs, ".unwrap()"),
+ ty::Adt(adt, args) => (adt, args, ".unwrap()"),
_ => return false,
};
@@ -2165,7 +2165,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
("NonZeroI128", tcx.types.i128),
];
- let int_type = substs.type_at(0);
+ let int_type = args.type_at(0);
let Some(nonzero_alias) = coercable_types.iter().find_map(|(nonzero_alias, t)| {
if *t == int_type && self.can_coerce(expr_ty, *t) { Some(nonzero_alias) } else { None }
diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs
index f9af357f0e79..4d37f725c940 100644
--- a/compiler/rustc_hir_typeck/src/gather_locals.rs
+++ b/compiler/rustc_hir_typeck/src/gather_locals.rs
@@ -153,7 +153,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
// ascription, or if it's an implicit `self` parameter
traits::SizedArgumentType(
if ty_span == ident.span
- && self.fcx.tcx.is_closure_or_coroutine(self.fcx.body_id.into())
+ && self.fcx.tcx.is_closure_like(self.fcx.body_id.into())
{
None
} else {
diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs
index f9297550c573..fefaf9967253 100644
--- a/compiler/rustc_hir_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs
@@ -273,7 +273,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
deref.region,
ty::TypeAndMut { ty: target, mutbl: deref.mutbl },
);
- self.cat_rvalue(expr.hir_id, expr.span, ref_ty)
+ self.cat_rvalue(expr.hir_id, ref_ty)
} else {
previous()?
};
@@ -285,7 +285,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
| adjustment::Adjust::Borrow(_)
| adjustment::Adjust::DynStar => {
// Result is an rvalue.
- Ok(self.cat_rvalue(expr.hir_id, expr.span, target))
+ Ok(self.cat_rvalue(expr.hir_id, target))
}
}
}
@@ -374,7 +374,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
| hir::ExprKind::Repeat(..)
| hir::ExprKind::InlineAsm(..)
| hir::ExprKind::OffsetOf(..)
- | hir::ExprKind::Err(_) => Ok(self.cat_rvalue(expr.hir_id, expr.span, expr_ty)),
+ | hir::ExprKind::Err(_) => Ok(self.cat_rvalue(expr.hir_id, expr_ty)),
}
}
@@ -396,7 +396,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
| DefKind::AssocFn,
_,
)
- | Res::SelfCtor(..) => Ok(self.cat_rvalue(hir_id, span, expr_ty)),
+ | Res::SelfCtor(..) => Ok(self.cat_rvalue(hir_id, expr_ty)),
Res::Def(DefKind::Static(_), _) => {
Ok(PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::StaticItem, Vec::new()))
@@ -433,13 +433,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
}
#[instrument(level = "debug", skip(self), ret)]
- pub(crate) fn cat_rvalue(
- &self,
- hir_id: hir::HirId,
- // FIXME: remove
- _span: Span,
- expr_ty: Ty<'tcx>,
- ) -> PlaceWithHirId<'tcx> {
+ pub(crate) fn cat_rvalue(&self, hir_id: hir::HirId, expr_ty: Ty<'tcx>) -> PlaceWithHirId<'tcx> {
PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Rvalue, Vec::new())
}
@@ -487,7 +481,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
};
let ref_ty = Ty::new_ref(self.tcx(), region, ty::TypeAndMut { ty: place_ty, mutbl });
- let base = self.cat_rvalue(expr.hir_id, expr.span, ref_ty);
+ let base = self.cat_rvalue(expr.hir_id, ref_ty);
self.cat_deref(expr, base)
}
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index 3a44c6c24104..4e9cb92919af 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -7,7 +7,7 @@ use rustc_hir::GenericArg;
use rustc_hir_analysis::astconv::generics::{
check_generic_arg_count_for_call, create_args_for_parent_generic_args,
};
-use rustc_hir_analysis::astconv::{AstConv, CreateSubstsForGenericArgsCtxt, IsMethodCall};
+use rustc_hir_analysis::astconv::{AstConv, CreateInstantiationsForGenericArgsCtxt, IsMethodCall};
use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk};
use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext};
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion};
@@ -95,7 +95,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
// Adjust the self expression the user provided and obtain the adjusted type.
let self_ty = self.adjust_self_ty(unadjusted_self_ty, pick);
- // Create substitutions for the method's type parameters.
+ // Create generic args for the method's type parameters.
let rcvr_args = self.fresh_receiver_args(self_ty, pick);
let all_args = self.instantiate_method_args(pick, segment, rcvr_args);
@@ -246,11 +246,11 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
target
}
- /// Returns a set of substitutions for the method *receiver* where all type and region
- /// parameters are instantiated with fresh variables. This substitution does not include any
+ /// Returns a set of generic parameters for the method *receiver* where all type and region
+ /// parameters are instantiated with fresh variables. This generic paramters does not include any
/// parameters declared on the method itself.
///
- /// Note that this substitution may include late-bound regions from the impl level. If so,
+ /// Note that this generic parameters may include late-bound regions from the impl level. If so,
/// these are instantiated later in the `instantiate_method_sig` routine.
fn fresh_receiver_args(
&mut self,
@@ -272,8 +272,8 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
self.extract_existential_trait_ref(self_ty, |this, object_ty, principal| {
// The object data has no entry for the Self
// Type. For the purposes of this method call, we
- // substitute the object type itself. This
- // wouldn't be a sound substitution in all cases,
+ // instantiate the object type itself. This
+ // wouldn't be a sound instantiation in all cases,
// since each instance of the object type is a
// different existential and hence could match
// distinct types (e.g., if `Self` appeared as an
@@ -362,16 +362,18 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
IsMethodCall::Yes,
);
- // Create subst for early-bound lifetime parameters, combining
- // parameters from the type and those from the method.
+ // Create generic paramters for early-bound lifetime parameters,
+ // combining parameters from the type and those from the method.
assert_eq!(generics.parent_count, parent_args.len());
- struct MethodSubstsCtxt<'a, 'tcx> {
+ struct MethodInstantiationsCtxt<'a, 'tcx> {
cfcx: &'a ConfirmContext<'a, 'tcx>,
pick: &'a probe::Pick<'tcx>,
seg: &'a hir::PathSegment<'tcx>,
}
- impl<'a, 'tcx> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for MethodSubstsCtxt<'a, 'tcx> {
+ impl<'a, 'tcx> CreateInstantiationsForGenericArgsCtxt<'a, 'tcx>
+ for MethodInstantiationsCtxt<'a, 'tcx>
+ {
fn args_for_def_id(
&mut self,
def_id: DefId,
@@ -437,7 +439,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
false,
None,
&arg_count_correct,
- &mut MethodSubstsCtxt { cfcx: self, pick, seg },
+ &mut MethodInstantiationsCtxt { cfcx: self, pick, seg },
);
// When the method is confirmed, the `args` includes
@@ -538,15 +540,15 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
debug!("instantiate_method_sig(pick={:?}, all_args={:?})", pick, all_args);
// Instantiate the bounds on the method with the
- // type/early-bound-regions substitutions performed. There can
+ // type/early-bound-regions instatiations performed. There can
// be no late-bound regions appearing here.
let def_id = pick.item.def_id;
let method_predicates = self.tcx.predicates_of(def_id).instantiate(self.tcx, all_args);
- debug!("method_predicates after subst = {:?}", method_predicates);
+ debug!("method_predicates after instantitation = {:?}", method_predicates);
let sig = self.tcx.fn_sig(def_id).instantiate(self.tcx, all_args);
- debug!("type scheme substituted, sig={:?}", sig);
+ debug!("type scheme instantiated, sig={:?}", sig);
let sig = self.instantiate_binder_with_fresh_vars(sig);
debug!("late-bound lifetimes from method instantiated, sig={:?}", sig);
diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs
index 804d6ff2cb57..fb969c82d8ae 100644
--- a/compiler/rustc_hir_typeck/src/method/mod.rs
+++ b/compiler/rustc_hir_typeck/src/method/mod.rs
@@ -38,7 +38,7 @@ pub struct MethodCallee<'tcx> {
pub args: GenericArgsRef<'tcx>,
/// Instantiated method signature, i.e., it has been
- /// substituted, normalized, and has had late-bound
+ /// instantiated, normalized, and has had late-bound
/// lifetimes replaced with inference variables.
pub sig: ty::FnSig<'tcx>,
}
@@ -395,7 +395,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
debug!("lookup_in_trait_adjusted: method_item={:?}", method_item);
let mut obligations = vec![];
- // Instantiate late-bound regions and substitute the trait
+ // Instantiate late-bound regions and instantiate the trait
// parameters into the method type to get the actual method type.
//
// N.B., instantiate late-bound regions before normalizing the
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index a446c7aa42bb..d7edc70bce82 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -111,7 +111,7 @@ pub(crate) struct Candidate<'tcx> {
// The way this is handled is through `xform_self_ty`. It contains
// the receiver type of this candidate, but `xform_self_ty`,
// `xform_ret_ty` and `kind` (which contains the predicates) have the
- // generic parameters of this candidate substituted with the *same set*
+ // generic parameters of this candidate instantiated with the *same set*
// of inference variables, which acts as some weird sort of "query".
//
// When we check out a candidate, we require `xform_self_ty` to be
@@ -799,7 +799,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
// the `Self` type. An [`ObjectSafetyViolation::SupertraitSelf`] error
// will be reported by `object_safety.rs` if the method refers to the
// `Self` type anywhere other than the receiver. Here, we use a
- // substitution that replaces `Self` with the object type itself. Hence,
+ // instantiation that replaces `Self` with the object type itself. Hence,
// a `&self` method will wind up with an argument type like `&dyn Trait`.
let trait_ref = principal.with_self_ty(self.tcx, self_ty);
self.elaborate_bounds(iter::once(trait_ref), |this, new_trait_ref, item| {
@@ -1857,8 +1857,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
assert!(!args.has_escaping_bound_vars());
// It is possible for type parameters or early-bound lifetimes
- // to appear in the signature of `self`. The substitutions we
- // are given do not include type/lifetime parameters for the
+ // to appear in the signature of `self`. The generic parameters
+ // we are given do not include type/lifetime parameters for the
// method yet. So create fresh variables here for those too,
// if there are any.
let generics = self.tcx.generics_of(method);
@@ -1889,7 +1889,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
self.instantiate_bound_regions_with_erased(xform_fn_sig)
}
- /// Gets the type of an impl and generate substitutions with inference vars.
+ /// Gets the type of an impl and generate generic parameters with inference vars.
fn impl_ty_and_args(
&self,
impl_def_id: DefId,
@@ -1913,7 +1913,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
/// late-bound regions with 'static. Otherwise, if we were going to replace late-bound
/// regions with actual region variables as is proper, we'd have to ensure that the same
/// region got replaced with the same variable, which requires a bit more coordination
- /// and/or tracking the substitution and
+ /// and/or tracking the instantiations and
/// so forth.
fn instantiate_bound_regions_with_erased(&self, value: ty::Binder<'tcx, T>) -> T
where
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 7fc51e36a2b6..ab5c0f327051 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -3134,12 +3134,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if self
.tcx
.all_impls(candidate.def_id)
- .filter(|imp_did| {
- self.tcx.impl_polarity(*imp_did) == ty::ImplPolarity::Negative
+ .map(|imp_did| {
+ self.tcx.impl_trait_header(imp_did).expect(
+ "inherent impls can't be candidates, only trait impls can be",
+ )
})
- .any(|imp_did| {
- let imp =
- self.tcx.impl_trait_ref(imp_did).unwrap().instantiate_identity();
+ .filter(|header| {
+ header.skip_binder().polarity == ty::ImplPolarity::Negative
+ })
+ .any(|header| {
+ let imp = header.instantiate_identity().trait_ref;
let imp_simp =
simplify_type(self.tcx, imp.self_ty(), TreatParams::ForLookup);
imp_simp.is_some_and(|s| s == simp_rcvr_ty)
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 67aa92185852..5026fbe4b806 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -1389,7 +1389,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
field_map
.get(&ident)
.map(|(i, f)| {
- self.write_field_index(field.hir_id, *i);
+ // FIXME: handle nested fields
+ self.write_field_index(field.hir_id, *i, Vec::new());
self.tcx.check_stability(f.did, Some(pat.hir_id), span, None);
self.field_ty(span, f, args)
})
diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs
index 1eaaf30043b4..6c5715b323c9 100644
--- a/compiler/rustc_hir_typeck/src/place_op.rs
+++ b/compiler/rustc_hir_typeck/src/place_op.rs
@@ -357,7 +357,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
PlaceOp::Deref => None,
PlaceOp::Index => {
// We would need to recover the `T` used when we resolve `<_ as Index>::index`
- // in try_index_step. This is the subst at index 1.
+ // in try_index_step. This is the arg at index 1.
//
// Note: we should *not* use `expr_ty` of index_expr here because autoderef
// during coercions can cause type of index_expr to differ from `T` (#72002).
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 94f6c06157ef..5ce80ef5c10d 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -1,6 +1,6 @@
// Type resolution: the phase that finds all the types in the AST with
// unresolved type variables and replaces "ty_var" types with their
-// substitutions.
+// generic parameters.
use crate::FnCtxt;
use rustc_data_structures::unord::ExtendUnord;
@@ -596,6 +596,11 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
{
self.typeck_results.field_indices_mut().insert(hir_id, index);
}
+ if let Some(nested_fields) =
+ self.fcx.typeck_results.borrow_mut().nested_fields_mut().remove(hir_id)
+ {
+ self.typeck_results.nested_fields_mut().insert(hir_id, nested_fields);
+ }
}
#[instrument(skip(self, span), level = "debug")]
@@ -616,7 +621,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
self.write_ty_to_typeck_results(hir_id, n_ty);
debug!(?n_ty);
- // Resolve any substitutions
+ // Resolve any generic parameters
if let Some(args) = self.fcx.typeck_results.borrow().node_args_opt(hir_id) {
let args = self.resolve(args, &span);
debug!("write_args_to_tcx({:?}, {:?})", hir_id, args);
diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs
index 14cc8c260e21..8311a7351333 100644
--- a/compiler/rustc_incremental/src/persist/dirty_clean.rs
+++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs
@@ -63,7 +63,7 @@ const BASE_HIR: &[&str] = &[
/// `impl` implementation of struct/trait
const BASE_IMPL: &[&str] =
- &[label_strs::associated_item_def_ids, label_strs::generics_of, label_strs::impl_trait_ref];
+ &[label_strs::associated_item_def_ids, label_strs::generics_of, label_strs::impl_trait_header];
/// DepNodes for mir_built/Optimized, which is relevant in "executable"
/// code, i.e., functions+methods
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 156a4f710176..99882a42abc3 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -191,7 +191,7 @@ impl CanonicalizeMode for CanonicalizeQueryResponse {
//
// rust-lang/rust#57464: `impl Trait` can leak local
// scopes (in manner violating typeck). Therefore, use
- // `span_delayed_bug` to allow type error over an ICE.
+ // `delayed_bug` to allow type error over an ICE.
canonicalizer
.tcx
.dcx()
diff --git a/compiler/rustc_infer/src/infer/canonical/substitute.rs b/compiler/rustc_infer/src/infer/canonical/instantiate.rs
similarity index 80%
rename from compiler/rustc_infer/src/infer/canonical/substitute.rs
rename to compiler/rustc_infer/src/infer/canonical/instantiate.rs
index e0b97bb160ca..f6b583151fdf 100644
--- a/compiler/rustc_infer/src/infer/canonical/substitute.rs
+++ b/compiler/rustc_infer/src/infer/canonical/instantiate.rs
@@ -1,4 +1,4 @@
-//! This module contains code to substitute new values into a
+//! This module contains code to instantiate new values into a
//! `Canonical<'tcx, T>`.
//!
//! For an overview of what canonicalization is and how it fits into
@@ -16,17 +16,17 @@ use rustc_middle::ty::{self, TyCtxt};
pub trait CanonicalExt<'tcx, V> {
/// Instantiate the wrapped value, replacing each canonical value
/// with the value given in `var_values`.
- fn substitute(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V
+ fn instantiate(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V
where
V: TypeFoldable>;
- /// Allows one to apply a substitute to some subset of
+ /// Allows one to apply a instantiation to some subset of
/// `self.value`. Invoke `projection_fn` with `self.value` to get
/// a value V that is expressed in terms of the same canonical
/// variables bound in `self` (usually this extracts from subset
- /// of `self`). Apply the substitution `var_values` to this value
+ /// of `self`). Apply the instantiation `var_values` to this value
/// V, replacing each of the canonical variables.
- fn substitute_projected(
+ fn instantiate_projected(
&self,
tcx: TyCtxt<'tcx>,
var_values: &CanonicalVarValues<'tcx>,
@@ -37,14 +37,14 @@ pub trait CanonicalExt<'tcx, V> {
}
impl<'tcx, V> CanonicalExt<'tcx, V> for Canonical<'tcx, V> {
- fn substitute(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V
+ fn instantiate(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V
where
V: TypeFoldable>,
{
- self.substitute_projected(tcx, var_values, |value| value.clone())
+ self.instantiate_projected(tcx, var_values, |value| value.clone())
}
- fn substitute_projected(
+ fn instantiate_projected(
&self,
tcx: TyCtxt<'tcx>,
var_values: &CanonicalVarValues<'tcx>,
@@ -55,14 +55,14 @@ impl<'tcx, V> CanonicalExt<'tcx, V> for Canonical<'tcx, V> {
{
assert_eq!(self.variables.len(), var_values.len());
let value = projection_fn(&self.value);
- substitute_value(tcx, var_values, value)
+ instantiate_value(tcx, var_values, value)
}
}
-/// Substitute the values from `var_values` into `value`. `var_values`
+/// Instantiate the values from `var_values` into `value`. `var_values`
/// must be values for the set of canonical variables that appear in
/// `value`.
-pub(super) fn substitute_value<'tcx, T>(
+pub(super) fn instantiate_value<'tcx, T>(
tcx: TyCtxt<'tcx>,
var_values: &CanonicalVarValues<'tcx>,
value: T,
diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs
index 1f68a5a9c617..1d203a29b149 100644
--- a/compiler/rustc_infer/src/infer/canonical/mod.rs
+++ b/compiler/rustc_infer/src/infer/canonical/mod.rs
@@ -30,24 +30,24 @@ use rustc_middle::ty::GenericArg;
use rustc_middle::ty::{self, List, Ty, TyCtxt};
use rustc_span::Span;
+pub use instantiate::CanonicalExt;
pub use rustc_middle::infer::canonical::*;
-pub use substitute::CanonicalExt;
mod canonicalizer;
+mod instantiate;
pub mod query_response;
-mod substitute;
impl<'tcx> InferCtxt<'tcx> {
- /// Creates a substitution S for the canonical value with fresh
+ /// Creates an instantiation S for the canonical value with fresh
/// inference variables and applies it to the canonical value.
- /// Returns both the instantiated result *and* the substitution S.
+ /// Returns both the instantiated result *and* the instantiation S.
///
/// This can be invoked as part of constructing an
/// inference context at the start of a query (see
/// `InferCtxtBuilder::build_with_canonical`). It basically
/// brings the canonical value "into scope" within your new infcx.
///
- /// At the end of processing, the substitution S (once
+ /// At the end of processing, the instantiation S (once
/// canonicalized) then represents the values that you computed
/// for each of the canonical inputs to your query.
pub fn instantiate_canonical_with_fresh_inference_vars(
@@ -73,14 +73,14 @@ impl<'tcx> InferCtxt<'tcx> {
let canonical_inference_vars =
self.instantiate_canonical_vars(span, canonical.variables, |ui| universes[ui]);
- let result = canonical.substitute(self.tcx, &canonical_inference_vars);
+ let result = canonical.instantiate(self.tcx, &canonical_inference_vars);
(result, canonical_inference_vars)
}
/// Given the "infos" about the canonical variables from some
/// canonical, creates fresh variables with the same
/// characteristics (see `instantiate_canonical_var` for
- /// details). You can then use `substitute` to instantiate the
+ /// details). You can then use `instantiate` to instantiate the
/// canonical variable with these inference variables.
fn instantiate_canonical_vars(
&self,
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index 1f071a9ff0bc..216b2e70abff 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -7,7 +7,7 @@
//!
//! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
-use crate::infer::canonical::substitute::{substitute_value, CanonicalExt};
+use crate::infer::canonical::instantiate::{instantiate_value, CanonicalExt};
use crate::infer::canonical::{
Canonical, CanonicalQueryResponse, CanonicalVarValues, Certainty, OriginalQueryValues,
QueryOutlivesConstraint, QueryRegionConstraints, QueryResponse,
@@ -189,18 +189,18 @@ impl<'tcx> InferCtxt<'tcx> {
where
R: Debug + TypeFoldable>,
{
- let InferOk { value: result_subst, mut obligations } =
- self.query_response_substitution(cause, param_env, original_values, query_response)?;
+ let InferOk { value: result_args, mut obligations } =
+ self.query_response_instantiation(cause, param_env, original_values, query_response)?;
obligations.extend(self.query_outlives_constraints_into_obligations(
cause,
param_env,
&query_response.value.region_constraints.outlives,
- &result_subst,
+ &result_args,
));
let user_result: R =
- query_response.substitute_projected(self.tcx, &result_subst, |q_r| q_r.value.clone());
+ query_response.instantiate_projected(self.tcx, &result_args, |q_r| q_r.value.clone());
Ok(InferOk { value: user_result, obligations })
}
@@ -225,11 +225,11 @@ impl<'tcx> InferCtxt<'tcx> {
/// basic operations as `instantiate_query_response_and_region_obligations` but
/// it returns its result differently:
///
- /// - It creates a substitution `S` that maps from the original
+ /// - It creates an instantiation `S` that maps from the original
/// query variables to the values computed in the query
/// result. If any errors arise, they are propagated back as an
/// `Err` result.
- /// - In the case of a successful substitution, we will append
+ /// - In the case of a successful instantiation, we will append
/// `QueryOutlivesConstraint` values onto the
/// `output_query_region_constraints` vector for the solver to
/// use (if an error arises, some values may also be pushed, but
@@ -239,7 +239,7 @@ impl<'tcx> InferCtxt<'tcx> {
/// that must be processed. In this case, those subobligations
/// are propagated back in the return value.
/// - Finally, the query result (of type `R`) is propagated back,
- /// after applying the substitution `S`.
+ /// after applying the instantiation `S`.
pub fn instantiate_nll_query_response_and_region_obligations(
&self,
cause: &ObligationCause<'tcx>,
@@ -251,8 +251,13 @@ impl<'tcx> InferCtxt<'tcx> {
where
R: Debug + TypeFoldable>,
{
- let InferOk { value: result_subst, mut obligations } = self
- .query_response_substitution_guess(cause, param_env, original_values, query_response)?;
+ let InferOk { value: result_args, mut obligations } = self
+ .query_response_instantiation_guess(
+ cause,
+ param_env,
+ original_values,
+ query_response,
+ )?;
// Compute `QueryOutlivesConstraint` values that unify each of
// the original values `v_o` that was canonicalized into a
@@ -262,7 +267,7 @@ impl<'tcx> InferCtxt<'tcx> {
for (index, original_value) in original_values.var_values.iter().enumerate() {
// ...with the value `v_r` of that variable from the query.
- let result_value = query_response.substitute_projected(self.tcx, &result_subst, |v| {
+ let result_value = query_response.instantiate_projected(self.tcx, &result_args, |v| {
v.var_values[BoundVar::new(index)]
});
match (original_value.unpack(), result_value.unpack()) {
@@ -321,7 +326,7 @@ impl<'tcx> InferCtxt<'tcx> {
// ...also include the other query region constraints from the query.
output_query_region_constraints.outlives.extend(
query_response.value.region_constraints.outlives.iter().filter_map(|&r_c| {
- let r_c = substitute_value(self.tcx, &result_subst, r_c);
+ let r_c = instantiate_value(self.tcx, &result_args, r_c);
// Screen out `'a: 'a` cases.
let ty::OutlivesPredicate(k1, r2) = r_c.0;
@@ -336,26 +341,26 @@ impl<'tcx> InferCtxt<'tcx> {
.region_constraints
.member_constraints
.iter()
- .map(|p_c| substitute_value(self.tcx, &result_subst, p_c.clone())),
+ .map(|p_c| instantiate_value(self.tcx, &result_args, p_c.clone())),
);
let user_result: R =
- query_response.substitute_projected(self.tcx, &result_subst, |q_r| q_r.value.clone());
+ query_response.instantiate_projected(self.tcx, &result_args, |q_r| q_r.value.clone());
Ok(InferOk { value: user_result, obligations })
}
/// Given the original values and the (canonicalized) result from
- /// computing a query, returns a substitution that can be applied
+ /// computing a query, returns an instantiation that can be applied
/// to the query result to convert the result back into the
/// original namespace.
///
- /// The substitution also comes accompanied with subobligations
+ /// The instantiation also comes accompanied with subobligations
/// that arose from unification; these might occur if (for
/// example) we are doing lazy normalization and the value
/// assigned to a type variable is unified with an unnormalized
/// projection.
- fn query_response_substitution(
+ fn query_response_instantiation(
&self,
cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
@@ -366,11 +371,11 @@ impl<'tcx> InferCtxt<'tcx> {
R: Debug + TypeFoldable>,
{
debug!(
- "query_response_substitution(original_values={:#?}, query_response={:#?})",
+ "query_response_instantiation(original_values={:#?}, query_response={:#?})",
original_values, query_response,
);
- let mut value = self.query_response_substitution_guess(
+ let mut value = self.query_response_instantiation_guess(
cause,
param_env,
original_values,
@@ -378,7 +383,7 @@ impl<'tcx> InferCtxt<'tcx> {
)?;
value.obligations.extend(
- self.unify_query_response_substitution_guess(
+ self.unify_query_response_instantiation_guess(
cause,
param_env,
original_values,
@@ -392,7 +397,7 @@ impl<'tcx> InferCtxt<'tcx> {
}
/// Given the original values and the (canonicalized) result from
- /// computing a query, returns a **guess** at a substitution that
+ /// computing a query, returns a **guess** at an instantiation that
/// can be applied to the query result to convert the result back
/// into the original namespace. This is called a **guess**
/// because it uses a quick heuristic to find the values for each
@@ -401,7 +406,7 @@ impl<'tcx> InferCtxt<'tcx> {
/// variable instead. Therefore, the result of this method must be
/// properly unified
#[instrument(level = "debug", skip(self, cause, param_env))]
- fn query_response_substitution_guess(
+ fn query_response_instantiation_guess(
&self,
cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
@@ -450,7 +455,7 @@ impl<'tcx> InferCtxt<'tcx> {
if let ty::Bound(debruijn, b) = *result_value.kind() {
// ...in which case we would set `canonical_vars[0]` to `Some(?U)`.
- // We only allow a `ty::INNERMOST` index in substitutions.
+ // We only allow a `ty::INNERMOST` index in generic parameters.
assert_eq!(debruijn, ty::INNERMOST);
opt_values[b.var] = Some(*original_value);
}
@@ -460,7 +465,7 @@ impl<'tcx> InferCtxt<'tcx> {
if let ty::ReBound(debruijn, br) = *result_value {
// ... in which case we would set `canonical_vars[0]` to `Some('static)`.
- // We only allow a `ty::INNERMOST` index in substitutions.
+ // We only allow a `ty::INNERMOST` index in generic parameters.
assert_eq!(debruijn, ty::INNERMOST);
opt_values[br.var] = Some(*original_value);
}
@@ -469,7 +474,7 @@ impl<'tcx> InferCtxt<'tcx> {
if let ty::ConstKind::Bound(debruijn, b) = result_value.kind() {
// ...in which case we would set `canonical_vars[0]` to `Some(const X)`.
- // We only allow a `ty::INNERMOST` index in substitutions.
+ // We only allow a `ty::INNERMOST` index in generic parameters.
assert_eq!(debruijn, ty::INNERMOST);
opt_values[b] = Some(*original_value);
}
@@ -477,10 +482,10 @@ impl<'tcx> InferCtxt<'tcx> {
}
}
- // Create a result substitution: if we found a value for a
+ // Create result arguments: if we found a value for a
// given variable in the loop above, use that. Otherwise, use
// a fresh inference variable.
- let result_subst = CanonicalVarValues {
+ let result_args = CanonicalVarValues {
var_values: self.tcx.mk_args_from_iter(
query_response.variables.iter().enumerate().map(|(index, info)| {
if info.universe() != ty::UniverseIndex::ROOT {
@@ -511,8 +516,8 @@ impl<'tcx> InferCtxt<'tcx> {
// Carry all newly resolved opaque types to the caller's scope
for &(a, b) in &query_response.value.opaque_types {
- let a = substitute_value(self.tcx, &result_subst, a);
- let b = substitute_value(self.tcx, &result_subst, b);
+ let a = instantiate_value(self.tcx, &result_args, a);
+ let b = instantiate_value(self.tcx, &result_args, b);
debug!(?a, ?b, "constrain opaque type");
// We use equate here instead of, for example, just registering the
// opaque type's hidden value directly, because we may be instantiating
@@ -532,7 +537,7 @@ impl<'tcx> InferCtxt<'tcx> {
);
}
- Ok(InferOk { value: result_subst, obligations })
+ Ok(InferOk { value: result_args, obligations })
}
/// Given a "guess" at the values for the canonical variables in
@@ -540,13 +545,13 @@ impl<'tcx> InferCtxt<'tcx> {
/// query result. Often, but not always, this is a no-op, because
/// we already found the mapping in the "guessing" step.
///
- /// See also: `query_response_substitution_guess`
- fn unify_query_response_substitution_guess(
+ /// See also: [`Self::query_response_instantiation_guess`]
+ fn unify_query_response_instantiation_guess(
&self,
cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
original_values: &OriginalQueryValues<'tcx>,
- result_subst: &CanonicalVarValues<'tcx>,
+ result_args: &CanonicalVarValues<'tcx>,
query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>,
) -> InferResult<'tcx, ()>
where
@@ -554,15 +559,15 @@ impl<'tcx> InferCtxt<'tcx> {
{
// A closure that yields the result value for the given
// canonical variable; this is taken from
- // `query_response.var_values` after applying the substitution
- // `result_subst`.
- let substituted_query_response = |index: BoundVar| -> GenericArg<'tcx> {
- query_response.substitute_projected(self.tcx, result_subst, |v| v.var_values[index])
+ // `query_response.var_values` after applying the instantiation
+ // by `result_args`.
+ let instantiated_query_response = |index: BoundVar| -> GenericArg<'tcx> {
+ query_response.instantiate_projected(self.tcx, result_args, |v| v.var_values[index])
};
// Unify the original value for each variable with the value
- // taken from `query_response` (after applying `result_subst`).
- self.unify_canonical_vars(cause, param_env, original_values, substituted_query_response)
+ // taken from `query_response` (after applying `result_args`).
+ self.unify_canonical_vars(cause, param_env, original_values, instantiated_query_response)
}
/// Converts the region constraints resulting from a query into an
@@ -571,11 +576,11 @@ impl<'tcx> InferCtxt<'tcx> {
&'a self,
cause: &'a ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
- unsubstituted_region_constraints: &'a [QueryOutlivesConstraint<'tcx>],
- result_subst: &'a CanonicalVarValues<'tcx>,
+ uninstantiated_region_constraints: &'a [QueryOutlivesConstraint<'tcx>],
+ result_args: &'a CanonicalVarValues<'tcx>,
) -> impl Iterator> + 'a + Captures<'tcx> {
- unsubstituted_region_constraints.iter().map(move |&constraint| {
- let predicate = substitute_value(self.tcx, result_subst, constraint);
+ uninstantiated_region_constraints.iter().map(move |&constraint| {
+ let predicate = instantiate_value(self.tcx, result_args, constraint);
self.query_outlives_constraint_to_obligation(predicate, cause.clone(), param_env)
})
}
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 78ef70398e5e..0bf4598608f2 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -679,7 +679,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
/// inference context that contains each of the bound values
/// within instantiated as a fresh variable. The `f` closure is
/// invoked with the new infcx, along with the instantiated value
- /// `V` and a substitution `S`. This substitution `S` maps from
+ /// `V` and a instantiation `S`. This instantiation `S` maps from
/// the bound values in `C` to their instantiated values in `V`
/// (in other words, `S(C) = V`).
pub fn build_with_canonical(
@@ -691,8 +691,8 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
T: TypeFoldable>,
{
let infcx = self.build();
- let (value, subst) = infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical);
- (infcx, value, subst)
+ let (value, args) = infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical);
+ (infcx, value, args)
}
pub fn build(&mut self) -> InferCtxt<'tcx> {
@@ -1194,13 +1194,13 @@ impl<'tcx> InferCtxt<'tcx> {
}
GenericParamDefKind::Type { .. } => {
// Create a type inference variable for the given
- // type parameter definition. The substitutions are
+ // type parameter definition. The generic parameters are
// for actual parameters that may be referred to by
// the default of this type parameter, if it exists.
// e.g., `struct Foo(...);` when
// used in a path such as `Foo::::new()` will
// use an inference variable for `C` with `[T, U]`
- // as the substitutions for the default, `(T, U)`.
+ // as the generic parameters for the default, `(T, U)`.
let ty_var_id = self.inner.borrow_mut().type_variables().new_var(
self.universe(),
TypeVariableOrigin {
@@ -1256,7 +1256,7 @@ impl<'tcx> InferCtxt<'tcx> {
ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(effect_vid), ty).into()
}
- /// Given a set of generics defined on a type or impl, returns a substitution mapping each
+ /// Given a set of generics defined on a type or impl, returns the generic parameters mapping each
/// type/region parameter to a fresh inference variable.
pub fn fresh_args_for_item(&self, span: Span, def_id: DefId) -> GenericArgsRef<'tcx> {
GenericArgs::for_item(self.tcx, def_id, |param, _| self.var_for_def(span, param))
@@ -1411,7 +1411,7 @@ impl<'tcx> InferCtxt<'tcx> {
T: TypeFoldable>,
{
if !value.has_infer() {
- return value; // Avoid duplicated subst-folding.
+ return value; // Avoid duplicated type-folding.
}
let mut r = InferenceLiteralEraser { tcx: self.tcx };
value.fold_with(&mut r)
@@ -1458,7 +1458,7 @@ impl<'tcx> InferCtxt<'tcx> {
// Instantiates the bound variables in a given binder with fresh inference
// variables in the current universe.
//
- // Use this method if you'd like to find some substitution of the binder's
+ // Use this method if you'd like to find some generic parameters of the binder's
// variables (e.g. during a method call). If there isn't a [`BoundRegionConversionTime`]
// that corresponds to your use case, consider whether or not you should
// use [`InferCtxt::enter_forall`] instead.
@@ -1603,10 +1603,10 @@ impl<'tcx> InferCtxt<'tcx> {
/// Resolves and evaluates a constant.
///
/// The constant can be located on a trait like `::C`, in which case the given
- /// substitutions and environment are used to resolve the constant. Alternatively if the
- /// constant has generic parameters in scope the substitutions are used to evaluate the value of
+ /// generic parameters and environment are used to resolve the constant. Alternatively if the
+ /// constant has generic parameters in scope the instantiations are used to evaluate the value of
/// the constant. For example in `fn foo() { let _ = [0; bar::()]; }` the repeat count
- /// constant `bar::()` requires a substitution for `T`, if the substitution for `T` is still
+ /// constant `bar::()` requires a instantiation for `T`, if the instantiation for `T` is still
/// too generic for the constant to be evaluated then `Err(ErrorHandled::TooGeneric)` is
/// returned.
///
@@ -1652,7 +1652,7 @@ impl<'tcx> InferCtxt<'tcx> {
let unevaluated = ty::UnevaluatedConst { def: unevaluated.def, args: args_erased };
// The return value is the evaluated value which doesn't contain any reference to inference
- // variables, thus we don't need to substitute back the original values.
+ // variables, thus we don't need to instantiate back the original values.
tcx.const_eval_resolve_for_typeck(param_env_erased, unevaluated, span)
}
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index 46c4f80cb0cb..ec674407e523 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -219,7 +219,7 @@ impl<'tcx> InferCtxt<'tcx> {
/// ```
///
/// As indicating in the comments above, each of those references
- /// is (in the compiler) basically a substitution (`args`)
+ /// is (in the compiler) basically generic paramters (`args`)
/// applied to the type of a suitable `def_id` (which identifies
/// `Foo1` or `Foo2`).
///
diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
index 236dc4ec3848..d547f51f3819 100644
--- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
+++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
@@ -25,7 +25,7 @@ use crate::infer::region_constraints::VerifyIfEq;
/// * `None` if `some_type` cannot be made equal to `test_ty`,
/// no matter the values of the variables in `exists`.
/// * `Some(r)` with a suitable bound (typically the value of `bound_region`, modulo
-/// any bound existential variables, which will be substituted) for the
+/// any bound existential variables, which will be instantiated) for the
/// type under test.
///
/// NB: This function uses a simplistic, syntactic version of type equality.
@@ -59,7 +59,7 @@ pub fn extract_verify_if_eq<'tcx>(
}
} else {
// The region does not contain any bound variables, so we don't need
- // to do any substitution.
+ // to do any instantiation.
//
// Example:
//
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index 5d2f51c689b9..24b351988bf6 100644
--- a/compiler/rustc_infer/src/infer/outlives/verify.rs
+++ b/compiler/rustc_infer/src/infer/outlives/verify.rs
@@ -277,7 +277,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
/// ```
///
/// If we were given the `DefId` of `Foo::Bar`, we would return
- /// `'a`. You could then apply the substitutions from the
+ /// `'a`. You could then apply the instantiations from the
/// projection to convert this into your namespace. This also
/// works if the user writes `where >::Bar: 'a` on
/// the trait. In fact, it works by searching for just such a
diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs
index 417c8695e248..bc16d613ccbc 100644
--- a/compiler/rustc_infer/src/infer/relate/generalize.rs
+++ b/compiler/rustc_infer/src/infer/relate/generalize.rs
@@ -183,14 +183,14 @@ where
fn relate_item_args(
&mut self,
item_def_id: DefId,
- a_subst: ty::GenericArgsRef<'tcx>,
- b_subst: ty::GenericArgsRef<'tcx>,
+ a_arg: ty::GenericArgsRef<'tcx>,
+ b_arg: ty::GenericArgsRef<'tcx>,
) -> RelateResult<'tcx, ty::GenericArgsRef<'tcx>> {
if self.ambient_variance == ty::Variance::Invariant {
// Avoid fetching the variance if we are in an invariant
// context; no need, and it can induce dependency cycles
// (e.g., #41849).
- relate::relate_args_invariantly(self, a_subst, b_subst)
+ relate::relate_args_invariantly(self, a_arg, b_arg)
} else {
let tcx = self.tcx();
let opt_variances = tcx.variances_of(item_def_id);
@@ -198,8 +198,8 @@ where
self,
item_def_id,
opt_variances,
- a_subst,
- b_subst,
+ a_arg,
+ b_arg,
false,
)
}
diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs
index 58b8110157bf..8b81eac87390 100644
--- a/compiler/rustc_infer/src/infer/type_variable.rs
+++ b/compiler/rustc_infer/src/infer/type_variable.rs
@@ -118,7 +118,7 @@ pub enum TypeVariableOriginKind {
AdjustmentType,
/// In type check, when we are type checking a function that
- /// returns `-> dyn Foo`, we substitute a type variable for the
+ /// returns `-> dyn Foo`, we instantiate a type variable with the
/// return type for diagnostic purposes.
DynReturnFn,
LatticeVariable,
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index 50190058a768..e9df0505cbbd 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -285,7 +285,8 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
let obligations =
predicates.predicates.iter().enumerate().map(|(index, &(clause, span))| {
elaboratable.child_with_derived_cause(
- clause.subst_supertrait(tcx, &bound_clause.rebind(data.trait_ref)),
+ clause
+ .instantiate_supertrait(tcx, &bound_clause.rebind(data.trait_ref)),
span,
bound_clause.rebind(data),
index,
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index e66ea6f2ca96..2a4eefb7f771 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -194,16 +194,16 @@ impl<'tcx> Queries<'tcx> {
let Some((def_id, _)) = tcx.entry_fn(()) else { return };
for attr in tcx.get_attrs(def_id, sym::rustc_error) {
match attr.meta_item_list() {
- // Check if there is a `#[rustc_error(span_delayed_bug_from_inside_query)]`.
+ // Check if there is a `#[rustc_error(delayed_bug_from_inside_query)]`.
Some(list)
if list.iter().any(|list_item| {
matches!(
list_item.ident().map(|i| i.name),
- Some(sym::span_delayed_bug_from_inside_query)
+ Some(sym::delayed_bug_from_inside_query)
)
}) =>
{
- tcx.ensure().trigger_span_delayed_bug(def_id);
+ tcx.ensure().trigger_delayed_bug(def_id);
}
// Bare `#[rustc_error]`.
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 5652a34103b0..785895e0ab82 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -319,6 +319,11 @@ lint_invalid_nan_comparisons_lt_le_gt_ge = incorrect NaN comparison, NaN is not
lint_invalid_reference_casting_assign_to_ref = assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
.label = casting happend here
+lint_invalid_reference_casting_bigger_layout = casting references to a bigger memory layout than the backing allocation is undefined behavior, even if the reference is unused
+ .label = casting happend here
+ .alloc = backing allocation comes from here
+ .layout = casting from `{$from_ty}` ({$from_size} bytes) to `{$to_ty}` ({$to_size} bytes)
+
lint_invalid_reference_casting_borrow_as_mut = casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
.label = casting happend here
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 42d9760f8aa1..7445e2e80b40 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -716,7 +716,7 @@ pub enum InvalidFromUtf8Diag {
// reference_casting.rs
#[derive(LintDiagnostic)]
-pub enum InvalidReferenceCastingDiag {
+pub enum InvalidReferenceCastingDiag<'tcx> {
#[diag(lint_invalid_reference_casting_borrow_as_mut)]
#[note(lint_invalid_reference_casting_note_book)]
BorrowAsMut {
@@ -733,6 +733,18 @@ pub enum InvalidReferenceCastingDiag {
#[note(lint_invalid_reference_casting_note_ty_has_interior_mutability)]
ty_has_interior_mutability: Option<()>,
},
+ #[diag(lint_invalid_reference_casting_bigger_layout)]
+ #[note(lint_layout)]
+ BiggerLayout {
+ #[label]
+ orig_cast: Option,
+ #[label(lint_alloc)]
+ alloc: Span,
+ from_ty: Ty<'tcx>,
+ from_size: u64,
+ to_ty: Ty<'tcx>,
+ to_size: u64,
+ },
}
// hidden_unicode_codepoints.rs
diff --git a/compiler/rustc_lint/src/reference_casting.rs b/compiler/rustc_lint/src/reference_casting.rs
index 9e6cca853178..519ab8bd50fe 100644
--- a/compiler/rustc_lint/src/reference_casting.rs
+++ b/compiler/rustc_lint/src/reference_casting.rs
@@ -1,6 +1,7 @@
use rustc_ast::Mutability;
use rustc_hir::{Expr, ExprKind, UnOp};
-use rustc_middle::ty::{self, TypeAndMut};
+use rustc_middle::ty::layout::LayoutOf as _;
+use rustc_middle::ty::{self, layout::TyAndLayout, TypeAndMut};
use rustc_span::sym;
use crate::{lints::InvalidReferenceCastingDiag, LateContext, LateLintPass, LintContext};
@@ -38,13 +39,19 @@ declare_lint_pass!(InvalidReferenceCasting => [INVALID_REFERENCE_CASTING]);
impl<'tcx> LateLintPass<'tcx> for InvalidReferenceCasting {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
if let Some((e, pat)) = borrow_or_assign(cx, expr) {
- if matches!(pat, PatternKind::Borrow { mutbl: Mutability::Mut } | PatternKind::Assign) {
- let init = cx.expr_or_init(e);
+ let init = cx.expr_or_init(e);
+ let orig_cast = if init.span != e.span { Some(init.span) } else { None };
- let Some(ty_has_interior_mutability) = is_cast_from_ref_to_mut_ptr(cx, init) else {
- return;
- };
- let orig_cast = if init.span != e.span { Some(init.span) } else { None };
+ // small cache to avoid recomputing needlesly computing peel_casts of init
+ let mut peel_casts = {
+ let mut peel_casts_cache = None;
+ move || *peel_casts_cache.get_or_insert_with(|| peel_casts(cx, init))
+ };
+
+ if matches!(pat, PatternKind::Borrow { mutbl: Mutability::Mut } | PatternKind::Assign)
+ && let Some(ty_has_interior_mutability) =
+ is_cast_from_ref_to_mut_ptr(cx, init, &mut peel_casts)
+ {
let ty_has_interior_mutability = ty_has_interior_mutability.then_some(());
cx.emit_span_lint(
@@ -63,6 +70,23 @@ impl<'tcx> LateLintPass<'tcx> for InvalidReferenceCasting {
},
);
}
+
+ if let Some((from_ty_layout, to_ty_layout, e_alloc)) =
+ is_cast_to_bigger_memory_layout(cx, init, &mut peel_casts)
+ {
+ cx.emit_span_lint(
+ INVALID_REFERENCE_CASTING,
+ expr.span,
+ InvalidReferenceCastingDiag::BiggerLayout {
+ orig_cast,
+ alloc: e_alloc.span,
+ from_ty: from_ty_layout.ty,
+ from_size: from_ty_layout.layout.size().bytes(),
+ to_ty: to_ty_layout.ty,
+ to_size: to_ty_layout.layout.size().bytes(),
+ },
+ );
+ }
}
}
}
@@ -124,6 +148,7 @@ fn borrow_or_assign<'tcx>(
fn is_cast_from_ref_to_mut_ptr<'tcx>(
cx: &LateContext<'tcx>,
orig_expr: &'tcx Expr<'tcx>,
+ mut peel_casts: impl FnMut() -> (&'tcx Expr<'tcx>, bool),
) -> Option {
let end_ty = cx.typeck_results().node_type(orig_expr.hir_id);
@@ -132,7 +157,7 @@ fn is_cast_from_ref_to_mut_ptr<'tcx>(
return None;
}
- let (e, need_check_freeze) = peel_casts(cx, orig_expr);
+ let (e, need_check_freeze) = peel_casts();
let start_ty = cx.typeck_results().node_type(e.hir_id);
if let ty::Ref(_, inner_ty, Mutability::Not) = start_ty.kind() {
@@ -151,6 +176,49 @@ fn is_cast_from_ref_to_mut_ptr<'tcx>(
}
}
+fn is_cast_to_bigger_memory_layout<'tcx>(
+ cx: &LateContext<'tcx>,
+ orig_expr: &'tcx Expr<'tcx>,
+ mut peel_casts: impl FnMut() -> (&'tcx Expr<'tcx>, bool),
+) -> Option<(TyAndLayout<'tcx>, TyAndLayout<'tcx>, Expr<'tcx>)> {
+ let end_ty = cx.typeck_results().node_type(orig_expr.hir_id);
+
+ let ty::RawPtr(TypeAndMut { ty: inner_end_ty, mutbl: _ }) = end_ty.kind() else {
+ return None;
+ };
+
+ let (e, _) = peel_casts();
+ let start_ty = cx.typeck_results().node_type(e.hir_id);
+
+ let ty::Ref(_, inner_start_ty, _) = start_ty.kind() else {
+ return None;
+ };
+
+ // try to find the underlying allocation
+ let e_alloc = cx.expr_or_init(e);
+ let e_alloc =
+ if let ExprKind::AddrOf(_, _, inner_expr) = e_alloc.kind { inner_expr } else { e_alloc };
+ let alloc_ty = cx.typeck_results().node_type(e_alloc.hir_id);
+
+ // if we do not find it we bail out, as this may not be UB
+ // see https://github.com/rust-lang/unsafe-code-guidelines/issues/256
+ if alloc_ty.is_any_ptr() {
+ return None;
+ }
+
+ let from_layout = cx.layout_of(*inner_start_ty).ok()?;
+ let alloc_layout = cx.layout_of(alloc_ty).ok()?;
+ let to_layout = cx.layout_of(*inner_end_ty).ok()?;
+
+ if to_layout.layout.size() > from_layout.layout.size()
+ && to_layout.layout.size() > alloc_layout.layout.size()
+ {
+ Some((from_layout, to_layout, *e_alloc))
+ } else {
+ None
+ }
+}
+
fn peel_casts<'tcx>(cx: &LateContext<'tcx>, mut e: &'tcx Expr<'tcx>) -> (&'tcx Expr<'tcx>, bool) {
let mut gone_trough_unsafe_cell_raw_get = false;
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 11cb1bb6d9e6..72e9744295bc 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1084,6 +1084,8 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
parent_did,
false,
data.is_non_exhaustive,
+ // FIXME: unnamed fields in crate metadata is unimplemented yet.
+ false,
),
)
}
@@ -1126,6 +1128,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
adt_kind,
variants.into_iter().map(|(_, variant)| variant).collect(),
repr,
+ false,
)
}
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 988388edfd5f..d79d4b226a54 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -215,7 +215,7 @@ provide! { tcx, def_id, other, cdata,
variances_of => { table }
fn_sig => { table }
codegen_fn_attrs => { table }
- impl_trait_ref => { table }
+ impl_trait_header => { table }
const_param_default => { table }
object_lifetime_default => { table }
thir_abstract_const => { table }
@@ -234,7 +234,6 @@ provide! { tcx, def_id, other, cdata,
unused_generic_params => { cdata.root.tables.unused_generic_params.get(cdata, def_id.index) }
def_kind => { cdata.def_kind(def_id.index) }
impl_parent => { table }
- impl_polarity => { table_direct }
defaultness => { table_direct }
constness => { table_direct }
coerce_unsized_info => {
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 6ca1973396f8..4a24c038f7ae 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1969,10 +1969,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
let def_id = id.owner_id.to_def_id();
self.tables.defaultness.set_some(def_id.index, tcx.defaultness(def_id));
- self.tables.impl_polarity.set_some(def_id.index, tcx.impl_polarity(def_id));
- if of_trait && let Some(trait_ref) = tcx.impl_trait_ref(def_id) {
- record!(self.tables.impl_trait_ref[def_id] <- trait_ref);
+ if of_trait && let Some(header) = tcx.impl_trait_header(def_id) {
+ record!(self.tables.impl_trait_header[def_id] <- header);
+ let trait_ref = header.map_bound(|h| h.trait_ref);
let trait_ref = trait_ref.instantiate_identity();
let simplified_self_ty = fast_reject::simplify_type(
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 8205e995c196..4d0a6cb60ee7 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -423,7 +423,7 @@ define_tables! {
variances_of: Table>,
fn_sig: Table>>>,
codegen_fn_attrs: Table>,
- impl_trait_ref: Table>>>,
+ impl_trait_header: Table>>>,
const_param_default: Table>>>,
object_lifetime_default: Table>,
optimized_mir: Table>>,
@@ -433,7 +433,6 @@ define_tables! {
promoted_mir: Table>>>,
thir_abstract_const: Table>>>,
impl_parent: Table,
- impl_polarity: Table,
constness: Table,
defaultness: Table,
// FIXME(eddyb) perhaps compute this on the fly if cheap enough?
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 50817dd0a809..8e1cb6a514f8 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -756,6 +756,13 @@ impl<'hir> Map<'hir> {
}
}
+ pub fn expect_field(self, id: HirId) -> &'hir FieldDef<'hir> {
+ match self.tcx.hir_node(id) {
+ Node::Field(field) => field,
+ _ => bug!("expected field, found {}", self.node_to_string(id)),
+ }
+ }
+
pub fn expect_foreign_item(self, id: OwnerId) -> &'hir ForeignItem<'hir> {
match self.tcx.hir_owner_node(id) {
OwnerNode::ForeignItem(item) => item,
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index e544c2a26e82..7b65c11bc3c8 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -53,7 +53,7 @@ impl<'tcx> ty::TypeFoldable> for CanonicalVarInfos<'tcx> {
/// A set of values corresponding to the canonical variables from some
/// `Canonical`. You can give these values to
-/// `canonical_value.substitute` to substitute them into the canonical
+/// `canonical_value.instantiate` to instantiate them into the canonical
/// value at the right places.
///
/// When you canonicalize a value `V`, you get back one of these
diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs
index 5f9e7f6e3685..e8aca5f2e7d8 100644
--- a/compiler/rustc_middle/src/mir/interpret/queries.rs
+++ b/compiler/rustc_middle/src/mir/interpret/queries.rs
@@ -11,13 +11,13 @@ use rustc_session::lint;
use rustc_span::{Span, DUMMY_SP};
impl<'tcx> TyCtxt<'tcx> {
- /// Evaluates a constant without providing any substitutions. This is useful to evaluate consts
+ /// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts
/// that can't take any generic arguments like statics, const items or enum discriminants. If a
/// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned.
#[instrument(skip(self), level = "debug")]
pub fn const_eval_poly(self, def_id: DefId) -> EvalToConstValueResult<'tcx> {
- // In some situations def_id will have substitutions within scope, but they aren't allowed
- // to be used. So we can't use `Instance::mono`, instead we feed unresolved substitutions
+ // In some situations def_id will have generic parameters within scope, but they aren't allowed
+ // to be used. So we can't use `Instance::mono`, instead we feed unresolved generic parameters
// into `const_eval` which will return `ErrorHandled::ToGeneric` if any of them are
// encountered.
let args = GenericArgs::identity_for_item(self, def_id);
@@ -29,10 +29,10 @@ impl<'tcx> TyCtxt<'tcx> {
/// Resolves and evaluates a constant.
///
/// The constant can be located on a trait like `::C`, in which case the given
- /// substitutions and environment are used to resolve the constant. Alternatively if the
- /// constant has generic parameters in scope the substitutions are used to evaluate the value of
+ /// generic parameters and environment are used to resolve the constant. Alternatively if the
+ /// constant has generic parameters in scope the generic parameters are used to evaluate the value of
/// the constant. For example in `fn foo() { let _ = [0; bar::()]; }` the repeat count
- /// constant `bar::()` requires a substitution for `T`, if the substitution for `T` is still
+ /// constant `bar::()` requires a instantiation for `T`, if the instantiation for `T` is still
/// too generic for the constant to be evaluated then `Err(ErrorHandled::TooGeneric)` is
/// returned.
#[instrument(level = "debug", skip(self))]
@@ -214,13 +214,13 @@ impl<'tcx> TyCtxtAt<'tcx> {
}
impl<'tcx> TyCtxtEnsure<'tcx> {
- /// Evaluates a constant without providing any substitutions. This is useful to evaluate consts
+ /// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts
/// that can't take any generic arguments like statics, const items or enum discriminants. If a
/// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned.
#[instrument(skip(self), level = "debug")]
pub fn const_eval_poly(self, def_id: DefId) {
- // In some situations def_id will have substitutions within scope, but they aren't allowed
- // to be used. So we can't use `Instance::mono`, instead we feed unresolved substitutions
+ // In some situations def_id will have generic parameters within scope, but they aren't allowed
+ // to be used. So we can't use `Instance::mono`, instead we feed unresolved generic parameters
// into `const_eval` which will return `ErrorHandled::ToGeneric` if any of them are
// encountered.
let args = GenericArgs::identity_for_item(self.tcx, def_id);
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index 6937df7bb189..3cd251caf5e3 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -186,7 +186,7 @@ impl<'tcx> MonoItem<'tcx> {
MonoItem::GlobalAsm(..) => return true,
};
- !tcx.subst_and_check_impossible_predicates((def_id, &args))
+ !tcx.instantiate_and_check_impossible_predicates((def_id, &args))
}
pub fn local_span(&self, tcx: TyCtxt<'tcx>) -> Option {
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index b601b465668e..a011f6114de9 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -491,7 +491,7 @@ fn write_mir_sig(tcx: TyCtxt<'_>, body: &Body<'_>, w: &mut dyn io::Write) -> io:
let kind = tcx.def_kind(def_id);
let is_function = match kind {
DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) => true,
- _ => tcx.is_closure_or_coroutine(def_id),
+ _ => tcx.is_closure_like(def_id),
};
match (kind, body.source.promoted) {
(_, Some(i)) => write!(w, "{i:?} in ")?,
diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs
index a272a51f3274..5666a59e38e8 100644
--- a/compiler/rustc_middle/src/query/erase.rs
+++ b/compiler/rustc_middle/src/query/erase.rs
@@ -177,8 +177,8 @@ impl EraseType for Option> {
type Result = [u8; size_of::