mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
Auto merge of #107768 - matthiaskrgr:rollup-9u4cal4, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - #107719 (Remove `arena_cache` modifier from `upstream_monomorphizations_for`) - #107740 (Avoid locking the global context across the `after_expansion` callback) - #107746 (Split fn_ctxt/adjust_fulfillment_errors from fn_ctxt/checks) - #107749 (allow quick-edit convenience) - #107750 (make more readable) - #107755 (remove binder from query constraints) - #107756 (miri: fix ICE when running out of address space) - #107764 (llvm-16: Use Triple.h from new header location.) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
3f059f6046
@ -83,16 +83,8 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
||||
}
|
||||
self.constraints.member_constraints = tmp;
|
||||
|
||||
for (predicate, constraint_category) in outlives {
|
||||
// At the moment, we never generate any "higher-ranked"
|
||||
// region constraints like `for<'a> 'a: 'b`. At some point
|
||||
// when we move to universes, we will, and this assertion
|
||||
// will start to fail.
|
||||
let predicate = predicate.no_bound_vars().unwrap_or_else(|| {
|
||||
bug!("query_constraint {:?} contained bound vars", predicate,);
|
||||
});
|
||||
|
||||
self.convert(predicate, *constraint_category);
|
||||
for &(predicate, constraint_category) in outlives {
|
||||
self.convert(predicate, constraint_category);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,13 +78,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
col: u32,
|
||||
) -> MPlaceTy<'tcx, M::Provenance> {
|
||||
let loc_details = &self.tcx.sess.opts.unstable_opts.location_detail;
|
||||
// This can fail if rustc runs out of memory right here. Trying to emit an error would be
|
||||
// pointless, since that would require allocating more memory than these short strings.
|
||||
let file = if loc_details.file {
|
||||
self.allocate_str(filename.as_str(), MemoryKind::CallerLocation, Mutability::Not)
|
||||
.unwrap()
|
||||
} else {
|
||||
// FIXME: This creates a new allocation each time. It might be preferable to
|
||||
// perform this allocation only once, and re-use the `MPlaceTy`.
|
||||
// See https://github.com/rust-lang/rust/pull/89920#discussion_r730012398
|
||||
self.allocate_str("<redacted>", MemoryKind::CallerLocation, Mutability::Not)
|
||||
self.allocate_str("<redacted>", MemoryKind::CallerLocation, Mutability::Not).unwrap()
|
||||
};
|
||||
let line = if loc_details.line { Scalar::from_u32(line) } else { Scalar::from_u32(0) };
|
||||
let col = if loc_details.column { Scalar::from_u32(col) } else { Scalar::from_u32(0) };
|
||||
@ -95,8 +98,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
.bound_type_of(self.tcx.require_lang_item(LangItem::PanicLocation, None))
|
||||
.subst(*self.tcx, self.tcx.mk_substs([self.tcx.lifetimes.re_erased.into()].iter()));
|
||||
let loc_layout = self.layout_of(loc_ty).unwrap();
|
||||
// This can fail if rustc runs out of memory right here. Trying to emit an error would be
|
||||
// pointless, since that would require allocating more memory than a Location.
|
||||
let location = self.allocate(loc_layout, MemoryKind::CallerLocation).unwrap();
|
||||
|
||||
// Initialize fields.
|
||||
|
@ -291,7 +291,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
|
||||
fn adjust_alloc_base_pointer(
|
||||
ecx: &InterpCx<'mir, 'tcx, Self>,
|
||||
ptr: Pointer,
|
||||
) -> Pointer<Self::Provenance>;
|
||||
) -> InterpResult<'tcx, Pointer<Self::Provenance>>;
|
||||
|
||||
/// "Int-to-pointer cast"
|
||||
fn ptr_from_addr_cast(
|
||||
@ -505,8 +505,8 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
|
||||
fn adjust_alloc_base_pointer(
|
||||
_ecx: &InterpCx<$mir, $tcx, Self>,
|
||||
ptr: Pointer<AllocId>,
|
||||
) -> Pointer<AllocId> {
|
||||
ptr
|
||||
) -> InterpResult<$tcx, Pointer<AllocId>> {
|
||||
Ok(ptr)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -171,7 +171,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
_ => {}
|
||||
}
|
||||
// And we need to get the provenance.
|
||||
Ok(M::adjust_alloc_base_pointer(self, ptr))
|
||||
M::adjust_alloc_base_pointer(self, ptr)
|
||||
}
|
||||
|
||||
pub fn create_fn_alloc_ptr(
|
||||
@ -200,8 +200,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
kind: MemoryKind<M::MemoryKind>,
|
||||
) -> InterpResult<'tcx, Pointer<M::Provenance>> {
|
||||
let alloc = Allocation::uninit(size, align, M::PANIC_ON_ALLOC_FAIL)?;
|
||||
// We can `unwrap` since `alloc` contains no pointers.
|
||||
Ok(self.allocate_raw_ptr(alloc, kind).unwrap())
|
||||
self.allocate_raw_ptr(alloc, kind)
|
||||
}
|
||||
|
||||
pub fn allocate_bytes_ptr(
|
||||
@ -210,10 +209,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
align: Align,
|
||||
kind: MemoryKind<M::MemoryKind>,
|
||||
mutability: Mutability,
|
||||
) -> Pointer<M::Provenance> {
|
||||
) -> InterpResult<'tcx, Pointer<M::Provenance>> {
|
||||
let alloc = Allocation::from_bytes(bytes, align, mutability);
|
||||
// We can `unwrap` since `alloc` contains no pointers.
|
||||
self.allocate_raw_ptr(alloc, kind).unwrap()
|
||||
self.allocate_raw_ptr(alloc, kind)
|
||||
}
|
||||
|
||||
/// This can fail only of `alloc` contains provenance.
|
||||
@ -230,7 +228,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
);
|
||||
let alloc = M::adjust_allocation(self, id, Cow::Owned(alloc), Some(kind))?;
|
||||
self.memory.alloc_map.insert(id, (kind, alloc.into_owned()));
|
||||
Ok(M::adjust_alloc_base_pointer(self, Pointer::from(id)))
|
||||
M::adjust_alloc_base_pointer(self, Pointer::from(id))
|
||||
}
|
||||
|
||||
pub fn reallocate_ptr(
|
||||
|
@ -754,8 +754,8 @@ where
|
||||
str: &str,
|
||||
kind: MemoryKind<M::MemoryKind>,
|
||||
mutbl: Mutability,
|
||||
) -> MPlaceTy<'tcx, M::Provenance> {
|
||||
let ptr = self.allocate_bytes_ptr(str.as_bytes(), Align::ONE, kind, mutbl);
|
||||
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
|
||||
let ptr = self.allocate_bytes_ptr(str.as_bytes(), Align::ONE, kind, mutbl)?;
|
||||
let meta = Scalar::from_machine_usize(u64::try_from(str.len()).unwrap(), self);
|
||||
let mplace = MemPlace { ptr: ptr.into(), meta: MemPlaceMeta::Meta(meta) };
|
||||
|
||||
@ -764,7 +764,7 @@ where
|
||||
ty::TypeAndMut { ty: self.tcx.types.str_, mutbl },
|
||||
);
|
||||
let layout = self.layout_of(ty).unwrap();
|
||||
MPlaceTy { mplace, layout, align: layout.align.abi }
|
||||
Ok(MPlaceTy { mplace, layout, align: layout.align.abi })
|
||||
}
|
||||
|
||||
/// Writes the aggregate to the destination.
|
||||
|
@ -326,14 +326,16 @@ fn run_compiler(
|
||||
}
|
||||
}
|
||||
|
||||
let mut gctxt = queries.global_ctxt()?;
|
||||
// Make sure name resolution and macro expansion is run.
|
||||
queries.global_ctxt()?;
|
||||
|
||||
if callbacks.after_expansion(compiler, queries) == Compilation::Stop {
|
||||
return early_exit();
|
||||
}
|
||||
|
||||
// Make sure the `output_filenames` query is run for its side
|
||||
// effects of writing the dep-info and reporting errors.
|
||||
gctxt.enter(|tcx| tcx.output_filenames(()));
|
||||
queries.global_ctxt()?.enter(|tcx| tcx.output_filenames(()));
|
||||
|
||||
if sess.opts.output_types.contains_key(&OutputType::DepInfo)
|
||||
&& sess.opts.output_types.len() == 1
|
||||
@ -345,7 +347,7 @@ fn run_compiler(
|
||||
return early_exit();
|
||||
}
|
||||
|
||||
gctxt.enter(|tcx| {
|
||||
queries.global_ctxt()?.enter(|tcx| {
|
||||
let result = tcx.analysis(());
|
||||
if sess.opts.unstable_opts.save_analysis {
|
||||
let crate_name = tcx.crate_name(LOCAL_CRATE);
|
||||
@ -362,8 +364,6 @@ fn run_compiler(
|
||||
result
|
||||
})?;
|
||||
|
||||
drop(gctxt);
|
||||
|
||||
if callbacks.after_analysis(compiler, queries) == Compilation::Stop {
|
||||
return early_exit();
|
||||
}
|
||||
|
@ -1,10 +1,382 @@
|
||||
use crate::FnCtxt;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_middle::ty::{self, DefIdTree, Ty};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::traits::ObligationCauseCode;
|
||||
use rustc_middle::ty::{self, DefIdTree, Ty, TypeSuperVisitable, TypeVisitable, TypeVisitor};
|
||||
use rustc_span::{self, Span};
|
||||
use rustc_trait_selection::traits;
|
||||
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
pub fn adjust_fulfillment_error_for_expr_obligation(
|
||||
&self,
|
||||
error: &mut traits::FulfillmentError<'tcx>,
|
||||
) -> bool {
|
||||
let (traits::ExprItemObligation(def_id, hir_id, idx) | traits::ExprBindingObligation(def_id, _, hir_id, idx))
|
||||
= *error.obligation.cause.code().peel_derives() else { return false; };
|
||||
let hir = self.tcx.hir();
|
||||
let hir::Node::Expr(expr) = hir.get(hir_id) else { return false; };
|
||||
|
||||
let Some(unsubstituted_pred) =
|
||||
self.tcx.predicates_of(def_id).instantiate_identity(self.tcx).predicates.into_iter().nth(idx)
|
||||
else { return false; };
|
||||
|
||||
let generics = self.tcx.generics_of(def_id);
|
||||
let predicate_substs = match unsubstituted_pred.kind().skip_binder() {
|
||||
ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => pred.trait_ref.substs,
|
||||
ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => pred.projection_ty.substs,
|
||||
_ => ty::List::empty(),
|
||||
};
|
||||
|
||||
let find_param_matching = |matches: &dyn Fn(&ty::ParamTy) -> bool| {
|
||||
predicate_substs.types().find_map(|ty| {
|
||||
ty.walk().find_map(|arg| {
|
||||
if let ty::GenericArgKind::Type(ty) = arg.unpack()
|
||||
&& let ty::Param(param_ty) = ty.kind()
|
||||
&& matches(param_ty)
|
||||
{
|
||||
Some(arg)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
})
|
||||
};
|
||||
|
||||
// Prefer generics that are local to the fn item, since these are likely
|
||||
// to be the cause of the unsatisfied predicate.
|
||||
let mut param_to_point_at = find_param_matching(&|param_ty| {
|
||||
self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) == def_id
|
||||
});
|
||||
// Fall back to generic that isn't local to the fn item. This will come
|
||||
// from a trait or impl, for example.
|
||||
let mut fallback_param_to_point_at = find_param_matching(&|param_ty| {
|
||||
self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) != def_id
|
||||
&& param_ty.name != rustc_span::symbol::kw::SelfUpper
|
||||
});
|
||||
// Finally, the `Self` parameter is possibly the reason that the predicate
|
||||
// is unsatisfied. This is less likely to be true for methods, because
|
||||
// method probe means that we already kinda check that the predicates due
|
||||
// to the `Self` type are true.
|
||||
let mut self_param_to_point_at =
|
||||
find_param_matching(&|param_ty| param_ty.name == rustc_span::symbol::kw::SelfUpper);
|
||||
|
||||
// Finally, for ambiguity-related errors, we actually want to look
|
||||
// for a parameter that is the source of the inference type left
|
||||
// over in this predicate.
|
||||
if let traits::FulfillmentErrorCode::CodeAmbiguity = error.code {
|
||||
fallback_param_to_point_at = None;
|
||||
self_param_to_point_at = None;
|
||||
param_to_point_at =
|
||||
self.find_ambiguous_parameter_in(def_id, error.root_obligation.predicate);
|
||||
}
|
||||
|
||||
if self.closure_span_overlaps_error(error, expr.span) {
|
||||
return false;
|
||||
}
|
||||
|
||||
match &expr.kind {
|
||||
hir::ExprKind::Path(qpath) => {
|
||||
if let hir::Node::Expr(hir::Expr {
|
||||
kind: hir::ExprKind::Call(callee, args),
|
||||
hir_id: call_hir_id,
|
||||
span: call_span,
|
||||
..
|
||||
}) = hir.get_parent(expr.hir_id)
|
||||
&& callee.hir_id == expr.hir_id
|
||||
{
|
||||
if self.closure_span_overlaps_error(error, *call_span) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for param in
|
||||
[param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
{
|
||||
if self.blame_specific_arg_if_possible(
|
||||
error,
|
||||
def_id,
|
||||
param,
|
||||
*call_hir_id,
|
||||
callee.span,
|
||||
None,
|
||||
args,
|
||||
)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Notably, we only point to params that are local to the
|
||||
// item we're checking, since those are the ones we are able
|
||||
// to look in the final `hir::PathSegment` for. Everything else
|
||||
// would require a deeper search into the `qpath` than I think
|
||||
// is worthwhile.
|
||||
if let Some(param_to_point_at) = param_to_point_at
|
||||
&& self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
hir::ExprKind::MethodCall(segment, receiver, args, ..) => {
|
||||
for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
{
|
||||
if self.blame_specific_arg_if_possible(
|
||||
error,
|
||||
def_id,
|
||||
param,
|
||||
hir_id,
|
||||
segment.ident.span,
|
||||
Some(receiver),
|
||||
args,
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if let Some(param_to_point_at) = param_to_point_at
|
||||
&& self.point_at_generic_if_possible(error, def_id, param_to_point_at, segment)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
hir::ExprKind::Struct(qpath, fields, ..) => {
|
||||
if let Res::Def(
|
||||
hir::def::DefKind::Struct | hir::def::DefKind::Variant,
|
||||
variant_def_id,
|
||||
) = self.typeck_results.borrow().qpath_res(qpath, hir_id)
|
||||
{
|
||||
for param in
|
||||
[param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
|
||||
{
|
||||
if let Some(param) = param {
|
||||
let refined_expr = self.point_at_field_if_possible(
|
||||
def_id,
|
||||
param,
|
||||
variant_def_id,
|
||||
fields,
|
||||
);
|
||||
|
||||
match refined_expr {
|
||||
None => {}
|
||||
Some((refined_expr, _)) => {
|
||||
error.obligation.cause.span = refined_expr
|
||||
.span
|
||||
.find_ancestor_in_same_ctxt(error.obligation.cause.span)
|
||||
.unwrap_or(refined_expr.span);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(param_to_point_at) = param_to_point_at
|
||||
&& self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn point_at_path_if_possible(
|
||||
&self,
|
||||
error: &mut traits::FulfillmentError<'tcx>,
|
||||
def_id: DefId,
|
||||
param: ty::GenericArg<'tcx>,
|
||||
qpath: &hir::QPath<'tcx>,
|
||||
) -> bool {
|
||||
match qpath {
|
||||
hir::QPath::Resolved(_, path) => {
|
||||
if let Some(segment) = path.segments.last()
|
||||
&& self.point_at_generic_if_possible(error, def_id, param, segment)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
hir::QPath::TypeRelative(_, segment) => {
|
||||
if self.point_at_generic_if_possible(error, def_id, param, segment) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn point_at_generic_if_possible(
|
||||
&self,
|
||||
error: &mut traits::FulfillmentError<'tcx>,
|
||||
def_id: DefId,
|
||||
param_to_point_at: ty::GenericArg<'tcx>,
|
||||
segment: &hir::PathSegment<'tcx>,
|
||||
) -> bool {
|
||||
let own_substs = self
|
||||
.tcx
|
||||
.generics_of(def_id)
|
||||
.own_substs(ty::InternalSubsts::identity_for_item(self.tcx, def_id));
|
||||
let Some((index, _)) = own_substs
|
||||
.iter()
|
||||
.filter(|arg| matches!(arg.unpack(), ty::GenericArgKind::Type(_)))
|
||||
.enumerate()
|
||||
.find(|(_, arg)| **arg == param_to_point_at) else { return false };
|
||||
let Some(arg) = segment
|
||||
.args()
|
||||
.args
|
||||
.iter()
|
||||
.filter(|arg| matches!(arg, hir::GenericArg::Type(_)))
|
||||
.nth(index) else { return false; };
|
||||
error.obligation.cause.span = arg
|
||||
.span()
|
||||
.find_ancestor_in_same_ctxt(error.obligation.cause.span)
|
||||
.unwrap_or(arg.span());
|
||||
true
|
||||
}
|
||||
|
||||
fn find_ambiguous_parameter_in<T: TypeVisitable<'tcx>>(
|
||||
&self,
|
||||
item_def_id: DefId,
|
||||
t: T,
|
||||
) -> Option<ty::GenericArg<'tcx>> {
|
||||
struct FindAmbiguousParameter<'a, 'tcx>(&'a FnCtxt<'a, 'tcx>, DefId);
|
||||
impl<'tcx> TypeVisitor<'tcx> for FindAmbiguousParameter<'_, 'tcx> {
|
||||
type BreakTy = ty::GenericArg<'tcx>;
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> {
|
||||
if let Some(origin) = self.0.type_var_origin(ty)
|
||||
&& let rustc_infer::infer::type_variable::TypeVariableOriginKind::TypeParameterDefinition(_, Some(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) = ty::InternalSubsts::identity_for_item(self.0.tcx, self.1)
|
||||
.get(index as usize)
|
||||
{
|
||||
ControlFlow::Break(*subst)
|
||||
} else {
|
||||
ty.super_visit_with(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
t.visit_with(&mut FindAmbiguousParameter(self, item_def_id)).break_value()
|
||||
}
|
||||
|
||||
fn closure_span_overlaps_error(
|
||||
&self,
|
||||
error: &traits::FulfillmentError<'tcx>,
|
||||
span: Span,
|
||||
) -> bool {
|
||||
if let traits::FulfillmentErrorCode::CodeSelectionError(
|
||||
traits::SelectionError::OutputTypeParameterMismatch(_, expected, _),
|
||||
) = error.code
|
||||
&& let ty::Closure(def_id, _) | ty::Generator(def_id, ..) = expected.skip_binder().self_ty().kind()
|
||||
&& span.overlaps(self.tcx.def_span(*def_id))
|
||||
{
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn point_at_field_if_possible(
|
||||
&self,
|
||||
def_id: DefId,
|
||||
param_to_point_at: ty::GenericArg<'tcx>,
|
||||
variant_def_id: DefId,
|
||||
expr_fields: &[hir::ExprField<'tcx>],
|
||||
) -> Option<(&'tcx hir::Expr<'tcx>, Ty<'tcx>)> {
|
||||
let def = self.tcx.adt_def(def_id);
|
||||
|
||||
let identity_substs = ty::InternalSubsts::identity_for_item(self.tcx, def_id);
|
||||
let fields_referencing_param: Vec<_> = def
|
||||
.variant_with_id(variant_def_id)
|
||||
.fields
|
||||
.iter()
|
||||
.filter(|field| {
|
||||
let field_ty = field.ty(self.tcx, identity_substs);
|
||||
Self::find_param_in_ty(field_ty.into(), param_to_point_at)
|
||||
})
|
||||
.collect();
|
||||
|
||||
if let [field] = fields_referencing_param.as_slice() {
|
||||
for expr_field in expr_fields {
|
||||
// Look for the ExprField that matches the field, using the
|
||||
// same rules that check_expr_struct uses for macro hygiene.
|
||||
if self.tcx.adjust_ident(expr_field.ident, variant_def_id) == field.ident(self.tcx)
|
||||
{
|
||||
return Some((expr_field.expr, self.tcx.type_of(field.did)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// - `blame_specific_*` means that the function will recursively traverse the expression,
|
||||
/// looking for the most-specific-possible span to blame.
|
||||
///
|
||||
/// - `point_at_*` means that the function will only go "one level", pointing at the specific
|
||||
/// expression mentioned.
|
||||
///
|
||||
/// `blame_specific_arg_if_possible` will find the most-specific expression anywhere inside
|
||||
/// the provided function call expression, and mark it as responsible for the fullfillment
|
||||
/// error.
|
||||
fn blame_specific_arg_if_possible(
|
||||
&self,
|
||||
error: &mut traits::FulfillmentError<'tcx>,
|
||||
def_id: DefId,
|
||||
param_to_point_at: ty::GenericArg<'tcx>,
|
||||
call_hir_id: hir::HirId,
|
||||
callee_span: Span,
|
||||
receiver: Option<&'tcx hir::Expr<'tcx>>,
|
||||
args: &'tcx [hir::Expr<'tcx>],
|
||||
) -> bool {
|
||||
let ty = self.tcx.type_of(def_id);
|
||||
if !ty.is_fn() {
|
||||
return false;
|
||||
}
|
||||
let sig = ty.fn_sig(self.tcx).skip_binder();
|
||||
let args_referencing_param: Vec<_> = sig
|
||||
.inputs()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(_, ty)| Self::find_param_in_ty((**ty).into(), param_to_point_at))
|
||||
.collect();
|
||||
// If there's one field that references the given generic, great!
|
||||
if let [(idx, _)] = args_referencing_param.as_slice()
|
||||
&& let Some(arg) = receiver
|
||||
.map_or(args.get(*idx), |rcvr| if *idx == 0 { Some(rcvr) } else { args.get(*idx - 1) }) {
|
||||
|
||||
error.obligation.cause.span = arg.span.find_ancestor_in_same_ctxt(error.obligation.cause.span).unwrap_or(arg.span);
|
||||
|
||||
if let hir::Node::Expr(arg_expr) = self.tcx.hir().get(arg.hir_id) {
|
||||
// This is more specific than pointing at the entire argument.
|
||||
self.blame_specific_expr_if_possible(error, arg_expr)
|
||||
}
|
||||
|
||||
error.obligation.cause.map_code(|parent_code| {
|
||||
ObligationCauseCode::FunctionArgumentObligation {
|
||||
arg_hir_id: arg.hir_id,
|
||||
call_hir_id,
|
||||
parent_code,
|
||||
}
|
||||
});
|
||||
return true;
|
||||
} else if args_referencing_param.len() > 0 {
|
||||
// If more than one argument applies, then point to the callee span at least...
|
||||
// We have chance to fix this up further in `point_at_generics_if_possible`
|
||||
error.obligation.cause.span = callee_span;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively searches for the most-specific blamable expression.
|
||||
* For example, if you have a chain of constraints like:
|
||||
|
@ -26,7 +26,7 @@ use rustc_infer::infer::InferOk;
|
||||
use rustc_infer::infer::TypeTrace;
|
||||
use rustc_middle::ty::adjustment::AllowTwoPhase;
|
||||
use rustc_middle::ty::visit::TypeVisitable;
|
||||
use rustc_middle::ty::{self, DefIdTree, IsSuggestable, Ty, TypeSuperVisitable, TypeVisitor};
|
||||
use rustc_middle::ty::{self, DefIdTree, IsSuggestable, Ty};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::symbol::{kw, Ident};
|
||||
use rustc_span::{self, sym, Span};
|
||||
@ -36,8 +36,6 @@ use std::iter;
|
||||
use std::mem;
|
||||
use std::slice;
|
||||
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
pub(in super::super) fn check_casts(&mut self) {
|
||||
// don't hold the borrow to deferred_cast_checks while checking to avoid borrow checker errors
|
||||
@ -1758,372 +1756,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn adjust_fulfillment_error_for_expr_obligation(
|
||||
&self,
|
||||
error: &mut traits::FulfillmentError<'tcx>,
|
||||
) -> bool {
|
||||
let (traits::ExprItemObligation(def_id, hir_id, idx) | traits::ExprBindingObligation(def_id, _, hir_id, idx))
|
||||
= *error.obligation.cause.code().peel_derives() else { return false; };
|
||||
let hir = self.tcx.hir();
|
||||
let hir::Node::Expr(expr) = hir.get(hir_id) else { return false; };
|
||||
|
||||
let Some(unsubstituted_pred) =
|
||||
self.tcx.predicates_of(def_id).instantiate_identity(self.tcx).predicates.into_iter().nth(idx)
|
||||
else { return false; };
|
||||
|
||||
let generics = self.tcx.generics_of(def_id);
|
||||
let predicate_substs = match unsubstituted_pred.kind().skip_binder() {
|
||||
ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => pred.trait_ref.substs,
|
||||
ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => pred.projection_ty.substs,
|
||||
_ => ty::List::empty(),
|
||||
};
|
||||
|
||||
let find_param_matching = |matches: &dyn Fn(&ty::ParamTy) -> bool| {
|
||||
predicate_substs.types().find_map(|ty| {
|
||||
ty.walk().find_map(|arg| {
|
||||
if let ty::GenericArgKind::Type(ty) = arg.unpack()
|
||||
&& let ty::Param(param_ty) = ty.kind()
|
||||
&& matches(param_ty)
|
||||
{
|
||||
Some(arg)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
})
|
||||
};
|
||||
|
||||
// Prefer generics that are local to the fn item, since these are likely
|
||||
// to be the cause of the unsatisfied predicate.
|
||||
let mut param_to_point_at = find_param_matching(&|param_ty| {
|
||||
self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) == def_id
|
||||
});
|
||||
// Fall back to generic that isn't local to the fn item. This will come
|
||||
// from a trait or impl, for example.
|
||||
let mut fallback_param_to_point_at = find_param_matching(&|param_ty| {
|
||||
self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) != def_id
|
||||
&& param_ty.name != rustc_span::symbol::kw::SelfUpper
|
||||
});
|
||||
// Finally, the `Self` parameter is possibly the reason that the predicate
|
||||
// is unsatisfied. This is less likely to be true for methods, because
|
||||
// method probe means that we already kinda check that the predicates due
|
||||
// to the `Self` type are true.
|
||||
let mut self_param_to_point_at =
|
||||
find_param_matching(&|param_ty| param_ty.name == rustc_span::symbol::kw::SelfUpper);
|
||||
|
||||
// Finally, for ambiguity-related errors, we actually want to look
|
||||
// for a parameter that is the source of the inference type left
|
||||
// over in this predicate.
|
||||
if let traits::FulfillmentErrorCode::CodeAmbiguity = error.code {
|
||||
fallback_param_to_point_at = None;
|
||||
self_param_to_point_at = None;
|
||||
param_to_point_at =
|
||||
self.find_ambiguous_parameter_in(def_id, error.root_obligation.predicate);
|
||||
}
|
||||
|
||||
if self.closure_span_overlaps_error(error, expr.span) {
|
||||
return false;
|
||||
}
|
||||
|
||||
match &expr.kind {
|
||||
hir::ExprKind::Path(qpath) => {
|
||||
if let hir::Node::Expr(hir::Expr {
|
||||
kind: hir::ExprKind::Call(callee, args),
|
||||
hir_id: call_hir_id,
|
||||
span: call_span,
|
||||
..
|
||||
}) = hir.get_parent(expr.hir_id)
|
||||
&& callee.hir_id == expr.hir_id
|
||||
{
|
||||
if self.closure_span_overlaps_error(error, *call_span) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for param in
|
||||
[param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
{
|
||||
if self.blame_specific_arg_if_possible(
|
||||
error,
|
||||
def_id,
|
||||
param,
|
||||
*call_hir_id,
|
||||
callee.span,
|
||||
None,
|
||||
args,
|
||||
)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Notably, we only point to params that are local to the
|
||||
// item we're checking, since those are the ones we are able
|
||||
// to look in the final `hir::PathSegment` for. Everything else
|
||||
// would require a deeper search into the `qpath` than I think
|
||||
// is worthwhile.
|
||||
if let Some(param_to_point_at) = param_to_point_at
|
||||
&& self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
hir::ExprKind::MethodCall(segment, receiver, args, ..) => {
|
||||
for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
{
|
||||
if self.blame_specific_arg_if_possible(
|
||||
error,
|
||||
def_id,
|
||||
param,
|
||||
hir_id,
|
||||
segment.ident.span,
|
||||
Some(receiver),
|
||||
args,
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if let Some(param_to_point_at) = param_to_point_at
|
||||
&& self.point_at_generic_if_possible(error, def_id, param_to_point_at, segment)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
hir::ExprKind::Struct(qpath, fields, ..) => {
|
||||
if let Res::Def(DefKind::Struct | DefKind::Variant, variant_def_id) =
|
||||
self.typeck_results.borrow().qpath_res(qpath, hir_id)
|
||||
{
|
||||
for param in
|
||||
[param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
|
||||
{
|
||||
if let Some(param) = param {
|
||||
let refined_expr = self.point_at_field_if_possible(
|
||||
def_id,
|
||||
param,
|
||||
variant_def_id,
|
||||
fields,
|
||||
);
|
||||
|
||||
match refined_expr {
|
||||
None => {}
|
||||
Some((refined_expr, _)) => {
|
||||
error.obligation.cause.span = refined_expr
|
||||
.span
|
||||
.find_ancestor_in_same_ctxt(error.obligation.cause.span)
|
||||
.unwrap_or(refined_expr.span);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(param_to_point_at) = param_to_point_at
|
||||
&& self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn closure_span_overlaps_error(
|
||||
&self,
|
||||
error: &traits::FulfillmentError<'tcx>,
|
||||
span: Span,
|
||||
) -> bool {
|
||||
if let traits::FulfillmentErrorCode::CodeSelectionError(
|
||||
traits::SelectionError::OutputTypeParameterMismatch(_, expected, _),
|
||||
) = error.code
|
||||
&& let ty::Closure(def_id, _) | ty::Generator(def_id, ..) = expected.skip_binder().self_ty().kind()
|
||||
&& span.overlaps(self.tcx.def_span(*def_id))
|
||||
{
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// - `blame_specific_*` means that the function will recursively traverse the expression,
|
||||
/// looking for the most-specific-possible span to blame.
|
||||
///
|
||||
/// - `point_at_*` means that the function will only go "one level", pointing at the specific
|
||||
/// expression mentioned.
|
||||
///
|
||||
/// `blame_specific_arg_if_possible` will find the most-specific expression anywhere inside
|
||||
/// the provided function call expression, and mark it as responsible for the fullfillment
|
||||
/// error.
|
||||
fn blame_specific_arg_if_possible(
|
||||
&self,
|
||||
error: &mut traits::FulfillmentError<'tcx>,
|
||||
def_id: DefId,
|
||||
param_to_point_at: ty::GenericArg<'tcx>,
|
||||
call_hir_id: hir::HirId,
|
||||
callee_span: Span,
|
||||
receiver: Option<&'tcx hir::Expr<'tcx>>,
|
||||
args: &'tcx [hir::Expr<'tcx>],
|
||||
) -> bool {
|
||||
let ty = self.tcx.type_of(def_id);
|
||||
if !ty.is_fn() {
|
||||
return false;
|
||||
}
|
||||
let sig = ty.fn_sig(self.tcx).skip_binder();
|
||||
let args_referencing_param: Vec<_> = sig
|
||||
.inputs()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(_, ty)| Self::find_param_in_ty((**ty).into(), param_to_point_at))
|
||||
.collect();
|
||||
// If there's one field that references the given generic, great!
|
||||
if let [(idx, _)] = args_referencing_param.as_slice()
|
||||
&& let Some(arg) = receiver
|
||||
.map_or(args.get(*idx), |rcvr| if *idx == 0 { Some(rcvr) } else { args.get(*idx - 1) }) {
|
||||
|
||||
error.obligation.cause.span = arg.span.find_ancestor_in_same_ctxt(error.obligation.cause.span).unwrap_or(arg.span);
|
||||
|
||||
if let hir::Node::Expr(arg_expr) = self.tcx.hir().get(arg.hir_id) {
|
||||
// This is more specific than pointing at the entire argument.
|
||||
self.blame_specific_expr_if_possible(error, arg_expr)
|
||||
}
|
||||
|
||||
error.obligation.cause.map_code(|parent_code| {
|
||||
ObligationCauseCode::FunctionArgumentObligation {
|
||||
arg_hir_id: arg.hir_id,
|
||||
call_hir_id,
|
||||
parent_code,
|
||||
}
|
||||
});
|
||||
return true;
|
||||
} else if args_referencing_param.len() > 0 {
|
||||
// If more than one argument applies, then point to the callee span at least...
|
||||
// We have chance to fix this up further in `point_at_generics_if_possible`
|
||||
error.obligation.cause.span = callee_span;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
// FIXME: Make this private and move to mod adjust_fulfillment_errors
|
||||
pub fn point_at_field_if_possible(
|
||||
&self,
|
||||
def_id: DefId,
|
||||
param_to_point_at: ty::GenericArg<'tcx>,
|
||||
variant_def_id: DefId,
|
||||
expr_fields: &[hir::ExprField<'tcx>],
|
||||
) -> Option<(&'tcx hir::Expr<'tcx>, Ty<'tcx>)> {
|
||||
let def = self.tcx.adt_def(def_id);
|
||||
|
||||
let identity_substs = ty::InternalSubsts::identity_for_item(self.tcx, def_id);
|
||||
let fields_referencing_param: Vec<_> = def
|
||||
.variant_with_id(variant_def_id)
|
||||
.fields
|
||||
.iter()
|
||||
.filter(|field| {
|
||||
let field_ty = field.ty(self.tcx, identity_substs);
|
||||
Self::find_param_in_ty(field_ty.into(), param_to_point_at)
|
||||
})
|
||||
.collect();
|
||||
|
||||
if let [field] = fields_referencing_param.as_slice() {
|
||||
for expr_field in expr_fields {
|
||||
// Look for the ExprField that matches the field, using the
|
||||
// same rules that check_expr_struct uses for macro hygiene.
|
||||
if self.tcx.adjust_ident(expr_field.ident, variant_def_id) == field.ident(self.tcx)
|
||||
{
|
||||
return Some((expr_field.expr, self.tcx.type_of(field.did)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn point_at_path_if_possible(
|
||||
&self,
|
||||
error: &mut traits::FulfillmentError<'tcx>,
|
||||
def_id: DefId,
|
||||
param: ty::GenericArg<'tcx>,
|
||||
qpath: &QPath<'tcx>,
|
||||
) -> bool {
|
||||
match qpath {
|
||||
hir::QPath::Resolved(_, path) => {
|
||||
if let Some(segment) = path.segments.last()
|
||||
&& self.point_at_generic_if_possible(error, def_id, param, segment)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
hir::QPath::TypeRelative(_, segment) => {
|
||||
if self.point_at_generic_if_possible(error, def_id, param, segment) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn point_at_generic_if_possible(
|
||||
&self,
|
||||
error: &mut traits::FulfillmentError<'tcx>,
|
||||
def_id: DefId,
|
||||
param_to_point_at: ty::GenericArg<'tcx>,
|
||||
segment: &hir::PathSegment<'tcx>,
|
||||
) -> bool {
|
||||
let own_substs = self
|
||||
.tcx
|
||||
.generics_of(def_id)
|
||||
.own_substs(ty::InternalSubsts::identity_for_item(self.tcx, def_id));
|
||||
let Some((index, _)) = own_substs
|
||||
.iter()
|
||||
.filter(|arg| matches!(arg.unpack(), ty::GenericArgKind::Type(_)))
|
||||
.enumerate()
|
||||
.find(|(_, arg)| **arg == param_to_point_at) else { return false };
|
||||
let Some(arg) = segment
|
||||
.args()
|
||||
.args
|
||||
.iter()
|
||||
.filter(|arg| matches!(arg, hir::GenericArg::Type(_)))
|
||||
.nth(index) else { return false; };
|
||||
error.obligation.cause.span = arg
|
||||
.span()
|
||||
.find_ancestor_in_same_ctxt(error.obligation.cause.span)
|
||||
.unwrap_or(arg.span());
|
||||
true
|
||||
}
|
||||
|
||||
fn find_ambiguous_parameter_in<T: TypeVisitable<'tcx>>(
|
||||
&self,
|
||||
item_def_id: DefId,
|
||||
t: T,
|
||||
) -> Option<ty::GenericArg<'tcx>> {
|
||||
struct FindAmbiguousParameter<'a, 'tcx>(&'a FnCtxt<'a, 'tcx>, DefId);
|
||||
impl<'tcx> TypeVisitor<'tcx> for FindAmbiguousParameter<'_, 'tcx> {
|
||||
type BreakTy = ty::GenericArg<'tcx>;
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> {
|
||||
if let Some(origin) = self.0.type_var_origin(ty)
|
||||
&& let TypeVariableOriginKind::TypeParameterDefinition(_, Some(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) = ty::InternalSubsts::identity_for_item(self.0.tcx, self.1)
|
||||
.get(index as usize)
|
||||
{
|
||||
ControlFlow::Break(*subst)
|
||||
} else {
|
||||
ty.super_visit_with(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
t.visit_with(&mut FindAmbiguousParameter(self, item_def_id)).break_value()
|
||||
}
|
||||
|
||||
fn label_fn_like(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
|
@ -268,14 +268,12 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
(GenericArgKind::Lifetime(v_o), GenericArgKind::Lifetime(v_r)) => {
|
||||
// To make `v_o = v_r`, we emit `v_o: v_r` and `v_r: v_o`.
|
||||
if v_o != v_r {
|
||||
output_query_region_constraints.outlives.push((
|
||||
ty::Binder::dummy(ty::OutlivesPredicate(v_o.into(), v_r)),
|
||||
constraint_category,
|
||||
));
|
||||
output_query_region_constraints.outlives.push((
|
||||
ty::Binder::dummy(ty::OutlivesPredicate(v_r.into(), v_o)),
|
||||
constraint_category,
|
||||
));
|
||||
output_query_region_constraints
|
||||
.outlives
|
||||
.push((ty::OutlivesPredicate(v_o.into(), v_r), constraint_category));
|
||||
output_query_region_constraints
|
||||
.outlives
|
||||
.push((ty::OutlivesPredicate(v_r.into(), v_o), constraint_category));
|
||||
}
|
||||
}
|
||||
|
||||
@ -318,10 +316,8 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
query_response.value.region_constraints.outlives.iter().filter_map(|&r_c| {
|
||||
let r_c = substitute_value(self.tcx, &result_subst, r_c);
|
||||
|
||||
// Screen out `'a: 'a` cases -- we skip the binder here but
|
||||
// only compare the inner values to one another, so they are still at
|
||||
// consistent binding levels.
|
||||
let ty::OutlivesPredicate(k1, r2) = r_c.0.skip_binder();
|
||||
// Screen out `'a: 'a` cases.
|
||||
let ty::OutlivesPredicate(k1, r2) = r_c.0;
|
||||
if k1 != r2.into() { Some(r_c) } else { None }
|
||||
}),
|
||||
);
|
||||
@ -559,11 +555,11 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
|
||||
pub fn query_outlives_constraint_to_obligation(
|
||||
&self,
|
||||
predicate: QueryOutlivesConstraint<'tcx>,
|
||||
(predicate, _): QueryOutlivesConstraint<'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> Obligation<'tcx, ty::Predicate<'tcx>> {
|
||||
let ty::OutlivesPredicate(k1, r2) = predicate.0.skip_binder();
|
||||
let ty::OutlivesPredicate(k1, r2) = predicate;
|
||||
|
||||
let atom = match k1.unpack() {
|
||||
GenericArgKind::Lifetime(r1) => {
|
||||
@ -578,7 +574,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
span_bug!(cause.span, "unexpected const outlives {:?}", predicate);
|
||||
}
|
||||
};
|
||||
let predicate = predicate.0.rebind(atom);
|
||||
let predicate = ty::Binder::dummy(atom);
|
||||
|
||||
Obligation::new(self.tcx, cause, param_env, predicate)
|
||||
}
|
||||
@ -643,8 +639,7 @@ pub fn make_query_region_constraints<'tcx>(
|
||||
let outlives: Vec<_> = constraints
|
||||
.iter()
|
||||
.map(|(k, origin)| {
|
||||
// no bound vars in the code above
|
||||
let constraint = ty::Binder::dummy(match *k {
|
||||
let constraint = match *k {
|
||||
// Swap regions because we are going from sub (<=) to outlives
|
||||
// (>=).
|
||||
Constraint::VarSubVar(v1, v2) => ty::OutlivesPredicate(
|
||||
@ -658,16 +653,12 @@ pub fn make_query_region_constraints<'tcx>(
|
||||
ty::OutlivesPredicate(tcx.mk_region(ty::ReVar(v2)).into(), r1)
|
||||
}
|
||||
Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r2.into(), r1),
|
||||
});
|
||||
};
|
||||
(constraint, origin.to_constraint_category())
|
||||
})
|
||||
.chain(
|
||||
outlives_obligations
|
||||
// no bound vars in the code above
|
||||
.map(|(ty, r, constraint_category)| {
|
||||
(ty::Binder::dummy(ty::OutlivesPredicate(ty.into(), r)), constraint_category)
|
||||
}),
|
||||
)
|
||||
.chain(outlives_obligations.map(|(ty, r, constraint_category)| {
|
||||
(ty::OutlivesPredicate(ty.into(), r), constraint_category)
|
||||
}))
|
||||
.collect();
|
||||
|
||||
QueryRegionConstraints { outlives, member_constraints: member_constraints.clone() }
|
||||
|
@ -4,7 +4,6 @@
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/Analysis/Lint.h"
|
||||
#include "llvm/Analysis/Passes.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
@ -44,6 +43,12 @@
|
||||
#include "llvm/IR/IRPrintingPasses.h"
|
||||
#include "llvm/Linker/Linker.h"
|
||||
|
||||
#if LLVM_VERSION_GE(16, 0)
|
||||
#include "llvm/TargetParser/Triple.h"
|
||||
#else
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#endif
|
||||
|
||||
extern "C" void LLVMRustSetLastError(const char *);
|
||||
|
||||
enum class LLVMRustResult { Success, Failure };
|
||||
|
@ -324,10 +324,8 @@ impl<'tcx, V> Canonical<'tcx, V> {
|
||||
}
|
||||
}
|
||||
|
||||
pub type QueryOutlivesConstraint<'tcx> = (
|
||||
ty::Binder<'tcx, ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>>,
|
||||
ConstraintCategory<'tcx>,
|
||||
);
|
||||
pub type QueryOutlivesConstraint<'tcx> =
|
||||
(ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>, ConstraintCategory<'tcx>);
|
||||
|
||||
TrivialTypeTraversalAndLiftImpls! {
|
||||
for <'tcx> {
|
||||
|
@ -430,8 +430,10 @@ pub enum ResourceExhaustionInfo {
|
||||
///
|
||||
/// The exact limit is set by the `const_eval_limit` attribute.
|
||||
StepLimitReached,
|
||||
/// There is not enough memory to perform an allocation.
|
||||
/// There is not enough memory (on the host) to perform an allocation.
|
||||
MemoryExhausted,
|
||||
/// The address space (of the target) is full.
|
||||
AddressSpaceFull,
|
||||
}
|
||||
|
||||
impl fmt::Display for ResourceExhaustionInfo {
|
||||
@ -447,6 +449,9 @@ impl fmt::Display for ResourceExhaustionInfo {
|
||||
MemoryExhausted => {
|
||||
write!(f, "tried to allocate more memory than available to compiler")
|
||||
}
|
||||
AddressSpaceFull => {
|
||||
write!(f, "there are no more free addresses in the address space")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1541,7 +1541,6 @@ rustc_queries! {
|
||||
query upstream_monomorphizations_for(def_id: DefId)
|
||||
-> Option<&'tcx FxHashMap<SubstsRef<'tcx>, CrateNum>>
|
||||
{
|
||||
arena_cache
|
||||
desc { |tcx|
|
||||
"collecting available upstream monomorphizations for `{}`",
|
||||
tcx.def_path_str(def_id),
|
||||
|
@ -5,3 +5,4 @@ title = "The rustc book"
|
||||
|
||||
[output.html]
|
||||
git-repository-url = "https://github.com/rust-lang/rust/tree/master/src/doc/rustc"
|
||||
edit-url-template = "https://github.com/rust-lang/rust/edit/master/src/doc/rustc/{path}"
|
||||
|
@ -562,7 +562,7 @@ Supported values for this option are:
|
||||
* `v0` — The "v0" mangling scheme. The specific format is not specified at
|
||||
this time.
|
||||
|
||||
The default if not specified will use a compiler-chosen default which may
|
||||
The default, if not specified, will use a compiler-chosen default which may
|
||||
change in the future.
|
||||
|
||||
[name mangling]: https://en.wikipedia.org/wiki/Name_mangling
|
||||
|
@ -162,11 +162,14 @@ impl<'mir, 'tcx> GlobalStateInner {
|
||||
Ok(Pointer::new(Some(Provenance::Wildcard), Size::from_bytes(addr)))
|
||||
}
|
||||
|
||||
fn alloc_base_addr(ecx: &MiriInterpCx<'mir, 'tcx>, alloc_id: AllocId) -> u64 {
|
||||
fn alloc_base_addr(
|
||||
ecx: &MiriInterpCx<'mir, 'tcx>,
|
||||
alloc_id: AllocId,
|
||||
) -> InterpResult<'tcx, u64> {
|
||||
let mut global_state = ecx.machine.intptrcast.borrow_mut();
|
||||
let global_state = &mut *global_state;
|
||||
|
||||
match global_state.base_addr.entry(alloc_id) {
|
||||
Ok(match global_state.base_addr.entry(alloc_id) {
|
||||
Entry::Occupied(entry) => *entry.get(),
|
||||
Entry::Vacant(entry) => {
|
||||
// There is nothing wrong with a raw pointer being cast to an integer only after
|
||||
@ -181,7 +184,10 @@ impl<'mir, 'tcx> GlobalStateInner {
|
||||
rng.gen_range(0..16)
|
||||
};
|
||||
// From next_base_addr + slack, round up to adjust for alignment.
|
||||
let base_addr = global_state.next_base_addr.checked_add(slack).unwrap();
|
||||
let base_addr = global_state
|
||||
.next_base_addr
|
||||
.checked_add(slack)
|
||||
.ok_or_else(|| err_exhaust!(AddressSpaceFull))?;
|
||||
let base_addr = Self::align_addr(base_addr, align.bytes());
|
||||
entry.insert(base_addr);
|
||||
trace!(
|
||||
@ -197,24 +203,33 @@ impl<'mir, 'tcx> GlobalStateInner {
|
||||
// of at least 1 to avoid two allocations having the same base address.
|
||||
// (The logic in `alloc_id_from_addr` assumes unique addresses, and different
|
||||
// function/vtable pointers need to be distinguishable!)
|
||||
global_state.next_base_addr = base_addr.checked_add(max(size.bytes(), 1)).unwrap();
|
||||
global_state.next_base_addr = base_addr
|
||||
.checked_add(max(size.bytes(), 1))
|
||||
.ok_or_else(|| err_exhaust!(AddressSpaceFull))?;
|
||||
// Even if `Size` didn't overflow, we might still have filled up the address space.
|
||||
if global_state.next_base_addr > ecx.machine_usize_max() {
|
||||
throw_exhaust!(AddressSpaceFull);
|
||||
}
|
||||
// Given that `next_base_addr` increases in each allocation, pushing the
|
||||
// corresponding tuple keeps `int_to_ptr_map` sorted
|
||||
global_state.int_to_ptr_map.push((base_addr, alloc_id));
|
||||
|
||||
base_addr
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Convert a relative (tcx) pointer to an absolute address.
|
||||
pub fn rel_ptr_to_addr(ecx: &MiriInterpCx<'mir, 'tcx>, ptr: Pointer<AllocId>) -> u64 {
|
||||
pub fn rel_ptr_to_addr(
|
||||
ecx: &MiriInterpCx<'mir, 'tcx>,
|
||||
ptr: Pointer<AllocId>,
|
||||
) -> InterpResult<'tcx, u64> {
|
||||
let (alloc_id, offset) = ptr.into_parts(); // offset is relative (AllocId provenance)
|
||||
let base_addr = GlobalStateInner::alloc_base_addr(ecx, alloc_id);
|
||||
let base_addr = GlobalStateInner::alloc_base_addr(ecx, alloc_id)?;
|
||||
|
||||
// Add offset with the right kind of pointer-overflowing arithmetic.
|
||||
let dl = ecx.data_layout();
|
||||
dl.overflowing_offset(base_addr, offset.bytes()).0
|
||||
Ok(dl.overflowing_offset(base_addr, offset.bytes()).0)
|
||||
}
|
||||
|
||||
/// When a pointer is used for a memory access, this computes where in which allocation the
|
||||
@ -232,7 +247,9 @@ impl<'mir, 'tcx> GlobalStateInner {
|
||||
GlobalStateInner::alloc_id_from_addr(ecx, addr.bytes())?
|
||||
};
|
||||
|
||||
let base_addr = GlobalStateInner::alloc_base_addr(ecx, alloc_id);
|
||||
// This cannot fail: since we already have a pointer with that provenance, rel_ptr_to_addr
|
||||
// must have been called in the past.
|
||||
let base_addr = GlobalStateInner::alloc_base_addr(ecx, alloc_id).unwrap();
|
||||
|
||||
// Wrapping "addr - base_addr"
|
||||
let dl = ecx.data_layout();
|
||||
|
@ -971,7 +971,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
|
||||
fn adjust_alloc_base_pointer(
|
||||
ecx: &MiriInterpCx<'mir, 'tcx>,
|
||||
ptr: Pointer<AllocId>,
|
||||
) -> Pointer<Provenance> {
|
||||
) -> InterpResult<'tcx, Pointer<Provenance>> {
|
||||
if cfg!(debug_assertions) {
|
||||
// The machine promises to never call us on thread-local or extern statics.
|
||||
let alloc_id = ptr.provenance;
|
||||
@ -985,17 +985,17 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
let absolute_addr = intptrcast::GlobalStateInner::rel_ptr_to_addr(ecx, ptr);
|
||||
let absolute_addr = intptrcast::GlobalStateInner::rel_ptr_to_addr(ecx, ptr)?;
|
||||
let tag = if let Some(borrow_tracker) = &ecx.machine.borrow_tracker {
|
||||
borrow_tracker.borrow_mut().base_ptr_tag(ptr.provenance, &ecx.machine)
|
||||
} else {
|
||||
// Value does not matter, SB is disabled
|
||||
BorTag::default()
|
||||
};
|
||||
Pointer::new(
|
||||
Ok(Pointer::new(
|
||||
Provenance::Concrete { alloc_id: ptr.provenance, tag },
|
||||
Size::from_bytes(absolute_addr),
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -190,9 +190,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||
0 => {
|
||||
// These are "mutable" allocations as we consider them to be owned by the callee.
|
||||
let name_alloc =
|
||||
this.allocate_str(&name, MiriMemoryKind::Rust.into(), Mutability::Mut);
|
||||
this.allocate_str(&name, MiriMemoryKind::Rust.into(), Mutability::Mut)?;
|
||||
let filename_alloc =
|
||||
this.allocate_str(&filename, MiriMemoryKind::Rust.into(), Mutability::Mut);
|
||||
this.allocate_str(&filename, MiriMemoryKind::Rust.into(), Mutability::Mut)?;
|
||||
|
||||
this.write_immediate(
|
||||
name_alloc.to_ref(this),
|
||||
|
@ -172,7 +172,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
// First arg: message.
|
||||
let msg = this.allocate_str(msg, MiriMemoryKind::Machine.into(), Mutability::Not);
|
||||
let msg = this.allocate_str(msg, MiriMemoryKind::Machine.into(), Mutability::Not)?;
|
||||
|
||||
// Call the lang item.
|
||||
let panic = this.tcx.lang_items().panic_fn().unwrap();
|
||||
|
Loading…
Reference in New Issue
Block a user