Auto merge of #3624 - rust-lang:rustup-2024-05-23, r=RalfJung
Automatic Rustup
This commit is contained in:
commit
6ea763b9e2
167 changed files with 1888 additions and 1808 deletions
|
|
@ -81,8 +81,17 @@ pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
pub enum TrailingBrace<'a> {
|
||||
/// Trailing brace in a macro call, like the one in `x as *const brace! {}`.
|
||||
/// We will suggest changing the macro call to a different delimiter.
|
||||
MacCall(&'a ast::MacCall),
|
||||
/// Trailing brace in any other expression, such as `a + B {}`. We will
|
||||
/// suggest wrapping the innermost expression in parentheses: `a + (B {})`.
|
||||
Expr(&'a ast::Expr),
|
||||
}
|
||||
|
||||
/// If an expression ends with `}`, returns the innermost expression ending in the `}`
|
||||
pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
|
||||
pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<TrailingBrace<'_>> {
|
||||
loop {
|
||||
match &expr.kind {
|
||||
AddrOf(_, _, e)
|
||||
|
|
@ -111,10 +120,14 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
|
|||
| Struct(..)
|
||||
| TryBlock(..)
|
||||
| While(..)
|
||||
| ConstBlock(_) => break Some(expr),
|
||||
| ConstBlock(_) => break Some(TrailingBrace::Expr(expr)),
|
||||
|
||||
Cast(_, ty) => {
|
||||
break type_trailing_braced_mac_call(ty).map(TrailingBrace::MacCall);
|
||||
}
|
||||
|
||||
MacCall(mac) => {
|
||||
break (mac.args.delim == Delimiter::Brace).then_some(expr);
|
||||
break (mac.args.delim == Delimiter::Brace).then_some(TrailingBrace::MacCall(mac));
|
||||
}
|
||||
|
||||
InlineAsm(_) | OffsetOf(_, _) | IncludedBytes(_) | FormatArgs(_) => {
|
||||
|
|
@ -131,7 +144,6 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
|
|||
| MethodCall(_)
|
||||
| Tup(_)
|
||||
| Lit(_)
|
||||
| Cast(_, _)
|
||||
| Type(_, _)
|
||||
| Await(_, _)
|
||||
| Field(_, _)
|
||||
|
|
@ -148,3 +160,78 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// If the type's last token is `}`, it must be due to a braced macro call, such
|
||||
/// as in `*const brace! { ... }`. Returns that trailing macro call.
|
||||
fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> {
|
||||
loop {
|
||||
match &ty.kind {
|
||||
ast::TyKind::MacCall(mac) => {
|
||||
break (mac.args.delim == Delimiter::Brace).then_some(mac);
|
||||
}
|
||||
|
||||
ast::TyKind::Ptr(mut_ty) | ast::TyKind::Ref(_, mut_ty) => {
|
||||
ty = &mut_ty.ty;
|
||||
}
|
||||
|
||||
ast::TyKind::BareFn(fn_ty) => match &fn_ty.decl.output {
|
||||
ast::FnRetTy::Default(_) => break None,
|
||||
ast::FnRetTy::Ty(ret) => ty = ret,
|
||||
},
|
||||
|
||||
ast::TyKind::Path(_, path) => match path_return_type(path) {
|
||||
Some(trailing_ty) => ty = trailing_ty,
|
||||
None => break None,
|
||||
},
|
||||
|
||||
ast::TyKind::TraitObject(bounds, _) | ast::TyKind::ImplTrait(_, bounds, _) => {
|
||||
match bounds.last() {
|
||||
Some(ast::GenericBound::Trait(bound, _)) => {
|
||||
match path_return_type(&bound.trait_ref.path) {
|
||||
Some(trailing_ty) => ty = trailing_ty,
|
||||
None => break None,
|
||||
}
|
||||
}
|
||||
Some(ast::GenericBound::Outlives(_)) | None => break None,
|
||||
}
|
||||
}
|
||||
|
||||
ast::TyKind::Slice(..)
|
||||
| ast::TyKind::Array(..)
|
||||
| ast::TyKind::Never
|
||||
| ast::TyKind::Tup(..)
|
||||
| ast::TyKind::Paren(..)
|
||||
| ast::TyKind::Typeof(..)
|
||||
| ast::TyKind::Infer
|
||||
| ast::TyKind::ImplicitSelf
|
||||
| ast::TyKind::CVarArgs
|
||||
| ast::TyKind::Pat(..)
|
||||
| ast::TyKind::Dummy
|
||||
| ast::TyKind::Err(..) => break None,
|
||||
|
||||
// These end in brace, but cannot occur in a let-else statement.
|
||||
// They are only parsed as fields of a data structure. For the
|
||||
// purpose of denying trailing braces in the expression of a
|
||||
// let-else, we can disregard these.
|
||||
ast::TyKind::AnonStruct(..) | ast::TyKind::AnonUnion(..) => break None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the trailing return type in the given path, if it has one.
|
||||
///
|
||||
/// ```ignore (illustrative)
|
||||
/// ::std::ops::FnOnce(&str) -> fn() -> *const c_void
|
||||
/// ^^^^^^^^^^^^^^^^^^^^^
|
||||
/// ```
|
||||
fn path_return_type(path: &ast::Path) -> Option<&ast::Ty> {
|
||||
let last_segment = path.segments.last()?;
|
||||
let args = last_segment.args.as_ref()?;
|
||||
match &**args {
|
||||
ast::GenericArgs::Parenthesized(args) => match &args.output {
|
||||
ast::FnRetTy::Default(_) => None,
|
||||
ast::FnRetTy::Ty(ret) => Some(ret),
|
||||
},
|
||||
ast::GenericArgs::AngleBracketed(_) => None,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
|||
|
||||
fn convert(
|
||||
&mut self,
|
||||
predicate: ty::OutlivesPredicate<ty::GenericArg<'tcx>, ty::Region<'tcx>>,
|
||||
predicate: ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>,
|
||||
constraint_category: ConstraintCategory<'tcx>,
|
||||
) {
|
||||
debug!("generate: constraints at: {:#?}", self.locations);
|
||||
|
|
@ -276,7 +276,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
|||
&self,
|
||||
ty: Ty<'tcx>,
|
||||
next_outlives_predicates: &mut Vec<(
|
||||
ty::OutlivesPredicate<ty::GenericArg<'tcx>, ty::Region<'tcx>>,
|
||||
ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>,
|
||||
ConstraintCategory<'tcx>,
|
||||
)>,
|
||||
) -> Ty<'tcx> {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ use rustc_codegen_ssa::mir::operand::OperandRef;
|
|||
use rustc_codegen_ssa::mir::place::PlaceRef;
|
||||
use rustc_codegen_ssa::traits::{BaseTypeMethods, BuilderMethods};
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::mir::BinOp;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::layout::HasTyCtxt;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
|
|
@ -122,12 +123,12 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
let in_ty = arg_tys[0];
|
||||
|
||||
let comparison = match name {
|
||||
sym::simd_eq => Some(hir::BinOpKind::Eq),
|
||||
sym::simd_ne => Some(hir::BinOpKind::Ne),
|
||||
sym::simd_lt => Some(hir::BinOpKind::Lt),
|
||||
sym::simd_le => Some(hir::BinOpKind::Le),
|
||||
sym::simd_gt => Some(hir::BinOpKind::Gt),
|
||||
sym::simd_ge => Some(hir::BinOpKind::Ge),
|
||||
sym::simd_eq => Some(BinOp::Eq),
|
||||
sym::simd_ne => Some(BinOp::Ne),
|
||||
sym::simd_lt => Some(BinOp::Lt),
|
||||
sym::simd_le => Some(BinOp::Le),
|
||||
sym::simd_gt => Some(BinOp::Gt),
|
||||
sym::simd_ge => Some(BinOp::Ge),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
|
|||
use rustc_codegen_ssa::mir::place::PlaceRef;
|
||||
use rustc_codegen_ssa::traits::*;
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::mir::BinOp;
|
||||
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf};
|
||||
use rustc_middle::ty::{self, GenericArgsRef, Ty};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
|
|
@ -1104,12 +1105,12 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
let in_ty = arg_tys[0];
|
||||
|
||||
let comparison = match name {
|
||||
sym::simd_eq => Some(hir::BinOpKind::Eq),
|
||||
sym::simd_ne => Some(hir::BinOpKind::Ne),
|
||||
sym::simd_lt => Some(hir::BinOpKind::Lt),
|
||||
sym::simd_le => Some(hir::BinOpKind::Le),
|
||||
sym::simd_gt => Some(hir::BinOpKind::Gt),
|
||||
sym::simd_ge => Some(hir::BinOpKind::Ge),
|
||||
sym::simd_eq => Some(BinOp::Eq),
|
||||
sym::simd_ne => Some(BinOp::Ne),
|
||||
sym::simd_lt => Some(BinOp::Lt),
|
||||
sym::simd_le => Some(BinOp::Le),
|
||||
sym::simd_gt => Some(BinOp::Gt),
|
||||
sym::simd_ge => Some(BinOp::Ge),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
|
|||
use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
|
||||
use rustc_data_structures::sync::par_map;
|
||||
use rustc_data_structures::unord::UnordMap;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
|
|
@ -30,6 +29,7 @@ use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, Debugger
|
|||
use rustc_middle::middle::exported_symbols;
|
||||
use rustc_middle::middle::exported_symbols::SymbolExportKind;
|
||||
use rustc_middle::middle::lang_items;
|
||||
use rustc_middle::mir::BinOp;
|
||||
use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem};
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
|
||||
|
|
@ -46,32 +46,32 @@ use std::time::{Duration, Instant};
|
|||
|
||||
use itertools::Itertools;
|
||||
|
||||
pub fn bin_op_to_icmp_predicate(op: hir::BinOpKind, signed: bool) -> IntPredicate {
|
||||
pub fn bin_op_to_icmp_predicate(op: BinOp, signed: bool) -> IntPredicate {
|
||||
match op {
|
||||
hir::BinOpKind::Eq => IntPredicate::IntEQ,
|
||||
hir::BinOpKind::Ne => IntPredicate::IntNE,
|
||||
hir::BinOpKind::Lt => {
|
||||
BinOp::Eq => IntPredicate::IntEQ,
|
||||
BinOp::Ne => IntPredicate::IntNE,
|
||||
BinOp::Lt => {
|
||||
if signed {
|
||||
IntPredicate::IntSLT
|
||||
} else {
|
||||
IntPredicate::IntULT
|
||||
}
|
||||
}
|
||||
hir::BinOpKind::Le => {
|
||||
BinOp::Le => {
|
||||
if signed {
|
||||
IntPredicate::IntSLE
|
||||
} else {
|
||||
IntPredicate::IntULE
|
||||
}
|
||||
}
|
||||
hir::BinOpKind::Gt => {
|
||||
BinOp::Gt => {
|
||||
if signed {
|
||||
IntPredicate::IntSGT
|
||||
} else {
|
||||
IntPredicate::IntUGT
|
||||
}
|
||||
}
|
||||
hir::BinOpKind::Ge => {
|
||||
BinOp::Ge => {
|
||||
if signed {
|
||||
IntPredicate::IntSGE
|
||||
} else {
|
||||
|
|
@ -86,14 +86,14 @@ pub fn bin_op_to_icmp_predicate(op: hir::BinOpKind, signed: bool) -> IntPredicat
|
|||
}
|
||||
}
|
||||
|
||||
pub fn bin_op_to_fcmp_predicate(op: hir::BinOpKind) -> RealPredicate {
|
||||
pub fn bin_op_to_fcmp_predicate(op: BinOp) -> RealPredicate {
|
||||
match op {
|
||||
hir::BinOpKind::Eq => RealPredicate::RealOEQ,
|
||||
hir::BinOpKind::Ne => RealPredicate::RealUNE,
|
||||
hir::BinOpKind::Lt => RealPredicate::RealOLT,
|
||||
hir::BinOpKind::Le => RealPredicate::RealOLE,
|
||||
hir::BinOpKind::Gt => RealPredicate::RealOGT,
|
||||
hir::BinOpKind::Ge => RealPredicate::RealOGE,
|
||||
BinOp::Eq => RealPredicate::RealOEQ,
|
||||
BinOp::Ne => RealPredicate::RealUNE,
|
||||
BinOp::Lt => RealPredicate::RealOLT,
|
||||
BinOp::Le => RealPredicate::RealOLE,
|
||||
BinOp::Gt => RealPredicate::RealOGT,
|
||||
BinOp::Ge => RealPredicate::RealOGE,
|
||||
op => {
|
||||
bug!(
|
||||
"comparison_op_to_fcmp_predicate: expected comparison operator, \
|
||||
|
|
@ -110,7 +110,7 @@ pub fn compare_simd_types<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
rhs: Bx::Value,
|
||||
t: Ty<'tcx>,
|
||||
ret_ty: Bx::Type,
|
||||
op: hir::BinOpKind,
|
||||
op: BinOp,
|
||||
) -> Bx::Value {
|
||||
let signed = match t.kind() {
|
||||
ty::Float(_) => {
|
||||
|
|
|
|||
|
|
@ -195,6 +195,7 @@ pub enum CodegenErrors {
|
|||
EmptyVersionNumber,
|
||||
EncodingVersionMismatch { version_array: String, rlink_version: u32 },
|
||||
RustcVersionMismatch { rustc_version: String },
|
||||
CorruptFile,
|
||||
}
|
||||
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
|
|
@ -265,7 +266,9 @@ impl CodegenResults {
|
|||
});
|
||||
}
|
||||
|
||||
let mut decoder = MemDecoder::new(&data[4..], 0);
|
||||
let Ok(mut decoder) = MemDecoder::new(&data[4..], 0) else {
|
||||
return Err(CodegenErrors::CorruptFile);
|
||||
};
|
||||
let rustc_version = decoder.read_str();
|
||||
if rustc_version != sess.cfg_version {
|
||||
return Err(CodegenErrors::RustcVersionMismatch {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ use crate::common::IntPredicate;
|
|||
use crate::traits::*;
|
||||
use crate::MemFlags;
|
||||
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::ty::cast::{CastTy, IntTy};
|
||||
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
|
||||
|
|
@ -896,9 +895,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
| mir::BinOp::Le
|
||||
| mir::BinOp::Ge => {
|
||||
if is_float {
|
||||
bx.fcmp(base::bin_op_to_fcmp_predicate(op.to_hir_binop()), lhs, rhs)
|
||||
bx.fcmp(base::bin_op_to_fcmp_predicate(op), lhs, rhs)
|
||||
} else {
|
||||
bx.icmp(base::bin_op_to_icmp_predicate(op.to_hir_binop(), is_signed), lhs, rhs)
|
||||
bx.icmp(base::bin_op_to_icmp_predicate(op, is_signed), lhs, rhs)
|
||||
}
|
||||
}
|
||||
mir::BinOp::Cmp => {
|
||||
|
|
@ -912,16 +911,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
// `PartialOrd`, so only use it in debug for now. Once LLVM can handle it
|
||||
// better (see <https://github.com/llvm/llvm-project/issues/73417>), it'll
|
||||
// be worth trying it in optimized builds as well.
|
||||
let is_gt = bx.icmp(pred(hir::BinOpKind::Gt), lhs, rhs);
|
||||
let is_gt = bx.icmp(pred(mir::BinOp::Gt), lhs, rhs);
|
||||
let gtext = bx.zext(is_gt, bx.type_i8());
|
||||
let is_lt = bx.icmp(pred(hir::BinOpKind::Lt), lhs, rhs);
|
||||
let is_lt = bx.icmp(pred(mir::BinOp::Lt), lhs, rhs);
|
||||
let ltext = bx.zext(is_lt, bx.type_i8());
|
||||
bx.unchecked_ssub(gtext, ltext)
|
||||
} else {
|
||||
// These operations are those expected by `tests/codegen/integer-cmp.rs`,
|
||||
// from <https://github.com/rust-lang/rust/pull/63767>.
|
||||
let is_lt = bx.icmp(pred(hir::BinOpKind::Lt), lhs, rhs);
|
||||
let is_ne = bx.icmp(pred(hir::BinOpKind::Ne), lhs, rhs);
|
||||
let is_lt = bx.icmp(pred(mir::BinOp::Lt), lhs, rhs);
|
||||
let is_ne = bx.icmp(pred(mir::BinOp::Ne), lhs, rhs);
|
||||
let ge = bx.select(
|
||||
is_ne,
|
||||
bx.cx().const_i8(Ordering::Greater as i8),
|
||||
|
|
|
|||
|
|
@ -25,9 +25,9 @@ use rustc_target::spec::abi::Abi as CallAbi;
|
|||
use crate::errors::{LongRunning, LongRunningWarn};
|
||||
use crate::fluent_generated as fluent;
|
||||
use crate::interpret::{
|
||||
self, compile_time_machine, err_ub, throw_exhaust, throw_inval, throw_ub_custom,
|
||||
self, compile_time_machine, err_ub, throw_exhaust, throw_inval, throw_ub_custom, throw_unsup,
|
||||
throw_unsup_format, AllocId, AllocRange, ConstAllocation, CtfeProvenance, FnArg, FnVal, Frame,
|
||||
ImmTy, InterpCx, InterpResult, MPlaceTy, OpTy, Pointer, PointerArithmetic, Scalar,
|
||||
GlobalAlloc, ImmTy, InterpCx, InterpResult, MPlaceTy, OpTy, Pointer, PointerArithmetic, Scalar,
|
||||
};
|
||||
|
||||
use super::error::*;
|
||||
|
|
@ -759,11 +759,21 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
|||
ecx: &InterpCx<'mir, 'tcx, Self>,
|
||||
alloc_id: AllocId,
|
||||
) -> InterpResult<'tcx> {
|
||||
// Check if this is the currently evaluated static.
|
||||
if Some(alloc_id) == ecx.machine.static_root_ids.map(|(id, _)| id) {
|
||||
Err(ConstEvalErrKind::RecursiveStatic.into())
|
||||
} else {
|
||||
Ok(())
|
||||
return Err(ConstEvalErrKind::RecursiveStatic.into());
|
||||
}
|
||||
// If this is another static, make sure we fire off the query to detect cycles.
|
||||
// But only do that when checks for static recursion are enabled.
|
||||
if ecx.machine.static_root_ids.is_some() {
|
||||
if let Some(GlobalAlloc::Static(def_id)) = ecx.tcx.try_get_global_alloc(alloc_id) {
|
||||
if ecx.tcx.is_foreign_item(def_id) {
|
||||
throw_unsup!(ExternStatic(def_id));
|
||||
}
|
||||
ecx.ctfe_query(|tcx| tcx.eval_static_initializer(def_id))?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -255,6 +255,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
name = intrinsic_name,
|
||||
);
|
||||
}
|
||||
// This will always return 0.
|
||||
(a, b)
|
||||
}
|
||||
(Err(_), _) | (_, Err(_)) => {
|
||||
|
|
|
|||
|
|
@ -413,6 +413,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
/// to the allocation it points to. Supports both shared and mutable references, as the actual
|
||||
/// checking is offloaded to a helper closure.
|
||||
///
|
||||
/// `alloc_size` will only get called for non-zero-sized accesses.
|
||||
///
|
||||
/// Returns `None` if and only if the size is 0.
|
||||
fn check_and_deref_ptr<T>(
|
||||
&self,
|
||||
|
|
@ -425,18 +427,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
M::ProvenanceExtra,
|
||||
) -> InterpResult<'tcx, (Size, Align, T)>,
|
||||
) -> InterpResult<'tcx, Option<T>> {
|
||||
// Everything is okay with size 0.
|
||||
if size.bytes() == 0 {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
Ok(match self.ptr_try_get_alloc_id(ptr) {
|
||||
Err(addr) => {
|
||||
// We couldn't get a proper allocation. This is only okay if the access size is 0,
|
||||
// and the address is not null.
|
||||
if size.bytes() > 0 || addr == 0 {
|
||||
throw_ub!(DanglingIntPointer(addr, msg));
|
||||
}
|
||||
None
|
||||
// We couldn't get a proper allocation.
|
||||
throw_ub!(DanglingIntPointer(addr, msg));
|
||||
}
|
||||
Ok((alloc_id, offset, prov)) => {
|
||||
let (alloc_size, _alloc_align, ret_val) = alloc_size(alloc_id, offset, prov)?;
|
||||
// Test bounds. This also ensures non-null.
|
||||
// Test bounds.
|
||||
// It is sufficient to check this for the end pointer. Also check for overflow!
|
||||
if offset.checked_add(size, &self.tcx).map_or(true, |end| end > alloc_size) {
|
||||
throw_ub!(PointerOutOfBounds {
|
||||
|
|
@ -447,14 +450,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
msg,
|
||||
})
|
||||
}
|
||||
// Ensure we never consider the null pointer dereferenceable.
|
||||
if M::Provenance::OFFSET_IS_ADDR {
|
||||
assert_ne!(ptr.addr(), Size::ZERO);
|
||||
}
|
||||
|
||||
// We can still be zero-sized in this branch, in which case we have to
|
||||
// return `None`.
|
||||
if size.bytes() == 0 { None } else { Some(ret_val) }
|
||||
Some(ret_val)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -641,16 +638,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
size,
|
||||
CheckInAllocMsg::MemoryAccessTest,
|
||||
|alloc_id, offset, prov| {
|
||||
if !self.memory.validation_in_progress.get() {
|
||||
// We want to call the hook on *all* accesses that involve an AllocId,
|
||||
// including zero-sized accesses. That means we have to do it here
|
||||
// rather than below in the `Some` branch.
|
||||
M::before_alloc_read(self, alloc_id)?;
|
||||
}
|
||||
let alloc = self.get_alloc_raw(alloc_id)?;
|
||||
Ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc)))
|
||||
},
|
||||
)?;
|
||||
// We want to call the hook on *all* accesses that involve an AllocId, including zero-sized
|
||||
// accesses. That means we cannot rely on the closure above or the `Some` branch below. We
|
||||
// do this after `check_and_deref_ptr` to ensure some basic sanity has already been checked.
|
||||
if !self.memory.validation_in_progress.get() {
|
||||
if let Ok((alloc_id, ..)) = self.ptr_try_get_alloc_id(ptr) {
|
||||
M::before_alloc_read(self, alloc_id)?;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((alloc_id, offset, prov, alloc)) = ptr_and_alloc {
|
||||
let range = alloc_range(offset, size);
|
||||
|
|
|
|||
|
|
@ -434,6 +434,11 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
|||
found_bytes: has.bytes()
|
||||
},
|
||||
);
|
||||
// Make sure this is non-null. We checked dereferenceability above, but if `size` is zero
|
||||
// that does not imply non-null.
|
||||
if self.ecx.scalar_may_be_null(Scalar::from_maybe_pointer(place.ptr(), self.ecx))? {
|
||||
throw_validation_failure!(self.path, NullPtr { ptr_kind })
|
||||
}
|
||||
// Do not allow pointers to uninhabited types.
|
||||
if place.layout.abi.is_uninhabited() {
|
||||
let ty = place.layout.ty;
|
||||
|
|
@ -456,8 +461,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
|||
// `!` is a ZST and we want to validate it.
|
||||
if let Ok((alloc_id, _offset, _prov)) = self.ecx.ptr_try_get_alloc_id(place.ptr()) {
|
||||
let mut skip_recursive_check = false;
|
||||
let alloc_actual_mutbl = mutability(self.ecx, alloc_id);
|
||||
if let GlobalAlloc::Static(did) = self.ecx.tcx.global_alloc(alloc_id) {
|
||||
if let Some(GlobalAlloc::Static(did)) = self.ecx.tcx.try_get_global_alloc(alloc_id)
|
||||
{
|
||||
let DefKind::Static { nested, .. } = self.ecx.tcx.def_kind(did) else { bug!() };
|
||||
// Special handling for pointers to statics (irrespective of their type).
|
||||
assert!(!self.ecx.tcx.is_thread_local_static(did));
|
||||
|
|
@ -495,6 +500,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
|||
// If this allocation has size zero, there is no actual mutability here.
|
||||
let (size, _align, _alloc_kind) = self.ecx.get_alloc_info(alloc_id);
|
||||
if size != Size::ZERO {
|
||||
let alloc_actual_mutbl = mutability(self.ecx, alloc_id);
|
||||
// Mutable pointer to immutable memory is no good.
|
||||
if ptr_expected_mutbl == Mutability::Mut
|
||||
&& alloc_actual_mutbl == Mutability::Not
|
||||
|
|
@ -831,6 +837,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
|
|||
trace!("visit_value: {:?}, {:?}", *op, op.layout);
|
||||
|
||||
// Check primitive types -- the leaves of our recursive descent.
|
||||
// We assume that the Scalar validity range does not restrict these values
|
||||
// any further than `try_visit_primitive` does!
|
||||
if self.try_visit_primitive(op)? {
|
||||
return Ok(());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ driver_impl_ice_path_error = the ICE couldn't be written to `{$path}`: {$error}
|
|||
driver_impl_ice_path_error_env = the environment variable `RUSTC_ICE` is set to `{$env_var}`
|
||||
driver_impl_ice_version = rustc {$version} running on {$triple}
|
||||
|
||||
driver_impl_rlink_corrupt_file = corrupt metadata encountered in `{$file}`
|
||||
|
||||
driver_impl_rlink_empty_version_number = The input does not contain version number
|
||||
|
||||
driver_impl_rlink_encoding_version_mismatch = .rlink file was produced with encoding version `{$version_array}`, but the current version is `{$rlink_version}`
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ mod signal_handler {
|
|||
|
||||
use crate::session_diagnostics::{
|
||||
RLinkEmptyVersionNumber, RLinkEncodingVersionMismatch, RLinkRustcVersionMismatch,
|
||||
RLinkWrongFileType, RlinkNotAFile, RlinkUnableToRead,
|
||||
RLinkWrongFileType, RlinkCorruptFile, RlinkNotAFile, RlinkUnableToRead,
|
||||
};
|
||||
|
||||
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||
|
|
@ -645,8 +645,7 @@ fn process_rlink(sess: &Session, compiler: &interface::Compiler) {
|
|||
match err {
|
||||
CodegenErrors::WrongFileType => dcx.emit_fatal(RLinkWrongFileType),
|
||||
CodegenErrors::EmptyVersionNumber => dcx.emit_fatal(RLinkEmptyVersionNumber),
|
||||
CodegenErrors::EncodingVersionMismatch { version_array, rlink_version } => sess
|
||||
.dcx()
|
||||
CodegenErrors::EncodingVersionMismatch { version_array, rlink_version } => dcx
|
||||
.emit_fatal(RLinkEncodingVersionMismatch { version_array, rlink_version }),
|
||||
CodegenErrors::RustcVersionMismatch { rustc_version } => {
|
||||
dcx.emit_fatal(RLinkRustcVersionMismatch {
|
||||
|
|
@ -654,6 +653,9 @@ fn process_rlink(sess: &Session, compiler: &interface::Compiler) {
|
|||
current_version: sess.cfg_version,
|
||||
})
|
||||
}
|
||||
CodegenErrors::CorruptFile => {
|
||||
dcx.emit_fatal(RlinkCorruptFile { file });
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -32,6 +32,12 @@ pub(crate) struct RLinkRustcVersionMismatch<'a> {
|
|||
#[diag(driver_impl_rlink_no_a_file)]
|
||||
pub(crate) struct RlinkNotAFile;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(driver_impl_rlink_corrupt_file)]
|
||||
pub(crate) struct RlinkCorruptFile<'a> {
|
||||
pub file: &'a std::path::Path,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(driver_impl_ice)]
|
||||
pub(crate) struct Ice;
|
||||
|
|
|
|||
|
|
@ -118,6 +118,15 @@ impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::FnSig<I> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<I: rustc_type_ir::Interner, T> IntoDiagArg for rustc_type_ir::Binder<I, T>
|
||||
where
|
||||
T: IntoDiagArg,
|
||||
{
|
||||
fn into_diag_arg(self) -> DiagArgValue {
|
||||
self.skip_binder().into_diag_arg()
|
||||
}
|
||||
}
|
||||
|
||||
into_diag_arg_for_number!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize);
|
||||
|
||||
impl IntoDiagArg for bool {
|
||||
|
|
|
|||
|
|
@ -371,9 +371,9 @@ hir_analysis_pass_to_variadic_function = can't pass `{$ty}` to variadic function
|
|||
.suggestion = cast the value to `{$cast_ty}`
|
||||
.help = cast the value to `{$cast_ty}`
|
||||
|
||||
hir_analysis_pattern_type_non_const_range = "range patterns must have constant range start and end"
|
||||
hir_analysis_pattern_type_wild_pat = "wildcard patterns are not permitted for pattern types"
|
||||
.label = "this type is the same as the inner type without a pattern"
|
||||
hir_analysis_pattern_type_non_const_range = range patterns must have constant range start and end
|
||||
hir_analysis_pattern_type_wild_pat = wildcard patterns are not permitted for pattern types
|
||||
.label = this type is the same as the inner type without a pattern
|
||||
hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind}
|
||||
.label = not allowed in type signatures
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
|
|||
use rustc_infer::traits::FulfillmentError;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::query::Key;
|
||||
use rustc_middle::ty::print::PrintTraitRefExt as _;
|
||||
use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _};
|
||||
use rustc_middle::ty::GenericParamDefKind;
|
||||
use rustc_middle::ty::{self, suggest_constraining_type_param};
|
||||
use rustc_middle::ty::{AdtDef, Ty, TyCtxt, TypeVisitableExt};
|
||||
|
|
@ -1382,7 +1382,7 @@ pub enum GenericsArgsErrExtend<'tcx> {
|
|||
span: Span,
|
||||
},
|
||||
SelfTyParam(Span),
|
||||
TyParam(DefId),
|
||||
Param(DefId),
|
||||
DefVariant,
|
||||
None,
|
||||
}
|
||||
|
|
@ -1498,11 +1498,11 @@ fn generics_args_err_extend<'a>(
|
|||
GenericsArgsErrExtend::DefVariant => {
|
||||
err.note("enum variants can't have type parameters");
|
||||
}
|
||||
GenericsArgsErrExtend::TyParam(def_id) => {
|
||||
if let Some(span) = tcx.def_ident_span(def_id) {
|
||||
let name = tcx.item_name(def_id);
|
||||
err.span_note(span, format!("type parameter `{name}` defined here"));
|
||||
}
|
||||
GenericsArgsErrExtend::Param(def_id) => {
|
||||
let span = tcx.def_ident_span(def_id).unwrap();
|
||||
let kind = tcx.def_descr(def_id);
|
||||
let name = tcx.item_name(def_id);
|
||||
err.span_note(span, format!("{kind} `{name}` defined here"));
|
||||
}
|
||||
GenericsArgsErrExtend::SelfTyParam(span) => {
|
||||
err.span_suggestion_verbose(
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
|||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_middle::middle::stability::AllowUnstable;
|
||||
use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
|
||||
use rustc_middle::ty::print::PrintPolyTraitRefExt as _;
|
||||
use rustc_middle::ty::{
|
||||
self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt,
|
||||
TypeVisitableExt,
|
||||
|
|
@ -1757,7 +1758,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
assert_eq!(opt_self_ty, None);
|
||||
let _ = self.prohibit_generic_args(
|
||||
path.segments.iter(),
|
||||
GenericsArgsErrExtend::TyParam(def_id),
|
||||
GenericsArgsErrExtend::Param(def_id),
|
||||
);
|
||||
self.lower_ty_param(hir_id)
|
||||
}
|
||||
|
|
@ -2190,10 +2191,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
|
||||
hir::ExprKind::Path(hir::QPath::Resolved(
|
||||
_,
|
||||
&hir::Path {
|
||||
res: Res::Def(DefKind::ConstParam, def_id), ..
|
||||
path @ &hir::Path {
|
||||
res: Res::Def(DefKind::ConstParam, def_id),
|
||||
..
|
||||
},
|
||||
)) => {
|
||||
let _ = self.prohibit_generic_args(
|
||||
path.segments.iter(),
|
||||
GenericsArgsErrExtend::Param(def_id),
|
||||
);
|
||||
let ty = tcx
|
||||
.type_of(def_id)
|
||||
.no_bound_vars()
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use smallvec::smallvec;
|
|||
/// Tracks the `T: 'a` or `'a: 'a` predicates that we have inferred
|
||||
/// must be added to the struct header.
|
||||
pub(crate) type RequiredPredicates<'tcx> =
|
||||
FxIndexMap<ty::OutlivesPredicate<GenericArg<'tcx>, ty::Region<'tcx>>, Span>;
|
||||
FxIndexMap<ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>, Span>;
|
||||
|
||||
/// Given a requirement `T: 'a` or `'b: 'a`, deduce the
|
||||
/// outlives_component and add it to `required_predicates`
|
||||
|
|
|
|||
|
|
@ -373,8 +373,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let Some(arg_ty) = self.node_ty_opt(args[idx].hir_id) else {
|
||||
return false;
|
||||
};
|
||||
let possible_rcvr_ty = expr_finder.uses.iter().find_map(|binding| {
|
||||
let possible_rcvr_ty = expr_finder.uses.iter().rev().find_map(|binding| {
|
||||
let possible_rcvr_ty = self.node_ty_opt(binding.hir_id)?;
|
||||
if possible_rcvr_ty.is_ty_var() {
|
||||
return None;
|
||||
}
|
||||
// Fudge the receiver, so we can do new inference on it.
|
||||
let possible_rcvr_ty = possible_rcvr_ty.fold_with(&mut fudger);
|
||||
let method = self
|
||||
|
|
@ -386,6 +389,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
binding,
|
||||
)
|
||||
.ok()?;
|
||||
// Make sure we select the same method that we started with...
|
||||
if Some(method.def_id)
|
||||
!= self.typeck_results.borrow().type_dependent_def_id(call_expr.hir_id)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
// Unify the method signature with our incompatible arg, to
|
||||
// do inference in the *opposite* direction and to find out
|
||||
// what our ideal rcvr ty would look like.
|
||||
|
|
@ -456,6 +465,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
) else {
|
||||
continue;
|
||||
};
|
||||
// Make sure we select the same method that we started with...
|
||||
if Some(method.def_id)
|
||||
!= self.typeck_results.borrow().type_dependent_def_id(parent_expr.hir_id)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
let ideal_rcvr_ty = rcvr_ty.fold_with(&mut fudger);
|
||||
let ideal_method = self
|
||||
|
|
@ -505,13 +520,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// blame arg, if possible. Don't do this if we're coming from
|
||||
// arg mismatch code, because we'll possibly suggest a mutually
|
||||
// incompatible fix at the original mismatch site.
|
||||
// HACK(compiler-errors): We don't actually consider the implications
|
||||
// of our inference guesses in `emit_type_mismatch_suggestions`, so
|
||||
// only suggest things when we know our type error is precisely due to
|
||||
// a type mismatch, and not via some projection or something. See #116155.
|
||||
if matches!(source, TypeMismatchSource::Ty(_))
|
||||
&& let Some(ideal_method) = ideal_method
|
||||
&& let ideal_arg_ty = self.resolve_vars_if_possible(ideal_method.sig.inputs()[idx + 1])
|
||||
// HACK(compiler-errors): We don't actually consider the implications
|
||||
// of our inference guesses in `emit_type_mismatch_suggestions`, so
|
||||
// only suggest things when we know our type error is precisely due to
|
||||
// a type mismatch, and not via some projection or something. See #116155.
|
||||
&& Some(ideal_method.def_id)
|
||||
== self
|
||||
.typeck_results
|
||||
.borrow()
|
||||
.type_dependent_def_id(parent_expr.hir_id)
|
||||
&& let ideal_arg_ty =
|
||||
self.resolve_vars_if_possible(ideal_method.sig.inputs()[idx + 1])
|
||||
&& !ideal_arg_ty.has_non_region_infer()
|
||||
{
|
||||
self.emit_type_mismatch_suggestions(
|
||||
|
|
|
|||
|
|
@ -204,6 +204,60 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
fake_reads: Default::default(),
|
||||
};
|
||||
|
||||
let _ = euv::ExprUseVisitor::new(
|
||||
&FnCtxt::new(self, self.tcx.param_env(closure_def_id), closure_def_id),
|
||||
&mut delegate,
|
||||
)
|
||||
.consume_body(body);
|
||||
|
||||
// There are several curious situations with coroutine-closures where
|
||||
// analysis is too aggressive with borrows when the coroutine-closure is
|
||||
// marked `move`. Specifically:
|
||||
//
|
||||
// 1. If the coroutine-closure was inferred to be `FnOnce` during signature
|
||||
// inference, then it's still possible that we try to borrow upvars from
|
||||
// the coroutine-closure because they are not used by the coroutine body
|
||||
// in a way that forces a move. See the test:
|
||||
// `async-await/async-closures/force-move-due-to-inferred-kind.rs`.
|
||||
//
|
||||
// 2. If the coroutine-closure is forced to be `FnOnce` due to the way it
|
||||
// uses its upvars, but not *all* upvars would force the closure to `FnOnce`.
|
||||
// See the test: `async-await/async-closures/force-move-due-to-actually-fnonce.rs`.
|
||||
//
|
||||
// This would lead to an impossible to satisfy situation, since `AsyncFnOnce`
|
||||
// coroutine bodies can't borrow from their parent closure. To fix this,
|
||||
// we force the inner coroutine to also be `move`. This only matters for
|
||||
// coroutine-closures that are `move` since otherwise they themselves will
|
||||
// be borrowing from the outer environment, so there's no self-borrows occuring.
|
||||
//
|
||||
// One *important* note is that we do a call to `process_collected_capture_information`
|
||||
// to eagerly test whether the coroutine would end up `FnOnce`, but we do this
|
||||
// *before* capturing all the closure args by-value below, since that would always
|
||||
// cause the analysis to return `FnOnce`.
|
||||
if let UpvarArgs::Coroutine(..) = args
|
||||
&& let hir::CoroutineKind::Desugared(_, hir::CoroutineSource::Closure) =
|
||||
self.tcx.coroutine_kind(closure_def_id).expect("coroutine should have kind")
|
||||
&& let parent_hir_id =
|
||||
self.tcx.local_def_id_to_hir_id(self.tcx.local_parent(closure_def_id))
|
||||
&& let parent_ty = self.node_ty(parent_hir_id)
|
||||
&& let hir::CaptureBy::Value { move_kw } =
|
||||
self.tcx.hir_node(parent_hir_id).expect_closure().capture_clause
|
||||
{
|
||||
// (1.) Closure signature inference forced this closure to `FnOnce`.
|
||||
if let Some(ty::ClosureKind::FnOnce) = self.closure_kind(parent_ty) {
|
||||
capture_clause = hir::CaptureBy::Value { move_kw };
|
||||
}
|
||||
// (2.) The way that the closure uses its upvars means it's `FnOnce`.
|
||||
else if let (_, ty::ClosureKind::FnOnce, _) = self
|
||||
.process_collected_capture_information(
|
||||
capture_clause,
|
||||
&delegate.capture_information,
|
||||
)
|
||||
{
|
||||
capture_clause = hir::CaptureBy::Value { move_kw };
|
||||
}
|
||||
}
|
||||
|
||||
// As noted in `lower_coroutine_body_with_moved_arguments`, we default the capture mode
|
||||
// to `ByRef` for the `async {}` block internal to async fns/closure. This means
|
||||
// that we would *not* be moving all of the parameters into the async block by default.
|
||||
|
|
@ -253,34 +307,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
let _ = euv::ExprUseVisitor::new(
|
||||
&FnCtxt::new(self, self.tcx.param_env(closure_def_id), closure_def_id),
|
||||
&mut delegate,
|
||||
)
|
||||
.consume_body(body);
|
||||
|
||||
// If a coroutine is comes from a coroutine-closure that is `move`, but
|
||||
// the coroutine-closure was inferred to be `FnOnce` during signature
|
||||
// inference, then it's still possible that we try to borrow upvars from
|
||||
// the coroutine-closure because they are not used by the coroutine body
|
||||
// in a way that forces a move.
|
||||
//
|
||||
// This would lead to an impossible to satisfy situation, since `AsyncFnOnce`
|
||||
// coroutine bodies can't borrow from their parent closure. To fix this,
|
||||
// we force the inner coroutine to also be `move`. This only matters for
|
||||
// coroutine-closures that are `move` since otherwise they themselves will
|
||||
// be borrowing from the outer environment, so there's no self-borrows occuring.
|
||||
if let UpvarArgs::Coroutine(..) = args
|
||||
&& let hir::CoroutineKind::Desugared(_, hir::CoroutineSource::Closure) =
|
||||
self.tcx.coroutine_kind(closure_def_id).expect("coroutine should have kind")
|
||||
&& let parent_hir_id =
|
||||
self.tcx.local_def_id_to_hir_id(self.tcx.local_parent(closure_def_id))
|
||||
&& let parent_ty = self.node_ty(parent_hir_id)
|
||||
&& let Some(ty::ClosureKind::FnOnce) = self.closure_kind(parent_ty)
|
||||
{
|
||||
capture_clause = self.tcx.hir_node(parent_hir_id).expect_closure().capture_clause;
|
||||
}
|
||||
|
||||
debug!(
|
||||
"For closure={:?}, capture_information={:#?}",
|
||||
closure_def_id, delegate.capture_information
|
||||
|
|
@ -289,7 +315,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.log_capture_analysis_first_pass(closure_def_id, &delegate.capture_information, span);
|
||||
|
||||
let (capture_information, closure_kind, origin) = self
|
||||
.process_collected_capture_information(capture_clause, delegate.capture_information);
|
||||
.process_collected_capture_information(capture_clause, &delegate.capture_information);
|
||||
|
||||
self.compute_min_captures(closure_def_id, capture_information, span);
|
||||
|
||||
|
|
@ -545,13 +571,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
fn process_collected_capture_information(
|
||||
&self,
|
||||
capture_clause: hir::CaptureBy,
|
||||
capture_information: InferredCaptureInformation<'tcx>,
|
||||
capture_information: &InferredCaptureInformation<'tcx>,
|
||||
) -> (InferredCaptureInformation<'tcx>, ty::ClosureKind, Option<(Span, Place<'tcx>)>) {
|
||||
let mut closure_kind = ty::ClosureKind::LATTICE_BOTTOM;
|
||||
let mut origin: Option<(Span, Place<'tcx>)> = None;
|
||||
|
||||
let processed = capture_information
|
||||
.into_iter()
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|(place, mut capture_info)| {
|
||||
// Apply rules for safety before inferring closure kind
|
||||
let (place, capture_kind) =
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ incremental_cargo_help_2 =
|
|||
incremental_copy_workproduct_to_cache =
|
||||
error copying object file `{$from}` to incremental directory as `{$to}`: {$err}
|
||||
|
||||
incremental_corrupt_file = corrupt incremental compilation artifact found at `{$path}`. This file will automatically be ignored and deleted. If you see this message repeatedly or can provoke it without manually manipulating the compiler's artifacts, please file an issue. The incremental compilation system relies on hardlinks and filesystem locks behaving correctly, and may not deal well with OS crashes, so whatever information you can provide about your filesystem or other state may be very relevant.
|
||||
|
||||
incremental_create_dep_graph = failed to create dependency graph at `{$path}`: {$err}
|
||||
|
||||
incremental_create_incr_comp_dir =
|
||||
|
|
|
|||
|
|
@ -306,3 +306,9 @@ pub struct DeleteWorkProduct<'a> {
|
|||
pub path: &'a Path,
|
||||
pub err: std::io::Error,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(incremental_corrupt_file)]
|
||||
pub struct CorruptFile<'a> {
|
||||
pub path: &'a Path,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -115,7 +115,12 @@ fn load_dep_graph(sess: &Session) -> LoadResult<(Arc<SerializedDepGraph>, WorkPr
|
|||
|
||||
if let LoadResult::Ok { data: (work_products_data, start_pos) } = load_result {
|
||||
// Decode the list of work_products
|
||||
let mut work_product_decoder = MemDecoder::new(&work_products_data[..], start_pos);
|
||||
let Ok(mut work_product_decoder) =
|
||||
MemDecoder::new(&work_products_data[..], start_pos)
|
||||
else {
|
||||
sess.dcx().emit_warn(errors::CorruptFile { path: &work_products_path });
|
||||
return LoadResult::DataOutOfDate;
|
||||
};
|
||||
let work_products: Vec<SerializedWorkProduct> =
|
||||
Decodable::decode(&mut work_product_decoder);
|
||||
|
||||
|
|
@ -145,7 +150,10 @@ fn load_dep_graph(sess: &Session) -> LoadResult<(Arc<SerializedDepGraph>, WorkPr
|
|||
LoadResult::DataOutOfDate => LoadResult::DataOutOfDate,
|
||||
LoadResult::LoadDepGraph(path, err) => LoadResult::LoadDepGraph(path, err),
|
||||
LoadResult::Ok { data: (bytes, start_pos) } => {
|
||||
let mut decoder = MemDecoder::new(&bytes, start_pos);
|
||||
let Ok(mut decoder) = MemDecoder::new(&bytes, start_pos) else {
|
||||
sess.dcx().emit_warn(errors::CorruptFile { path: &path });
|
||||
return LoadResult::DataOutOfDate;
|
||||
};
|
||||
let prev_commandline_args_hash = u64::decode(&mut decoder);
|
||||
|
||||
if prev_commandline_args_hash != expected_hash {
|
||||
|
|
@ -181,9 +189,14 @@ pub fn load_query_result_cache(sess: &Session) -> Option<OnDiskCache<'_>> {
|
|||
|
||||
let _prof_timer = sess.prof.generic_activity("incr_comp_load_query_result_cache");
|
||||
|
||||
match load_data(&query_cache_path(sess), sess) {
|
||||
let path = query_cache_path(sess);
|
||||
match load_data(&path, sess) {
|
||||
LoadResult::Ok { data: (bytes, start_pos) } => {
|
||||
Some(OnDiskCache::new(sess, bytes, start_pos))
|
||||
let cache = OnDiskCache::new(sess, bytes, start_pos).unwrap_or_else(|()| {
|
||||
sess.dcx().emit_warn(errors::CorruptFile { path: &path });
|
||||
OnDiskCache::new_empty(sess.source_map())
|
||||
});
|
||||
Some(cache)
|
||||
}
|
||||
_ => Some(OnDiskCache::new_empty(sess.source_map())),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,8 +64,7 @@ struct OutlivesEnvironmentBuilder<'tcx> {
|
|||
/// "Region-bound pairs" tracks outlives relations that are known to
|
||||
/// be true, either because of explicit where-clauses like `T: 'a` or
|
||||
/// because of implied bounds.
|
||||
pub type RegionBoundPairs<'tcx> =
|
||||
FxIndexSet<ty::OutlivesPredicate<GenericKind<'tcx>, Region<'tcx>>>;
|
||||
pub type RegionBoundPairs<'tcx> = FxIndexSet<ty::OutlivesPredicate<'tcx, GenericKind<'tcx>>>;
|
||||
|
||||
impl<'tcx> OutlivesEnvironment<'tcx> {
|
||||
/// Create a builder using `ParamEnv` and add explicit outlives bounds into it.
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
|||
pub fn approx_declared_bounds_from_env(
|
||||
&self,
|
||||
alias_ty: ty::AliasTy<'tcx>,
|
||||
) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> {
|
||||
) -> Vec<ty::PolyTypeOutlivesPredicate<'tcx>> {
|
||||
let erased_alias_ty = self.tcx.erase_regions(alias_ty.to_ty(self.tcx));
|
||||
self.declared_generic_bounds_from_env_for_erased_ty(erased_alias_ty)
|
||||
}
|
||||
|
|
@ -193,7 +193,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
|||
fn declared_generic_bounds_from_env(
|
||||
&self,
|
||||
generic_ty: Ty<'tcx>,
|
||||
) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> {
|
||||
) -> Vec<ty::PolyTypeOutlivesPredicate<'tcx>> {
|
||||
assert!(matches!(generic_ty.kind(), ty::Param(_) | ty::Placeholder(_)));
|
||||
self.declared_generic_bounds_from_env_for_erased_ty(generic_ty)
|
||||
}
|
||||
|
|
@ -213,7 +213,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
|||
fn declared_generic_bounds_from_env_for_erased_ty(
|
||||
&self,
|
||||
erased_ty: Ty<'tcx>,
|
||||
) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> {
|
||||
) -> Vec<ty::PolyTypeOutlivesPredicate<'tcx>> {
|
||||
let tcx = self.tcx;
|
||||
|
||||
// To start, collect bounds from user environment. Note that
|
||||
|
|
|
|||
|
|
@ -159,7 +159,9 @@ where
|
|||
if !target.contains(&self.backtrace_target) {
|
||||
return Ok(());
|
||||
}
|
||||
let backtrace = std::backtrace::Backtrace::capture();
|
||||
// Use Backtrace::force_capture because we don't want to depend on the
|
||||
// RUST_BACKTRACE environment variable being set.
|
||||
let backtrace = std::backtrace::Backtrace::force_capture();
|
||||
writeln!(writer, "stack backtrace: \n{backtrace:?}")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ pub fn type_decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2:
|
|||
quote! {}
|
||||
};
|
||||
|
||||
s.add_impl_generic(parse_quote! {#decoder_ty: ::rustc_type_ir::codec::TyDecoder #bound });
|
||||
s.add_impl_generic(parse_quote! { #decoder_ty: ::rustc_type_ir::codec::TyDecoder #bound });
|
||||
s.add_bounds(synstructure::AddBounds::Fields);
|
||||
s.underscore_const(true);
|
||||
|
||||
|
|
@ -34,7 +34,7 @@ pub fn meta_decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2:
|
|||
|
||||
pub fn decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
|
||||
let decoder_ty = quote! { __D };
|
||||
s.add_impl_generic(parse_quote! {#decoder_ty: ::rustc_span::SpanDecoder});
|
||||
s.add_impl_generic(parse_quote! { #decoder_ty: ::rustc_span::SpanDecoder });
|
||||
s.add_bounds(synstructure::AddBounds::Generics);
|
||||
s.underscore_const(true);
|
||||
|
||||
|
|
@ -43,7 +43,7 @@ pub fn decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::Toke
|
|||
|
||||
pub fn decodable_generic_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
|
||||
let decoder_ty = quote! { __D };
|
||||
s.add_impl_generic(parse_quote! {#decoder_ty: ::rustc_serialize::Decoder});
|
||||
s.add_impl_generic(parse_quote! { #decoder_ty: ::rustc_serialize::Decoder });
|
||||
s.add_bounds(synstructure::AddBounds::Generics);
|
||||
s.underscore_const(true);
|
||||
|
||||
|
|
@ -120,7 +120,7 @@ fn decode_field(field: &syn::Field) -> proc_macro2::TokenStream {
|
|||
let __decoder = quote! { __decoder };
|
||||
// Use the span of the field for the method call, so
|
||||
// that backtraces will point to the field.
|
||||
quote_spanned! {field_span=> #decode_inner_method(#__decoder) }
|
||||
quote_spanned! { field_span=> #decode_inner_method(#__decoder) }
|
||||
}
|
||||
|
||||
pub fn type_encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
|
||||
|
|
@ -133,7 +133,7 @@ pub fn type_encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2:
|
|||
};
|
||||
|
||||
let encoder_ty = quote! { __E };
|
||||
s.add_impl_generic(parse_quote! {#encoder_ty: ::rustc_type_ir::codec::TyEncoder #bound });
|
||||
s.add_impl_generic(parse_quote! { #encoder_ty: ::rustc_type_ir::codec::TyEncoder #bound });
|
||||
s.add_bounds(synstructure::AddBounds::Fields);
|
||||
s.underscore_const(true);
|
||||
|
||||
|
|
@ -142,7 +142,7 @@ pub fn type_encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2:
|
|||
|
||||
pub fn meta_encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
|
||||
if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") {
|
||||
s.add_impl_generic(parse_quote! {'tcx});
|
||||
s.add_impl_generic(parse_quote! { 'tcx });
|
||||
}
|
||||
s.add_impl_generic(parse_quote! { '__a });
|
||||
let encoder_ty = quote! { EncodeContext<'__a, 'tcx> };
|
||||
|
|
@ -154,7 +154,7 @@ pub fn meta_encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2:
|
|||
|
||||
pub fn encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
|
||||
let encoder_ty = quote! { __E };
|
||||
s.add_impl_generic(parse_quote! { #encoder_ty: ::rustc_span::SpanEncoder});
|
||||
s.add_impl_generic(parse_quote! { #encoder_ty: ::rustc_span::SpanEncoder });
|
||||
s.add_bounds(synstructure::AddBounds::Generics);
|
||||
s.underscore_const(true);
|
||||
|
||||
|
|
@ -163,7 +163,7 @@ pub fn encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::Toke
|
|||
|
||||
pub fn encodable_generic_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
|
||||
let encoder_ty = quote! { __E };
|
||||
s.add_impl_generic(parse_quote! { #encoder_ty: ::rustc_serialize::Encoder});
|
||||
s.add_impl_generic(parse_quote! { #encoder_ty: ::rustc_serialize::Encoder });
|
||||
s.add_bounds(synstructure::AddBounds::Generics);
|
||||
s.underscore_const(true);
|
||||
|
||||
|
|
|
|||
|
|
@ -853,7 +853,12 @@ fn get_metadata_section<'p>(
|
|||
slice_owned(mmap, Deref::deref)
|
||||
}
|
||||
};
|
||||
let blob = MetadataBlob(raw_bytes);
|
||||
let Ok(blob) = MetadataBlob::new(raw_bytes) else {
|
||||
return Err(MetadataError::LoadFailure(format!(
|
||||
"corrupt metadata encountered in {}",
|
||||
filename.display()
|
||||
)));
|
||||
};
|
||||
match blob.check_compatibility(cfg_version) {
|
||||
Ok(()) => Ok(blob),
|
||||
Err(None) => Err(MetadataError::LoadFailure(format!(
|
||||
|
|
|
|||
|
|
@ -40,10 +40,9 @@ use rustc_span::hygiene::HygieneDecodeContext;
|
|||
mod cstore_impl;
|
||||
|
||||
/// A reference to the raw binary version of crate metadata.
|
||||
/// A `MetadataBlob` internally is just a reference counted pointer to
|
||||
/// the actual data, so cloning it is cheap.
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct MetadataBlob(pub(crate) OwnedSlice);
|
||||
/// This struct applies [`MemDecoder`]'s validation when constructed
|
||||
/// so that later constructions are guaranteed to succeed.
|
||||
pub(crate) struct MetadataBlob(OwnedSlice);
|
||||
|
||||
impl std::ops::Deref for MetadataBlob {
|
||||
type Target = [u8];
|
||||
|
|
@ -54,6 +53,19 @@ impl std::ops::Deref for MetadataBlob {
|
|||
}
|
||||
}
|
||||
|
||||
impl MetadataBlob {
|
||||
/// Runs the [`MemDecoder`] validation and if it passes, constructs a new [`MetadataBlob`].
|
||||
pub fn new(slice: OwnedSlice) -> Result<Self, ()> {
|
||||
if MemDecoder::new(&slice, 0).is_ok() { Ok(Self(slice)) } else { Err(()) }
|
||||
}
|
||||
|
||||
/// Since this has passed the validation of [`MetadataBlob::new`], this returns bytes which are
|
||||
/// known to pass the [`MemDecoder`] validation.
|
||||
pub fn bytes(&self) -> &OwnedSlice {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// A map from external crate numbers (as decoded from some crate file) to
|
||||
/// local crate numbers (as generated during this session). Each external
|
||||
/// crate may refer to types in other external crates, and each has their
|
||||
|
|
@ -165,7 +177,14 @@ pub(super) trait Metadata<'a, 'tcx>: Copy {
|
|||
fn decoder(self, pos: usize) -> DecodeContext<'a, 'tcx> {
|
||||
let tcx = self.tcx();
|
||||
DecodeContext {
|
||||
opaque: MemDecoder::new(self.blob(), pos),
|
||||
// FIXME: This unwrap should never panic because we check that it won't when creating
|
||||
// `MetadataBlob`. Ideally we'd just have a `MetadataDecoder` and hand out subslices of
|
||||
// it as we do elsewhere in the compiler using `MetadataDecoder::split_at`. But we own
|
||||
// the data for the decoder so holding onto the `MemDecoder` too would make us a
|
||||
// self-referential struct which is downright goofy because `MetadataBlob` is already
|
||||
// self-referential. Probably `MemDecoder` should contain an `OwnedSlice`, but that
|
||||
// demands a significant refactoring due to our crate graph.
|
||||
opaque: MemDecoder::new(self.blob(), pos).unwrap(),
|
||||
cdata: self.cdata(),
|
||||
blob: self.blob(),
|
||||
sess: self.sess().or(tcx.map(|tcx| tcx.sess)),
|
||||
|
|
@ -393,7 +412,7 @@ impl<'a, 'tcx> TyDecoder for DecodeContext<'a, 'tcx> {
|
|||
where
|
||||
F: FnOnce(&mut Self) -> R,
|
||||
{
|
||||
let new_opaque = MemDecoder::new(self.opaque.data(), pos);
|
||||
let new_opaque = self.opaque.split_at(pos);
|
||||
let old_opaque = mem::replace(&mut self.opaque, new_opaque);
|
||||
let old_state = mem::replace(&mut self.lazy_state, LazyState::NoNode);
|
||||
let r = f(self);
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for DefPathHashMapRef<'static>
|
|||
fn decode(d: &mut DecodeContext<'a, 'tcx>) -> DefPathHashMapRef<'static> {
|
||||
let len = d.read_usize();
|
||||
let pos = d.position();
|
||||
let o = d.blob().clone().0.slice(|blob| &blob[pos..pos + len]);
|
||||
let o = d.blob().bytes().clone().slice(|blob| &blob[pos..pos + len]);
|
||||
|
||||
// Although we already have the data we need via the `OwnedSlice`, we still need
|
||||
// to advance the `DecodeContext`'s position so it's in a valid state after
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ use std::collections::hash_map::Entry;
|
|||
use crate::infer::MemberConstraint;
|
||||
use crate::mir::ConstraintCategory;
|
||||
use crate::ty::GenericArg;
|
||||
use crate::ty::{self, List, Region, Ty, TyCtxt, TypeFlags, TypeVisitableExt};
|
||||
use crate::ty::{self, List, Ty, TyCtxt, TypeFlags, TypeVisitableExt};
|
||||
|
||||
pub type Canonical<'tcx, V> = ir::Canonical<TyCtxt<'tcx>, V>;
|
||||
pub type CanonicalVarInfo<'tcx> = ir::CanonicalVarInfo<TyCtxt<'tcx>>;
|
||||
|
|
@ -141,7 +141,7 @@ impl<'tcx, R> QueryResponse<'tcx, R> {
|
|||
}
|
||||
|
||||
pub type QueryOutlivesConstraint<'tcx> =
|
||||
(ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>, ConstraintCategory<'tcx>);
|
||||
(ty::OutlivesPredicate<'tcx, GenericArg<'tcx>>, ConstraintCategory<'tcx>);
|
||||
|
||||
TrivialTypeTraversalImpls! {
|
||||
crate::infer::canonical::Certainty,
|
||||
|
|
|
|||
|
|
@ -295,7 +295,7 @@ impl BorrowKind {
|
|||
}
|
||||
|
||||
impl BinOp {
|
||||
pub fn to_hir_binop(self) -> hir::BinOpKind {
|
||||
pub(crate) fn to_hir_binop(self) -> hir::BinOpKind {
|
||||
match self {
|
||||
BinOp::Add => hir::BinOpKind::Add,
|
||||
BinOp::Sub => hir::BinOpKind::Sub,
|
||||
|
|
|
|||
|
|
@ -154,24 +154,25 @@ impl EncodedSourceFileId {
|
|||
|
||||
impl<'sess> OnDiskCache<'sess> {
|
||||
/// Creates a new `OnDiskCache` instance from the serialized data in `data`.
|
||||
pub fn new(sess: &'sess Session, data: Mmap, start_pos: usize) -> Self {
|
||||
debug_assert!(sess.opts.incremental.is_some());
|
||||
///
|
||||
/// The serialized cache has some basic integrity checks, if those checks indicate that the
|
||||
/// on-disk data is corrupt, an error is returned.
|
||||
pub fn new(sess: &'sess Session, data: Mmap, start_pos: usize) -> Result<Self, ()> {
|
||||
assert!(sess.opts.incremental.is_some());
|
||||
|
||||
// Wrap in a scope so we can borrow `data`.
|
||||
let footer: Footer = {
|
||||
let mut decoder = MemDecoder::new(&data, start_pos);
|
||||
let mut decoder = MemDecoder::new(&data, start_pos)?;
|
||||
|
||||
// Decode the *position* of the footer, which can be found in the
|
||||
// last 8 bytes of the file.
|
||||
let footer_pos = decoder
|
||||
.with_position(decoder.len() - IntEncodedWithFixedSize::ENCODED_SIZE, |decoder| {
|
||||
IntEncodedWithFixedSize::decode(decoder).0 as usize
|
||||
});
|
||||
// Decode the file footer, which contains all the lookup tables, etc.
|
||||
decoder.with_position(footer_pos, |decoder| decode_tagged(decoder, TAG_FILE_FOOTER))
|
||||
};
|
||||
// Decode the *position* of the footer, which can be found in the
|
||||
// last 8 bytes of the file.
|
||||
let footer_pos = decoder
|
||||
.with_position(decoder.len() - IntEncodedWithFixedSize::ENCODED_SIZE, |decoder| {
|
||||
IntEncodedWithFixedSize::decode(decoder).0 as usize
|
||||
});
|
||||
// Decode the file footer, which contains all the lookup tables, etc.
|
||||
let footer: Footer =
|
||||
decoder.with_position(footer_pos, |decoder| decode_tagged(decoder, TAG_FILE_FOOTER));
|
||||
|
||||
Self {
|
||||
Ok(Self {
|
||||
serialized_data: RwLock::new(Some(data)),
|
||||
file_index_to_stable_id: footer.file_index_to_stable_id,
|
||||
file_index_to_file: Default::default(),
|
||||
|
|
@ -184,7 +185,7 @@ impl<'sess> OnDiskCache<'sess> {
|
|||
expn_data: footer.expn_data,
|
||||
foreign_expn_data: footer.foreign_expn_data,
|
||||
hygiene_context: Default::default(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn new_empty(source_map: &'sess SourceMap) -> Self {
|
||||
|
|
@ -437,7 +438,8 @@ impl<'sess> OnDiskCache<'sess> {
|
|||
let serialized_data = self.serialized_data.read();
|
||||
let mut decoder = CacheDecoder {
|
||||
tcx,
|
||||
opaque: MemDecoder::new(serialized_data.as_deref().unwrap_or(&[]), pos.to_usize()),
|
||||
opaque: MemDecoder::new(serialized_data.as_deref().unwrap_or(&[]), pos.to_usize())
|
||||
.unwrap(),
|
||||
source_map: self.source_map,
|
||||
file_index_to_file: &self.file_index_to_file,
|
||||
file_index_to_stable_id: &self.file_index_to_stable_id,
|
||||
|
|
@ -558,7 +560,7 @@ impl<'a, 'tcx> TyDecoder for CacheDecoder<'a, 'tcx> {
|
|||
{
|
||||
debug_assert!(pos < self.opaque.len());
|
||||
|
||||
let new_opaque = MemDecoder::new(self.opaque.data(), pos);
|
||||
let new_opaque = self.opaque.split_at(pos);
|
||||
let old_opaque = mem::replace(&mut self.opaque, new_opaque);
|
||||
let r = f(self);
|
||||
self.opaque = old_opaque;
|
||||
|
|
|
|||
|
|
@ -115,18 +115,11 @@ impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for Ty<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E>
|
||||
for ty::Binder<'tcx, ty::PredicateKind<'tcx>>
|
||||
{
|
||||
fn encode(&self, e: &mut E) {
|
||||
self.bound_vars().encode(e);
|
||||
encode_with_shorthand(e, &self.skip_binder(), TyEncoder::predicate_shorthands);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Predicate<'tcx> {
|
||||
fn encode(&self, e: &mut E) {
|
||||
self.kind().encode(e);
|
||||
let kind = self.kind();
|
||||
kind.bound_vars().encode(e);
|
||||
encode_with_shorthand(e, &kind.skip_binder(), TyEncoder::predicate_shorthands);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -233,13 +226,11 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for Ty<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D>
|
||||
for ty::Binder<'tcx, ty::PredicateKind<'tcx>>
|
||||
{
|
||||
fn decode(decoder: &mut D) -> ty::Binder<'tcx, ty::PredicateKind<'tcx>> {
|
||||
impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Predicate<'tcx> {
|
||||
fn decode(decoder: &mut D) -> ty::Predicate<'tcx> {
|
||||
let bound_vars = Decodable::decode(decoder);
|
||||
// Handle shorthands first, if we have a usize > 0x80.
|
||||
ty::Binder::bind_with_vars(
|
||||
let predicate_kind = ty::Binder::bind_with_vars(
|
||||
if decoder.positioned_at_shorthand() {
|
||||
let pos = decoder.read_usize();
|
||||
assert!(pos >= SHORTHAND_OFFSET);
|
||||
|
|
@ -250,13 +241,7 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D>
|
|||
<ty::PredicateKind<'tcx> as Decodable<D>>::decode(decoder)
|
||||
},
|
||||
bound_vars,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Predicate<'tcx> {
|
||||
fn decode(decoder: &mut D) -> ty::Predicate<'tcx> {
|
||||
let predicate_kind = Decodable::decode(decoder);
|
||||
);
|
||||
decoder.interner().mk_predicate(predicate_kind)
|
||||
}
|
||||
}
|
||||
|
|
@ -599,32 +584,3 @@ macro_rules! implement_ty_decoder {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_binder_encode_decode {
|
||||
($($t:ty),+ $(,)?) => {
|
||||
$(
|
||||
impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Binder<'tcx, $t> {
|
||||
fn encode(&self, e: &mut E) {
|
||||
self.bound_vars().encode(e);
|
||||
self.as_ref().skip_binder().encode(e);
|
||||
}
|
||||
}
|
||||
impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Binder<'tcx, $t> {
|
||||
fn decode(decoder: &mut D) -> Self {
|
||||
let bound_vars = Decodable::decode(decoder);
|
||||
ty::Binder::bind_with_vars(Decodable::decode(decoder), bound_vars)
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
impl_binder_encode_decode! {
|
||||
&'tcx ty::List<Ty<'tcx>>,
|
||||
ty::FnSig<'tcx>,
|
||||
ty::Predicate<'tcx>,
|
||||
ty::TraitPredicate<'tcx>,
|
||||
ty::ExistentialPredicate<'tcx>,
|
||||
ty::TraitRef<'tcx>,
|
||||
ty::ExistentialTraitRef<'tcx>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,8 +31,7 @@ use crate::ty::{
|
|||
self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Clauses, Const, ConstData,
|
||||
GenericParamDefKind, ImplPolarity, List, ListWithCachedTypeInfo, ParamConst, ParamTy, Pattern,
|
||||
PatternKind, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, PredicatePolarity,
|
||||
Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid, TypeVisitable,
|
||||
Visibility,
|
||||
Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid, Visibility,
|
||||
};
|
||||
use crate::ty::{GenericArg, GenericArgs, GenericArgsRef};
|
||||
use rustc_ast::{self as ast, attr};
|
||||
|
|
@ -96,9 +95,8 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
type GenericArg = ty::GenericArg<'tcx>;
|
||||
type Term = ty::Term<'tcx>;
|
||||
|
||||
type Binder<T: TypeVisitable<TyCtxt<'tcx>>> = Binder<'tcx, T>;
|
||||
type BoundVars = &'tcx List<ty::BoundVariableKind>;
|
||||
type BoundVar = ty::BoundVariableKind;
|
||||
type BoundVarKinds = &'tcx List<ty::BoundVariableKind>;
|
||||
type BoundVarKind = ty::BoundVariableKind;
|
||||
|
||||
type CanonicalVars = CanonicalVarInfos<'tcx>;
|
||||
type PredefinedOpaques = solve::PredefinedOpaques<'tcx>;
|
||||
|
|
@ -123,7 +121,6 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
type Abi = abi::Abi;
|
||||
|
||||
type Const = ty::Const<'tcx>;
|
||||
type AliasConst = ty::UnevaluatedConst<'tcx>;
|
||||
type PlaceholderConst = ty::PlaceholderConst;
|
||||
type ParamConst = ty::ParamConst;
|
||||
type BoundConst = ty::BoundVar;
|
||||
|
|
@ -138,15 +135,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
|
||||
type ParamEnv = ty::ParamEnv<'tcx>;
|
||||
type Predicate = Predicate<'tcx>;
|
||||
type TraitPredicate = ty::TraitPredicate<'tcx>;
|
||||
type RegionOutlivesPredicate = ty::RegionOutlivesPredicate<'tcx>;
|
||||
type TypeOutlivesPredicate = ty::TypeOutlivesPredicate<'tcx>;
|
||||
type ProjectionPredicate = ty::ProjectionPredicate<'tcx>;
|
||||
type NormalizesTo = ty::NormalizesTo<'tcx>;
|
||||
type SubtypePredicate = ty::SubtypePredicate<'tcx>;
|
||||
|
||||
type CoercePredicate = ty::CoercePredicate<'tcx>;
|
||||
type ClosureKind = ty::ClosureKind;
|
||||
type Clause = Clause<'tcx>;
|
||||
|
||||
type Clauses = ty::Clauses<'tcx>;
|
||||
|
||||
|
|
@ -245,6 +234,10 @@ impl<'tcx> rustc_type_ir::inherent::Abi<TyCtxt<'tcx>> for abi::Abi {
|
|||
}
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::Safety<TyCtxt<'tcx>> for hir::Safety {
|
||||
fn is_safe(self) -> bool {
|
||||
matches!(self, hir::Safety::Safe)
|
||||
}
|
||||
|
||||
fn prefix_str(self) -> &'static str {
|
||||
self.prefix_str()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,6 +51,14 @@ impl<'tcx> rustc_type_ir::inherent::GenericArgs<TyCtxt<'tcx>> for ty::GenericArg
|
|||
fn identity_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::GenericArgsRef<'tcx> {
|
||||
GenericArgs::identity_for_item(tcx, def_id)
|
||||
}
|
||||
|
||||
fn extend_with_error(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: DefId,
|
||||
original_args: &[ty::GenericArg<'tcx>],
|
||||
) -> ty::GenericArgsRef<'tcx> {
|
||||
ty::GenericArgs::extend_with_error(tcx, def_id, original_args)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::IntoKind for GenericArg<'tcx> {
|
||||
|
|
|
|||
|
|
@ -1,15 +1,13 @@
|
|||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::intern::Interned;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_macros::{
|
||||
extension, HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable,
|
||||
};
|
||||
use rustc_macros::{extension, HashStable};
|
||||
use rustc_type_ir as ir;
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use crate::ty::{
|
||||
self, Binder, DebruijnIndex, EarlyBinder, PredicatePolarity, Term, Ty, TyCtxt, TypeFlags,
|
||||
Upcast, UpcastFrom, WithCachedTypeInfo,
|
||||
self, DebruijnIndex, EarlyBinder, PredicatePolarity, Ty, TyCtxt, TypeFlags, Upcast, UpcastFrom,
|
||||
WithCachedTypeInfo,
|
||||
};
|
||||
|
||||
pub type TraitRef<'tcx> = ir::TraitRef<TyCtxt<'tcx>>;
|
||||
|
|
@ -24,6 +22,15 @@ pub type PredicateKind<'tcx> = ir::PredicateKind<TyCtxt<'tcx>>;
|
|||
pub type NormalizesTo<'tcx> = ir::NormalizesTo<TyCtxt<'tcx>>;
|
||||
pub type CoercePredicate<'tcx> = ir::CoercePredicate<TyCtxt<'tcx>>;
|
||||
pub type SubtypePredicate<'tcx> = ir::SubtypePredicate<TyCtxt<'tcx>>;
|
||||
pub type OutlivesPredicate<'tcx, T> = ir::OutlivesPredicate<TyCtxt<'tcx>, T>;
|
||||
pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate<'tcx, ty::Region<'tcx>>;
|
||||
pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate<'tcx, Ty<'tcx>>;
|
||||
pub type PolyTraitPredicate<'tcx> = ty::Binder<'tcx, TraitPredicate<'tcx>>;
|
||||
pub type PolyRegionOutlivesPredicate<'tcx> = ty::Binder<'tcx, RegionOutlivesPredicate<'tcx>>;
|
||||
pub type PolyTypeOutlivesPredicate<'tcx> = ty::Binder<'tcx, TypeOutlivesPredicate<'tcx>>;
|
||||
pub type PolySubtypePredicate<'tcx> = ty::Binder<'tcx, SubtypePredicate<'tcx>>;
|
||||
pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, CoercePredicate<'tcx>>;
|
||||
pub type PolyProjectionPredicate<'tcx> = ty::Binder<'tcx, ProjectionPredicate<'tcx>>;
|
||||
|
||||
/// A statement that can be proven by a trait solver. This includes things that may
|
||||
/// show up in where clauses, such as trait predicates and projection predicates,
|
||||
|
|
@ -155,6 +162,8 @@ pub struct Clause<'tcx>(
|
|||
pub(super) Interned<'tcx, WithCachedTypeInfo<ty::Binder<'tcx, PredicateKind<'tcx>>>>,
|
||||
);
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::Clause<TyCtxt<'tcx>> for Clause<'tcx> {}
|
||||
|
||||
impl<'tcx> Clause<'tcx> {
|
||||
pub fn as_predicate(self) -> Predicate<'tcx> {
|
||||
Predicate(self.0)
|
||||
|
|
@ -231,34 +240,6 @@ impl<'tcx> ExistentialPredicate<'tcx> {
|
|||
|
||||
pub type PolyExistentialPredicate<'tcx> = ty::Binder<'tcx, ExistentialPredicate<'tcx>>;
|
||||
|
||||
impl<'tcx> PolyExistentialPredicate<'tcx> {
|
||||
/// Given an existential predicate like `?Self: PartialEq<u32>` (e.g., derived from `dyn PartialEq<u32>`),
|
||||
/// and a concrete type `self_ty`, returns a full predicate where the existentially quantified variable `?Self`
|
||||
/// has been replaced with `self_ty` (e.g., `self_ty: PartialEq<u32>`, in our example).
|
||||
pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::Clause<'tcx> {
|
||||
match self.skip_binder() {
|
||||
ExistentialPredicate::Trait(tr) => {
|
||||
self.rebind(tr).with_self_ty(tcx, self_ty).upcast(tcx)
|
||||
}
|
||||
ExistentialPredicate::Projection(p) => {
|
||||
self.rebind(p.with_self_ty(tcx, self_ty)).upcast(tcx)
|
||||
}
|
||||
ExistentialPredicate::AutoTrait(did) => {
|
||||
let generics = tcx.generics_of(did);
|
||||
let trait_ref = if generics.own_params.len() == 1 {
|
||||
ty::TraitRef::new(tcx, did, [self_ty])
|
||||
} else {
|
||||
// If this is an ill-formed auto trait, then synthesize
|
||||
// new error args for the missing generics.
|
||||
let err_args = ty::GenericArgs::extend_with_error(tcx, did, &[self_ty.into()]);
|
||||
ty::TraitRef::new(tcx, did, err_args)
|
||||
};
|
||||
self.rebind(trait_ref).upcast(tcx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ty::List<ty::PolyExistentialPredicate<'tcx>> {
|
||||
/// Returns the "principal `DefId`" of this set of existential predicates.
|
||||
///
|
||||
|
|
@ -322,49 +303,9 @@ impl<'tcx> ty::List<ty::PolyExistentialPredicate<'tcx>> {
|
|||
}
|
||||
|
||||
pub type PolyTraitRef<'tcx> = ty::Binder<'tcx, TraitRef<'tcx>>;
|
||||
|
||||
impl<'tcx> PolyTraitRef<'tcx> {
|
||||
pub fn self_ty(&self) -> ty::Binder<'tcx, Ty<'tcx>> {
|
||||
self.map_bound_ref(|tr| tr.self_ty())
|
||||
}
|
||||
|
||||
pub fn def_id(&self) -> DefId {
|
||||
self.skip_binder().def_id
|
||||
}
|
||||
}
|
||||
|
||||
pub type PolyExistentialTraitRef<'tcx> = ty::Binder<'tcx, ExistentialTraitRef<'tcx>>;
|
||||
|
||||
impl<'tcx> PolyExistentialTraitRef<'tcx> {
|
||||
pub fn def_id(&self) -> DefId {
|
||||
self.skip_binder().def_id
|
||||
}
|
||||
|
||||
/// Object types don't have a self type specified. Therefore, when
|
||||
/// we convert the principal trait-ref into a normal trait-ref,
|
||||
/// you must give *some* self type. A common choice is `mk_err()`
|
||||
/// or some placeholder type.
|
||||
pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::PolyTraitRef<'tcx> {
|
||||
self.map_bound(|trait_ref| trait_ref.with_self_ty(tcx, self_ty))
|
||||
}
|
||||
}
|
||||
|
||||
pub type PolyExistentialProjection<'tcx> = ty::Binder<'tcx, ExistentialProjection<'tcx>>;
|
||||
|
||||
impl<'tcx> PolyExistentialProjection<'tcx> {
|
||||
pub fn with_self_ty(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
) -> ty::PolyProjectionPredicate<'tcx> {
|
||||
self.map_bound(|p| p.with_self_ty(tcx, self_ty))
|
||||
}
|
||||
|
||||
pub fn item_def_id(&self) -> DefId {
|
||||
self.skip_binder().def_id
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Clause<'tcx> {
|
||||
/// Performs a instantiation suitable for going from a
|
||||
/// poly-trait-ref to supertraits that must hold if that
|
||||
|
|
@ -471,73 +412,6 @@ impl<'tcx> Clause<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub type PolyTraitPredicate<'tcx> = ty::Binder<'tcx, TraitPredicate<'tcx>>;
|
||||
|
||||
impl<'tcx> PolyTraitPredicate<'tcx> {
|
||||
pub fn def_id(self) -> DefId {
|
||||
// Ok to skip binder since trait `DefId` does not care about regions.
|
||||
self.skip_binder().def_id()
|
||||
}
|
||||
|
||||
pub fn self_ty(self) -> ty::Binder<'tcx, Ty<'tcx>> {
|
||||
self.map_bound(|trait_ref| trait_ref.self_ty())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn polarity(self) -> PredicatePolarity {
|
||||
self.skip_binder().polarity
|
||||
}
|
||||
}
|
||||
|
||||
/// `A: B`
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
|
||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
pub struct OutlivesPredicate<A, B>(pub A, pub B);
|
||||
pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>;
|
||||
pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>;
|
||||
pub type PolyRegionOutlivesPredicate<'tcx> = ty::Binder<'tcx, RegionOutlivesPredicate<'tcx>>;
|
||||
pub type PolyTypeOutlivesPredicate<'tcx> = ty::Binder<'tcx, TypeOutlivesPredicate<'tcx>>;
|
||||
|
||||
pub type PolySubtypePredicate<'tcx> = ty::Binder<'tcx, SubtypePredicate<'tcx>>;
|
||||
|
||||
pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, CoercePredicate<'tcx>>;
|
||||
|
||||
pub type PolyProjectionPredicate<'tcx> = Binder<'tcx, ProjectionPredicate<'tcx>>;
|
||||
|
||||
impl<'tcx> PolyProjectionPredicate<'tcx> {
|
||||
/// Returns the `DefId` of the trait of the associated item being projected.
|
||||
#[inline]
|
||||
pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId {
|
||||
self.skip_binder().projection_term.trait_def_id(tcx)
|
||||
}
|
||||
|
||||
/// Get the [PolyTraitRef] required for this projection to be well formed.
|
||||
/// Note that for generic associated types the predicates of the associated
|
||||
/// type also need to be checked.
|
||||
#[inline]
|
||||
pub fn required_poly_trait_ref(&self, tcx: TyCtxt<'tcx>) -> PolyTraitRef<'tcx> {
|
||||
// Note: unlike with `TraitRef::to_poly_trait_ref()`,
|
||||
// `self.0.trait_ref` is permitted to have escaping regions.
|
||||
// This is because here `self` has a `Binder` and so does our
|
||||
// return value, so we are preserving the number of binding
|
||||
// levels.
|
||||
self.map_bound(|predicate| predicate.projection_term.trait_ref(tcx))
|
||||
}
|
||||
|
||||
pub fn term(&self) -> Binder<'tcx, Term<'tcx>> {
|
||||
self.map_bound(|predicate| predicate.term)
|
||||
}
|
||||
|
||||
/// The `DefId` of the `TraitItem` for the associated type.
|
||||
///
|
||||
/// Note that this is not the `DefId` of the `TraitRef` containing this
|
||||
/// associated type, which is in `tcx.associated_item(projection_def_id()).container`.
|
||||
pub fn projection_def_id(&self) -> DefId {
|
||||
// Ok to skip binder since trait `DefId` does not care about regions.
|
||||
self.skip_binder().projection_term.def_id
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ToPolyTraitRef<'tcx> {
|
||||
fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx>;
|
||||
}
|
||||
|
|
@ -554,8 +428,8 @@ impl<'tcx> UpcastFrom<TyCtxt<'tcx>, PredicateKind<'tcx>> for Predicate<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> UpcastFrom<TyCtxt<'tcx>, Binder<'tcx, PredicateKind<'tcx>>> for Predicate<'tcx> {
|
||||
fn upcast_from(from: Binder<'tcx, PredicateKind<'tcx>>, tcx: TyCtxt<'tcx>) -> Self {
|
||||
impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ty::Binder<'tcx, PredicateKind<'tcx>>> for Predicate<'tcx> {
|
||||
fn upcast_from(from: ty::Binder<'tcx, PredicateKind<'tcx>>, tcx: TyCtxt<'tcx>) -> Self {
|
||||
tcx.mk_predicate(from)
|
||||
}
|
||||
}
|
||||
|
|
@ -566,8 +440,8 @@ impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ClauseKind<'tcx>> for Predicate<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> UpcastFrom<TyCtxt<'tcx>, Binder<'tcx, ClauseKind<'tcx>>> for Predicate<'tcx> {
|
||||
fn upcast_from(from: Binder<'tcx, ClauseKind<'tcx>>, tcx: TyCtxt<'tcx>) -> Self {
|
||||
impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ty::Binder<'tcx, ClauseKind<'tcx>>> for Predicate<'tcx> {
|
||||
fn upcast_from(from: ty::Binder<'tcx, ClauseKind<'tcx>>, tcx: TyCtxt<'tcx>) -> Self {
|
||||
tcx.mk_predicate(from.map_bound(PredicateKind::Clause))
|
||||
}
|
||||
}
|
||||
|
|
@ -580,12 +454,12 @@ impl<'tcx> UpcastFrom<TyCtxt<'tcx>, Clause<'tcx>> for Predicate<'tcx> {
|
|||
|
||||
impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ClauseKind<'tcx>> for Clause<'tcx> {
|
||||
fn upcast_from(from: ClauseKind<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
|
||||
tcx.mk_predicate(Binder::dummy(PredicateKind::Clause(from))).expect_clause()
|
||||
tcx.mk_predicate(ty::Binder::dummy(PredicateKind::Clause(from))).expect_clause()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> UpcastFrom<TyCtxt<'tcx>, Binder<'tcx, ClauseKind<'tcx>>> for Clause<'tcx> {
|
||||
fn upcast_from(from: Binder<'tcx, ClauseKind<'tcx>>, tcx: TyCtxt<'tcx>) -> Self {
|
||||
impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ty::Binder<'tcx, ClauseKind<'tcx>>> for Clause<'tcx> {
|
||||
fn upcast_from(from: ty::Binder<'tcx, ClauseKind<'tcx>>, tcx: TyCtxt<'tcx>) -> Self {
|
||||
tcx.mk_predicate(from.map_bound(|clause| PredicateKind::Clause(clause))).expect_clause()
|
||||
}
|
||||
}
|
||||
|
|
@ -609,22 +483,22 @@ impl<'tcx> UpcastFrom<TyCtxt<'tcx>, TraitRef<'tcx>> for Clause<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> UpcastFrom<TyCtxt<'tcx>, Binder<'tcx, TraitRef<'tcx>>> for Predicate<'tcx> {
|
||||
fn upcast_from(from: Binder<'tcx, TraitRef<'tcx>>, tcx: TyCtxt<'tcx>) -> Self {
|
||||
impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ty::Binder<'tcx, TraitRef<'tcx>>> for Predicate<'tcx> {
|
||||
fn upcast_from(from: ty::Binder<'tcx, TraitRef<'tcx>>, tcx: TyCtxt<'tcx>) -> Self {
|
||||
let pred: PolyTraitPredicate<'tcx> = from.upcast(tcx);
|
||||
pred.upcast(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> UpcastFrom<TyCtxt<'tcx>, Binder<'tcx, TraitRef<'tcx>>> for Clause<'tcx> {
|
||||
fn upcast_from(from: Binder<'tcx, TraitRef<'tcx>>, tcx: TyCtxt<'tcx>) -> Self {
|
||||
impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ty::Binder<'tcx, TraitRef<'tcx>>> for Clause<'tcx> {
|
||||
fn upcast_from(from: ty::Binder<'tcx, TraitRef<'tcx>>, tcx: TyCtxt<'tcx>) -> Self {
|
||||
let pred: PolyTraitPredicate<'tcx> = from.upcast(tcx);
|
||||
pred.upcast(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> UpcastFrom<TyCtxt<'tcx>, Binder<'tcx, TraitRef<'tcx>>> for PolyTraitPredicate<'tcx> {
|
||||
fn upcast_from(from: Binder<'tcx, TraitRef<'tcx>>, _tcx: TyCtxt<'tcx>) -> Self {
|
||||
impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ty::Binder<'tcx, TraitRef<'tcx>>> for PolyTraitPredicate<'tcx> {
|
||||
fn upcast_from(from: ty::Binder<'tcx, TraitRef<'tcx>>, _tcx: TyCtxt<'tcx>) -> Self {
|
||||
from.map_bound(|trait_ref| TraitPredicate {
|
||||
trait_ref,
|
||||
polarity: PredicatePolarity::Positive,
|
||||
|
|
@ -664,10 +538,8 @@ impl<'tcx> UpcastFrom<TyCtxt<'tcx>, PolyRegionOutlivesPredicate<'tcx>> for Predi
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> UpcastFrom<TyCtxt<'tcx>, OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>
|
||||
for Predicate<'tcx>
|
||||
{
|
||||
fn upcast_from(from: OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>, tcx: TyCtxt<'tcx>) -> Self {
|
||||
impl<'tcx> UpcastFrom<TyCtxt<'tcx>, TypeOutlivesPredicate<'tcx>> for Predicate<'tcx> {
|
||||
fn upcast_from(from: TypeOutlivesPredicate<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
|
||||
ty::Binder::dummy(PredicateKind::Clause(ClauseKind::TypeOutlives(from))).upcast(tcx)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2860,10 +2860,9 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T, U, P: PrettyPrinter<'tcx>> Print<'tcx, P> for ty::OutlivesPredicate<T, U>
|
||||
impl<'tcx, T, P: PrettyPrinter<'tcx>> Print<'tcx, P> for ty::OutlivesPredicate<'tcx, T>
|
||||
where
|
||||
T: Print<'tcx, P>,
|
||||
U: Print<'tcx, P>,
|
||||
{
|
||||
fn print(&self, cx: &mut P) -> Result<(), PrintError> {
|
||||
define_scoped_cx!(cx);
|
||||
|
|
@ -2934,12 +2933,13 @@ impl<'tcx> ty::TraitRef<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
#[extension(pub trait PrintPolyTraitRefExt<'tcx>)]
|
||||
impl<'tcx> ty::Binder<'tcx, ty::TraitRef<'tcx>> {
|
||||
pub fn print_only_trait_path(self) -> ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>> {
|
||||
fn print_only_trait_path(self) -> ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>> {
|
||||
self.map_bound(|tr| tr.print_only_trait_path())
|
||||
}
|
||||
|
||||
pub fn print_trait_sugared(self) -> ty::Binder<'tcx, TraitRefPrintSugared<'tcx>> {
|
||||
fn print_trait_sugared(self) -> ty::Binder<'tcx, TraitRefPrintSugared<'tcx>> {
|
||||
self.map_bound(|tr| tr.print_trait_sugared())
|
||||
}
|
||||
}
|
||||
|
|
@ -2960,8 +2960,9 @@ impl<'tcx> ty::TraitPredicate<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
#[extension(pub trait PrintPolyTraitPredicateExt<'tcx>)]
|
||||
impl<'tcx> ty::PolyTraitPredicate<'tcx> {
|
||||
pub fn print_modifiers_and_trait_path(
|
||||
fn print_modifiers_and_trait_path(
|
||||
self,
|
||||
) -> ty::Binder<'tcx, TraitPredPrintModifiersAndPath<'tcx>> {
|
||||
self.map_bound(TraitPredPrintModifiersAndPath)
|
||||
|
|
@ -3014,21 +3015,7 @@ forward_display_to_print! {
|
|||
ty::Region<'tcx>,
|
||||
Ty<'tcx>,
|
||||
&'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
||||
ty::Const<'tcx>,
|
||||
|
||||
// HACK(eddyb) these are exhaustive instead of generic,
|
||||
// because `for<'tcx>` isn't possible yet.
|
||||
ty::PolyExistentialProjection<'tcx>,
|
||||
ty::PolyExistentialTraitRef<'tcx>,
|
||||
ty::Binder<'tcx, ty::TraitRef<'tcx>>,
|
||||
ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
|
||||
ty::Binder<'tcx, TraitRefPrintSugared<'tcx>>,
|
||||
ty::Binder<'tcx, ty::FnSig<'tcx>>,
|
||||
ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
|
||||
ty::Binder<'tcx, TraitPredPrintModifiersAndPath<'tcx>>,
|
||||
ty::Binder<'tcx, ty::ProjectionPredicate<'tcx>>,
|
||||
ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>,
|
||||
ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>
|
||||
ty::Const<'tcx>
|
||||
}
|
||||
|
||||
define_print! {
|
||||
|
|
|
|||
|
|
@ -384,6 +384,10 @@ impl<'tcx> rustc_type_ir::inherent::BoundVarLike<TyCtxt<'tcx>> for BoundRegion {
|
|||
fn var(self) -> BoundVar {
|
||||
self.var
|
||||
}
|
||||
|
||||
fn assert_eq(self, var: ty::BoundVariableKind) {
|
||||
assert_eq!(self.kind, var.expect_region())
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for BoundRegion {
|
||||
|
|
|
|||
|
|
@ -387,38 +387,6 @@ impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for ty::AdtDef<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T: TypeFoldable<TyCtxt<'tcx>>> TypeFoldable<TyCtxt<'tcx>> for ty::Binder<'tcx, T> {
|
||||
fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
|
||||
self,
|
||||
folder: &mut F,
|
||||
) -> Result<Self, F::Error> {
|
||||
folder.try_fold_binder(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T: TypeVisitable<TyCtxt<'tcx>>> TypeVisitable<TyCtxt<'tcx>> for ty::Binder<'tcx, T> {
|
||||
fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result {
|
||||
visitor.visit_binder(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T: TypeFoldable<TyCtxt<'tcx>>> TypeSuperFoldable<TyCtxt<'tcx>> for ty::Binder<'tcx, T> {
|
||||
fn try_super_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
|
||||
self,
|
||||
folder: &mut F,
|
||||
) -> Result<Self, F::Error> {
|
||||
self.try_map_bound(|ty| ty.try_fold_with(folder))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T: TypeVisitable<TyCtxt<'tcx>>> TypeSuperVisitable<TyCtxt<'tcx>>
|
||||
for ty::Binder<'tcx, T>
|
||||
{
|
||||
fn super_visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result {
|
||||
self.as_ref().skip_binder().visit_with(visitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> {
|
||||
fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
|
||||
self,
|
||||
|
|
|
|||
|
|
@ -3,17 +3,16 @@
|
|||
#![allow(rustc::usage_of_ty_tykind)]
|
||||
|
||||
use crate::infer::canonical::Canonical;
|
||||
use crate::ty::visit::ValidateBoundVars;
|
||||
use crate::ty::InferTy::*;
|
||||
use crate::ty::{
|
||||
self, AdtDef, BoundRegionKind, Discr, Region, Ty, TyCtxt, TypeFlags, TypeSuperVisitable,
|
||||
TypeVisitable, TypeVisitableExt, TypeVisitor,
|
||||
TypeVisitable, TypeVisitor,
|
||||
};
|
||||
use crate::ty::{GenericArg, GenericArgs, GenericArgsRef};
|
||||
use crate::ty::{List, ParamEnv};
|
||||
use hir::def::{CtorKind, DefKind};
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_errors::{DiagArgValue, ErrorGuaranteed, IntoDiagArg, MultiSpan};
|
||||
use rustc_errors::{ErrorGuaranteed, MultiSpan};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::LangItem;
|
||||
|
|
@ -21,11 +20,11 @@ use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable};
|
|||
use rustc_span::symbol::{sym, Symbol};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT};
|
||||
use rustc_target::spec::abi::{self, Abi};
|
||||
use rustc_target::spec::abi;
|
||||
use std::assert_matches::debug_assert_matches;
|
||||
use std::borrow::Cow;
|
||||
use std::iter;
|
||||
use std::ops::{ControlFlow, Deref, Range};
|
||||
use std::ops::{ControlFlow, Range};
|
||||
use ty::util::IntTypeExt;
|
||||
|
||||
use rustc_type_ir::TyKind::*;
|
||||
|
|
@ -40,6 +39,7 @@ pub type TyKind<'tcx> = ir::TyKind<TyCtxt<'tcx>>;
|
|||
pub type TypeAndMut<'tcx> = ir::TypeAndMut<TyCtxt<'tcx>>;
|
||||
pub type AliasTy<'tcx> = ir::AliasTy<TyCtxt<'tcx>>;
|
||||
pub type FnSig<'tcx> = ir::FnSig<TyCtxt<'tcx>>;
|
||||
pub type Binder<'tcx, T> = ir::Binder<TyCtxt<'tcx>, T>;
|
||||
|
||||
pub trait Article {
|
||||
fn article(&self) -> &'static str;
|
||||
|
|
@ -373,7 +373,7 @@ impl<'tcx> CoroutineClosureArgs<'tcx> {
|
|||
self.split().signature_parts_ty
|
||||
}
|
||||
|
||||
pub fn coroutine_closure_sig(self) -> ty::Binder<'tcx, CoroutineClosureSignature<'tcx>> {
|
||||
pub fn coroutine_closure_sig(self) -> Binder<'tcx, CoroutineClosureSignature<'tcx>> {
|
||||
let interior = self.coroutine_witness_ty();
|
||||
let ty::FnPtr(sig) = self.signature_parts_ty().kind() else { bug!() };
|
||||
sig.map_bound(|sig| {
|
||||
|
|
@ -401,6 +401,45 @@ impl<'tcx> CoroutineClosureArgs<'tcx> {
|
|||
pub fn coroutine_witness_ty(self) -> Ty<'tcx> {
|
||||
self.split().coroutine_witness_ty
|
||||
}
|
||||
|
||||
pub fn has_self_borrows(&self) -> bool {
|
||||
match self.coroutine_captures_by_ref_ty().kind() {
|
||||
ty::FnPtr(sig) => sig
|
||||
.skip_binder()
|
||||
.visit_with(&mut HasRegionsBoundAt { binder: ty::INNERMOST })
|
||||
.is_break(),
|
||||
ty::Error(_) => true,
|
||||
_ => bug!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Unlike `has_escaping_bound_vars` or `outermost_exclusive_binder`, this will
|
||||
/// detect only regions bound *at* the debruijn index.
|
||||
struct HasRegionsBoundAt {
|
||||
binder: ty::DebruijnIndex,
|
||||
}
|
||||
// FIXME: Could be optimized to not walk into components with no escaping bound vars.
|
||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasRegionsBoundAt {
|
||||
type Result = ControlFlow<()>;
|
||||
fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
|
||||
&mut self,
|
||||
t: &ty::Binder<'tcx, T>,
|
||||
) -> Self::Result {
|
||||
self.binder.shift_in(1);
|
||||
t.super_visit_with(self)?;
|
||||
self.binder.shift_out(1);
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
fn visit_region(&mut self, r: ty::Region<'tcx>) -> Self::Result {
|
||||
if let ty::ReBound(binder, _) = *r
|
||||
&& self.binder == binder
|
||||
{
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)]
|
||||
|
|
@ -898,203 +937,6 @@ impl BoundVariableKind {
|
|||
}
|
||||
}
|
||||
|
||||
/// Binder is a binder for higher-ranked lifetimes or types. It is part of the
|
||||
/// compiler's representation for things like `for<'a> Fn(&'a isize)`
|
||||
/// (which would be represented by the type `PolyTraitRef ==
|
||||
/// Binder<'tcx, TraitRef>`). Note that when we instantiate,
|
||||
/// erase, or otherwise "discharge" these bound vars, we change the
|
||||
/// type from `Binder<'tcx, T>` to just `T` (see
|
||||
/// e.g., `liberate_late_bound_regions`).
|
||||
///
|
||||
/// `Decodable` and `Encodable` are implemented for `Binder<T>` using the `impl_binder_encode_decode!` macro.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
#[derive(HashStable, Lift)]
|
||||
pub struct Binder<'tcx, T> {
|
||||
value: T,
|
||||
bound_vars: &'tcx List<BoundVariableKind>,
|
||||
}
|
||||
|
||||
impl<'tcx, T> Binder<'tcx, T>
|
||||
where
|
||||
T: TypeVisitable<TyCtxt<'tcx>>,
|
||||
{
|
||||
/// Wraps `value` in a binder, asserting that `value` does not
|
||||
/// contain any bound vars that would be bound by the
|
||||
/// binder. This is commonly used to 'inject' a value T into a
|
||||
/// different binding level.
|
||||
#[track_caller]
|
||||
pub fn dummy(value: T) -> Binder<'tcx, T> {
|
||||
assert!(
|
||||
!value.has_escaping_bound_vars(),
|
||||
"`{value:?}` has escaping bound vars, so it cannot be wrapped in a dummy binder."
|
||||
);
|
||||
Binder { value, bound_vars: ty::List::empty() }
|
||||
}
|
||||
|
||||
pub fn bind_with_vars(value: T, bound_vars: &'tcx List<BoundVariableKind>) -> Binder<'tcx, T> {
|
||||
if cfg!(debug_assertions) {
|
||||
let mut validator = ValidateBoundVars::new(bound_vars);
|
||||
value.visit_with(&mut validator);
|
||||
}
|
||||
Binder { value, bound_vars }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T> rustc_type_ir::inherent::BoundVars<TyCtxt<'tcx>> for ty::Binder<'tcx, T> {
|
||||
fn bound_vars(&self) -> &'tcx List<ty::BoundVariableKind> {
|
||||
self.bound_vars
|
||||
}
|
||||
|
||||
fn has_no_bound_vars(&self) -> bool {
|
||||
self.bound_vars.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T> Binder<'tcx, T> {
|
||||
/// Skips the binder and returns the "bound" value. This is a
|
||||
/// risky thing to do because it's easy to get confused about
|
||||
/// De Bruijn indices and the like. It is usually better to
|
||||
/// discharge the binder using `no_bound_vars` or
|
||||
/// `instantiate_bound_regions` or something like
|
||||
/// that. `skip_binder` is only valid when you are either
|
||||
/// extracting data that has nothing to do with bound vars, you
|
||||
/// are doing some sort of test that does not involve bound
|
||||
/// regions, or you are being very careful about your depth
|
||||
/// accounting.
|
||||
///
|
||||
/// Some examples where `skip_binder` is reasonable:
|
||||
///
|
||||
/// - extracting the `DefId` from a PolyTraitRef;
|
||||
/// - comparing the self type of a PolyTraitRef to see if it is equal to
|
||||
/// a type parameter `X`, since the type `X` does not reference any regions
|
||||
pub fn skip_binder(self) -> T {
|
||||
self.value
|
||||
}
|
||||
|
||||
pub fn bound_vars(&self) -> &'tcx List<BoundVariableKind> {
|
||||
self.bound_vars
|
||||
}
|
||||
|
||||
pub fn as_ref(&self) -> Binder<'tcx, &T> {
|
||||
Binder { value: &self.value, bound_vars: self.bound_vars }
|
||||
}
|
||||
|
||||
pub fn as_deref(&self) -> Binder<'tcx, &T::Target>
|
||||
where
|
||||
T: Deref,
|
||||
{
|
||||
Binder { value: &self.value, bound_vars: self.bound_vars }
|
||||
}
|
||||
|
||||
pub fn map_bound_ref<F, U: TypeVisitable<TyCtxt<'tcx>>>(&self, f: F) -> Binder<'tcx, U>
|
||||
where
|
||||
F: FnOnce(&T) -> U,
|
||||
{
|
||||
self.as_ref().map_bound(f)
|
||||
}
|
||||
|
||||
pub fn map_bound<F, U: TypeVisitable<TyCtxt<'tcx>>>(self, f: F) -> Binder<'tcx, U>
|
||||
where
|
||||
F: FnOnce(T) -> U,
|
||||
{
|
||||
let Binder { value, bound_vars } = self;
|
||||
let value = f(value);
|
||||
if cfg!(debug_assertions) {
|
||||
let mut validator = ValidateBoundVars::new(bound_vars);
|
||||
value.visit_with(&mut validator);
|
||||
}
|
||||
Binder { value, bound_vars }
|
||||
}
|
||||
|
||||
pub fn try_map_bound<F, U: TypeVisitable<TyCtxt<'tcx>>, E>(
|
||||
self,
|
||||
f: F,
|
||||
) -> Result<Binder<'tcx, U>, E>
|
||||
where
|
||||
F: FnOnce(T) -> Result<U, E>,
|
||||
{
|
||||
let Binder { value, bound_vars } = self;
|
||||
let value = f(value)?;
|
||||
if cfg!(debug_assertions) {
|
||||
let mut validator = ValidateBoundVars::new(bound_vars);
|
||||
value.visit_with(&mut validator);
|
||||
}
|
||||
Ok(Binder { value, bound_vars })
|
||||
}
|
||||
|
||||
/// Wraps a `value` in a binder, using the same bound variables as the
|
||||
/// current `Binder`. This should not be used if the new value *changes*
|
||||
/// the bound variables. Note: the (old or new) value itself does not
|
||||
/// necessarily need to *name* all the bound variables.
|
||||
///
|
||||
/// This currently doesn't do anything different than `bind`, because we
|
||||
/// don't actually track bound vars. However, semantically, it is different
|
||||
/// because bound vars aren't allowed to change here, whereas they are
|
||||
/// in `bind`. This may be (debug) asserted in the future.
|
||||
pub fn rebind<U>(&self, value: U) -> Binder<'tcx, U>
|
||||
where
|
||||
U: TypeVisitable<TyCtxt<'tcx>>,
|
||||
{
|
||||
Binder::bind_with_vars(value, self.bound_vars)
|
||||
}
|
||||
|
||||
/// Unwraps and returns the value within, but only if it contains
|
||||
/// no bound vars at all. (In other words, if this binder --
|
||||
/// and indeed any enclosing binder -- doesn't bind anything at
|
||||
/// all.) Otherwise, returns `None`.
|
||||
///
|
||||
/// (One could imagine having a method that just unwraps a single
|
||||
/// binder, but permits late-bound vars bound by enclosing
|
||||
/// binders, but that would require adjusting the debruijn
|
||||
/// indices, and given the shallow binding structure we often use,
|
||||
/// would not be that useful.)
|
||||
pub fn no_bound_vars(self) -> Option<T>
|
||||
where
|
||||
T: TypeVisitable<TyCtxt<'tcx>>,
|
||||
{
|
||||
// `self.value` is equivalent to `self.skip_binder()`
|
||||
if self.value.has_escaping_bound_vars() { None } else { Some(self.skip_binder()) }
|
||||
}
|
||||
|
||||
/// Splits the contents into two things that share the same binder
|
||||
/// level as the original, returning two distinct binders.
|
||||
///
|
||||
/// `f` should consider bound regions at depth 1 to be free, and
|
||||
/// anything it produces with bound regions at depth 1 will be
|
||||
/// bound in the resulting return values.
|
||||
pub fn split<U, V, F>(self, f: F) -> (Binder<'tcx, U>, Binder<'tcx, V>)
|
||||
where
|
||||
F: FnOnce(T) -> (U, V),
|
||||
{
|
||||
let Binder { value, bound_vars } = self;
|
||||
let (u, v) = f(value);
|
||||
(Binder { value: u, bound_vars }, Binder { value: v, bound_vars })
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T> Binder<'tcx, Option<T>> {
|
||||
pub fn transpose(self) -> Option<Binder<'tcx, T>> {
|
||||
let Binder { value, bound_vars } = self;
|
||||
value.map(|value| Binder { value, bound_vars })
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T: IntoIterator> Binder<'tcx, T> {
|
||||
pub fn iter(self) -> impl Iterator<Item = ty::Binder<'tcx, T::Item>> {
|
||||
let Binder { value, bound_vars } = self;
|
||||
value.into_iter().map(|value| Binder { value, bound_vars })
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T> IntoDiagArg for Binder<'tcx, T>
|
||||
where
|
||||
T: IntoDiagArg,
|
||||
{
|
||||
fn into_diag_arg(self) -> DiagArgValue {
|
||||
self.value.into_diag_arg()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)]
|
||||
pub struct GenSig<'tcx> {
|
||||
pub resume_ty: Ty<'tcx>,
|
||||
|
|
@ -1103,48 +945,6 @@ pub struct GenSig<'tcx> {
|
|||
}
|
||||
|
||||
pub type PolyFnSig<'tcx> = Binder<'tcx, FnSig<'tcx>>;
|
||||
|
||||
impl<'tcx> PolyFnSig<'tcx> {
|
||||
#[inline]
|
||||
pub fn inputs(&self) -> Binder<'tcx, &'tcx [Ty<'tcx>]> {
|
||||
self.map_bound_ref(|fn_sig| fn_sig.inputs())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
pub fn input(&self, index: usize) -> ty::Binder<'tcx, Ty<'tcx>> {
|
||||
self.map_bound_ref(|fn_sig| fn_sig.inputs()[index])
|
||||
}
|
||||
|
||||
pub fn inputs_and_output(&self) -> ty::Binder<'tcx, &'tcx List<Ty<'tcx>>> {
|
||||
self.map_bound_ref(|fn_sig| fn_sig.inputs_and_output)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn output(&self) -> ty::Binder<'tcx, Ty<'tcx>> {
|
||||
self.map_bound_ref(|fn_sig| fn_sig.output())
|
||||
}
|
||||
|
||||
pub fn c_variadic(&self) -> bool {
|
||||
self.skip_binder().c_variadic
|
||||
}
|
||||
|
||||
pub fn safety(&self) -> hir::Safety {
|
||||
self.skip_binder().safety
|
||||
}
|
||||
|
||||
pub fn abi(&self) -> abi::Abi {
|
||||
self.skip_binder().abi
|
||||
}
|
||||
|
||||
pub fn is_fn_trait_compatible(&self) -> bool {
|
||||
matches!(
|
||||
self.skip_binder(),
|
||||
ty::FnSig { safety: rustc_hir::Safety::Safe, abi: Abi::Rust, c_variadic: false, .. }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub type CanonicalPolyFnSig<'tcx> = Canonical<'tcx, Binder<'tcx, FnSig<'tcx>>>;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
|
||||
|
|
@ -1203,6 +1003,10 @@ impl<'tcx> rustc_type_ir::inherent::BoundVarLike<TyCtxt<'tcx>> for BoundTy {
|
|||
fn var(self) -> BoundVar {
|
||||
self.var
|
||||
}
|
||||
|
||||
fn assert_eq(self, var: ty::BoundVariableKind) {
|
||||
assert_eq!(self.kind, var.expect_ty())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
|
||||
|
|
@ -2001,7 +1805,7 @@ impl<'tcx> Ty<'tcx> {
|
|||
FnPtr(f) => *f,
|
||||
Error(_) => {
|
||||
// ignore errors (#54954)
|
||||
ty::Binder::dummy(ty::FnSig {
|
||||
Binder::dummy(ty::FnSig {
|
||||
inputs_and_output: ty::List::empty(),
|
||||
c_variadic: false,
|
||||
safety: hir::Safety::Safe,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use crate::ty::{self, Binder, Ty, TyCtxt, TypeFlags};
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::sso::SsoHashSet;
|
||||
use rustc_type_ir::fold::TypeFoldable;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
|
|
@ -145,103 +144,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct ValidateBoundVars<'tcx> {
|
||||
bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
|
||||
binder_index: ty::DebruijnIndex,
|
||||
// We may encounter the same variable at different levels of binding, so
|
||||
// this can't just be `Ty`
|
||||
visited: SsoHashSet<(ty::DebruijnIndex, Ty<'tcx>)>,
|
||||
}
|
||||
|
||||
impl<'tcx> ValidateBoundVars<'tcx> {
|
||||
pub fn new(bound_vars: &'tcx ty::List<ty::BoundVariableKind>) -> Self {
|
||||
ValidateBoundVars {
|
||||
bound_vars,
|
||||
binder_index: ty::INNERMOST,
|
||||
visited: SsoHashSet::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ValidateBoundVars<'tcx> {
|
||||
type Result = ControlFlow<()>;
|
||||
|
||||
fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
|
||||
&mut self,
|
||||
t: &Binder<'tcx, T>,
|
||||
) -> Self::Result {
|
||||
self.binder_index.shift_in(1);
|
||||
let result = t.super_visit_with(self);
|
||||
self.binder_index.shift_out(1);
|
||||
result
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
|
||||
if t.outer_exclusive_binder() < self.binder_index
|
||||
|| !self.visited.insert((self.binder_index, t))
|
||||
{
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
match *t.kind() {
|
||||
ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => {
|
||||
if self.bound_vars.len() <= bound_ty.var.as_usize() {
|
||||
bug!("Not enough bound vars: {:?} not found in {:?}", t, self.bound_vars);
|
||||
}
|
||||
let list_var = self.bound_vars[bound_ty.var.as_usize()];
|
||||
match list_var {
|
||||
ty::BoundVariableKind::Ty(kind) => {
|
||||
if kind != bound_ty.kind {
|
||||
bug!(
|
||||
"Mismatched type kinds: {:?} doesn't var in list {:?}",
|
||||
bound_ty.kind,
|
||||
list_var
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
bug!("Mismatched bound variable kinds! Expected type, found {:?}", list_var)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => (),
|
||||
};
|
||||
|
||||
t.super_visit_with(self)
|
||||
}
|
||||
|
||||
fn visit_region(&mut self, r: ty::Region<'tcx>) -> Self::Result {
|
||||
match *r {
|
||||
ty::ReBound(index, br) if index == self.binder_index => {
|
||||
if self.bound_vars.len() <= br.var.as_usize() {
|
||||
bug!("Not enough bound vars: {:?} not found in {:?}", br, self.bound_vars);
|
||||
}
|
||||
let list_var = self.bound_vars[br.var.as_usize()];
|
||||
match list_var {
|
||||
ty::BoundVariableKind::Region(kind) => {
|
||||
if kind != br.kind {
|
||||
bug!(
|
||||
"Mismatched region kinds: {:?} doesn't match var ({:?}) in list ({:?})",
|
||||
br.kind,
|
||||
list_var,
|
||||
self.bound_vars
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => bug!(
|
||||
"Mismatched bound variable kinds! Expected region, found {:?}",
|
||||
list_var
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
_ => (),
|
||||
};
|
||||
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Collects all the late-bound regions at the innermost binding level
|
||||
/// into a hash set.
|
||||
struct LateBoundRegionsCollector {
|
||||
|
|
|
|||
|
|
@ -217,10 +217,9 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I>
|
|||
self.infcx.interner()
|
||||
}
|
||||
|
||||
fn fold_binder<T>(&mut self, t: I::Binder<T>) -> I::Binder<T>
|
||||
fn fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T>
|
||||
where
|
||||
T: TypeFoldable<I>,
|
||||
I::Binder<T>: TypeSuperFoldable<I>,
|
||||
{
|
||||
self.binder_index.shift_in(1);
|
||||
let t = t.super_fold_with(self);
|
||||
|
|
@ -455,10 +454,9 @@ impl<I: Interner> TypeFolder<I> for RegionsToStatic<I> {
|
|||
self.interner
|
||||
}
|
||||
|
||||
fn fold_binder<T>(&mut self, t: I::Binder<T>) -> I::Binder<T>
|
||||
fn fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T>
|
||||
where
|
||||
T: TypeFoldable<I>,
|
||||
I::Binder<T>: TypeSuperFoldable<I>,
|
||||
{
|
||||
self.binder.shift_in(1);
|
||||
let t = t.super_fold_with(self);
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ use ast::Label;
|
|||
use rustc_ast as ast;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, Delimiter, TokenKind};
|
||||
use rustc_ast::util::classify;
|
||||
use rustc_ast::util::classify::{self, TrailingBrace};
|
||||
use rustc_ast::{AttrStyle, AttrVec, LocalKind, MacCall, MacCallStmt, MacStmtStyle};
|
||||
use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, HasAttrs, Local, Recovered, Stmt};
|
||||
use rustc_ast::{StmtKind, DUMMY_NODE_ID};
|
||||
|
|
@ -407,18 +407,24 @@ impl<'a> Parser<'a> {
|
|||
|
||||
fn check_let_else_init_trailing_brace(&self, init: &ast::Expr) {
|
||||
if let Some(trailing) = classify::expr_trailing_brace(init) {
|
||||
let sugg = match &trailing.kind {
|
||||
ExprKind::MacCall(mac) => errors::WrapInParentheses::MacroArgs {
|
||||
left: mac.args.dspan.open,
|
||||
right: mac.args.dspan.close,
|
||||
},
|
||||
_ => errors::WrapInParentheses::Expression {
|
||||
left: trailing.span.shrink_to_lo(),
|
||||
right: trailing.span.shrink_to_hi(),
|
||||
},
|
||||
let (span, sugg) = match trailing {
|
||||
TrailingBrace::MacCall(mac) => (
|
||||
mac.span(),
|
||||
errors::WrapInParentheses::MacroArgs {
|
||||
left: mac.args.dspan.open,
|
||||
right: mac.args.dspan.close,
|
||||
},
|
||||
),
|
||||
TrailingBrace::Expr(expr) => (
|
||||
expr.span,
|
||||
errors::WrapInParentheses::Expression {
|
||||
left: expr.span.shrink_to_lo(),
|
||||
right: expr.span.shrink_to_hi(),
|
||||
},
|
||||
),
|
||||
};
|
||||
self.dcx().emit_err(errors::InvalidCurlyInLetElse {
|
||||
span: trailing.span.with_lo(trailing.span.hi() - BytePos(1)),
|
||||
span: span.with_lo(span.hi() - BytePos(1)),
|
||||
sugg,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -425,10 +425,11 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
|
|||
&& let ItemKind::Impl(impl_ref) =
|
||||
self.tcx.hir().expect_item(local_impl_id).kind
|
||||
{
|
||||
if self.tcx.visibility(trait_id).is_public()
|
||||
&& matches!(trait_item.kind, hir::TraitItemKind::Fn(..))
|
||||
if matches!(trait_item.kind, hir::TraitItemKind::Fn(..))
|
||||
&& !ty_ref_to_pub_struct(self.tcx, impl_ref.self_ty)
|
||||
{
|
||||
// skip methods of private ty,
|
||||
// they would be solved in `solve_rest_impl_items`
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -485,32 +486,46 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
|
|||
|
||||
fn solve_rest_impl_items(&mut self, mut unsolved_impl_items: Vec<(hir::ItemId, LocalDefId)>) {
|
||||
let mut ready;
|
||||
(ready, unsolved_impl_items) = unsolved_impl_items
|
||||
.into_iter()
|
||||
.partition(|&(impl_id, _)| self.impl_item_with_used_self(impl_id));
|
||||
(ready, unsolved_impl_items) =
|
||||
unsolved_impl_items.into_iter().partition(|&(impl_id, impl_item_id)| {
|
||||
self.impl_item_with_used_self(impl_id, impl_item_id)
|
||||
});
|
||||
|
||||
while !ready.is_empty() {
|
||||
self.worklist =
|
||||
ready.into_iter().map(|(_, id)| (id, ComesFromAllowExpect::No)).collect();
|
||||
self.mark_live_symbols();
|
||||
|
||||
(ready, unsolved_impl_items) = unsolved_impl_items
|
||||
.into_iter()
|
||||
.partition(|&(impl_id, _)| self.impl_item_with_used_self(impl_id));
|
||||
(ready, unsolved_impl_items) =
|
||||
unsolved_impl_items.into_iter().partition(|&(impl_id, impl_item_id)| {
|
||||
self.impl_item_with_used_self(impl_id, impl_item_id)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn impl_item_with_used_self(&mut self, impl_id: hir::ItemId) -> bool {
|
||||
fn impl_item_with_used_self(&mut self, impl_id: hir::ItemId, impl_item_id: LocalDefId) -> bool {
|
||||
if let TyKind::Path(hir::QPath::Resolved(_, path)) =
|
||||
self.tcx.hir().item(impl_id).expect_impl().self_ty.kind
|
||||
&& let Res::Def(def_kind, def_id) = path.res
|
||||
&& let Some(local_def_id) = def_id.as_local()
|
||||
&& matches!(def_kind, DefKind::Struct | DefKind::Enum | DefKind::Union)
|
||||
{
|
||||
self.live_symbols.contains(&local_def_id)
|
||||
} else {
|
||||
false
|
||||
if self.tcx.visibility(impl_item_id).is_public() {
|
||||
// for the public method, we don't know the trait item is used or not,
|
||||
// so we mark the method live if the self is used
|
||||
return self.live_symbols.contains(&local_def_id);
|
||||
}
|
||||
|
||||
if let Some(trait_item_id) = self.tcx.associated_item(impl_item_id).trait_item_def_id
|
||||
&& let Some(local_id) = trait_item_id.as_local()
|
||||
{
|
||||
// for the private method, we can know the trait item is used or not,
|
||||
// so we mark the method live if the self is used and the trait item is used
|
||||
return self.live_symbols.contains(&local_id)
|
||||
&& self.live_symbols.contains(&local_def_id);
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -745,20 +760,22 @@ fn check_item<'tcx>(
|
|||
matches!(fn_sig.decl.implicit_self, hir::ImplicitSelfKind::None);
|
||||
}
|
||||
|
||||
// for impl trait blocks, mark associate functions live if the trait is public
|
||||
// for trait impl blocks,
|
||||
// mark the method live if the self_ty is public,
|
||||
// or the method is public and may construct self
|
||||
if of_trait
|
||||
&& (!matches!(tcx.def_kind(local_def_id), DefKind::AssocFn)
|
||||
|| tcx.visibility(local_def_id).is_public()
|
||||
&& (ty_is_pub || may_construct_self))
|
||||
{
|
||||
worklist.push((local_def_id, ComesFromAllowExpect::No));
|
||||
} else if of_trait && tcx.visibility(local_def_id).is_public() {
|
||||
// pub method && private ty & methods not construct self
|
||||
unsolved_impl_items.push((id, local_def_id));
|
||||
} else if let Some(comes_from_allow) =
|
||||
has_allow_dead_code_or_lang_attr(tcx, local_def_id)
|
||||
{
|
||||
worklist.push((local_def_id, comes_from_allow));
|
||||
} else if of_trait {
|
||||
// private method || public method not constructs self
|
||||
unsolved_impl_items.push((id, local_def_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -182,15 +182,13 @@ impl SerializedDepGraph {
|
|||
pub fn decode<D: Deps>(d: &mut MemDecoder<'_>) -> Arc<SerializedDepGraph> {
|
||||
// The last 16 bytes are the node count and edge count.
|
||||
debug!("position: {:?}", d.position());
|
||||
let (node_count, edge_count, graph_size) =
|
||||
d.with_position(d.len() - 3 * IntEncodedWithFixedSize::ENCODED_SIZE, |d| {
|
||||
let (node_count, edge_count) =
|
||||
d.with_position(d.len() - 2 * IntEncodedWithFixedSize::ENCODED_SIZE, |d| {
|
||||
debug!("position: {:?}", d.position());
|
||||
let node_count = IntEncodedWithFixedSize::decode(d).0 as usize;
|
||||
let edge_count = IntEncodedWithFixedSize::decode(d).0 as usize;
|
||||
let graph_size = IntEncodedWithFixedSize::decode(d).0 as usize;
|
||||
(node_count, edge_count, graph_size)
|
||||
(node_count, edge_count)
|
||||
});
|
||||
assert_eq!(d.len(), graph_size);
|
||||
debug!("position: {:?}", d.position());
|
||||
|
||||
debug!(?node_count, ?edge_count);
|
||||
|
|
@ -606,8 +604,6 @@ impl<D: Deps> EncoderState<D> {
|
|||
debug!("position: {:?}", encoder.position());
|
||||
IntEncodedWithFixedSize(node_count).encode(&mut encoder);
|
||||
IntEncodedWithFixedSize(edge_count).encode(&mut encoder);
|
||||
let graph_size = encoder.position() + IntEncodedWithFixedSize::ENCODED_SIZE;
|
||||
IntEncodedWithFixedSize(graph_size as u64).encode(&mut encoder);
|
||||
debug!("position: {:?}", encoder.position());
|
||||
// Drop the encoder so that nothing is written after the counts.
|
||||
let result = encoder.finish();
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ use crate::int_overflow::DebugStrictAdd;
|
|||
|
||||
pub type FileEncodeResult = Result<usize, (PathBuf, io::Error)>;
|
||||
|
||||
pub const MAGIC_END_BYTES: &[u8] = b"rust-end-file";
|
||||
|
||||
/// The size of the buffer in `FileEncoder`.
|
||||
const BUF_SIZE: usize = 8192;
|
||||
|
||||
|
|
@ -181,6 +183,7 @@ impl FileEncoder {
|
|||
}
|
||||
|
||||
pub fn finish(&mut self) -> FileEncodeResult {
|
||||
self.write_all(MAGIC_END_BYTES);
|
||||
self.flush();
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
|
|
@ -261,15 +264,18 @@ pub struct MemDecoder<'a> {
|
|||
|
||||
impl<'a> MemDecoder<'a> {
|
||||
#[inline]
|
||||
pub fn new(data: &'a [u8], position: usize) -> MemDecoder<'a> {
|
||||
pub fn new(data: &'a [u8], position: usize) -> Result<MemDecoder<'a>, ()> {
|
||||
let data = data.strip_suffix(MAGIC_END_BYTES).ok_or(())?;
|
||||
let Range { start, end } = data.as_ptr_range();
|
||||
MemDecoder { start, current: data[position..].as_ptr(), end, _marker: PhantomData }
|
||||
Ok(MemDecoder { start, current: data[position..].as_ptr(), end, _marker: PhantomData })
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn data(&self) -> &'a [u8] {
|
||||
// SAFETY: This recovers the original slice, only using members we never modify.
|
||||
unsafe { std::slice::from_raw_parts(self.start, self.len()) }
|
||||
pub fn split_at(&self, position: usize) -> MemDecoder<'a> {
|
||||
assert!(position <= self.len());
|
||||
// SAFETY: We checked above that this offset is within the original slice
|
||||
let current = unsafe { self.start.add(position) };
|
||||
MemDecoder { start: self.start, current, end: self.end, _marker: PhantomData }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
use rustc_serialize::leb128::*;
|
||||
use rustc_serialize::opaque::MemDecoder;
|
||||
use rustc_serialize::opaque::MAGIC_END_BYTES;
|
||||
use rustc_serialize::Decoder;
|
||||
|
||||
macro_rules! impl_test_unsigned_leb128 {
|
||||
|
|
@ -25,13 +27,15 @@ macro_rules! impl_test_unsigned_leb128 {
|
|||
let n = $write_fn_name(&mut buf, x);
|
||||
stream.extend(&buf[..n]);
|
||||
}
|
||||
let stream_end = stream.len();
|
||||
stream.extend(MAGIC_END_BYTES);
|
||||
|
||||
let mut decoder = rustc_serialize::opaque::MemDecoder::new(&stream, 0);
|
||||
let mut decoder = MemDecoder::new(&stream, 0).unwrap();
|
||||
for &expected in &values {
|
||||
let actual = $read_fn_name(&mut decoder);
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
assert_eq!(stream.len(), decoder.position());
|
||||
assert_eq!(stream_end, decoder.position());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -72,13 +76,15 @@ macro_rules! impl_test_signed_leb128 {
|
|||
let n = $write_fn_name(&mut buf, x);
|
||||
stream.extend(&buf[..n]);
|
||||
}
|
||||
let stream_end = stream.len();
|
||||
stream.extend(MAGIC_END_BYTES);
|
||||
|
||||
let mut decoder = rustc_serialize::opaque::MemDecoder::new(&stream, 0);
|
||||
let mut decoder = MemDecoder::new(&stream, 0).unwrap();
|
||||
for &expected in &values {
|
||||
let actual = $read_fn_name(&mut decoder);
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
assert_eq!(stream.len(), decoder.position());
|
||||
assert_eq!(stream_end, decoder.position());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ fn check_round_trip<
|
|||
encoder.finish().unwrap();
|
||||
|
||||
let data = fs::read(&tmpfile).unwrap();
|
||||
let mut decoder = MemDecoder::new(&data[..], 0);
|
||||
let mut decoder = MemDecoder::new(&data[..], 0).unwrap();
|
||||
for value in values {
|
||||
let decoded = Decodable::decode(&mut decoder);
|
||||
assert_eq!(value, decoded);
|
||||
|
|
|
|||
|
|
@ -707,12 +707,11 @@ impl<'tcx> Stable<'tcx> for ty::TraitPredicate<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx, A, B, U, V> Stable<'tcx> for ty::OutlivesPredicate<A, B>
|
||||
impl<'tcx, T> Stable<'tcx> for ty::OutlivesPredicate<'tcx, T>
|
||||
where
|
||||
A: Stable<'tcx, T = U>,
|
||||
B: Stable<'tcx, T = V>,
|
||||
T: Stable<'tcx>,
|
||||
{
|
||||
type T = stable_mir::ty::OutlivesPredicate<U, V>;
|
||||
type T = stable_mir::ty::OutlivesPredicate<T::T, Region>;
|
||||
|
||||
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
|
||||
let ty::OutlivesPredicate(a, b) = self;
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ use std::cell::RefCell;
|
|||
use std::collections::hash_map::Entry;
|
||||
use std::fmt;
|
||||
use std::hash::Hash;
|
||||
use tracing::{debug, trace};
|
||||
|
||||
/// A `SyntaxContext` represents a chain of pairs `(ExpnId, Transparency)` named "marks".
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
|
|
|
|||
|
|
@ -33,15 +33,16 @@
|
|||
#![feature(rustdoc_internals)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
// The code produced by the `Encodable`/`Decodable` derive macros refer to
|
||||
// `rustc_span::Span{Encoder,Decoder}`. That's fine outside this crate, but doesn't work inside
|
||||
// this crate without this line making `rustc_span` available.
|
||||
extern crate self as rustc_span;
|
||||
|
||||
#[macro_use]
|
||||
extern crate tracing;
|
||||
|
||||
use rustc_data_structures::{outline, AtomicRef};
|
||||
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
|
||||
use rustc_serialize::opaque::{FileEncoder, MemDecoder};
|
||||
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
|
||||
use tracing::debug;
|
||||
|
||||
mod caching_source_map_view;
|
||||
pub mod source_map;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ use rustc_macros::{Decodable, Encodable};
|
|||
use std::fs;
|
||||
use std::io::{self, BorrowedBuf, Read};
|
||||
use std::path;
|
||||
use tracing::{debug, instrument, trace};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
|
|
|||
|
|
@ -300,14 +300,11 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
|
|||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
// If `Fn`/`FnMut`, we only implement this goal if we
|
||||
// have no captures.
|
||||
let no_borrows = match args.tupled_upvars_ty().kind() {
|
||||
ty::Tuple(tys) => tys.is_empty(),
|
||||
ty::Error(_) => false,
|
||||
_ => bug!("tuple_fields called on non-tuple"),
|
||||
};
|
||||
if closure_kind != ty::ClosureKind::FnOnce && !no_borrows {
|
||||
// A coroutine-closure implements `FnOnce` *always*, since it may
|
||||
// always be called once. It additionally implements `Fn`/`FnMut`
|
||||
// only if it has no upvars referencing the closure-env lifetime,
|
||||
// and if the closure kind permits it.
|
||||
if closure_kind != ty::ClosureKind::FnOnce && args.has_self_borrows() {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,8 @@ use crate::infer::InferCtxtExt as _;
|
|||
use crate::traits::error_reporting::type_err_ctxt_ext::InferCtxtPrivExt;
|
||||
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
|
||||
use rustc_middle::ty::print::{
|
||||
with_forced_trimmed_paths, with_no_trimmed_paths, PrintTraitPredicateExt as _,
|
||||
with_forced_trimmed_paths, with_no_trimmed_paths, PrintPolyTraitPredicateExt as _,
|
||||
PrintTraitPredicateExt as _,
|
||||
};
|
||||
|
||||
use itertools::EitherOrBoth;
|
||||
|
|
|
|||
|
|
@ -162,8 +162,7 @@ pub fn compute_implied_outlives_bounds_compat_inner<'tcx>(
|
|||
let mut checked_wf_args = rustc_data_structures::fx::FxHashSet::default();
|
||||
let mut wf_args = vec![ty.into()];
|
||||
|
||||
let mut outlives_bounds: Vec<ty::OutlivesPredicate<ty::GenericArg<'tcx>, ty::Region<'tcx>>> =
|
||||
vec![];
|
||||
let mut outlives_bounds: Vec<ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>> = vec![];
|
||||
|
||||
while let Some(arg) = wf_args.pop() {
|
||||
if !checked_wf_args.insert(arg) {
|
||||
|
|
|
|||
|
|
@ -418,20 +418,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
// Ambiguity if upvars haven't been constrained yet
|
||||
&& !args.tupled_upvars_ty().is_ty_var()
|
||||
{
|
||||
let no_borrows = match args.tupled_upvars_ty().kind() {
|
||||
ty::Tuple(tys) => tys.is_empty(),
|
||||
ty::Error(_) => false,
|
||||
_ => bug!("tuple_fields called on non-tuple"),
|
||||
};
|
||||
// A coroutine-closure implements `FnOnce` *always*, since it may
|
||||
// always be called once. It additionally implements `Fn`/`FnMut`
|
||||
// only if it has no upvars (therefore no borrows from the closure
|
||||
// that would need to be represented with a lifetime) and if the
|
||||
// closure kind permits it.
|
||||
// FIXME(async_closures): Actually, it could also implement `Fn`/`FnMut`
|
||||
// if it takes all of its upvars by copy, and none by ref. This would
|
||||
// require us to record a bit more information during upvar analysis.
|
||||
if no_borrows && closure_kind.extends(kind) {
|
||||
// only if it has no upvars referencing the closure-env lifetime,
|
||||
// and if the closure kind permits it.
|
||||
if closure_kind.extends(kind) && !args.has_self_borrows() {
|
||||
candidates.vec.push(ClosureCandidate { is_const });
|
||||
} else if kind == ty::ClosureKind::FnOnce {
|
||||
candidates.vec.push(ClosureCandidate { is_const });
|
||||
|
|
|
|||
340
compiler/rustc_type_ir/src/binder.rs
Normal file
340
compiler/rustc_type_ir/src/binder.rs
Normal file
|
|
@ -0,0 +1,340 @@
|
|||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
use std::ops::{ControlFlow, Deref};
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
use rustc_macros::HashStable_NoContext;
|
||||
use rustc_serialize::Decodable;
|
||||
|
||||
use crate::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
|
||||
use crate::inherent::*;
|
||||
use crate::lift::Lift;
|
||||
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
|
||||
use crate::{self as ty, Interner, SsoHashSet};
|
||||
|
||||
/// Binder is a binder for higher-ranked lifetimes or types. It is part of the
|
||||
/// compiler's representation for things like `for<'a> Fn(&'a isize)`
|
||||
/// (which would be represented by the type `PolyTraitRef ==
|
||||
/// Binder<I, TraitRef>`). Note that when we instantiate,
|
||||
/// erase, or otherwise "discharge" these bound vars, we change the
|
||||
/// type from `Binder<I, T>` to just `T` (see
|
||||
/// e.g., `liberate_late_bound_regions`).
|
||||
///
|
||||
/// `Decodable` and `Encodable` are implemented for `Binder<T>` using the `impl_binder_encode_decode!` macro.
|
||||
#[derive(derivative::Derivative)]
|
||||
#[derivative(
|
||||
Clone(bound = "T: Clone"),
|
||||
Copy(bound = "T: Copy"),
|
||||
Hash(bound = "T: Hash"),
|
||||
PartialEq(bound = "T: PartialEq"),
|
||||
Eq(bound = "T: Eq"),
|
||||
Debug(bound = "T: Debug")
|
||||
)]
|
||||
#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
|
||||
pub struct Binder<I: Interner, T> {
|
||||
value: T,
|
||||
bound_vars: I::BoundVarKinds,
|
||||
}
|
||||
|
||||
// FIXME: We manually derive `Lift` because the `derive(Lift_Generic)` doesn't
|
||||
// understand how to turn `T` to `T::Lifted` in the output `type Lifted`.
|
||||
impl<I: Interner, U: Interner, T> Lift<U> for Binder<I, T>
|
||||
where
|
||||
T: Lift<U>,
|
||||
I::BoundVarKinds: Lift<U, Lifted = U::BoundVarKinds>,
|
||||
{
|
||||
type Lifted = Binder<U, T::Lifted>;
|
||||
|
||||
fn lift_to_tcx(self, tcx: U) -> Option<Self::Lifted> {
|
||||
Some(Binder {
|
||||
value: self.value.lift_to_tcx(tcx)?,
|
||||
bound_vars: self.bound_vars.lift_to_tcx(tcx)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_binder_encode_decode {
|
||||
($($t:ty),+ $(,)?) => {
|
||||
$(
|
||||
impl<I: Interner, E: crate::TyEncoder<I = I>> rustc_serialize::Encodable<E> for ty::Binder<I, $t>
|
||||
where
|
||||
$t: rustc_serialize::Encodable<E>,
|
||||
I::BoundVarKinds: rustc_serialize::Encodable<E>,
|
||||
{
|
||||
fn encode(&self, e: &mut E) {
|
||||
self.bound_vars().encode(e);
|
||||
self.as_ref().skip_binder().encode(e);
|
||||
}
|
||||
}
|
||||
impl<I: Interner, D: crate::TyDecoder<I = I>> Decodable<D> for ty::Binder<I, $t>
|
||||
where
|
||||
$t: TypeVisitable<I> + rustc_serialize::Decodable<D>,
|
||||
I::BoundVarKinds: rustc_serialize::Decodable<D>,
|
||||
{
|
||||
fn decode(decoder: &mut D) -> Self {
|
||||
let bound_vars = Decodable::decode(decoder);
|
||||
ty::Binder::bind_with_vars(<$t>::decode(decoder), bound_vars)
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
impl_binder_encode_decode! {
|
||||
ty::FnSig<I>,
|
||||
ty::TraitPredicate<I>,
|
||||
ty::ExistentialPredicate<I>,
|
||||
ty::TraitRef<I>,
|
||||
ty::ExistentialTraitRef<I>,
|
||||
}
|
||||
|
||||
impl<I: Interner, T> Binder<I, T>
|
||||
where
|
||||
T: TypeVisitable<I>,
|
||||
{
|
||||
/// Wraps `value` in a binder, asserting that `value` does not
|
||||
/// contain any bound vars that would be bound by the
|
||||
/// binder. This is commonly used to 'inject' a value T into a
|
||||
/// different binding level.
|
||||
#[track_caller]
|
||||
pub fn dummy(value: T) -> Binder<I, T> {
|
||||
assert!(
|
||||
!value.has_escaping_bound_vars(),
|
||||
"`{value:?}` has escaping bound vars, so it cannot be wrapped in a dummy binder."
|
||||
);
|
||||
Binder { value, bound_vars: Default::default() }
|
||||
}
|
||||
|
||||
pub fn bind_with_vars(value: T, bound_vars: I::BoundVarKinds) -> Binder<I, T> {
|
||||
if cfg!(debug_assertions) {
|
||||
let mut validator = ValidateBoundVars::new(bound_vars);
|
||||
value.visit_with(&mut validator);
|
||||
}
|
||||
Binder { value, bound_vars }
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Binder<I, T> {
|
||||
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
|
||||
folder.try_fold_binder(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Binder<I, T> {
|
||||
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
|
||||
visitor.visit_binder(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner, T: TypeFoldable<I>> TypeSuperFoldable<I> for Binder<I, T> {
|
||||
fn try_super_fold_with<F: FallibleTypeFolder<I>>(
|
||||
self,
|
||||
folder: &mut F,
|
||||
) -> Result<Self, F::Error> {
|
||||
self.try_map_bound(|ty| ty.try_fold_with(folder))
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner, T: TypeVisitable<I>> TypeSuperVisitable<I> for Binder<I, T> {
|
||||
fn super_visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
|
||||
self.as_ref().skip_binder().visit_with(visitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner, T> Binder<I, T> {
|
||||
/// Skips the binder and returns the "bound" value. This is a
|
||||
/// risky thing to do because it's easy to get confused about
|
||||
/// De Bruijn indices and the like. It is usually better to
|
||||
/// discharge the binder using `no_bound_vars` or
|
||||
/// `instantiate_bound_regions` or something like
|
||||
/// that. `skip_binder` is only valid when you are either
|
||||
/// extracting data that has nothing to do with bound vars, you
|
||||
/// are doing some sort of test that does not involve bound
|
||||
/// regions, or you are being very careful about your depth
|
||||
/// accounting.
|
||||
///
|
||||
/// Some examples where `skip_binder` is reasonable:
|
||||
///
|
||||
/// - extracting the `DefId` from a PolyTraitRef;
|
||||
/// - comparing the self type of a PolyTraitRef to see if it is equal to
|
||||
/// a type parameter `X`, since the type `X` does not reference any regions
|
||||
pub fn skip_binder(self) -> T {
|
||||
self.value
|
||||
}
|
||||
|
||||
pub fn bound_vars(&self) -> I::BoundVarKinds {
|
||||
self.bound_vars
|
||||
}
|
||||
|
||||
pub fn as_ref(&self) -> Binder<I, &T> {
|
||||
Binder { value: &self.value, bound_vars: self.bound_vars }
|
||||
}
|
||||
|
||||
pub fn as_deref(&self) -> Binder<I, &T::Target>
|
||||
where
|
||||
T: Deref,
|
||||
{
|
||||
Binder { value: &self.value, bound_vars: self.bound_vars }
|
||||
}
|
||||
|
||||
pub fn map_bound_ref<F, U: TypeVisitable<I>>(&self, f: F) -> Binder<I, U>
|
||||
where
|
||||
F: FnOnce(&T) -> U,
|
||||
{
|
||||
self.as_ref().map_bound(f)
|
||||
}
|
||||
|
||||
pub fn map_bound<F, U: TypeVisitable<I>>(self, f: F) -> Binder<I, U>
|
||||
where
|
||||
F: FnOnce(T) -> U,
|
||||
{
|
||||
let Binder { value, bound_vars } = self;
|
||||
let value = f(value);
|
||||
if cfg!(debug_assertions) {
|
||||
let mut validator = ValidateBoundVars::new(bound_vars);
|
||||
value.visit_with(&mut validator);
|
||||
}
|
||||
Binder { value, bound_vars }
|
||||
}
|
||||
|
||||
pub fn try_map_bound<F, U: TypeVisitable<I>, E>(self, f: F) -> Result<Binder<I, U>, E>
|
||||
where
|
||||
F: FnOnce(T) -> Result<U, E>,
|
||||
{
|
||||
let Binder { value, bound_vars } = self;
|
||||
let value = f(value)?;
|
||||
if cfg!(debug_assertions) {
|
||||
let mut validator = ValidateBoundVars::new(bound_vars);
|
||||
value.visit_with(&mut validator);
|
||||
}
|
||||
Ok(Binder { value, bound_vars })
|
||||
}
|
||||
|
||||
/// Wraps a `value` in a binder, using the same bound variables as the
|
||||
/// current `Binder`. This should not be used if the new value *changes*
|
||||
/// the bound variables. Note: the (old or new) value itself does not
|
||||
/// necessarily need to *name* all the bound variables.
|
||||
///
|
||||
/// This currently doesn't do anything different than `bind`, because we
|
||||
/// don't actually track bound vars. However, semantically, it is different
|
||||
/// because bound vars aren't allowed to change here, whereas they are
|
||||
/// in `bind`. This may be (debug) asserted in the future.
|
||||
pub fn rebind<U>(&self, value: U) -> Binder<I, U>
|
||||
where
|
||||
U: TypeVisitable<I>,
|
||||
{
|
||||
Binder::bind_with_vars(value, self.bound_vars)
|
||||
}
|
||||
|
||||
/// Unwraps and returns the value within, but only if it contains
|
||||
/// no bound vars at all. (In other words, if this binder --
|
||||
/// and indeed any enclosing binder -- doesn't bind anything at
|
||||
/// all.) Otherwise, returns `None`.
|
||||
///
|
||||
/// (One could imagine having a method that just unwraps a single
|
||||
/// binder, but permits late-bound vars bound by enclosing
|
||||
/// binders, but that would require adjusting the debruijn
|
||||
/// indices, and given the shallow binding structure we often use,
|
||||
/// would not be that useful.)
|
||||
pub fn no_bound_vars(self) -> Option<T>
|
||||
where
|
||||
T: TypeVisitable<I>,
|
||||
{
|
||||
// `self.value` is equivalent to `self.skip_binder()`
|
||||
if self.value.has_escaping_bound_vars() { None } else { Some(self.skip_binder()) }
|
||||
}
|
||||
|
||||
/// Splits the contents into two things that share the same binder
|
||||
/// level as the original, returning two distinct binders.
|
||||
///
|
||||
/// `f` should consider bound regions at depth 1 to be free, and
|
||||
/// anything it produces with bound regions at depth 1 will be
|
||||
/// bound in the resulting return values.
|
||||
pub fn split<U, V, F>(self, f: F) -> (Binder<I, U>, Binder<I, V>)
|
||||
where
|
||||
F: FnOnce(T) -> (U, V),
|
||||
{
|
||||
let Binder { value, bound_vars } = self;
|
||||
let (u, v) = f(value);
|
||||
(Binder { value: u, bound_vars }, Binder { value: v, bound_vars })
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner, T> Binder<I, Option<T>> {
|
||||
pub fn transpose(self) -> Option<Binder<I, T>> {
|
||||
let Binder { value, bound_vars } = self;
|
||||
value.map(|value| Binder { value, bound_vars })
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner, T: IntoIterator> Binder<I, T> {
|
||||
pub fn iter(self) -> impl Iterator<Item = Binder<I, T::Item>> {
|
||||
let Binder { value, bound_vars } = self;
|
||||
value.into_iter().map(move |value| Binder { value, bound_vars })
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ValidateBoundVars<I: Interner> {
|
||||
bound_vars: I::BoundVarKinds,
|
||||
binder_index: ty::DebruijnIndex,
|
||||
// We may encounter the same variable at different levels of binding, so
|
||||
// this can't just be `Ty`
|
||||
visited: SsoHashSet<(ty::DebruijnIndex, I::Ty)>,
|
||||
}
|
||||
|
||||
impl<I: Interner> ValidateBoundVars<I> {
|
||||
pub fn new(bound_vars: I::BoundVarKinds) -> Self {
|
||||
ValidateBoundVars {
|
||||
bound_vars,
|
||||
binder_index: ty::INNERMOST,
|
||||
visited: SsoHashSet::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner> TypeVisitor<I> for ValidateBoundVars<I> {
|
||||
type Result = ControlFlow<()>;
|
||||
|
||||
fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &Binder<I, T>) -> Self::Result {
|
||||
self.binder_index.shift_in(1);
|
||||
let result = t.super_visit_with(self);
|
||||
self.binder_index.shift_out(1);
|
||||
result
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, t: I::Ty) -> Self::Result {
|
||||
if t.outer_exclusive_binder() < self.binder_index
|
||||
|| !self.visited.insert((self.binder_index, t))
|
||||
{
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
match t.kind() {
|
||||
ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => {
|
||||
let idx = bound_ty.var().as_usize();
|
||||
if self.bound_vars.len() <= idx {
|
||||
panic!("Not enough bound vars: {:?} not found in {:?}", t, self.bound_vars);
|
||||
}
|
||||
bound_ty.assert_eq(self.bound_vars[idx]);
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
|
||||
t.super_visit_with(self)
|
||||
}
|
||||
|
||||
fn visit_region(&mut self, r: I::Region) -> Self::Result {
|
||||
match r.kind() {
|
||||
ty::ReBound(index, br) if index == self.binder_index => {
|
||||
let idx = br.var().as_usize();
|
||||
if self.bound_vars.len() <= idx {
|
||||
panic!("Not enough bound vars: {:?} not found in {:?}", r, self.bound_vars);
|
||||
}
|
||||
br.assert_eq(self.bound_vars[idx]);
|
||||
}
|
||||
|
||||
_ => (),
|
||||
};
|
||||
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
|
|||
use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
|
||||
use std::fmt;
|
||||
|
||||
use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx};
|
||||
use crate::{self as ty, DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx};
|
||||
|
||||
use self::ConstKind::*;
|
||||
|
||||
|
|
@ -29,7 +29,7 @@ pub enum ConstKind<I: Interner> {
|
|||
/// An unnormalized const item such as an anon const or assoc const or free const item.
|
||||
/// Right now anything other than anon consts does not actually work properly but this
|
||||
/// should
|
||||
Unevaluated(I::AliasConst),
|
||||
Unevaluated(ty::UnevaluatedConst<I>),
|
||||
|
||||
/// Used to hold computed value.
|
||||
Value(I::ValueConst),
|
||||
|
|
|
|||
|
|
@ -48,8 +48,8 @@
|
|||
use rustc_index::{Idx, IndexVec};
|
||||
use std::mem;
|
||||
|
||||
use crate::Lrc;
|
||||
use crate::{visit::TypeVisitable, Interner};
|
||||
use crate::visit::TypeVisitable;
|
||||
use crate::{self as ty, Interner, Lrc};
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
type Never = !;
|
||||
|
|
@ -128,10 +128,9 @@ pub trait TypeSuperFoldable<I: Interner>: TypeFoldable<I> {
|
|||
pub trait TypeFolder<I: Interner>: FallibleTypeFolder<I, Error = Never> {
|
||||
fn interner(&self) -> I;
|
||||
|
||||
fn fold_binder<T>(&mut self, t: I::Binder<T>) -> I::Binder<T>
|
||||
fn fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T>
|
||||
where
|
||||
T: TypeFoldable<I>,
|
||||
I::Binder<T>: TypeSuperFoldable<I>,
|
||||
{
|
||||
t.super_fold_with(self)
|
||||
}
|
||||
|
|
@ -167,10 +166,9 @@ pub trait FallibleTypeFolder<I: Interner>: Sized {
|
|||
|
||||
fn interner(&self) -> I;
|
||||
|
||||
fn try_fold_binder<T>(&mut self, t: I::Binder<T>) -> Result<I::Binder<T>, Self::Error>
|
||||
fn try_fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> Result<ty::Binder<I, T>, Self::Error>
|
||||
where
|
||||
T: TypeFoldable<I>,
|
||||
I::Binder<T>: TypeSuperFoldable<I>,
|
||||
{
|
||||
t.try_super_fold_with(self)
|
||||
}
|
||||
|
|
@ -206,10 +204,9 @@ where
|
|||
TypeFolder::interner(self)
|
||||
}
|
||||
|
||||
fn try_fold_binder<T>(&mut self, t: I::Binder<T>) -> Result<I::Binder<T>, Never>
|
||||
fn try_fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> Result<ty::Binder<I, T>, Never>
|
||||
where
|
||||
T: TypeFoldable<I>,
|
||||
I::Binder<T>: TypeSuperFoldable<I>,
|
||||
{
|
||||
Ok(self.fold_binder(t))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,11 +8,8 @@ use std::hash::Hash;
|
|||
use std::ops::Deref;
|
||||
|
||||
use crate::fold::{TypeFoldable, TypeSuperFoldable};
|
||||
use crate::visit::{Flags, TypeSuperVisitable};
|
||||
use crate::{
|
||||
AliasTy, AliasTyKind, BoundVar, ConstKind, ConstVid, DebruijnIndex, DebugWithInfcx, InferConst,
|
||||
InferTy, Interner, RegionKind, TyKind, TyVid, UnevaluatedConst, UniverseIndex,
|
||||
};
|
||||
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
|
||||
use crate::{self as ty, DebugWithInfcx, Interner, UpcastFrom};
|
||||
|
||||
pub trait Ty<I: Interner<Ty = Self>>:
|
||||
Copy
|
||||
|
|
@ -21,24 +18,30 @@ pub trait Ty<I: Interner<Ty = Self>>:
|
|||
+ Eq
|
||||
+ Into<I::GenericArg>
|
||||
+ Into<I::Term>
|
||||
+ IntoKind<Kind = TyKind<I>>
|
||||
+ IntoKind<Kind = ty::TyKind<I>>
|
||||
+ TypeSuperVisitable<I>
|
||||
+ TypeSuperFoldable<I>
|
||||
+ Flags
|
||||
{
|
||||
fn new_bool(interner: I) -> Self;
|
||||
|
||||
fn new_infer(interner: I, var: InferTy) -> Self;
|
||||
fn new_infer(interner: I, var: ty::InferTy) -> Self;
|
||||
|
||||
fn new_var(interner: I, var: TyVid) -> Self;
|
||||
fn new_var(interner: I, var: ty::TyVid) -> Self;
|
||||
|
||||
fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar) -> Self;
|
||||
fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self;
|
||||
|
||||
fn new_alias(interner: I, kind: AliasTyKind, alias_ty: AliasTy<I>) -> Self;
|
||||
fn new_alias(interner: I, kind: ty::AliasTyKind, alias_ty: ty::AliasTy<I>) -> Self;
|
||||
}
|
||||
|
||||
pub trait Tys<I: Interner<Tys = Self>>:
|
||||
Copy + Debug + Hash + Eq + IntoIterator<Item = I::Ty> + Deref<Target: Deref<Target = [I::Ty]>>
|
||||
Copy
|
||||
+ Debug
|
||||
+ Hash
|
||||
+ Eq
|
||||
+ IntoIterator<Item = I::Ty>
|
||||
+ Deref<Target: Deref<Target = [I::Ty]>>
|
||||
+ TypeVisitable<I>
|
||||
{
|
||||
fn split_inputs_and_output(self) -> (I::FnInputTys, I::Ty);
|
||||
}
|
||||
|
|
@ -49,13 +52,21 @@ pub trait Abi<I: Interner<Abi = Self>>: Copy + Debug + Hash + Eq {
|
|||
}
|
||||
|
||||
pub trait Safety<I: Interner<Safety = Self>>: Copy + Debug + Hash + Eq {
|
||||
fn is_safe(self) -> bool;
|
||||
|
||||
fn prefix_str(self) -> &'static str;
|
||||
}
|
||||
|
||||
pub trait Region<I: Interner<Region = Self>>:
|
||||
Copy + DebugWithInfcx<I> + Hash + Eq + Into<I::GenericArg> + IntoKind<Kind = RegionKind<I>> + Flags
|
||||
Copy
|
||||
+ DebugWithInfcx<I>
|
||||
+ Hash
|
||||
+ Eq
|
||||
+ Into<I::GenericArg>
|
||||
+ IntoKind<Kind = ty::RegionKind<I>>
|
||||
+ Flags
|
||||
{
|
||||
fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar) -> Self;
|
||||
fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self;
|
||||
|
||||
fn new_static(interner: I) -> Self;
|
||||
}
|
||||
|
|
@ -67,18 +78,23 @@ pub trait Const<I: Interner<Const = Self>>:
|
|||
+ Eq
|
||||
+ Into<I::GenericArg>
|
||||
+ Into<I::Term>
|
||||
+ IntoKind<Kind = ConstKind<I>>
|
||||
+ IntoKind<Kind = ty::ConstKind<I>>
|
||||
+ TypeSuperVisitable<I>
|
||||
+ TypeSuperFoldable<I>
|
||||
+ Flags
|
||||
{
|
||||
fn new_infer(interner: I, var: InferConst, ty: I::Ty) -> Self;
|
||||
fn new_infer(interner: I, var: ty::InferConst, ty: I::Ty) -> Self;
|
||||
|
||||
fn new_var(interner: I, var: ConstVid, ty: I::Ty) -> Self;
|
||||
fn new_var(interner: I, var: ty::ConstVid, ty: I::Ty) -> Self;
|
||||
|
||||
fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar, ty: I::Ty) -> Self;
|
||||
fn new_anon_bound(
|
||||
interner: I,
|
||||
debruijn: ty::DebruijnIndex,
|
||||
var: ty::BoundVar,
|
||||
ty: I::Ty,
|
||||
) -> Self;
|
||||
|
||||
fn new_unevaluated(interner: I, uv: UnevaluatedConst<I>, ty: I::Ty) -> Self;
|
||||
fn new_unevaluated(interner: I, uv: ty::UnevaluatedConst<I>, ty: I::Ty) -> Self;
|
||||
|
||||
fn ty(self) -> I::Ty;
|
||||
}
|
||||
|
|
@ -100,6 +116,12 @@ pub trait GenericArgs<I: Interner<GenericArgs = Self>>:
|
|||
fn type_at(self, i: usize) -> I::Ty;
|
||||
|
||||
fn identity_for_item(interner: I, def_id: I::DefId) -> I::GenericArgs;
|
||||
|
||||
fn extend_with_error(
|
||||
tcx: I,
|
||||
def_id: I::DefId,
|
||||
original_args: &[I::GenericArg],
|
||||
) -> I::GenericArgs;
|
||||
}
|
||||
|
||||
pub trait Predicate<I: Interner<Predicate = Self>>:
|
||||
|
|
@ -108,14 +130,25 @@ pub trait Predicate<I: Interner<Predicate = Self>>:
|
|||
fn is_coinductive(self, interner: I) -> bool;
|
||||
}
|
||||
|
||||
pub trait Clause<I: Interner<Clause = Self>>:
|
||||
Copy
|
||||
+ Debug
|
||||
+ Hash
|
||||
+ Eq
|
||||
// FIXME: Remove these, uplift the `Upcast` impls.
|
||||
+ UpcastFrom<I, ty::Binder<I, ty::TraitRef<I>>>
|
||||
+ UpcastFrom<I, ty::Binder<I, ty::ProjectionPredicate<I>>>
|
||||
{
|
||||
}
|
||||
|
||||
/// Common capabilities of placeholder kinds
|
||||
pub trait PlaceholderLike: Copy + Debug + Hash + Eq {
|
||||
fn universe(self) -> UniverseIndex;
|
||||
fn var(self) -> BoundVar;
|
||||
fn universe(self) -> ty::UniverseIndex;
|
||||
fn var(self) -> ty::BoundVar;
|
||||
|
||||
fn with_updated_universe(self, ui: UniverseIndex) -> Self;
|
||||
fn with_updated_universe(self, ui: ty::UniverseIndex) -> Self;
|
||||
|
||||
fn new(ui: UniverseIndex, var: BoundVar) -> Self;
|
||||
fn new(ui: ty::UniverseIndex, var: ty::BoundVar) -> Self;
|
||||
}
|
||||
|
||||
pub trait IntoKind {
|
||||
|
|
@ -124,12 +157,8 @@ pub trait IntoKind {
|
|||
fn kind(self) -> Self::Kind;
|
||||
}
|
||||
|
||||
pub trait BoundVars<I: Interner> {
|
||||
fn bound_vars(&self) -> I::BoundVars;
|
||||
|
||||
fn has_no_bound_vars(&self) -> bool;
|
||||
}
|
||||
|
||||
pub trait BoundVarLike<I: Interner> {
|
||||
fn var(self) -> BoundVar;
|
||||
fn var(self) -> ty::BoundVar;
|
||||
|
||||
fn assert_eq(self, var: I::BoundVarKind);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,19 +28,28 @@ pub trait Interner:
|
|||
+ IrPrint<CoercePredicate<Self>>
|
||||
+ IrPrint<FnSig<Self>>
|
||||
{
|
||||
type DefId: Copy + Debug + Hash + Eq;
|
||||
type DefId: Copy + Debug + Hash + Eq + TypeVisitable<Self>;
|
||||
type AdtDef: Copy + Debug + Hash + Eq;
|
||||
|
||||
type GenericArgs: GenericArgs<Self>;
|
||||
/// The slice of args for a specific item. For a GAT like `type Foo<'a>`, it will be `['a]`,
|
||||
/// not including the args from the parent item (trait or impl).
|
||||
type OwnItemArgs: Copy + Debug + Hash + Eq;
|
||||
type GenericArg: Copy + DebugWithInfcx<Self> + Hash + Eq + IntoKind<Kind = GenericArgKind<Self>>;
|
||||
type Term: Copy + Debug + Hash + Eq + IntoKind<Kind = TermKind<Self>>;
|
||||
type GenericArg: Copy
|
||||
+ DebugWithInfcx<Self>
|
||||
+ Hash
|
||||
+ Eq
|
||||
+ IntoKind<Kind = GenericArgKind<Self>>
|
||||
+ TypeVisitable<Self>;
|
||||
type Term: Copy + Debug + Hash + Eq + IntoKind<Kind = TermKind<Self>> + TypeVisitable<Self>;
|
||||
|
||||
type Binder<T: TypeVisitable<Self>>: BoundVars<Self> + TypeSuperVisitable<Self>;
|
||||
type BoundVars: IntoIterator<Item = Self::BoundVar>;
|
||||
type BoundVar;
|
||||
type BoundVarKinds: Copy
|
||||
+ Debug
|
||||
+ Hash
|
||||
+ Eq
|
||||
+ Deref<Target: Deref<Target = [Self::BoundVarKind]>>
|
||||
+ Default;
|
||||
type BoundVarKind: Copy + Debug + Hash + Eq;
|
||||
|
||||
type CanonicalVars: Copy + Debug + Hash + Eq + IntoIterator<Item = CanonicalVarInfo<Self>>;
|
||||
type PredefinedOpaques: Copy + Debug + Hash + Eq;
|
||||
|
|
@ -51,7 +60,7 @@ pub trait Interner:
|
|||
// Kinds of tys
|
||||
type Ty: Ty<Self>;
|
||||
type Tys: Tys<Self>;
|
||||
type FnInputTys: Copy + Debug + Hash + Eq + Deref<Target = [Self::Ty]>;
|
||||
type FnInputTys: Copy + Debug + Hash + Eq + Deref<Target = [Self::Ty]> + TypeVisitable<Self>;
|
||||
type ParamTy: Copy + Debug + Hash + Eq;
|
||||
type BoundTy: Copy + Debug + Hash + Eq + BoundVarLike<Self>;
|
||||
type PlaceholderTy: PlaceholderLike;
|
||||
|
|
@ -67,7 +76,6 @@ pub trait Interner:
|
|||
|
||||
// Kinds of consts
|
||||
type Const: Const<Self>;
|
||||
type AliasConst: Copy + DebugWithInfcx<Self> + Hash + Eq;
|
||||
type PlaceholderConst: PlaceholderLike;
|
||||
type ParamConst: Copy + Debug + Hash + Eq;
|
||||
type BoundConst: Copy + Debug + Hash + Eq + BoundVarLike<Self>;
|
||||
|
|
@ -84,14 +92,7 @@ pub trait Interner:
|
|||
// Predicates
|
||||
type ParamEnv: Copy + Debug + Hash + Eq;
|
||||
type Predicate: Predicate<Self>;
|
||||
type TraitPredicate: Copy + Debug + Hash + Eq;
|
||||
type RegionOutlivesPredicate: Copy + Debug + Hash + Eq;
|
||||
type TypeOutlivesPredicate: Copy + Debug + Hash + Eq;
|
||||
type ProjectionPredicate: Copy + Debug + Hash + Eq;
|
||||
type NormalizesTo: Copy + Debug + Hash + Eq;
|
||||
type SubtypePredicate: Copy + Debug + Hash + Eq;
|
||||
type CoercePredicate: Copy + Debug + Hash + Eq;
|
||||
type ClosureKind: Copy + Debug + Hash + Eq;
|
||||
type Clause: Clause<Self>;
|
||||
type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable<Self> + Flags;
|
||||
|
||||
fn mk_canonical_var_infos(self, infos: &[CanonicalVarInfo<Self>]) -> Self::CanonicalVars;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
use std::fmt;
|
||||
|
||||
use crate::{
|
||||
AliasTerm, AliasTy, CoercePredicate, ExistentialProjection, ExistentialTraitRef, FnSig,
|
||||
Interner, NormalizesTo, ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef,
|
||||
AliasTerm, AliasTy, Binder, CoercePredicate, ExistentialProjection, ExistentialTraitRef, FnSig,
|
||||
Interner, NormalizesTo, OutlivesPredicate, ProjectionPredicate, SubtypePredicate,
|
||||
TraitPredicate, TraitRef,
|
||||
};
|
||||
|
||||
pub trait IrPrint<T> {
|
||||
|
|
@ -22,6 +23,15 @@ macro_rules! define_display_via_print {
|
|||
}
|
||||
}
|
||||
|
||||
impl<I: Interner, T> fmt::Display for Binder<I, T>
|
||||
where
|
||||
I: IrPrint<Binder<I, T>>,
|
||||
{
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
<I as IrPrint<Binder<I, T>>>::print(self, fmt)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! define_debug_via_print {
|
||||
($($ty:ident),+ $(,)?) => {
|
||||
$(
|
||||
|
|
@ -49,3 +59,12 @@ define_display_via_print!(
|
|||
);
|
||||
|
||||
define_debug_via_print!(TraitRef, ExistentialTraitRef, ExistentialProjection);
|
||||
|
||||
impl<I: Interner, T> fmt::Display for OutlivesPredicate<I, T>
|
||||
where
|
||||
I: IrPrint<OutlivesPredicate<I, T>>,
|
||||
{
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
<I as IrPrint<OutlivesPredicate<I, T>>>::print(self, fmt)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,10 +8,14 @@
|
|||
#[cfg(feature = "nightly")]
|
||||
extern crate self as rustc_type_ir;
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
use rustc_data_structures::sso::SsoHashSet;
|
||||
#[cfg(feature = "nightly")]
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
#[cfg(feature = "nightly")]
|
||||
use rustc_macros::{Decodable, Encodable, HashStable_NoContext};
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
use std::collections::HashSet as SsoHashSet;
|
||||
use std::fmt;
|
||||
use std::hash::Hash;
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
|
|
@ -31,6 +35,7 @@ pub mod ty_kind;
|
|||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
mod binder;
|
||||
mod canonical;
|
||||
mod const_kind;
|
||||
mod debug;
|
||||
|
|
@ -43,6 +48,7 @@ mod predicate_kind;
|
|||
mod region_kind;
|
||||
mod upcast;
|
||||
|
||||
pub use binder::*;
|
||||
pub use canonical::*;
|
||||
#[cfg(feature = "nightly")]
|
||||
pub use codec::*;
|
||||
|
|
@ -374,6 +380,10 @@ impl<I: Interner> inherent::BoundVarLike<I> for BoundVar {
|
|||
fn var(self) -> BoundVar {
|
||||
self
|
||||
}
|
||||
|
||||
fn assert_eq(self, _var: I::BoundVarKind) {
|
||||
unreachable!("FIXME: We really should have a separate `BoundConst` for consts")
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the various closure traits in the language. This
|
||||
|
|
|
|||
|
|
@ -6,10 +6,38 @@ use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEn
|
|||
use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
|
||||
|
||||
use crate::inherent::*;
|
||||
use crate::lift::Lift;
|
||||
use crate::upcast::Upcast;
|
||||
use crate::visit::TypeVisitableExt as _;
|
||||
use crate::{
|
||||
AliasTy, AliasTyKind, DebugWithInfcx, InferCtxtLike, Interner, UnevaluatedConst, WithInfcx,
|
||||
};
|
||||
use crate::{self as ty, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx};
|
||||
|
||||
/// `A: 'region`
|
||||
#[derive(derivative::Derivative)]
|
||||
#[derivative(
|
||||
Clone(bound = "A: Clone"),
|
||||
Copy(bound = "A: Copy"),
|
||||
Hash(bound = "A: Hash"),
|
||||
PartialEq(bound = "A: PartialEq"),
|
||||
Eq(bound = "A: Eq"),
|
||||
Debug(bound = "A: fmt::Debug")
|
||||
)]
|
||||
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
|
||||
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
|
||||
pub struct OutlivesPredicate<I: Interner, A>(pub A, pub I::Region);
|
||||
|
||||
// FIXME: We manually derive `Lift` because the `derive(Lift_Generic)` doesn't
|
||||
// understand how to turn `A` to `A::Lifted` in the output `type Lifted`.
|
||||
impl<I: Interner, U: Interner, A> Lift<U> for OutlivesPredicate<I, A>
|
||||
where
|
||||
A: Lift<U>,
|
||||
I::Region: Lift<U, Lifted = U::Region>,
|
||||
{
|
||||
type Lifted = OutlivesPredicate<U, A::Lifted>;
|
||||
|
||||
fn lift_to_tcx(self, tcx: U) -> Option<Self::Lifted> {
|
||||
Some(OutlivesPredicate(self.0.lift_to_tcx(tcx)?, self.1.lift_to_tcx(tcx)?))
|
||||
}
|
||||
}
|
||||
|
||||
/// A complete reference to a trait. These take numerous guises in syntax,
|
||||
/// but perhaps the most recognizable form is in a where-clause:
|
||||
|
|
@ -75,6 +103,16 @@ impl<I: Interner> TraitRef<I> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<I: Interner> ty::Binder<I, TraitRef<I>> {
|
||||
pub fn self_ty(&self) -> ty::Binder<I, I::Ty> {
|
||||
self.map_bound_ref(|tr| tr.self_ty())
|
||||
}
|
||||
|
||||
pub fn def_id(&self) -> I::DefId {
|
||||
self.skip_binder().def_id
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(derivative::Derivative)]
|
||||
#[derivative(
|
||||
Clone(bound = ""),
|
||||
|
|
@ -112,6 +150,22 @@ impl<I: Interner> TraitPredicate<I> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<I: Interner> ty::Binder<I, TraitPredicate<I>> {
|
||||
pub fn def_id(self) -> I::DefId {
|
||||
// Ok to skip binder since trait `DefId` does not care about regions.
|
||||
self.skip_binder().def_id()
|
||||
}
|
||||
|
||||
pub fn self_ty(self) -> ty::Binder<I, I::Ty> {
|
||||
self.map_bound(|trait_ref| trait_ref.self_ty())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn polarity(self) -> PredicatePolarity {
|
||||
self.skip_binder().polarity
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner> fmt::Debug for TraitPredicate<I> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// FIXME(effects) printing?
|
||||
|
|
@ -204,6 +258,34 @@ impl<I: Interner> DebugWithInfcx<I> for ExistentialPredicate<I> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<I: Interner> ty::Binder<I, ExistentialPredicate<I>> {
|
||||
/// Given an existential predicate like `?Self: PartialEq<u32>` (e.g., derived from `dyn PartialEq<u32>`),
|
||||
/// and a concrete type `self_ty`, returns a full predicate where the existentially quantified variable `?Self`
|
||||
/// has been replaced with `self_ty` (e.g., `self_ty: PartialEq<u32>`, in our example).
|
||||
pub fn with_self_ty(&self, tcx: I, self_ty: I::Ty) -> I::Clause {
|
||||
match self.skip_binder() {
|
||||
ExistentialPredicate::Trait(tr) => {
|
||||
self.rebind(tr).with_self_ty(tcx, self_ty).upcast(tcx)
|
||||
}
|
||||
ExistentialPredicate::Projection(p) => {
|
||||
self.rebind(p.with_self_ty(tcx, self_ty)).upcast(tcx)
|
||||
}
|
||||
ExistentialPredicate::AutoTrait(did) => {
|
||||
let generics = tcx.generics_of(did);
|
||||
let trait_ref = if generics.count() == 1 {
|
||||
ty::TraitRef::new(tcx, did, [self_ty])
|
||||
} else {
|
||||
// If this is an ill-formed auto trait, then synthesize
|
||||
// new error args for the missing generics.
|
||||
let err_args = GenericArgs::extend_with_error(tcx, did, &[self_ty.into()]);
|
||||
ty::TraitRef::new(tcx, did, err_args)
|
||||
};
|
||||
self.rebind(trait_ref).upcast(tcx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An existential reference to a trait, where `Self` is erased.
|
||||
/// For example, the trait object `Trait<'a, 'b, X, Y>` is:
|
||||
/// ```ignore (illustrative)
|
||||
|
|
@ -253,6 +335,20 @@ impl<I: Interner> ExistentialTraitRef<I> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<I: Interner> ty::Binder<I, ExistentialTraitRef<I>> {
|
||||
pub fn def_id(&self) -> I::DefId {
|
||||
self.skip_binder().def_id
|
||||
}
|
||||
|
||||
/// Object types don't have a self type specified. Therefore, when
|
||||
/// we convert the principal trait-ref into a normal trait-ref,
|
||||
/// you must give *some* self type. A common choice is `mk_err()`
|
||||
/// or some placeholder type.
|
||||
pub fn with_self_ty(&self, tcx: I, self_ty: I::Ty) -> ty::Binder<I, TraitRef<I>> {
|
||||
self.map_bound(|trait_ref| trait_ref.with_self_ty(tcx, self_ty))
|
||||
}
|
||||
}
|
||||
|
||||
/// A `ProjectionPredicate` for an `ExistentialTraitRef`.
|
||||
#[derive(derivative::Derivative)]
|
||||
#[derivative(
|
||||
|
|
@ -308,6 +404,16 @@ impl<I: Interner> ExistentialProjection<I> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<I: Interner> ty::Binder<I, ExistentialProjection<I>> {
|
||||
pub fn with_self_ty(&self, tcx: I, self_ty: I::Ty) -> ty::Binder<I, ProjectionPredicate<I>> {
|
||||
self.map_bound(|p| p.with_self_ty(tcx, self_ty))
|
||||
}
|
||||
|
||||
pub fn item_def_id(&self) -> I::DefId {
|
||||
self.skip_binder().def_id
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||
#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))]
|
||||
pub enum AliasTermKind {
|
||||
|
|
@ -414,7 +520,7 @@ impl<I: Interner> AliasTerm<I> {
|
|||
AliasTerm { def_id, args, _use_alias_term_new_instead: () }
|
||||
}
|
||||
|
||||
pub fn expect_ty(self, interner: I) -> AliasTy<I> {
|
||||
pub fn expect_ty(self, interner: I) -> ty::AliasTy<I> {
|
||||
match self.kind(interner) {
|
||||
AliasTermKind::ProjectionTy
|
||||
| AliasTermKind::InherentTy
|
||||
|
|
@ -424,7 +530,7 @@ impl<I: Interner> AliasTerm<I> {
|
|||
panic!("Cannot turn `UnevaluatedConst` into `AliasTy`")
|
||||
}
|
||||
}
|
||||
AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }
|
||||
ty::AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }
|
||||
}
|
||||
|
||||
pub fn kind(self, interner: I) -> AliasTermKind {
|
||||
|
|
@ -435,32 +541,32 @@ impl<I: Interner> AliasTerm<I> {
|
|||
match self.kind(interner) {
|
||||
AliasTermKind::ProjectionTy => Ty::new_alias(
|
||||
interner,
|
||||
AliasTyKind::Projection,
|
||||
AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
|
||||
ty::AliasTyKind::Projection,
|
||||
ty::AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
|
||||
)
|
||||
.into(),
|
||||
AliasTermKind::InherentTy => Ty::new_alias(
|
||||
interner,
|
||||
AliasTyKind::Inherent,
|
||||
AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
|
||||
ty::AliasTyKind::Inherent,
|
||||
ty::AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
|
||||
)
|
||||
.into(),
|
||||
AliasTermKind::OpaqueTy => Ty::new_alias(
|
||||
interner,
|
||||
AliasTyKind::Opaque,
|
||||
AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
|
||||
ty::AliasTyKind::Opaque,
|
||||
ty::AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
|
||||
)
|
||||
.into(),
|
||||
AliasTermKind::WeakTy => Ty::new_alias(
|
||||
interner,
|
||||
AliasTyKind::Weak,
|
||||
AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
|
||||
ty::AliasTyKind::Weak,
|
||||
ty::AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
|
||||
)
|
||||
.into(),
|
||||
AliasTermKind::UnevaluatedConst | AliasTermKind::ProjectionConst => {
|
||||
I::Const::new_unevaluated(
|
||||
interner,
|
||||
UnevaluatedConst::new(self.def_id, self.args),
|
||||
ty::UnevaluatedConst::new(self.def_id, self.args),
|
||||
interner.type_of_instantiated(self.def_id, self.args),
|
||||
)
|
||||
.into()
|
||||
|
|
@ -514,14 +620,14 @@ impl<I: Interner> AliasTerm<I> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<I: Interner> From<AliasTy<I>> for AliasTerm<I> {
|
||||
fn from(ty: AliasTy<I>) -> Self {
|
||||
impl<I: Interner> From<ty::AliasTy<I>> for AliasTerm<I> {
|
||||
fn from(ty: ty::AliasTy<I>) -> Self {
|
||||
AliasTerm { args: ty.args, def_id: ty.def_id, _use_alias_term_new_instead: () }
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner> From<UnevaluatedConst<I>> for AliasTerm<I> {
|
||||
fn from(ct: UnevaluatedConst<I>) -> Self {
|
||||
impl<I: Interner> From<ty::UnevaluatedConst<I>> for AliasTerm<I> {
|
||||
fn from(ct: ty::UnevaluatedConst<I>) -> Self {
|
||||
AliasTerm { args: ct.args, def_id: ct.def, _use_alias_term_new_instead: () }
|
||||
}
|
||||
}
|
||||
|
|
@ -571,6 +677,40 @@ impl<I: Interner> ProjectionPredicate<I> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<I: Interner> ty::Binder<I, ProjectionPredicate<I>> {
|
||||
/// Returns the `DefId` of the trait of the associated item being projected.
|
||||
#[inline]
|
||||
pub fn trait_def_id(&self, tcx: I) -> I::DefId {
|
||||
self.skip_binder().projection_term.trait_def_id(tcx)
|
||||
}
|
||||
|
||||
/// Get the trait ref required for this projection to be well formed.
|
||||
/// Note that for generic associated types the predicates of the associated
|
||||
/// type also need to be checked.
|
||||
#[inline]
|
||||
pub fn required_poly_trait_ref(&self, tcx: I) -> ty::Binder<I, TraitRef<I>> {
|
||||
// Note: unlike with `TraitRef::to_poly_trait_ref()`,
|
||||
// `self.0.trait_ref` is permitted to have escaping regions.
|
||||
// This is because here `self` has a `Binder` and so does our
|
||||
// return value, so we are preserving the number of binding
|
||||
// levels.
|
||||
self.map_bound(|predicate| predicate.projection_term.trait_ref(tcx))
|
||||
}
|
||||
|
||||
pub fn term(&self) -> ty::Binder<I, I::Term> {
|
||||
self.map_bound(|predicate| predicate.term)
|
||||
}
|
||||
|
||||
/// The `DefId` of the `TraitItem` for the associated type.
|
||||
///
|
||||
/// Note that this is not the `DefId` of the `TraitRef` containing this
|
||||
/// associated type, which is in `tcx.associated_item(projection_def_id()).container`.
|
||||
pub fn projection_def_id(&self) -> I::DefId {
|
||||
// Ok to skip binder since trait `DefId` does not care about regions.
|
||||
self.skip_binder().projection_term.def_id
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner> fmt::Debug for ProjectionPredicate<I> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "ProjectionPredicate({:?}, {:?})", self.projection_term, self.term)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEn
|
|||
use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
|
||||
use std::fmt;
|
||||
|
||||
use crate::Interner;
|
||||
use crate::{self as ty, Interner};
|
||||
|
||||
/// A clause is something that can appear in where bounds or be inferred
|
||||
/// by implied bounds.
|
||||
|
|
@ -15,17 +15,17 @@ pub enum ClauseKind<I: Interner> {
|
|||
/// Corresponds to `where Foo: Bar<A, B, C>`. `Foo` here would be
|
||||
/// the `Self` type of the trait reference and `A`, `B`, and `C`
|
||||
/// would be the type parameters.
|
||||
Trait(I::TraitPredicate),
|
||||
Trait(ty::TraitPredicate<I>),
|
||||
|
||||
/// `where 'a: 'b`
|
||||
RegionOutlives(I::RegionOutlivesPredicate),
|
||||
/// `where 'a: 'r`
|
||||
RegionOutlives(ty::OutlivesPredicate<I, I::Region>),
|
||||
|
||||
/// `where T: 'a`
|
||||
TypeOutlives(I::TypeOutlivesPredicate),
|
||||
/// `where T: 'r`
|
||||
TypeOutlives(ty::OutlivesPredicate<I, I::Ty>),
|
||||
|
||||
/// `where <T as TraitRef>::Name == X`, approximately.
|
||||
/// See the `ProjectionPredicate` struct for details.
|
||||
Projection(I::ProjectionPredicate),
|
||||
Projection(ty::ProjectionPredicate<I>),
|
||||
|
||||
/// Ensures that a const generic argument to a parameter `const N: u8`
|
||||
/// is of type `u8`.
|
||||
|
|
@ -75,7 +75,7 @@ pub enum PredicateKind<I: Interner> {
|
|||
/// This obligation is created most often when we have two
|
||||
/// unresolved type variables and hence don't have enough
|
||||
/// information to process the subtyping obligation yet.
|
||||
Subtype(I::SubtypePredicate),
|
||||
Subtype(ty::SubtypePredicate<I>),
|
||||
|
||||
/// `T1` coerced to `T2`
|
||||
///
|
||||
|
|
@ -85,7 +85,7 @@ pub enum PredicateKind<I: Interner> {
|
|||
/// obligation yet. At the moment, we actually process coercions
|
||||
/// very much like subtyping and don't handle the full coercion
|
||||
/// logic.
|
||||
Coerce(I::CoercePredicate),
|
||||
Coerce(ty::CoercePredicate<I>),
|
||||
|
||||
/// Constants must be equal. The first component is the const that is expected.
|
||||
ConstEquate(I::Const, I::Const),
|
||||
|
|
@ -102,7 +102,7 @@ pub enum PredicateKind<I: Interner> {
|
|||
/// `T as Trait>::Assoc`, `Projection(<T as Trait>::Assoc, ?x)` constrains `?x`
|
||||
/// to `<T as Trait>::Assoc` while `NormalizesTo(<T as Trait>::Assoc, ?x)`
|
||||
/// results in `NoSolution`.
|
||||
NormalizesTo(I::NormalizesTo),
|
||||
NormalizesTo(ty::NormalizesTo<I>),
|
||||
|
||||
/// Separate from `ClauseKind::Projection` which is used for normalization in new solver.
|
||||
/// This predicate requires two terms to be equal to eachother.
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Gen
|
|||
use std::fmt;
|
||||
|
||||
use crate::inherent::*;
|
||||
use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, TraitRef, WithInfcx};
|
||||
use crate::{self as ty, DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx};
|
||||
|
||||
use self::TyKind::*;
|
||||
|
||||
|
|
@ -514,7 +514,7 @@ impl<I: Interner> AliasTy<I> {
|
|||
/// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
|
||||
/// then this function would return a `T: StreamingIterator` trait reference and
|
||||
/// `['a]` as the own args.
|
||||
pub fn trait_ref_and_own_args(self, interner: I) -> (TraitRef<I>, I::OwnItemArgs) {
|
||||
pub fn trait_ref_and_own_args(self, interner: I) -> (ty::TraitRef<I>, I::OwnItemArgs) {
|
||||
debug_assert_eq!(self.kind(interner), AliasTyKind::Projection);
|
||||
interner.trait_ref_and_own_args_for_alias(self.def_id, self.args)
|
||||
}
|
||||
|
|
@ -526,7 +526,7 @@ impl<I: Interner> AliasTy<I> {
|
|||
/// WARNING: This will drop the args for generic associated types
|
||||
/// consider calling [Self::trait_ref_and_own_args] to get those
|
||||
/// as well.
|
||||
pub fn trait_ref(self, interner: I) -> TraitRef<I> {
|
||||
pub fn trait_ref(self, interner: I) -> ty::TraitRef<I> {
|
||||
self.trait_ref_and_own_args(interner).0
|
||||
}
|
||||
}
|
||||
|
|
@ -982,6 +982,49 @@ impl<I: Interner> FnSig<I> {
|
|||
pub fn output(self) -> I::Ty {
|
||||
self.split_inputs_and_output().1
|
||||
}
|
||||
|
||||
pub fn is_fn_trait_compatible(self) -> bool {
|
||||
let FnSig { safety, abi, c_variadic, .. } = self;
|
||||
!c_variadic && safety.is_safe() && abi.is_rust()
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner> ty::Binder<I, FnSig<I>> {
|
||||
#[inline]
|
||||
pub fn inputs(self) -> ty::Binder<I, I::FnInputTys> {
|
||||
self.map_bound(|fn_sig| fn_sig.inputs())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
pub fn input(self, index: usize) -> ty::Binder<I, I::Ty> {
|
||||
self.map_bound(|fn_sig| fn_sig.inputs()[index])
|
||||
}
|
||||
|
||||
pub fn inputs_and_output(self) -> ty::Binder<I, I::Tys> {
|
||||
self.map_bound(|fn_sig| fn_sig.inputs_and_output)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn output(self) -> ty::Binder<I, I::Ty> {
|
||||
self.map_bound(|fn_sig| fn_sig.output())
|
||||
}
|
||||
|
||||
pub fn c_variadic(self) -> bool {
|
||||
self.skip_binder().c_variadic
|
||||
}
|
||||
|
||||
pub fn safety(self) -> I::Safety {
|
||||
self.skip_binder().safety
|
||||
}
|
||||
|
||||
pub fn abi(self) -> I::Abi {
|
||||
self.skip_binder().abi
|
||||
}
|
||||
|
||||
pub fn is_fn_trait_compatible(&self) -> bool {
|
||||
self.skip_binder().is_fn_trait_compatible()
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner> fmt::Debug for FnSig<I> {
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ pub trait TypeVisitor<I: Interner>: Sized {
|
|||
#[cfg(not(feature = "nightly"))]
|
||||
type Result: VisitorResult;
|
||||
|
||||
fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &I::Binder<T>) -> Self::Result {
|
||||
fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
|
||||
t.super_visit_with(self)
|
||||
}
|
||||
|
||||
|
|
@ -376,11 +376,11 @@ impl std::fmt::Debug for HasTypeFlagsVisitor {
|
|||
impl<I: Interner> TypeVisitor<I> for HasTypeFlagsVisitor {
|
||||
type Result = ControlFlow<FoundFlags>;
|
||||
|
||||
fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &I::Binder<T>) -> Self::Result {
|
||||
fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
|
||||
// If we're looking for the HAS_BINDER_VARS flag, check if the
|
||||
// binder has vars. This won't be present in the binder's bound
|
||||
// value, so we need to check here too.
|
||||
if self.flags.intersects(TypeFlags::HAS_BINDER_VARS) && !t.has_no_bound_vars() {
|
||||
if self.flags.intersects(TypeFlags::HAS_BINDER_VARS) && !t.bound_vars().is_empty() {
|
||||
return ControlFlow::Break(FoundFlags);
|
||||
}
|
||||
|
||||
|
|
@ -476,7 +476,7 @@ struct HasEscapingVarsVisitor {
|
|||
impl<I: Interner> TypeVisitor<I> for HasEscapingVarsVisitor {
|
||||
type Result = ControlFlow<FoundEscapingVars>;
|
||||
|
||||
fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &I::Binder<T>) -> Self::Result {
|
||||
fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
|
||||
self.outer_index.shift_in(1);
|
||||
let result = t.super_visit_with(self);
|
||||
self.outer_index.shift_out(1);
|
||||
|
|
|
|||
|
|
@ -40,3 +40,15 @@ compiler-builtins-weak-intrinsics = ["compiler_builtins/weak-intrinsics"]
|
|||
panic_immediate_abort = ["core/panic_immediate_abort"]
|
||||
# Choose algorithms that are optimized for binary size instead of runtime performance
|
||||
optimize_for_size = ["core/optimize_for_size"]
|
||||
|
||||
[lints.rust.unexpected_cfgs]
|
||||
level = "warn"
|
||||
# x.py uses beta cargo, so `check-cfg` entries do not yet take effect
|
||||
# for rust-lang/rust. But for users of `-Zbuild-std` it does.
|
||||
# The unused warning is waiting for rust-lang/cargo#13925 to reach beta.
|
||||
check-cfg = [
|
||||
'cfg(bootstrap)',
|
||||
'cfg(no_global_oom_handling)',
|
||||
'cfg(no_rc)',
|
||||
'cfg(no_sync)',
|
||||
]
|
||||
|
|
|
|||
|
|
@ -36,3 +36,16 @@ optimize_for_size = []
|
|||
# Make `RefCell` store additional debugging information, which is printed out when
|
||||
# a borrow error occurs
|
||||
debug_refcell = []
|
||||
|
||||
[lints.rust.unexpected_cfgs]
|
||||
level = "warn"
|
||||
# x.py uses beta cargo, so `check-cfg` entries do not yet take effect
|
||||
# for rust-lang/rust. But for users of `-Zbuild-std` it does.
|
||||
# The unused warning is waiting for rust-lang/cargo#13925 to reach beta.
|
||||
check-cfg = [
|
||||
'cfg(bootstrap)',
|
||||
'cfg(no_fp_fmt_parse)',
|
||||
'cfg(stdarch_intel_sde)',
|
||||
# This matches `EXTRA_CHECK_CFGS` in `src/bootstrap/src/lib.rs`.
|
||||
'cfg(feature, values(any()))',
|
||||
]
|
||||
|
|
|
|||
|
|
@ -987,7 +987,7 @@ pub const unsafe fn assume(b: bool) {
|
|||
#[unstable(feature = "core_intrinsics", issue = "none")]
|
||||
#[rustc_intrinsic]
|
||||
#[rustc_nounwind]
|
||||
#[cfg_attr(not(bootstrap), miri::intrinsic_fallback_checks_ub)]
|
||||
#[cfg_attr(not(bootstrap), miri::intrinsic_fallback_is_spec)]
|
||||
pub const fn likely(b: bool) -> bool {
|
||||
b
|
||||
}
|
||||
|
|
@ -1007,7 +1007,7 @@ pub const fn likely(b: bool) -> bool {
|
|||
#[unstable(feature = "core_intrinsics", issue = "none")]
|
||||
#[rustc_intrinsic]
|
||||
#[rustc_nounwind]
|
||||
#[cfg_attr(not(bootstrap), miri::intrinsic_fallback_checks_ub)]
|
||||
#[cfg_attr(not(bootstrap), miri::intrinsic_fallback_is_spec)]
|
||||
pub const fn unlikely(b: bool) -> bool {
|
||||
b
|
||||
}
|
||||
|
|
@ -1483,10 +1483,10 @@ extern "rust-intrinsic" {
|
|||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Both the starting and resulting pointer must be either in bounds or one
|
||||
/// byte past the end of an allocated object. If either pointer is out of
|
||||
/// bounds or arithmetic overflow occurs then any further use of the
|
||||
/// returned value will result in undefined behavior.
|
||||
/// If the computed offset is non-zero, then both the starting and resulting pointer must be
|
||||
/// either in bounds or at the end of an allocated object. If either pointer is out
|
||||
/// of bounds or arithmetic overflow occurs then any further use of the returned value will
|
||||
/// result in undefined behavior.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is [`pointer::offset`].
|
||||
#[must_use = "returns a new pointer rather than modifying its argument"]
|
||||
|
|
@ -1502,7 +1502,7 @@ extern "rust-intrinsic" {
|
|||
/// # Safety
|
||||
///
|
||||
/// Unlike the `offset` intrinsic, this intrinsic does not restrict the
|
||||
/// resulting pointer to point into or one byte past the end of an allocated
|
||||
/// resulting pointer to point into or at the end of an allocated
|
||||
/// object, and it wraps with two's complement arithmetic. The resulting
|
||||
/// value is not necessarily valid to be used to actually access memory.
|
||||
///
|
||||
|
|
@ -2483,7 +2483,7 @@ extern "rust-intrinsic" {
|
|||
#[rustc_nounwind]
|
||||
#[rustc_do_not_const_check]
|
||||
#[inline]
|
||||
#[cfg_attr(not(bootstrap), miri::intrinsic_fallback_checks_ub)]
|
||||
#[cfg_attr(not(bootstrap), miri::intrinsic_fallback_is_spec)]
|
||||
pub const fn ptr_guaranteed_cmp<T>(ptr: *const T, other: *const T) -> u8 {
|
||||
(ptr == other) as u8
|
||||
}
|
||||
|
|
@ -2748,7 +2748,7 @@ pub const fn ub_checks() -> bool {
|
|||
#[unstable(feature = "core_intrinsics", issue = "none")]
|
||||
#[rustc_nounwind]
|
||||
#[rustc_intrinsic]
|
||||
#[cfg_attr(not(bootstrap), miri::intrinsic_fallback_checks_ub)]
|
||||
#[cfg_attr(not(bootstrap), miri::intrinsic_fallback_is_spec)]
|
||||
pub const unsafe fn const_allocate(_size: usize, _align: usize) -> *mut u8 {
|
||||
// const eval overrides this function, but runtime code for now just returns null pointers.
|
||||
// See <https://github.com/rust-lang/rust/issues/93935>.
|
||||
|
|
@ -2769,7 +2769,7 @@ pub const unsafe fn const_allocate(_size: usize, _align: usize) -> *mut u8 {
|
|||
#[unstable(feature = "core_intrinsics", issue = "none")]
|
||||
#[rustc_nounwind]
|
||||
#[rustc_intrinsic]
|
||||
#[cfg_attr(not(bootstrap), miri::intrinsic_fallback_checks_ub)]
|
||||
#[cfg_attr(not(bootstrap), miri::intrinsic_fallback_is_spec)]
|
||||
pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {
|
||||
// Runtime NOP
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1476,14 +1476,17 @@ mod prim_usize {}
|
|||
///
|
||||
/// For instance, this means that unsafe code in a safe function may assume these invariants are
|
||||
/// ensured of arguments passed by the caller, and it may assume that these invariants are ensured
|
||||
/// of return values from any safe functions it calls. In most cases, the inverse is also true:
|
||||
/// unsafe code must not violate these invariants when passing arguments to safe functions or
|
||||
/// returning values from safe functions; such violations may result in undefined behavior. Where
|
||||
/// exceptions to this latter requirement exist, they will be called out explicitly in documentation.
|
||||
/// of return values from any safe functions it calls.
|
||||
///
|
||||
/// For the other direction, things are more complicated: when unsafe code passes arguments
|
||||
/// to safe functions or returns values from safe functions, they generally must *at least*
|
||||
/// not violate these invariants. The full requirements are stronger, as the reference generally
|
||||
/// must point to data that is safe to use at type `T`.
|
||||
///
|
||||
/// It is not decided yet whether unsafe code may violate these invariants temporarily on internal
|
||||
/// data. As a consequence, unsafe code which violates these invariants temporarily on internal data
|
||||
/// may become unsound in future versions of Rust depending on how this question is decided.
|
||||
/// may be unsound or become unsound in future versions of Rust depending on how this question is
|
||||
/// decided.
|
||||
///
|
||||
/// [allocated object]: ptr#allocated-object
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
|
|||
|
|
@ -465,8 +465,9 @@ impl<T: ?Sized> *const T {
|
|||
/// If any of the following conditions are violated, the result is Undefined
|
||||
/// Behavior:
|
||||
///
|
||||
/// * Both the starting and resulting pointer must be either in bounds or one
|
||||
/// byte past the end of the same [allocated object].
|
||||
/// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting
|
||||
/// pointer must be either in bounds or at the end of the same [allocated object].
|
||||
/// (If it is zero, then the function is always well-defined.)
|
||||
///
|
||||
/// * The computed offset, **in bytes**, cannot overflow an `isize`.
|
||||
///
|
||||
|
|
@ -676,11 +677,11 @@ impl<T: ?Sized> *const T {
|
|||
/// If any of the following conditions are violated, the result is Undefined
|
||||
/// Behavior:
|
||||
///
|
||||
/// * Both `self` and `origin` must be either in bounds or one
|
||||
/// byte past the end of the same [allocated object].
|
||||
/// * `self` and `origin` must either
|
||||
///
|
||||
/// * Both pointers must be *derived from* a pointer to the same object.
|
||||
/// (See below for an example.)
|
||||
/// * both be *derived from* a pointer to the same [allocated object], and the memory range between
|
||||
/// the two pointers must be either empty or in bounds of that object. (See below for an example.)
|
||||
/// * or both be derived from an integer literal/constant, and point to the same address.
|
||||
///
|
||||
/// * The distance between the pointers, in bytes, must be an exact multiple
|
||||
/// of the size of `T`.
|
||||
|
|
@ -951,8 +952,9 @@ impl<T: ?Sized> *const T {
|
|||
/// If any of the following conditions are violated, the result is Undefined
|
||||
/// Behavior:
|
||||
///
|
||||
/// * Both the starting and resulting pointer must be either in bounds or one
|
||||
/// byte past the end of the same [allocated object].
|
||||
/// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting
|
||||
/// pointer must be either in bounds or at the end of the same [allocated object].
|
||||
/// (If it is zero, then the function is always well-defined.)
|
||||
///
|
||||
/// * The computed offset, **in bytes**, cannot overflow an `isize`.
|
||||
///
|
||||
|
|
@ -1035,8 +1037,9 @@ impl<T: ?Sized> *const T {
|
|||
/// If any of the following conditions are violated, the result is Undefined
|
||||
/// Behavior:
|
||||
///
|
||||
/// * Both the starting and resulting pointer must be either in bounds or one
|
||||
/// byte past the end of the same [allocated object].
|
||||
/// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting
|
||||
/// pointer must be either in bounds or at the end of the same [allocated object].
|
||||
/// (If it is zero, then the function is always well-defined.)
|
||||
///
|
||||
/// * The computed offset cannot exceed `isize::MAX` **bytes**.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -15,18 +15,13 @@
|
|||
//! The precise rules for validity are not determined yet. The guarantees that are
|
||||
//! provided at this point are very minimal:
|
||||
//!
|
||||
//! * A [null] pointer is *never* valid, not even for accesses of [size zero][zst].
|
||||
//! * For operations of [size zero][zst], *every* pointer is valid, including the [null] pointer.
|
||||
//! The following points are only concerned with non-zero-sized accesses.
|
||||
//! * A [null] pointer is *never* valid.
|
||||
//! * For a pointer to be valid, it is necessary, but not always sufficient, that the pointer
|
||||
//! be *dereferenceable*: the memory range of the given size starting at the pointer must all be
|
||||
//! within the bounds of a single allocated object. Note that in Rust,
|
||||
//! every (stack-allocated) variable is considered a separate allocated object.
|
||||
//! * Even for operations of [size zero][zst], the pointer must not be pointing to deallocated
|
||||
//! memory, i.e., deallocation makes pointers invalid even for zero-sized operations. However,
|
||||
//! casting any non-zero integer *literal* to a pointer is valid for zero-sized accesses, even if
|
||||
//! some memory happens to exist at that address and gets deallocated. This corresponds to writing
|
||||
//! your own allocator: allocating zero-sized objects is not very hard. The canonical way to
|
||||
//! obtain a pointer that is valid for zero-sized accesses is [`NonNull::dangling`].
|
||||
//FIXME: mention `ptr::dangling` above, once it is stable.
|
||||
//! * All accesses performed by functions in this module are *non-atomic* in the sense
|
||||
//! of [atomic operations] used to synchronize between threads. This means it is
|
||||
//! undefined behavior to perform two concurrent accesses to the same location from different
|
||||
|
|
|
|||
|
|
@ -480,8 +480,9 @@ impl<T: ?Sized> *mut T {
|
|||
/// If any of the following conditions are violated, the result is Undefined
|
||||
/// Behavior:
|
||||
///
|
||||
/// * Both the starting and resulting pointer must be either in bounds or one
|
||||
/// byte past the end of the same [allocated object].
|
||||
/// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting
|
||||
/// pointer must be either in bounds or at the end of the same [allocated object].
|
||||
/// (If it is zero, then the function is always well-defined.)
|
||||
///
|
||||
/// * The computed offset, **in bytes**, cannot overflow an `isize`.
|
||||
///
|
||||
|
|
@ -904,11 +905,11 @@ impl<T: ?Sized> *mut T {
|
|||
/// If any of the following conditions are violated, the result is Undefined
|
||||
/// Behavior:
|
||||
///
|
||||
/// * Both `self` and `origin` must be either in bounds or one
|
||||
/// byte past the end of the same [allocated object].
|
||||
/// * `self` and `origin` must either
|
||||
///
|
||||
/// * Both pointers must be *derived from* a pointer to the same object.
|
||||
/// (See below for an example.)
|
||||
/// * both be *derived from* a pointer to the same [allocated object], and the memory range between
|
||||
/// the two pointers must be either empty or in bounds of that object. (See below for an example.)
|
||||
/// * or both be derived from an integer literal/constant, and point to the same address.
|
||||
///
|
||||
/// * The distance between the pointers, in bytes, must be an exact multiple
|
||||
/// of the size of `T`.
|
||||
|
|
@ -1095,8 +1096,9 @@ impl<T: ?Sized> *mut T {
|
|||
/// If any of the following conditions are violated, the result is Undefined
|
||||
/// Behavior:
|
||||
///
|
||||
/// * Both the starting and resulting pointer must be either in bounds or one
|
||||
/// byte past the end of the same [allocated object].
|
||||
/// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting
|
||||
/// pointer must be either in bounds or at the end of the same [allocated object].
|
||||
/// (If it is zero, then the function is always well-defined.)
|
||||
///
|
||||
/// * The computed offset, **in bytes**, cannot overflow an `isize`.
|
||||
///
|
||||
|
|
@ -1179,8 +1181,9 @@ impl<T: ?Sized> *mut T {
|
|||
/// If any of the following conditions are violated, the result is Undefined
|
||||
/// Behavior:
|
||||
///
|
||||
/// * Both the starting and resulting pointer must be either in bounds or one
|
||||
/// byte past the end of the same [allocated object].
|
||||
/// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting
|
||||
/// pointer must be either in bounds or at the end of the same [allocated object].
|
||||
/// (If it is zero, then the function is always well-defined.)
|
||||
///
|
||||
/// * The computed offset cannot exceed `isize::MAX` **bytes**.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -97,3 +97,13 @@ heap_size = 0x8000000
|
|||
name = "stdbenches"
|
||||
path = "benches/lib.rs"
|
||||
test = true
|
||||
|
||||
[lints.rust.unexpected_cfgs]
|
||||
level = "warn"
|
||||
check-cfg = [
|
||||
'cfg(bootstrap)',
|
||||
'cfg(backtrace_in_libstd)',
|
||||
'cfg(netbsd10)',
|
||||
'cfg(target_arch, values("xtensa"))',
|
||||
'cfg(feature, values("std", "as_crate"))',
|
||||
]
|
||||
|
|
|
|||
|
|
@ -84,6 +84,9 @@ const EXTRA_CHECK_CFGS: &[(Option<Mode>, &str, Option<&[&'static str]>)] = &[
|
|||
(Some(Mode::ToolRustc), "rust_analyzer", None),
|
||||
(Some(Mode::ToolStd), "rust_analyzer", None),
|
||||
(Some(Mode::Codegen), "parallel_compiler", None),
|
||||
// NOTE: consider updating `check-cfg` entries in `std/Cargo.toml` too.
|
||||
// cfg(bootstrap) remove these once the bootstrap compiler supports
|
||||
// `lints.rust.unexpected_cfgs.check-cfg`
|
||||
(Some(Mode::Std), "stdarch_intel_sde", None),
|
||||
(Some(Mode::Std), "no_fp_fmt_parse", None),
|
||||
(Some(Mode::Std), "no_global_oom_handling", None),
|
||||
|
|
|
|||
|
|
@ -20,10 +20,10 @@
|
|||
- [\*-apple-darwin](platform-support/apple-darwin.md)
|
||||
- [i686-apple-darwin](platform-support/i686-apple-darwin.md)
|
||||
- [x86_64h-apple-darwin](platform-support/x86_64h-apple-darwin.md)
|
||||
- [arm64e-apple-darwin.md](platform-support/arm64e-apple-darwin.md)
|
||||
- [arm64e-apple-darwin](platform-support/arm64e-apple-darwin.md)
|
||||
- [\*-apple-ios](platform-support/apple-ios.md)
|
||||
- [\*-apple-ios-macabi](platform-support/apple-ios-macabi.md)
|
||||
- [arm64e-apple-ios.md](platform-support/arm64e-apple-ios.md)
|
||||
- [arm64e-apple-ios](platform-support/arm64e-apple-ios.md)
|
||||
- [\*-apple-tvos](platform-support/apple-tvos.md)
|
||||
- [\*-apple-watchos](platform-support/apple-watchos.md)
|
||||
- [\*-apple-visionos](platform-support/apple-visionos.md)
|
||||
|
|
|
|||
|
|
@ -344,7 +344,9 @@ pub(crate) fn load_call_locations(
|
|||
Ok(bytes) => bytes,
|
||||
Err(e) => dcx.fatal(format!("failed to load examples: {e}")),
|
||||
};
|
||||
let mut decoder = MemDecoder::new(&bytes, 0);
|
||||
let Ok(mut decoder) = MemDecoder::new(&bytes, 0) else {
|
||||
dcx.fatal(format!("Corrupt metadata encountered in {path}"))
|
||||
};
|
||||
let calls = AllCallLocations::decode(&mut decoder);
|
||||
|
||||
for (function, fn_calls) in calls.into_iter() {
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
b54dd08a84f3c07efbc2aaf63c3df219ae680a03
|
||||
9cdfe285ca724c801dc9f78d22b24ea69b787f26
|
||||
|
|
|
|||
|
|
@ -43,18 +43,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
if this.tcx.intrinsic(instance.def_id()).unwrap().must_be_overridden {
|
||||
throw_unsup_format!("unimplemented intrinsic: `{intrinsic_name}`")
|
||||
}
|
||||
let intrinsic_fallback_checks_ub = Symbol::intern("intrinsic_fallback_checks_ub");
|
||||
let intrinsic_fallback_is_spec = Symbol::intern("intrinsic_fallback_is_spec");
|
||||
if this
|
||||
.tcx
|
||||
.get_attrs_by_path(
|
||||
instance.def_id(),
|
||||
&[sym::miri, intrinsic_fallback_checks_ub],
|
||||
)
|
||||
.get_attrs_by_path(instance.def_id(), &[sym::miri, intrinsic_fallback_is_spec])
|
||||
.next()
|
||||
.is_none()
|
||||
{
|
||||
throw_unsup_format!(
|
||||
"miri can only use intrinsic fallback bodies that check UB. After verifying that `{intrinsic_name}` does so, add the `#[miri::intrinsic_fallback_checks_ub]` attribute to it; also ping @rust-lang/miri when you do that"
|
||||
"Miri can only use intrinsic fallback bodies that exactly reflect the specification: they fully check for UB and are as non-deterministic as possible. After verifying that `{intrinsic_name}` does so, add the `#[miri::intrinsic_fallback_is_spec]` attribute to it; also ping @rust-lang/miri when you do that"
|
||||
);
|
||||
}
|
||||
Ok(Some(ty::Instance {
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
// Make sure we find these even with many checks disabled.
|
||||
//@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation
|
||||
|
||||
fn main() {
|
||||
let p = {
|
||||
let b = Box::new(42);
|
||||
&*b as *const i32 as *const ()
|
||||
};
|
||||
let _x = unsafe { *p }; //~ ERROR: has been freed
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling
|
||||
--> $DIR/dangling_zst_deref.rs:LL:CC
|
||||
|
|
||||
LL | let _x = unsafe { *p };
|
||||
| ^^ memory access failed: ALLOC has been freed, so this pointer is dangling
|
||||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
help: ALLOC was allocated here:
|
||||
--> $DIR/dangling_zst_deref.rs:LL:CC
|
||||
|
|
||||
LL | let b = Box::new(42);
|
||||
| ^^^^^^^^^^^^
|
||||
help: ALLOC was deallocated here:
|
||||
--> $DIR/dangling_zst_deref.rs:LL:CC
|
||||
|
|
||||
LL | };
|
||||
| ^
|
||||
= note: BACKTRACE (of the first span):
|
||||
= note: inside `main` at $DIR/dangling_zst_deref.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
fn main() {
|
||||
// This pointer *could* be NULL so we cannot load from it, not even at ZST
|
||||
let ptr = (&0u8 as *const u8).wrapping_sub(0x800) as *const ();
|
||||
let _x: () = unsafe { *ptr }; //~ ERROR: out-of-bounds
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
error: Undefined Behavior: memory access failed: ALLOC has size 1, so pointer at offset -2048 is out-of-bounds
|
||||
--> $DIR/maybe_null_pointer_deref_zst.rs:LL:CC
|
||||
|
|
||||
LL | let _x: () = unsafe { *ptr };
|
||||
| ^^^^ memory access failed: ALLOC has size 1, so pointer at offset -2048 is out-of-bounds
|
||||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: BACKTRACE:
|
||||
= note: inside `main` at $DIR/maybe_null_pointer_deref_zst.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
fn main() {
|
||||
// This pointer *could* be NULL so we cannot load from it, not even at ZST.
|
||||
// Not using the () type here, as writes of that type do not even have MIR generated.
|
||||
// Also not assigning directly as that's array initialization, not assignment.
|
||||
let zst_val = [1u8; 0];
|
||||
let ptr = (&0u8 as *const u8).wrapping_sub(0x800) as *mut [u8; 0];
|
||||
unsafe { *ptr = zst_val }; //~ ERROR: out-of-bounds
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
error: Undefined Behavior: memory access failed: ALLOC has size 1, so pointer at offset -2048 is out-of-bounds
|
||||
--> $DIR/maybe_null_pointer_write_zst.rs:LL:CC
|
||||
|
|
||||
LL | unsafe { *ptr = zst_val };
|
||||
| ^^^^^^^^^^^^^^ memory access failed: ALLOC has size 1, so pointer at offset -2048 is out-of-bounds
|
||||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: BACKTRACE:
|
||||
= note: inside `main` at $DIR/maybe_null_pointer_write_zst.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
#[allow(deref_nullptr)]
|
||||
fn main() {
|
||||
let x: () = unsafe { *std::ptr::null() }; //~ ERROR: memory access failed: null pointer is a dangling pointer
|
||||
panic!("this should never print: {:?}", x);
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance)
|
||||
--> $DIR/null_pointer_deref_zst.rs:LL:CC
|
||||
|
|
||||
LL | let x: () = unsafe { *std::ptr::null() };
|
||||
| ^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance)
|
||||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: BACKTRACE:
|
||||
= note: inside `main` at $DIR/null_pointer_deref_zst.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
#[allow(deref_nullptr)]
|
||||
fn main() {
|
||||
// Not using the () type here, as writes of that type do not even have MIR generated.
|
||||
// Also not assigning directly as that's array initialization, not assignment.
|
||||
let zst_val = [1u8; 0];
|
||||
unsafe { std::ptr::null_mut::<[u8; 0]>().write(zst_val) };
|
||||
//~^ERROR: memory access failed: null pointer is a dangling pointer
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance)
|
||||
--> $DIR/null_pointer_write_zst.rs:LL:CC
|
||||
|
|
||||
LL | unsafe { std::ptr::null_mut::<[u8; 0]>().write(zst_val) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance)
|
||||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: BACKTRACE:
|
||||
= note: inside `main` at $DIR/null_pointer_write_zst.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
error: unsupported operation: miri can only use intrinsic fallback bodies that check UB. After verifying that `ptr_guaranteed_cmp` does so, add the `#[miri::intrinsic_fallback_checks_ub]` attribute to it; also ping @rust-lang/miri when you do that
|
||||
--> $DIR/intrinsic_fallback_checks_ub.rs:LL:CC
|
||||
|
|
||||
LL | ptr_guaranteed_cmp::<()>(std::ptr::null(), std::ptr::null());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ miri can only use intrinsic fallback bodies that check UB. After verifying that `ptr_guaranteed_cmp` does so, add the `#[miri::intrinsic_fallback_checks_ub]` attribute to it; also ping @rust-lang/miri when you do that
|
||||
|
|
||||
= help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support
|
||||
= note: BACKTRACE:
|
||||
= note: inside `main` at $DIR/intrinsic_fallback_checks_ub.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -10,5 +10,5 @@ pub const fn ptr_guaranteed_cmp<T>(ptr: *const T, other: *const T) -> u8 {
|
|||
|
||||
fn main() {
|
||||
ptr_guaranteed_cmp::<()>(std::ptr::null(), std::ptr::null());
|
||||
//~^ ERROR: can only use intrinsic fallback bodies that check UB.
|
||||
//~^ ERROR: can only use intrinsic fallback bodies that exactly reflect the specification
|
||||
}
|
||||
14
src/tools/miri/tests/fail/intrinsic_fallback_is_spec.stderr
Normal file
14
src/tools/miri/tests/fail/intrinsic_fallback_is_spec.stderr
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
error: unsupported operation: Miri can only use intrinsic fallback bodies that exactly reflect the specification: they fully check for UB and are as non-deterministic as possible. After verifying that `ptr_guaranteed_cmp` does so, add the `#[miri::intrinsic_fallback_is_spec]` attribute to it; also ping @rust-lang/miri when you do that
|
||||
--> $DIR/intrinsic_fallback_is_spec.rs:LL:CC
|
||||
|
|
||||
LL | ptr_guaranteed_cmp::<()>(std::ptr::null(), std::ptr::null());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Miri can only use intrinsic fallback bodies that exactly reflect the specification: they fully check for UB and are as non-deterministic as possible. After verifying that `ptr_guaranteed_cmp` does so, add the `#[miri::intrinsic_fallback_is_spec]` attribute to it; also ping @rust-lang/miri when you do that
|
||||
|
|
||||
= help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support
|
||||
= note: BACKTRACE:
|
||||
= note: inside `main` at $DIR/intrinsic_fallback_is_spec.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
#![feature(intrinsics)]
|
||||
|
||||
// Directly call intrinsic to avoid debug assertions in libstd
|
||||
extern "rust-intrinsic" {
|
||||
fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut data = [0u16; 4];
|
||||
let ptr = &mut data[0] as *mut u16;
|
||||
// Even copying 0 elements from NULL should error.
|
||||
unsafe {
|
||||
copy_nonoverlapping(std::ptr::null(), ptr, 0); //~ ERROR: memory access failed: null pointer is a dangling pointer
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance)
|
||||
--> $DIR/copy_null.rs:LL:CC
|
||||
|
|
||||
LL | copy_nonoverlapping(std::ptr::null(), ptr, 0);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance)
|
||||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: BACKTRACE:
|
||||
= note: inside `main` at $DIR/copy_null.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
//@compile-flags: -Zmiri-permissive-provenance
|
||||
|
||||
#[rustfmt::skip] // fails with "left behind trailing whitespace"
|
||||
fn main() {
|
||||
let x = 0 as *mut i32;
|
||||
let _x = x.wrapping_offset(8); // ok, this has no inbounds tag
|
||||
let _x = unsafe { x.offset(0) }; // UB despite offset 0, NULL is never inbounds
|
||||
//~^ERROR: null pointer is a dangling pointer
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
error: Undefined Behavior: out-of-bounds pointer arithmetic: null pointer is a dangling pointer (it has no provenance)
|
||||
--> $DIR/ptr_offset_0_plus_0.rs:LL:CC
|
||||
|
|
||||
LL | let _x = unsafe { x.offset(0) }; // UB despite offset 0, NULL is never inbounds
|
||||
| ^^^^^^^^^^^ out-of-bounds pointer arithmetic: null pointer is a dangling pointer (it has no provenance)
|
||||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: BACKTRACE:
|
||||
= note: inside `main` at $DIR/ptr_offset_0_plus_0.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
fn main() {
|
||||
let start_ptr = &4 as *const _ as *const u8;
|
||||
let length = 10;
|
||||
let end_ptr = start_ptr.wrapping_add(length);
|
||||
// Even if the offset is 0, a dangling OOB pointer is not allowed.
|
||||
unsafe { end_ptr.offset_from(end_ptr) }; //~ERROR: pointer at offset 10 is out-of-bounds
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue