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:
bors 2023-02-07 20:58:20 +00:00
commit 3f059f6046
19 changed files with 461 additions and 450 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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