mirror of https://github.com/rust-lang/rust.git
Merge from rustc
This commit is contained in:
commit
893615fb5f
|
@ -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.
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)),
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)?;
|
||||
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -340,7 +340,6 @@ impl<'cx, 'tcx> LoanInvalidationsGenerator<'cx, 'tcx> {
|
|||
self,
|
||||
self.tcx,
|
||||
self.body,
|
||||
location,
|
||||
(sd, place),
|
||||
self.borrow_set,
|
||||
|_| true,
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)]);
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)?;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)?;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 => {}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
||||
```
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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)),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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`).
|
||||
///
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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| {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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()),
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(()),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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).
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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>`.
|
||||
///
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -142,7 +142,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
|||
let param_ty = return_if_err!(self.mc.pat_ty_adjusted(param.pat));
|
||||
debug!("consume_body: param_ty = {:?}", param_ty);
|
||||
|
||||
let param_place = self.mc.cat_rvalue(param.hir_id, param.pat.span, param_ty);
|
||||
let param_place = self.mc.cat_rvalue(param.hir_id, param_ty);
|
||||
|
||||
self.walk_irrefutable_pat(¶m_place, param.pat);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
})
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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,
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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`).
|
||||
///
|
||||
|
|
|
@ -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:
|
||||
//
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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]`.
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue