Auto merge of #3298 - rust-lang:rustup-2024-02-13, r=oli-obk

Automatic Rustup
This commit is contained in:
bors 2024-02-13 08:33:04 +00:00
commit 41555ab4a3
279 changed files with 5460 additions and 1923 deletions

View File

@ -2107,9 +2107,9 @@ pub enum TyKind {
/// A tuple (`(A, B, C, D,...)`).
Tup(ThinVec<P<Ty>>),
/// An anonymous struct type i.e. `struct { foo: Type }`
AnonStruct(ThinVec<FieldDef>),
AnonStruct(NodeId, ThinVec<FieldDef>),
/// An anonymous union type i.e. `union { bar: Type }`
AnonUnion(ThinVec<FieldDef>),
AnonUnion(NodeId, ThinVec<FieldDef>),
/// A path (`module::module::...::Type`), optionally
/// "qualified", e.g., `<Vec<T> 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.

View File

@ -514,7 +514,8 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, 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));
}
}

View File

@ -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)
}
}

View File

@ -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,

View File

@ -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)),

View File

@ -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),
}

View File

@ -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);
}

View File

@ -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<AnnotatedBorrowFnSignature<'tcx>> {
// 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<AnnotatedBorrowFnSignature<'tcx>> {
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)?;

View File

@ -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()
}

View File

@ -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)
}

View File

@ -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,

View File

@ -340,7 +340,6 @@ impl<'cx, 'tcx> LoanInvalidationsGenerator<'cx, 'tcx> {
self,
self.tcx,
self.body,
location,
(sd, place),
self.borrow_set,
|_| true,

View File

@ -662,7 +662,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
polonius_output: Option<Rc<PoloniusOutput>>,
) -> (Option<ClosureRegionRequirements<'tcx>>, 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));

View File

@ -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::<FxIndexSet<_>>();
debug!(?subst_regions);
let arg_regions = arg_regions.into_iter().collect::<FxIndexSet<_>>();
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)

View File

@ -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;
}

View File

@ -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<FieldTy>;
super::assert_ty_bounds(
cx,

View File

@ -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<ty>;`.
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)]);

View File

@ -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());

View File

@ -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"),

View File

@ -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());

View File

@ -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,
};

View File

@ -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);

View File

@ -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)?;

View File

@ -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<G: EmissionGuarantee>(self, dcx: &DiagCtxt, builder: &mut DiagnosticBuilder<'_, G>);
fn add_args<G: EmissionGuarantee>(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<G: EmissionGuarantee>(
self,
dcx: &DiagCtxt,
builder: &mut DiagnosticBuilder<'_, G>,
) {
fn add_args<G: EmissionGuarantee>(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<G: EmissionGuarantee>(self, dcx: &DiagCtxt, err: &mut DiagnosticBuilder<'_, G>) {
fn add_args<G: EmissionGuarantee>(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<G: EmissionGuarantee>(
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<G: EmissionGuarantee>(self, _: &DiagCtxt, builder: &mut DiagnosticBuilder<'_, G>) {
fn add_args<G: EmissionGuarantee>(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<G: EmissionGuarantee>(
self,
dcx: &DiagCtxt,
builder: &mut DiagnosticBuilder<'_, G>,
) {
fn add_args<G: EmissionGuarantee>(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<G: EmissionGuarantee>(
self,
dcx: &DiagCtxt,
builder: &mut DiagnosticBuilder<'_, G>,
) {
fn add_args<G: EmissionGuarantee>(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<G: EmissionGuarantee>(self, _: &DiagCtxt, _: &mut DiagnosticBuilder<'_, G>) {}
fn add_args<G: EmissionGuarantee>(self, _: &mut DiagnosticBuilder<'_, G>) {}
}
impl rustc_errors::IntoDiagnosticArg for InternKind {

View File

@ -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<TyCtxt<'tcx>>,
>(
&self,
value: T,
) -> Result<T, ErrorHandled> {
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<T: TypeFoldable<TyCtxt<'tcx>>>(
pub(super) fn instantiate_from_frame_and_normalize_erasing_regions<
T: TypeFoldable<TyCtxt<'tcx>>,
>(
&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

View File

@ -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

View File

@ -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,

View File

@ -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)?;
}

View File

@ -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 {

View File

@ -19,11 +19,11 @@ where
}
struct FoundParam;
struct UsedParamsNeedSubstVisitor<'tcx> {
struct UsedParamsNeedInstantiationVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
}
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for UsedParamsNeedSubstVisitor<'tcx> {
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for UsedParamsNeedInstantiationVisitor<'tcx> {
type BreakTy = FoundParam;
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
@ -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 {

View File

@ -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 => {}

View File

@ -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;
}
}

View File

@ -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()

View File

@ -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
}

View File

@ -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);

View File

@ -22,9 +22,9 @@ fn foo<T>(x: Vec<T>) {
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:
```

View File

@ -15,9 +15,9 @@ There will be an error about `bool` not implementing `Index<u8>`, 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

View File

@ -15,9 +15,9 @@ there will be an error about `bool` not implementing `Index<u8>`, 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

View File

@ -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<i32>`, `bool` will be expected to
implement `A<bool>`, 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:

View File

@ -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::<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

View File

@ -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<ErrorGuaranteed>,
/// The error guarantee from all emitted lint errors. The length gives the
/// lint error count.
lint_err_guars: Vec<ErrorGuaranteed>,
/// The delayed bugs and their error guarantees.
delayed_bugs: Vec<(DelayedDiagnostic, ErrorGuaranteed)>,
good_path_delayed_bugs: Vec<DelayedDiagnostic>,
/// 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<DynEmitter>,
delayed_bugs: Vec<DelayedDiagnostic>,
good_path_delayed_bugs: Vec<DelayedDiagnostic>,
/// 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<MultiSpan>,
msg: impl Into<DiagnosticMessage>,
) -> 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<DiagnosticMessage>) -> 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<DiagnosticMessage>) -> 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<DiagnosticMessage>,
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<MultiSpan>,
msg: impl Into<DiagnosticMessage>,
) -> 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<DiagnosticMessage>) -> 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<MultiSpan>,
msg: impl Into<DiagnosticMessage>,
) -> 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<DiagnosticMessage>,
) -> 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<DiagnosticMessage>) -> 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<DiagnosticMessage>) -> 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<DiagnosticMessage>) -> 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<MultiSpan>,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, BugAbort> {
self.struct_bug(msg).with_span(span)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn span_fatal(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
self.struct_span_fatal(span, msg).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn span_err(
&self,
span: impl Into<MultiSpan>,
msg: impl Into<DiagnosticMessage>,
) -> ErrorGuaranteed {
self.struct_span_err(span, msg).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn span_warn(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) {
self.struct_span_warn(span, msg).emit()
}
#[track_caller]
pub fn span_bug(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
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<DiagnosticMessage>) -> ErrorGuaranteed {
DiagnosticBuilder::<ErrorGuaranteed>::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<MultiSpan>,
msg: impl Into<DiagnosticMessage>,
) -> ErrorGuaranteed {
DiagnosticBuilder::<ErrorGuaranteed>::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<DiagnosticMessage>) {
DiagnosticBuilder::<()>::new(self, GoodPathDelayedBug, msg).emit()
}
#[track_caller]
#[rustc_lint_diagnostics]
pub fn span_note(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) {
self.struct_span_note(span, msg).emit()
}
#[track_caller]
#[rustc_lint_diagnostics]
pub fn struct_span_note(
&self,
span: impl Into<MultiSpan>,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, ()> {
DiagnosticBuilder::new(self, Note, msg).with_span(span)
}
#[rustc_lint_diagnostics]
pub fn fatal(&self, msg: impl Into<DiagnosticMessage>) -> ! {
self.struct_fatal(msg).emit()
}
#[rustc_lint_diagnostics]
pub fn err(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
self.struct_err(msg).emit()
}
#[rustc_lint_diagnostics]
pub fn warn(&self, msg: impl Into<DiagnosticMessage>) {
self.struct_warn(msg).emit()
}
#[rustc_lint_diagnostics]
pub fn note(&self, msg: impl Into<DiagnosticMessage>) {
self.struct_note(msg).emit()
}
#[rustc_lint_diagnostics]
pub fn bug(&self, msg: impl Into<DiagnosticMessage>) -> ! {
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<ErrorGuaranteed> {
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<ErrorGuaranteed> {
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<ErrorGuaranteed> {
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<DiagnosticMessage>) -> 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<DiagnosticMessage>) -> ! {
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<MultiSpan>,
msg: impl Into<DiagnosticMessage>,
) -> 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<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
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<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, FatalAbort> {
DiagnosticBuilder::new(self, Fatal, msg)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn fatal(&self, msg: impl Into<DiagnosticMessage>) -> ! {
self.struct_fatal(msg).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_span_fatal(
&self,
span: impl Into<MultiSpan>,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, FatalAbort> {
self.struct_fatal(msg).with_span(span)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn span_fatal(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
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<DiagnosticMessage>) -> DiagnosticBuilder<'_> {
DiagnosticBuilder::new(self, Error, msg)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn err(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
self.struct_err(msg).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_span_err(
&self,
span: impl Into<MultiSpan>,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_> {
self.struct_err(msg).with_span(span)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn span_err(
&self,
span: impl Into<MultiSpan>,
msg: impl Into<DiagnosticMessage>,
) -> 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<DiagnosticMessage>) -> ErrorGuaranteed {
DiagnosticBuilder::<ErrorGuaranteed>::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<MultiSpan>,
msg: impl Into<DiagnosticMessage>,
) -> ErrorGuaranteed {
DiagnosticBuilder::<ErrorGuaranteed>::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<DiagnosticMessage>) {
DiagnosticBuilder::<()>::new(self, GoodPathDelayedBug, msg).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
DiagnosticBuilder::new(self, Warning, msg)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn warn(&self, msg: impl Into<DiagnosticMessage>) {
self.struct_warn(msg).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_span_warn(
&self,
span: impl Into<MultiSpan>,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, ()> {
self.struct_warn(msg).with_span(span)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn span_warn(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) {
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<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
DiagnosticBuilder::new(self, Note, msg)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn note(&self, msg: impl Into<DiagnosticMessage>) {
self.struct_note(msg).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_span_note(
&self,
span: impl Into<MultiSpan>,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, ()> {
DiagnosticBuilder::new(self, Note, msg).with_span(span)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn span_note(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) {
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<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
DiagnosticBuilder::new(self, Help, msg)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_allow(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
DiagnosticBuilder::new(self, Allow, msg)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_expect(
&self,
msg: impl Into<DiagnosticMessage>,
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<ErrorGuaranteed> {
self.err_guars.get(0).copied()
}
fn has_errors_or_lint_errors(&self) -> Option<ErrorGuaranteed> {
self.has_errors().or_else(|| self.lint_err_guars.get(0).copied())
}
fn has_errors_or_lint_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
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<DiagnosticMessage>) {
@ -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<LintExpectationId>),
/// 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.

View File

@ -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),

View File

@ -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)),

View File

@ -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

View File

@ -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 },
}
}
}

View File

@ -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., `<Vec<T> as Trait>::Type` or `<T>::Target`).
///

View File

@ -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);
}
}
}

View File

@ -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

View File

@ -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| {

View File

@ -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<Ty<'tcx>>,
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.

View File

@ -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);

View File

@ -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()),

View File

@ -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;
}
// <ty as Deref>
let trait_ref = ty::TraitRef::new(tcx, tcx.lang_items().deref_trait()?, [ty]);
let cause = traits::ObligationCause::misc(self.span, self.body_id);

View File

@ -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::<Vec<_>>();
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(()),

View File

@ -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

View File

@ -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);

View File

@ -56,7 +56,7 @@ type variable is an instance of a type parameter. That is,
given a generic function `fn foo<T>(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).

View File

@ -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);

View File

@ -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<TyCtxt<'tcx>>>(
// 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>(
/// `<P0 as Trait<P1..Pn>>::GAT<Pn..Pm>` 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<T: TypeFoldable<TyCtxt<'tcx>>>(
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<TyCtxt<'tcx>> for GATSubstCollector<'tcx> {
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GATArgsCollector<'tcx> {
type BreakTy = !;
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
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<T: Copy = String>`.
// 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<T: Copy = String>`, 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;
}
}

View File

@ -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

View File

@ -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<FieldIdx> {
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<Span> for FieldDeclSpan {
fn from(span: Span) -> Self {
Self::NotNested(span)
}
}
impl From<NestedSpan> for FieldDeclSpan {
fn from(span: NestedSpan) -> Self {
Self::Nested(span)
}
}
struct FieldUniquenessCheckContext<'tcx> {
tcx: TyCtxt<'tcx>,
seen_fields: FxHashMap<Ident, FieldDeclSpan>,
}
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<LocalDefId>,
@ -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<Ident, Span> = 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<ty::EarlyBinder<ty::TraitRef<'_>>> {
) -> Option<ty::EarlyBinder<ty::ImplTraitHeader<'_>>> {
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),
}
}

View File

@ -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

View File

@ -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());

View File

@ -119,7 +119,7 @@ pub fn identify_constrained_generic_params<'tcx>(
/// * `<U as Iterator>::Item = T` -- a desugared ProjectionPredicate
///
/// When we, for example, try to go over the trait-reference
/// `IntoIter<u32> as Trait`, we substitute the impl parameters with fresh
/// `IntoIter<u32> as Trait`, we instantiate the impl parameters with fresh
/// variables and match them with the impl trait-ref, so we know that
/// `$U = IntoIter<u32>`.
///

View File

@ -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<UnnamedFieldsReprFieldDefined>,
#[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,
}

View File

@ -34,8 +34,8 @@
//! impl<T, I: Iterator<Item=T>> SpecExtend<T> for I { /* default impl */ }
//! ```
//!
//! We get that the subst for `impl2` are `[T, std::vec::IntoIter<T>]`. `T` is
//! constrained to be `<I as Iterator>::Item`, so we check only
//! We get that the generic pamameters for `impl2` are `[T, std::vec::IntoIter<T>]`.
//! `T` is constrained to be `<I as Iterator>::Item`, so we check only
//! `std::vec::IntoIter<T>` 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

View File

@ -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);

View File

@ -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);
}

View File

@ -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);

View File

@ -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);

View File

@ -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).

View File

@ -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;
}
}

View File

@ -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(&param_place, param.pat);
}

View File

@ -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<usize>,
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<T>::method` and `<Foo<T>>::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,

View File

@ -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)
}

View File

@ -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<NonZero*> 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 }

View File

@ -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 {

View File

@ -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)
}

View File

@ -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);

View File

@ -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

View File

@ -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<T>(&self, value: ty::Binder<'tcx, T>) -> T
where

View File

@ -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)

View File

@ -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)
})

View File

@ -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<T>>::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).

View File

@ -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);

View File

@ -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

View File

@ -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()

View File

@ -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<TyCtxt<'tcx>>;
/// 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<T>(
fn instantiate_projected<T>(
&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<TyCtxt<'tcx>>,
{
self.substitute_projected(tcx, var_values, |value| value.clone())
self.instantiate_projected(tcx, var_values, |value| value.clone())
}
fn substitute_projected<T>(
fn instantiate_projected<T>(
&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,

View File

@ -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<T>(
@ -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,

View File

@ -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<TyCtxt<'tcx>>,
{
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<R>(
&self,
cause: &ObligationCause<'tcx>,
@ -251,8 +251,13 @@ impl<'tcx> InferCtxt<'tcx> {
where
R: Debug + TypeFoldable<TyCtxt<'tcx>>,
{
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<R>(
fn query_response_instantiation<R>(
&self,
cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
@ -366,11 +371,11 @@ impl<'tcx> InferCtxt<'tcx> {
R: Debug + TypeFoldable<TyCtxt<'tcx>>,
{
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<R>(
fn query_response_instantiation_guess<R>(
&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<R>(
/// See also: [`Self::query_response_instantiation_guess`]
fn unify_query_response_instantiation_guess<R>(
&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<Item = PredicateObligation<'tcx>> + '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)
})
}

View File

@ -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<T>(
@ -691,8 +691,8 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
T: TypeFoldable<TyCtxt<'tcx>>,
{
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<A, B, C = (A, B)>(...);` when
// used in a path such as `Foo::<T, U>::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<TyCtxt<'tcx>>,
{
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 `<A as B>::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<T>() { let _ = [0; bar::<T>()]; }` the repeat count
/// constant `bar::<T>()` requires a substitution for `T`, if the substitution for `T` is still
/// constant `bar::<T>()` 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)
}

View File

@ -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`).
///

View File

@ -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:
//

View File

@ -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 <Self as Foo<'a>>::Bar: 'a` on
/// the trait. In fact, it works by searching for just such a

View File

@ -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,
)
}

View File

@ -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,

View File

@ -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,

View File

@ -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]`.

View File

@ -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

View File

@ -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<Span>,
#[label(lint_alloc)]
alloc: Span,
from_ty: Ty<'tcx>,
from_size: u64,
to_ty: Ty<'tcx>,
to_size: u64,
},
}
// hidden_unicode_codepoints.rs

Some files were not shown because too many files have changed in this diff Show More