Compare commits
43 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c043085801 | ||
|
|
8a2c6ea409 | ||
|
|
c7db84b0a3 | ||
|
|
123611f208 | ||
|
|
e53dd52e16 | ||
|
|
e8327b0a79 | ||
|
|
77e29b25d0 | ||
|
|
f7d5a6467d | ||
|
|
8f3bbc1f5a | ||
|
|
9a82b6700a | ||
|
|
9ac3dcd7c9 | ||
|
|
544462ad8b | ||
|
|
ae196c772d | ||
|
|
a544b5df98 | ||
|
|
d5e9f9d67b | ||
|
|
64087bc8ec | ||
|
|
7312ac389f | ||
|
|
dbc2193d37 | ||
|
|
9e38745532 | ||
|
|
b1c72fbb72 | ||
|
|
efbc8957a6 | ||
|
|
b015d5712a | ||
|
|
9eaedddb7f | ||
|
|
d2580fdd58 | ||
|
|
6e65aba9a3 | ||
|
|
ad5108eaad | ||
|
|
626de862a5 | ||
|
|
83ef5059d6 | ||
|
|
195b849ea7 | ||
|
|
257a415e05 | ||
|
|
c73b3d20c6 | ||
|
|
f5421609d6 | ||
|
|
28c8d71544 | ||
|
|
6d4b1b38e7 | ||
|
|
e0d9d470df | ||
|
|
cbfa215893 | ||
|
|
52b19f7dda | ||
|
|
e8b0e6b990 | ||
|
|
3099121bb5 | ||
|
|
b541f1b198 | ||
|
|
bd523647a4 | ||
|
|
71dff62449 | ||
|
|
689e8c2099 |
364 changed files with 2037 additions and 1545 deletions
|
|
@ -1544,8 +1544,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
||||||
Rvalue::Use(operand)
|
Rvalue::Use(operand)
|
||||||
| Rvalue::Repeat(operand, _)
|
| Rvalue::Repeat(operand, _)
|
||||||
| Rvalue::UnaryOp(_ /*un_op*/, operand)
|
| Rvalue::UnaryOp(_ /*un_op*/, operand)
|
||||||
| Rvalue::Cast(_ /*cast_kind*/, operand, _ /*ty*/)
|
| Rvalue::Cast(_ /*cast_kind*/, operand, _ /*ty*/) => {
|
||||||
| Rvalue::ShallowInitBox(operand, _ /*ty*/) => {
|
|
||||||
self.consume_operand(location, (operand, span), state)
|
self.consume_operand(location, (operand, span), state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -297,8 +297,9 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
|
||||||
Rvalue::Use(operand)
|
Rvalue::Use(operand)
|
||||||
| Rvalue::Repeat(operand, _)
|
| Rvalue::Repeat(operand, _)
|
||||||
| Rvalue::UnaryOp(_ /*un_op*/, operand)
|
| Rvalue::UnaryOp(_ /*un_op*/, operand)
|
||||||
| Rvalue::Cast(_ /*cast_kind*/, operand, _ /*ty*/)
|
| Rvalue::Cast(_ /*cast_kind*/, operand, _ /*ty*/) => {
|
||||||
| Rvalue::ShallowInitBox(operand, _ /*ty*/) => self.consume_operand(location, operand),
|
self.consume_operand(location, operand)
|
||||||
|
}
|
||||||
|
|
||||||
&Rvalue::Discriminant(place) => {
|
&Rvalue::Discriminant(place) => {
|
||||||
self.access_place(
|
self.access_place(
|
||||||
|
|
|
||||||
|
|
@ -1004,17 +1004,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rvalue::ShallowInitBox(_operand, ty) => {
|
|
||||||
let trait_ref =
|
|
||||||
ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, span), [*ty]);
|
|
||||||
|
|
||||||
self.prove_trait_ref(
|
|
||||||
trait_ref,
|
|
||||||
location.to_locations(),
|
|
||||||
ConstraintCategory::SizedBound,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Rvalue::Cast(cast_kind, op, ty) => {
|
Rvalue::Cast(cast_kind, op, ty) => {
|
||||||
match *cast_kind {
|
match *cast_kind {
|
||||||
CastKind::PointerCoercion(
|
CastKind::PointerCoercion(
|
||||||
|
|
@ -2231,7 +2220,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
| Rvalue::Ref(..)
|
| Rvalue::Ref(..)
|
||||||
| Rvalue::RawPtr(..)
|
| Rvalue::RawPtr(..)
|
||||||
| Rvalue::Cast(..)
|
| Rvalue::Cast(..)
|
||||||
| Rvalue::ShallowInitBox(..)
|
|
||||||
| Rvalue::BinaryOp(..)
|
| Rvalue::BinaryOp(..)
|
||||||
| Rvalue::CopyForDeref(..)
|
| Rvalue::CopyForDeref(..)
|
||||||
| Rvalue::UnaryOp(..)
|
| Rvalue::UnaryOp(..)
|
||||||
|
|
|
||||||
|
|
@ -902,7 +902,6 @@ fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt:
|
||||||
lval.write_cvalue_transmute(fx, operand);
|
lval.write_cvalue_transmute(fx, operand);
|
||||||
}
|
}
|
||||||
Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in codegen"),
|
Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in codegen"),
|
||||||
Rvalue::ShallowInitBox(..) => bug!("`ShallowInitBox` in codegen"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StatementKind::StorageLive(_)
|
StatementKind::StorageLive(_)
|
||||||
|
|
|
||||||
|
|
@ -710,7 +710,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
OperandRef { val: operand.val, layout, move_annotation: None }
|
OperandRef { val: operand.val, layout, move_annotation: None }
|
||||||
}
|
}
|
||||||
mir::Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in codegen"),
|
mir::Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in codegen"),
|
||||||
mir::Rvalue::ShallowInitBox(..) => bug!("`ShallowInitBox` in codegen"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -646,8 +646,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||||
|
|
||||||
Rvalue::Cast(_, _, _) => {}
|
Rvalue::Cast(_, _, _) => {}
|
||||||
|
|
||||||
Rvalue::ShallowInitBox(_, _) => {}
|
|
||||||
|
|
||||||
Rvalue::UnaryOp(op, operand) => {
|
Rvalue::UnaryOp(op, operand) => {
|
||||||
let ty = operand.ty(self.body, self.tcx);
|
let ty = operand.ty(self.body, self.tcx);
|
||||||
match op {
|
match op {
|
||||||
|
|
|
||||||
|
|
@ -237,8 +237,7 @@ where
|
||||||
Rvalue::Use(operand)
|
Rvalue::Use(operand)
|
||||||
| Rvalue::Repeat(operand, _)
|
| Rvalue::Repeat(operand, _)
|
||||||
| Rvalue::UnaryOp(_, operand)
|
| Rvalue::UnaryOp(_, operand)
|
||||||
| Rvalue::Cast(_, operand, _)
|
| Rvalue::Cast(_, operand, _) => in_operand::<Q, _>(cx, in_local, operand),
|
||||||
| Rvalue::ShallowInitBox(operand, _) => in_operand::<Q, _>(cx, in_local, operand),
|
|
||||||
|
|
||||||
Rvalue::BinaryOp(_, box (lhs, rhs)) => {
|
Rvalue::BinaryOp(_, box (lhs, rhs)) => {
|
||||||
in_operand::<Q, _>(cx, in_local, lhs) || in_operand::<Q, _>(cx, in_local, rhs)
|
in_operand::<Q, _>(cx, in_local, lhs) || in_operand::<Q, _>(cx, in_local, rhs)
|
||||||
|
|
|
||||||
|
|
@ -192,7 +192,6 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
mir::Rvalue::Cast(..)
|
mir::Rvalue::Cast(..)
|
||||||
| mir::Rvalue::ShallowInitBox(..)
|
|
||||||
| mir::Rvalue::Use(..)
|
| mir::Rvalue::Use(..)
|
||||||
| mir::Rvalue::CopyForDeref(..)
|
| mir::Rvalue::CopyForDeref(..)
|
||||||
| mir::Rvalue::ThreadLocalRef(..)
|
| mir::Rvalue::ThreadLocalRef(..)
|
||||||
|
|
|
||||||
|
|
@ -236,7 +236,7 @@ impl<'tcx> CompileTimeInterpCx<'tcx> {
|
||||||
if self.tcx.is_lang_item(def_id, LangItem::PanicDisplay)
|
if self.tcx.is_lang_item(def_id, LangItem::PanicDisplay)
|
||||||
|| self.tcx.is_lang_item(def_id, LangItem::BeginPanic)
|
|| self.tcx.is_lang_item(def_id, LangItem::BeginPanic)
|
||||||
{
|
{
|
||||||
let args = self.copy_fn_args(args);
|
let args = Self::copy_fn_args(args);
|
||||||
// &str or &&str
|
// &str or &&str
|
||||||
assert!(args.len() == 1);
|
assert!(args.len() == 1);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,8 @@ use tracing::{info, instrument, trace};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
CtfeProvenance, FnVal, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, PlaceTy,
|
CtfeProvenance, FnVal, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, PlaceTy,
|
||||||
Projectable, Provenance, ReturnAction, ReturnContinuation, Scalar, StackPopInfo, interp_ok,
|
Projectable, Provenance, ReturnAction, ReturnContinuation, Scalar, interp_ok, throw_ub,
|
||||||
throw_ub, throw_ub_custom,
|
throw_ub_custom,
|
||||||
};
|
};
|
||||||
use crate::enter_trace_span;
|
use crate::enter_trace_span;
|
||||||
use crate::interpret::EnteredTraceSpan;
|
use crate::interpret::EnteredTraceSpan;
|
||||||
|
|
@ -43,25 +43,22 @@ impl<'tcx, Prov: Provenance> FnArg<'tcx, Prov> {
|
||||||
FnArg::InPlace(mplace) => &mplace.layout,
|
FnArg::InPlace(mplace) => &mplace.layout,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|
||||||
/// Make a copy of the given fn_arg. Any `InPlace` are degenerated to copies, no protection of the
|
/// Make a copy of the given fn_arg. Any `InPlace` are degenerated to copies, no protection of the
|
||||||
/// original memory occurs.
|
/// original memory occurs.
|
||||||
pub fn copy_fn_arg(&self, arg: &FnArg<'tcx, M::Provenance>) -> OpTy<'tcx, M::Provenance> {
|
pub fn copy_fn_arg(&self) -> OpTy<'tcx, Prov> {
|
||||||
match arg {
|
match self {
|
||||||
FnArg::Copy(op) => op.clone(),
|
FnArg::Copy(op) => op.clone(),
|
||||||
FnArg::InPlace(mplace) => mplace.clone().into(),
|
FnArg::InPlace(mplace) => mplace.clone().into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||||
/// Make a copy of the given fn_args. Any `InPlace` are degenerated to copies, no protection of the
|
/// Make a copy of the given fn_args. Any `InPlace` are degenerated to copies, no protection of the
|
||||||
/// original memory occurs.
|
/// original memory occurs.
|
||||||
pub fn copy_fn_args(
|
pub fn copy_fn_args(args: &[FnArg<'tcx, M::Provenance>]) -> Vec<OpTy<'tcx, M::Provenance>> {
|
||||||
&self,
|
args.iter().map(|fn_arg| fn_arg.copy_fn_arg()).collect()
|
||||||
args: &[FnArg<'tcx, M::Provenance>],
|
|
||||||
) -> Vec<OpTy<'tcx, M::Provenance>> {
|
|
||||||
args.iter().map(|fn_arg| self.copy_fn_arg(fn_arg)).collect()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function for argument untupling.
|
/// Helper function for argument untupling.
|
||||||
|
|
@ -319,7 +316,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||||
// We work with a copy of the argument for now; if this is in-place argument passing, we
|
// We work with a copy of the argument for now; if this is in-place argument passing, we
|
||||||
// will later protect the source it comes from. This means the callee cannot observe if we
|
// will later protect the source it comes from. This means the callee cannot observe if we
|
||||||
// did in-place of by-copy argument passing, except for pointer equality tests.
|
// did in-place of by-copy argument passing, except for pointer equality tests.
|
||||||
let caller_arg_copy = self.copy_fn_arg(caller_arg);
|
let caller_arg_copy = caller_arg.copy_fn_arg();
|
||||||
if !already_live {
|
if !already_live {
|
||||||
let local = callee_arg.as_local().unwrap();
|
let local = callee_arg.as_local().unwrap();
|
||||||
let meta = caller_arg_copy.meta();
|
let meta = caller_arg_copy.meta();
|
||||||
|
|
@ -616,7 +613,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||||
if let Some(fallback) = M::call_intrinsic(
|
if let Some(fallback) = M::call_intrinsic(
|
||||||
self,
|
self,
|
||||||
instance,
|
instance,
|
||||||
&self.copy_fn_args(args),
|
&Self::copy_fn_args(args),
|
||||||
destination,
|
destination,
|
||||||
target,
|
target,
|
||||||
unwind,
|
unwind,
|
||||||
|
|
@ -703,7 +700,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||||
// An `InPlace` does nothing here, we keep the original receiver intact. We can't
|
// An `InPlace` does nothing here, we keep the original receiver intact. We can't
|
||||||
// really pass the argument in-place anyway, and we are constructing a new
|
// really pass the argument in-place anyway, and we are constructing a new
|
||||||
// `Immediate` receiver.
|
// `Immediate` receiver.
|
||||||
let mut receiver = self.copy_fn_arg(&args[0]);
|
let mut receiver = args[0].copy_fn_arg();
|
||||||
let receiver_place = loop {
|
let receiver_place = loop {
|
||||||
match receiver.layout.ty.kind() {
|
match receiver.layout.ty.kind() {
|
||||||
ty::Ref(..) | ty::RawPtr(..) => {
|
ty::Ref(..) | ty::RawPtr(..) => {
|
||||||
|
|
@ -824,41 +821,50 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||||
with_caller_location: bool,
|
with_caller_location: bool,
|
||||||
) -> InterpResult<'tcx> {
|
) -> InterpResult<'tcx> {
|
||||||
trace!("init_fn_tail_call: {:#?}", fn_val);
|
trace!("init_fn_tail_call: {:#?}", fn_val);
|
||||||
|
|
||||||
// This is the "canonical" implementation of tails calls,
|
// This is the "canonical" implementation of tails calls,
|
||||||
// a pop of the current stack frame, followed by a normal call
|
// a pop of the current stack frame, followed by a normal call
|
||||||
// which pushes a new stack frame, with the return address from
|
// which pushes a new stack frame, with the return address from
|
||||||
// the popped stack frame.
|
// the popped stack frame.
|
||||||
//
|
//
|
||||||
// Note that we are using `pop_stack_frame_raw` and not `return_from_current_stack_frame`,
|
// Note that we cannot use `return_from_current_stack_frame`,
|
||||||
// as the latter "executes" the goto to the return block, but we don't want to,
|
// as that "executes" the goto to the return block, but we don't want to,
|
||||||
// only the tail called function should return to the current return block.
|
// only the tail called function should return to the current return block.
|
||||||
let StackPopInfo { return_action, return_cont, return_place } =
|
|
||||||
self.pop_stack_frame_raw(false, |_this, _return_place| {
|
|
||||||
// This function's return value is just discarded, the tail-callee will fill in the return place instead.
|
|
||||||
interp_ok(())
|
|
||||||
})?;
|
|
||||||
|
|
||||||
assert_eq!(return_action, ReturnAction::Normal);
|
// The arguments need to all be copied since the current stack frame will be removed
|
||||||
|
// before the callee even starts executing.
|
||||||
// Take the "stack pop cleanup" info, and use that to initiate the next call.
|
// FIXME(explicit_tail_calls,#144855): does this match what codegen does?
|
||||||
let ReturnContinuation::Goto { ret, unwind } = return_cont else {
|
let args = args.iter().map(|fn_arg| FnArg::Copy(fn_arg.copy_fn_arg())).collect::<Vec<_>>();
|
||||||
bug!("can't tailcall as root");
|
// Remove the frame from the stack.
|
||||||
|
let frame = self.pop_stack_frame_raw()?;
|
||||||
|
// Remember where this frame would have returned to.
|
||||||
|
let ReturnContinuation::Goto { ret, unwind } = frame.return_cont() else {
|
||||||
|
bug!("can't tailcall as root of the stack");
|
||||||
};
|
};
|
||||||
|
// There's no return value to deal with! Instead, we forward the old return place
|
||||||
|
// to the new function.
|
||||||
// FIXME(explicit_tail_calls):
|
// FIXME(explicit_tail_calls):
|
||||||
// we should check if both caller&callee can/n't unwind,
|
// we should check if both caller&callee can/n't unwind,
|
||||||
// see <https://github.com/rust-lang/rust/pull/113128#issuecomment-1614979803>
|
// see <https://github.com/rust-lang/rust/pull/113128#issuecomment-1614979803>
|
||||||
|
|
||||||
|
// Now push the new stack frame.
|
||||||
self.init_fn_call(
|
self.init_fn_call(
|
||||||
fn_val,
|
fn_val,
|
||||||
(caller_abi, caller_fn_abi),
|
(caller_abi, caller_fn_abi),
|
||||||
args,
|
&*args,
|
||||||
with_caller_location,
|
with_caller_location,
|
||||||
&return_place,
|
frame.return_place(),
|
||||||
ret,
|
ret,
|
||||||
unwind,
|
unwind,
|
||||||
)
|
)?;
|
||||||
|
|
||||||
|
// Finally, clear the local variables. Has to be done after pushing to support
|
||||||
|
// non-scalar arguments.
|
||||||
|
// FIXME(explicit_tail_calls,#144855): revisit this once codegen supports indirect
|
||||||
|
// arguments, to ensure the semantics are compatible.
|
||||||
|
let return_action = self.cleanup_stack_frame(/* unwinding */ false, frame)?;
|
||||||
|
assert_eq!(return_action, ReturnAction::Normal);
|
||||||
|
|
||||||
|
interp_ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn init_drop_in_place_call(
|
pub(super) fn init_drop_in_place_call(
|
||||||
|
|
@ -953,14 +959,18 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||||
// local's value out.
|
// local's value out.
|
||||||
let return_op =
|
let return_op =
|
||||||
self.local_to_op(mir::RETURN_PLACE, None).expect("return place should always be live");
|
self.local_to_op(mir::RETURN_PLACE, None).expect("return place should always be live");
|
||||||
// Do the actual pop + copy.
|
// Remove the frame from the stack.
|
||||||
let stack_pop_info = self.pop_stack_frame_raw(unwinding, |this, return_place| {
|
let frame = self.pop_stack_frame_raw()?;
|
||||||
this.copy_op_allow_transmute(&return_op, return_place)?;
|
// Copy the return value and remember the return continuation.
|
||||||
trace!("return value: {:?}", this.dump_place(return_place));
|
if !unwinding {
|
||||||
interp_ok(())
|
self.copy_op_allow_transmute(&return_op, frame.return_place())?;
|
||||||
})?;
|
trace!("return value: {:?}", self.dump_place(frame.return_place()));
|
||||||
|
}
|
||||||
match stack_pop_info.return_action {
|
let return_cont = frame.return_cont();
|
||||||
|
// Finish popping the stack frame.
|
||||||
|
let return_action = self.cleanup_stack_frame(unwinding, frame)?;
|
||||||
|
// Jump to the next block.
|
||||||
|
match return_action {
|
||||||
ReturnAction::Normal => {}
|
ReturnAction::Normal => {}
|
||||||
ReturnAction::NoJump => {
|
ReturnAction::NoJump => {
|
||||||
// The hook already did everything.
|
// The hook already did everything.
|
||||||
|
|
@ -978,7 +988,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||||
// Normal return, figure out where to jump.
|
// Normal return, figure out where to jump.
|
||||||
if unwinding {
|
if unwinding {
|
||||||
// Follow the unwind edge.
|
// Follow the unwind edge.
|
||||||
match stack_pop_info.return_cont {
|
match return_cont {
|
||||||
ReturnContinuation::Goto { unwind, .. } => {
|
ReturnContinuation::Goto { unwind, .. } => {
|
||||||
// This must be the very last thing that happens, since it can in fact push a new stack frame.
|
// This must be the very last thing that happens, since it can in fact push a new stack frame.
|
||||||
self.unwind_to_block(unwind)
|
self.unwind_to_block(unwind)
|
||||||
|
|
@ -989,7 +999,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Follow the normal return edge.
|
// Follow the normal return edge.
|
||||||
match stack_pop_info.return_cont {
|
match return_cont {
|
||||||
ReturnContinuation::Goto { ret, .. } => self.return_to_block(ret),
|
ReturnContinuation::Goto { ret, .. } => self.return_to_block(ret),
|
||||||
ReturnContinuation::Stop { .. } => {
|
ReturnContinuation::Stop { .. } => {
|
||||||
assert!(
|
assert!(
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ pub use self::operand::{ImmTy, Immediate, OpTy};
|
||||||
pub use self::place::{MPlaceTy, MemPlaceMeta, PlaceTy, Writeable};
|
pub use self::place::{MPlaceTy, MemPlaceMeta, PlaceTy, Writeable};
|
||||||
use self::place::{MemPlace, Place};
|
use self::place::{MemPlace, Place};
|
||||||
pub use self::projection::{OffsetMode, Projectable};
|
pub use self::projection::{OffsetMode, Projectable};
|
||||||
pub use self::stack::{Frame, FrameInfo, LocalState, ReturnContinuation, StackPopInfo};
|
pub use self::stack::{Frame, FrameInfo, LocalState, ReturnContinuation};
|
||||||
pub use self::util::EnteredTraceSpan;
|
pub use self::util::EnteredTraceSpan;
|
||||||
pub(crate) use self::util::create_static_alloc;
|
pub(crate) use self::util::create_static_alloc;
|
||||||
pub use self::validity::{CtfeValidationMode, RangeSet, RefTracking};
|
pub use self::validity::{CtfeValidationMode, RangeSet, RefTracking};
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ pub struct Frame<'tcx, Prov: Provenance = CtfeProvenance, Extra = ()> {
|
||||||
/// and its layout in the caller. This place is to be interpreted relative to the
|
/// and its layout in the caller. This place is to be interpreted relative to the
|
||||||
/// *caller's* stack frame. We use a `PlaceTy` instead of an `MPlaceTy` since this
|
/// *caller's* stack frame. We use a `PlaceTy` instead of an `MPlaceTy` since this
|
||||||
/// avoids having to move *all* return places into Miri's memory.
|
/// avoids having to move *all* return places into Miri's memory.
|
||||||
pub return_place: PlaceTy<'tcx, Prov>,
|
return_place: PlaceTy<'tcx, Prov>,
|
||||||
|
|
||||||
/// The list of locals for this stack frame, stored in order as
|
/// The list of locals for this stack frame, stored in order as
|
||||||
/// `[return_ptr, arguments..., variables..., temporaries...]`.
|
/// `[return_ptr, arguments..., variables..., temporaries...]`.
|
||||||
|
|
@ -127,19 +127,6 @@ pub enum ReturnContinuation {
|
||||||
Stop { cleanup: bool },
|
Stop { cleanup: bool },
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return type of [`InterpCx::pop_stack_frame_raw`].
|
|
||||||
pub struct StackPopInfo<'tcx, Prov: Provenance> {
|
|
||||||
/// Additional information about the action to be performed when returning from the popped
|
|
||||||
/// stack frame.
|
|
||||||
pub return_action: ReturnAction,
|
|
||||||
|
|
||||||
/// [`return_cont`](Frame::return_cont) of the popped stack frame.
|
|
||||||
pub return_cont: ReturnContinuation,
|
|
||||||
|
|
||||||
/// [`return_place`](Frame::return_place) of the popped stack frame.
|
|
||||||
pub return_place: PlaceTy<'tcx, Prov>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// State of a local variable including a memoized layout
|
/// State of a local variable including a memoized layout
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct LocalState<'tcx, Prov: Provenance = CtfeProvenance> {
|
pub struct LocalState<'tcx, Prov: Provenance = CtfeProvenance> {
|
||||||
|
|
@ -292,6 +279,14 @@ impl<'tcx, Prov: Provenance, Extra> Frame<'tcx, Prov, Extra> {
|
||||||
self.instance
|
self.instance
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn return_place(&self) -> &PlaceTy<'tcx, Prov> {
|
||||||
|
&self.return_place
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn return_cont(&self) -> ReturnContinuation {
|
||||||
|
self.return_cont
|
||||||
|
}
|
||||||
|
|
||||||
/// Return the `SourceInfo` of the current instruction.
|
/// Return the `SourceInfo` of the current instruction.
|
||||||
pub fn current_source_info(&self) -> Option<&mir::SourceInfo> {
|
pub fn current_source_info(&self) -> Option<&mir::SourceInfo> {
|
||||||
self.loc.left().map(|loc| self.body.source_info(loc))
|
self.loc.left().map(|loc| self.body.source_info(loc))
|
||||||
|
|
@ -417,35 +412,26 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||||
interp_ok(())
|
interp_ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Low-level helper that pops a stack frame from the stack and returns some information about
|
/// Low-level helper that pops a stack frame from the stack without any cleanup.
|
||||||
/// it.
|
/// This invokes `before_stack_pop`.
|
||||||
///
|
/// After calling this function, you need to deal with the return value, and then
|
||||||
/// This also deallocates locals, if necessary.
|
/// invoke `cleanup_stack_frame`.
|
||||||
/// `copy_ret_val` gets called after the frame has been taken from the stack but before the locals have been deallocated.
|
|
||||||
///
|
|
||||||
/// [`M::before_stack_pop`] and [`M::after_stack_pop`] are called by this function
|
|
||||||
/// automatically.
|
|
||||||
///
|
|
||||||
/// The high-level version of this is `return_from_current_stack_frame`.
|
|
||||||
///
|
|
||||||
/// [`M::before_stack_pop`]: Machine::before_stack_pop
|
|
||||||
/// [`M::after_stack_pop`]: Machine::after_stack_pop
|
|
||||||
pub(super) fn pop_stack_frame_raw(
|
pub(super) fn pop_stack_frame_raw(
|
||||||
&mut self,
|
&mut self,
|
||||||
unwinding: bool,
|
) -> InterpResult<'tcx, Frame<'tcx, M::Provenance, M::FrameExtra>> {
|
||||||
copy_ret_val: impl FnOnce(&mut Self, &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx>,
|
|
||||||
) -> InterpResult<'tcx, StackPopInfo<'tcx, M::Provenance>> {
|
|
||||||
M::before_stack_pop(self)?;
|
M::before_stack_pop(self)?;
|
||||||
let frame =
|
let frame =
|
||||||
self.stack_mut().pop().expect("tried to pop a stack frame, but there were none");
|
self.stack_mut().pop().expect("tried to pop a stack frame, but there were none");
|
||||||
|
interp_ok(frame)
|
||||||
|
}
|
||||||
|
|
||||||
// Copy return value (unless we are unwinding).
|
/// Deallocate local variables in the stack frame, and invoke `after_stack_pop`.
|
||||||
if !unwinding {
|
pub(super) fn cleanup_stack_frame(
|
||||||
copy_ret_val(self, &frame.return_place)?;
|
&mut self,
|
||||||
}
|
unwinding: bool,
|
||||||
|
frame: Frame<'tcx, M::Provenance, M::FrameExtra>,
|
||||||
|
) -> InterpResult<'tcx, ReturnAction> {
|
||||||
let return_cont = frame.return_cont;
|
let return_cont = frame.return_cont;
|
||||||
let return_place = frame.return_place.clone();
|
|
||||||
|
|
||||||
// Cleanup: deallocate locals.
|
// Cleanup: deallocate locals.
|
||||||
// Usually we want to clean up (deallocate locals), but in a few rare cases we don't.
|
// Usually we want to clean up (deallocate locals), but in a few rare cases we don't.
|
||||||
|
|
@ -455,7 +441,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||||
ReturnContinuation::Stop { cleanup, .. } => cleanup,
|
ReturnContinuation::Stop { cleanup, .. } => cleanup,
|
||||||
};
|
};
|
||||||
|
|
||||||
let return_action = if cleanup {
|
if cleanup {
|
||||||
for local in &frame.locals {
|
for local in &frame.locals {
|
||||||
self.deallocate_local(local.value)?;
|
self.deallocate_local(local.value)?;
|
||||||
}
|
}
|
||||||
|
|
@ -466,13 +452,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||||
// Call the machine hook, which determines the next steps.
|
// Call the machine hook, which determines the next steps.
|
||||||
let return_action = M::after_stack_pop(self, frame, unwinding)?;
|
let return_action = M::after_stack_pop(self, frame, unwinding)?;
|
||||||
assert_ne!(return_action, ReturnAction::NoCleanup);
|
assert_ne!(return_action, ReturnAction::NoCleanup);
|
||||||
return_action
|
interp_ok(return_action)
|
||||||
} else {
|
} else {
|
||||||
// We also skip the machine hook when there's no cleanup. This not a real "pop" anyway.
|
// We also skip the machine hook when there's no cleanup. This not a real "pop" anyway.
|
||||||
ReturnAction::NoCleanup
|
interp_ok(ReturnAction::NoCleanup)
|
||||||
};
|
}
|
||||||
|
|
||||||
interp_ok(StackPopInfo { return_action, return_cont, return_place })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// In the current stack frame, mark all locals as live that are not arguments and don't have
|
/// In the current stack frame, mark all locals as live that are not arguments and don't have
|
||||||
|
|
@ -655,7 +639,7 @@ impl<'a, 'tcx: 'a, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||||
let (_idx, callee_abi) = callee_abis.next().unwrap();
|
let (_idx, callee_abi) = callee_abis.next().unwrap();
|
||||||
assert!(self.check_argument_compat(caller_abi, callee_abi)?);
|
assert!(self.check_argument_compat(caller_abi, callee_abi)?);
|
||||||
// FIXME: do we have to worry about in-place argument passing?
|
// FIXME: do we have to worry about in-place argument passing?
|
||||||
let op = self.copy_fn_arg(fn_arg);
|
let op = fn_arg.copy_fn_arg();
|
||||||
let mplace = self.allocate(op.layout, MemoryKind::Stack)?;
|
let mplace = self.allocate(op.layout, MemoryKind::Stack)?;
|
||||||
self.copy_op(&op, &mplace)?;
|
self.copy_op(&op, &mplace)?;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -249,12 +249,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||||
self.write_immediate(*val, &dest)?;
|
self.write_immediate(*val, &dest)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShallowInitBox(ref operand, _) => {
|
|
||||||
let src = self.eval_operand(operand, None)?;
|
|
||||||
let v = self.read_immediate(&src)?;
|
|
||||||
self.write_immediate(*v, &dest)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Cast(cast_kind, ref operand, cast_ty) => {
|
Cast(cast_kind, ref operand, cast_ty) => {
|
||||||
let src = self.eval_operand(operand, None)?;
|
let src = self.eval_operand(operand, None)?;
|
||||||
let cast_ty =
|
let cast_ty =
|
||||||
|
|
|
||||||
|
|
@ -647,13 +647,8 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// This is not CTFE, so it's Miri with recursive checking.
|
// This is not CTFE, so it's Miri with recursive checking.
|
||||||
// FIXME: we do *not* check behind boxes, since creating a new box first creates it uninitialized
|
// FIXME: should we also `UnsafeCell` behind shared references? Currently that is not
|
||||||
// and then puts the value in there, so briefly we have a box with uninit contents.
|
|
||||||
// FIXME: should we also skip `UnsafeCell` behind shared references? Currently that is not
|
|
||||||
// needed since validation reads bypass Stacked Borrows and data race checks.
|
// needed since validation reads bypass Stacked Borrows and data race checks.
|
||||||
if matches!(ptr_kind, PointerKind::Box) {
|
|
||||||
return interp_ok(());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let path = &self.path;
|
let path = &self.path;
|
||||||
ref_tracking.track(place, || {
|
ref_tracking.track(place, || {
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,11 @@ use std::any::Any;
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::path::Component::Prefix;
|
use std::path::Component::Prefix;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::PathBuf;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use rustc_ast::attr::MarkedAttrs;
|
use rustc_ast::attr::MarkedAttrs;
|
||||||
use rustc_ast::token::MetaVarKind;
|
|
||||||
use rustc_ast::tokenstream::TokenStream;
|
use rustc_ast::tokenstream::TokenStream;
|
||||||
use rustc_ast::visit::{AssocCtxt, Visitor};
|
use rustc_ast::visit::{AssocCtxt, Visitor};
|
||||||
use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind, Safety};
|
use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind, Safety};
|
||||||
|
|
@ -22,14 +21,14 @@ use rustc_hir::limit::Limit;
|
||||||
use rustc_hir::{Stability, find_attr};
|
use rustc_hir::{Stability, find_attr};
|
||||||
use rustc_lint_defs::RegisteredTools;
|
use rustc_lint_defs::RegisteredTools;
|
||||||
use rustc_parse::MACRO_ARGUMENTS;
|
use rustc_parse::MACRO_ARGUMENTS;
|
||||||
use rustc_parse::parser::{AllowConstBlockItems, ForceCollect, Parser};
|
use rustc_parse::parser::Parser;
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_session::parse::ParseSess;
|
use rustc_session::parse::ParseSess;
|
||||||
use rustc_span::def_id::{CrateNum, DefId, LocalDefId};
|
use rustc_span::def_id::{CrateNum, DefId, LocalDefId};
|
||||||
use rustc_span::edition::Edition;
|
use rustc_span::edition::Edition;
|
||||||
use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId, MacroKind};
|
use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId, MacroKind};
|
||||||
use rustc_span::source_map::SourceMap;
|
use rustc_span::source_map::SourceMap;
|
||||||
use rustc_span::{DUMMY_SP, FileName, Ident, Span, Symbol, kw, sym};
|
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw};
|
||||||
use smallvec::{SmallVec, smallvec};
|
use smallvec::{SmallVec, smallvec};
|
||||||
use thin_vec::ThinVec;
|
use thin_vec::ThinVec;
|
||||||
|
|
||||||
|
|
@ -1421,80 +1420,3 @@ pub fn resolve_path(sess: &Session, path: impl Into<PathBuf>, span: Span) -> PRe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If this item looks like a specific enums from `rental`, emit a fatal error.
|
|
||||||
/// See #73345 and #83125 for more details.
|
|
||||||
/// FIXME(#73933): Remove this eventually.
|
|
||||||
fn pretty_printing_compatibility_hack(item: &Item, psess: &ParseSess) {
|
|
||||||
if let ast::ItemKind::Enum(ident, _, enum_def) = &item.kind
|
|
||||||
&& ident.name == sym::ProceduralMasqueradeDummyType
|
|
||||||
&& let [variant] = &*enum_def.variants
|
|
||||||
&& variant.ident.name == sym::Input
|
|
||||||
&& let FileName::Real(real) = psess.source_map().span_to_filename(ident.span)
|
|
||||||
&& let Some(c) = real
|
|
||||||
.local_path()
|
|
||||||
.unwrap_or(Path::new(""))
|
|
||||||
.components()
|
|
||||||
.flat_map(|c| c.as_os_str().to_str())
|
|
||||||
.find(|c| c.starts_with("rental") || c.starts_with("allsorts-rental"))
|
|
||||||
{
|
|
||||||
let crate_matches = if c.starts_with("allsorts-rental") {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
let mut version = c.trim_start_matches("rental-").split('.');
|
|
||||||
version.next() == Some("0")
|
|
||||||
&& version.next() == Some("5")
|
|
||||||
&& version.next().and_then(|c| c.parse::<u32>().ok()).is_some_and(|v| v < 6)
|
|
||||||
};
|
|
||||||
|
|
||||||
if crate_matches {
|
|
||||||
psess.dcx().emit_fatal(errors::ProcMacroBackCompat {
|
|
||||||
crate_name: "rental".to_string(),
|
|
||||||
fixed_version: "0.5.6".to_string(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn ann_pretty_printing_compatibility_hack(ann: &Annotatable, psess: &ParseSess) {
|
|
||||||
let item = match ann {
|
|
||||||
Annotatable::Item(item) => item,
|
|
||||||
Annotatable::Stmt(stmt) => match &stmt.kind {
|
|
||||||
ast::StmtKind::Item(item) => item,
|
|
||||||
_ => return,
|
|
||||||
},
|
|
||||||
_ => return,
|
|
||||||
};
|
|
||||||
pretty_printing_compatibility_hack(item, psess)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn stream_pretty_printing_compatibility_hack(
|
|
||||||
kind: MetaVarKind,
|
|
||||||
stream: &TokenStream,
|
|
||||||
psess: &ParseSess,
|
|
||||||
) {
|
|
||||||
let item = match kind {
|
|
||||||
MetaVarKind::Item => {
|
|
||||||
let mut parser = Parser::new(psess, stream.clone(), None);
|
|
||||||
// No need to collect tokens for this simple check.
|
|
||||||
parser
|
|
||||||
.parse_item(ForceCollect::No, AllowConstBlockItems::No)
|
|
||||||
.expect("failed to reparse item")
|
|
||||||
.expect("an actual item")
|
|
||||||
}
|
|
||||||
MetaVarKind::Stmt => {
|
|
||||||
let mut parser = Parser::new(psess, stream.clone(), None);
|
|
||||||
// No need to collect tokens for this simple check.
|
|
||||||
let stmt = parser
|
|
||||||
.parse_stmt(ForceCollect::No)
|
|
||||||
.expect("failed to reparse")
|
|
||||||
.expect("an actual stmt");
|
|
||||||
match &stmt.kind {
|
|
||||||
ast::StmtKind::Item(item) => item.clone(),
|
|
||||||
_ => return,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => return,
|
|
||||||
};
|
|
||||||
pretty_printing_compatibility_hack(&item, psess)
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -446,18 +446,6 @@ pub(crate) struct GlobDelegationTraitlessQpath {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
// This used to be the `proc_macro_back_compat` lint (#83125). It was later
|
|
||||||
// turned into a hard error.
|
|
||||||
#[derive(Diagnostic)]
|
|
||||||
#[diag("using an old version of `{$crate_name}`")]
|
|
||||||
#[note(
|
|
||||||
"older versions of the `{$crate_name}` crate no longer compile; please update to `{$crate_name}` v{$fixed_version}, or switch to one of the `{$crate_name}` alternatives"
|
|
||||||
)]
|
|
||||||
pub(crate) struct ProcMacroBackCompat {
|
|
||||||
pub crate_name: String,
|
|
||||||
pub fixed_version: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) use metavar_exprs::*;
|
pub(crate) use metavar_exprs::*;
|
||||||
mod metavar_exprs {
|
mod metavar_exprs {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
||||||
|
|
@ -105,11 +105,6 @@ impl MultiItemModifier for DeriveProcMacro {
|
||||||
// (e.g. `fn foo() { #[derive(Debug)] struct Bar; }`)
|
// (e.g. `fn foo() { #[derive(Debug)] struct Bar; }`)
|
||||||
let is_stmt = matches!(item, Annotatable::Stmt(..));
|
let is_stmt = matches!(item, Annotatable::Stmt(..));
|
||||||
|
|
||||||
// We used to have an alternative behaviour for crates that needed it.
|
|
||||||
// We had a lint for a long time, but now we just emit a hard error.
|
|
||||||
// Eventually we might remove the special case hard error check
|
|
||||||
// altogether. See #73345.
|
|
||||||
crate::base::ann_pretty_printing_compatibility_hack(&item, &ecx.sess.psess);
|
|
||||||
let input = item.to_tokens();
|
let input = item.to_tokens();
|
||||||
|
|
||||||
let invoc_id = ecx.current_expansion.id;
|
let invoc_id = ecx.current_expansion.id;
|
||||||
|
|
|
||||||
|
|
@ -103,8 +103,8 @@ impl ToInternal<token::LitKind> for LitKind {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStream, Span, Symbol>> {
|
impl FromInternal<TokenStream> for Vec<TokenTree<TokenStream, Span, Symbol>> {
|
||||||
fn from_internal((stream, rustc): (TokenStream, &mut Rustc<'_, '_>)) -> Self {
|
fn from_internal(stream: TokenStream) -> Self {
|
||||||
use rustc_ast::token::*;
|
use rustc_ast::token::*;
|
||||||
|
|
||||||
// Estimate the capacity as `stream.len()` rounded up to the next power
|
// Estimate the capacity as `stream.len()` rounded up to the next power
|
||||||
|
|
@ -115,22 +115,6 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
|
||||||
while let Some(tree) = iter.next() {
|
while let Some(tree) = iter.next() {
|
||||||
let (Token { kind, span }, joint) = match tree.clone() {
|
let (Token { kind, span }, joint) = match tree.clone() {
|
||||||
tokenstream::TokenTree::Delimited(span, _, mut delim, mut stream) => {
|
tokenstream::TokenTree::Delimited(span, _, mut delim, mut stream) => {
|
||||||
// We used to have an alternative behaviour for crates that
|
|
||||||
// needed it: a hack used to pass AST fragments to
|
|
||||||
// attribute and derive macros as a single nonterminal
|
|
||||||
// token instead of a token stream. Such token needs to be
|
|
||||||
// "unwrapped" and not represented as a delimited group. We
|
|
||||||
// had a lint for a long time, but now we just emit a hard
|
|
||||||
// error. Eventually we might remove the special case hard
|
|
||||||
// error check altogether. See #73345.
|
|
||||||
if let Delimiter::Invisible(InvisibleOrigin::MetaVar(kind)) = delim {
|
|
||||||
crate::base::stream_pretty_printing_compatibility_hack(
|
|
||||||
kind,
|
|
||||||
&stream,
|
|
||||||
rustc.psess(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// In `mk_delimited` we avoid nesting invisible delimited
|
// In `mk_delimited` we avoid nesting invisible delimited
|
||||||
// of the same `MetaVarKind`. Here we do the same but
|
// of the same `MetaVarKind`. Here we do the same but
|
||||||
// ignore the `MetaVarKind` because it is discarded when we
|
// ignore the `MetaVarKind` because it is discarded when we
|
||||||
|
|
@ -687,7 +671,7 @@ impl server::Server for Rustc<'_, '_> {
|
||||||
&mut self,
|
&mut self,
|
||||||
stream: Self::TokenStream,
|
stream: Self::TokenStream,
|
||||||
) -> Vec<TokenTree<Self::TokenStream, Self::Span, Self::Symbol>> {
|
) -> Vec<TokenTree<Self::TokenStream, Self::Span, Self::Symbol>> {
|
||||||
FromInternal::from_internal((stream, self))
|
FromInternal::from_internal(stream)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn span_debug(&mut self, span: Self::Span) -> String {
|
fn span_debug(&mut self, span: Self::Span) -> String {
|
||||||
|
|
|
||||||
|
|
@ -1208,7 +1208,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||||
rustc_intrinsic_const_stable_indirect, Normal,
|
rustc_intrinsic_const_stable_indirect, Normal,
|
||||||
template!(Word), WarnFollowing, EncodeCrossCrate::No, "this is an internal implementation detail",
|
template!(Word), WarnFollowing, EncodeCrossCrate::No, "this is an internal implementation detail",
|
||||||
),
|
),
|
||||||
gated!(
|
rustc_attr!(
|
||||||
rustc_allow_const_fn_unstable, Normal,
|
rustc_allow_const_fn_unstable, Normal,
|
||||||
template!(Word, List: &["feat1, feat2, ..."]), DuplicatesOk, EncodeCrossCrate::No,
|
template!(Word, List: &["feat1, feat2, ..."]), DuplicatesOk, EncodeCrossCrate::No,
|
||||||
"rustc_allow_const_fn_unstable side-steps feature gating and stability checks"
|
"rustc_allow_const_fn_unstable side-steps feature gating and stability checks"
|
||||||
|
|
|
||||||
|
|
@ -287,10 +287,6 @@ declare_features! (
|
||||||
(internal, panic_runtime, "1.10.0", Some(32837)),
|
(internal, panic_runtime, "1.10.0", Some(32837)),
|
||||||
/// Allows using pattern types.
|
/// Allows using pattern types.
|
||||||
(internal, pattern_types, "1.79.0", Some(123646)),
|
(internal, pattern_types, "1.79.0", Some(123646)),
|
||||||
/// Allows using `#[rustc_allow_const_fn_unstable]`.
|
|
||||||
/// This is an attribute on `const fn` for the same
|
|
||||||
/// purpose as `#[allow_internal_unstable]`.
|
|
||||||
(internal, rustc_allow_const_fn_unstable, "1.49.0", Some(69399)),
|
|
||||||
/// Allows using compiler's own crates.
|
/// Allows using compiler's own crates.
|
||||||
(unstable, rustc_private, "1.0.0", Some(27812)),
|
(unstable, rustc_private, "1.0.0", Some(27812)),
|
||||||
/// Allows using internal rustdoc features like `doc(keyword)`.
|
/// Allows using internal rustdoc features like `doc(keyword)`.
|
||||||
|
|
@ -493,7 +489,7 @@ declare_features! (
|
||||||
/// Allows the use of `#[ffi_pure]` on foreign functions.
|
/// Allows the use of `#[ffi_pure]` on foreign functions.
|
||||||
(unstable, ffi_pure, "1.45.0", Some(58329)),
|
(unstable, ffi_pure, "1.45.0", Some(58329)),
|
||||||
/// Allows marking trait functions as `final` to prevent overriding impls
|
/// Allows marking trait functions as `final` to prevent overriding impls
|
||||||
(unstable, final_associated_functions, "CURRENT_RUSTC_VERSION", Some(1)),
|
(unstable, final_associated_functions, "CURRENT_RUSTC_VERSION", Some(131179)),
|
||||||
/// Controlling the behavior of fmt::Debug
|
/// Controlling the behavior of fmt::Debug
|
||||||
(unstable, fmt_debug, "1.82.0", Some(129709)),
|
(unstable, fmt_debug, "1.82.0", Some(129709)),
|
||||||
/// Allows using `#[align(...)]` on function items
|
/// Allows using `#[align(...)]` on function items
|
||||||
|
|
|
||||||
|
|
@ -322,7 +322,7 @@ impl<'tcx> CleanVisitor<'tcx> {
|
||||||
if let Some(def_id) = dep_node.extract_def_id(self.tcx) {
|
if let Some(def_id) = dep_node.extract_def_id(self.tcx) {
|
||||||
format!("{:?}({})", dep_node.kind, self.tcx.def_path_str(def_id))
|
format!("{:?}({})", dep_node.kind, self.tcx.def_path_str(def_id))
|
||||||
} else {
|
} else {
|
||||||
format!("{:?}({:?})", dep_node.kind, dep_node.hash)
|
format!("{:?}({:?})", dep_node.kind, dep_node.key_fingerprint)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
//! This module defines the [`DepNode`] type which the compiler uses to represent
|
//! This module defines the [`DepNode`] type which the compiler uses to represent
|
||||||
//! nodes in the [dependency graph]. A `DepNode` consists of a [`DepKind`] (which
|
//! nodes in the [dependency graph]. A `DepNode` consists of a [`DepKind`] (which
|
||||||
//! specifies the kind of thing it represents, like a piece of HIR, MIR, etc.)
|
//! specifies the kind of thing it represents, like a piece of HIR, MIR, etc.)
|
||||||
//! and a [`Fingerprint`], a 128-bit hash value, the exact meaning of which
|
//! and a "key fingerprint", a 128-bit hash value, the exact meaning of which
|
||||||
//! depends on the node's `DepKind`. Together, the kind and the fingerprint
|
//! depends on the node's `DepKind`. Together, the kind and the key fingerprint
|
||||||
//! fully identify a dependency node, even across multiple compilation sessions.
|
//! fully identify a dependency node, even across multiple compilation sessions.
|
||||||
//! In other words, the value of the fingerprint does not depend on anything
|
//! In other words, the value of the key fingerprint does not depend on anything
|
||||||
//! that is specific to a given compilation session, like an unpredictable
|
//! that is specific to a given compilation session, like an unpredictable
|
||||||
//! interning key (e.g., `NodeId`, `DefId`, `Symbol`) or the numeric value of a
|
//! interning key (e.g., `NodeId`, `DefId`, `Symbol`) or the numeric value of a
|
||||||
//! pointer. The concept behind this could be compared to how git commit hashes
|
//! pointer. The concept behind this could be compared to how git commit hashes
|
||||||
|
|
@ -41,17 +41,9 @@
|
||||||
//! `DepNode`s could represent global concepts with only one value.
|
//! `DepNode`s could represent global concepts with only one value.
|
||||||
//! * Whether it is possible, in principle, to reconstruct a query key from a
|
//! * Whether it is possible, in principle, to reconstruct a query key from a
|
||||||
//! given `DepNode`. Many `DepKind`s only require a single `DefId` parameter,
|
//! given `DepNode`. Many `DepKind`s only require a single `DefId` parameter,
|
||||||
//! in which case it is possible to map the node's fingerprint back to the
|
//! in which case it is possible to map the node's key fingerprint back to the
|
||||||
//! `DefId` it was computed from. In other cases, too much information gets
|
//! `DefId` it was computed from. In other cases, too much information gets
|
||||||
//! lost during fingerprint computation.
|
//! lost when computing a key fingerprint.
|
||||||
//!
|
|
||||||
//! `make_compile_codegen_unit` and `make_compile_mono_items`, together with
|
|
||||||
//! `DepNode::new()`, ensure that only valid `DepNode` instances can be
|
|
||||||
//! constructed. For example, the API does not allow for constructing
|
|
||||||
//! parameterless `DepNode`s with anything other than a zeroed out fingerprint.
|
|
||||||
//! More generally speaking, it relieves the user of the `DepNode` API of
|
|
||||||
//! having to know how to compute the expected fingerprint for a given set of
|
|
||||||
//! node parameters.
|
|
||||||
//!
|
//!
|
||||||
//! [dependency graph]: https://rustc-dev-guide.rust-lang.org/query.html
|
//! [dependency graph]: https://rustc-dev-guide.rust-lang.org/query.html
|
||||||
|
|
||||||
|
|
@ -65,7 +57,7 @@ use rustc_hir::definitions::DefPathHash;
|
||||||
use rustc_macros::{Decodable, Encodable};
|
use rustc_macros::{Decodable, Encodable};
|
||||||
use rustc_span::Symbol;
|
use rustc_span::Symbol;
|
||||||
|
|
||||||
use super::{FingerprintStyle, SerializedDepNodeIndex};
|
use super::{KeyFingerprintStyle, SerializedDepNodeIndex};
|
||||||
use crate::ich::StableHashingContext;
|
use crate::ich::StableHashingContext;
|
||||||
use crate::mir::mono::MonoItem;
|
use crate::mir::mono::MonoItem;
|
||||||
use crate::ty::{TyCtxt, tls};
|
use crate::ty::{TyCtxt, tls};
|
||||||
|
|
@ -125,10 +117,20 @@ impl fmt::Debug for DepKind {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Combination of a [`DepKind`] and a key fingerprint that uniquely identifies
|
||||||
|
/// a node in the dep graph.
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub struct DepNode {
|
pub struct DepNode {
|
||||||
pub kind: DepKind,
|
pub kind: DepKind,
|
||||||
pub hash: PackedFingerprint,
|
|
||||||
|
/// This is _typically_ a hash of the query key, but sometimes not.
|
||||||
|
///
|
||||||
|
/// For example, `anon` nodes have a fingerprint that is derived from their
|
||||||
|
/// dependencies instead of a key.
|
||||||
|
///
|
||||||
|
/// In some cases the key value can be reconstructed from this fingerprint;
|
||||||
|
/// see [`KeyFingerprintStyle`].
|
||||||
|
pub key_fingerprint: PackedFingerprint,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DepNode {
|
impl DepNode {
|
||||||
|
|
@ -136,24 +138,23 @@ impl DepNode {
|
||||||
/// that the DepNode corresponding to the given DepKind actually
|
/// that the DepNode corresponding to the given DepKind actually
|
||||||
/// does not require any parameters.
|
/// does not require any parameters.
|
||||||
pub fn new_no_params<'tcx>(tcx: TyCtxt<'tcx>, kind: DepKind) -> DepNode {
|
pub fn new_no_params<'tcx>(tcx: TyCtxt<'tcx>, kind: DepKind) -> DepNode {
|
||||||
debug_assert_eq!(tcx.fingerprint_style(kind), FingerprintStyle::Unit);
|
debug_assert_eq!(tcx.key_fingerprint_style(kind), KeyFingerprintStyle::Unit);
|
||||||
DepNode { kind, hash: Fingerprint::ZERO.into() }
|
DepNode { kind, key_fingerprint: Fingerprint::ZERO.into() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn construct<'tcx, Key>(tcx: TyCtxt<'tcx>, kind: DepKind, arg: &Key) -> DepNode
|
pub fn construct<'tcx, Key>(tcx: TyCtxt<'tcx>, kind: DepKind, key: &Key) -> DepNode
|
||||||
where
|
where
|
||||||
Key: DepNodeKey<'tcx>,
|
Key: DepNodeKey<'tcx>,
|
||||||
{
|
{
|
||||||
let hash = arg.to_fingerprint(tcx);
|
let dep_node = DepNode { kind, key_fingerprint: key.to_fingerprint(tcx).into() };
|
||||||
let dep_node = DepNode { kind, hash: hash.into() };
|
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
{
|
{
|
||||||
if !tcx.fingerprint_style(kind).reconstructible()
|
if !tcx.key_fingerprint_style(kind).reconstructible()
|
||||||
&& (tcx.sess.opts.unstable_opts.incremental_info
|
&& (tcx.sess.opts.unstable_opts.incremental_info
|
||||||
|| tcx.sess.opts.unstable_opts.query_dep_graph)
|
|| tcx.sess.opts.unstable_opts.query_dep_graph)
|
||||||
{
|
{
|
||||||
tcx.dep_graph.register_dep_node_debug_str(dep_node, || arg.to_debug_str(tcx));
|
tcx.dep_graph.register_dep_node_debug_str(dep_node, || key.to_debug_str(tcx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -168,8 +169,8 @@ impl DepNode {
|
||||||
def_path_hash: DefPathHash,
|
def_path_hash: DefPathHash,
|
||||||
kind: DepKind,
|
kind: DepKind,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
debug_assert!(tcx.fingerprint_style(kind) == FingerprintStyle::DefPathHash);
|
debug_assert!(tcx.key_fingerprint_style(kind) == KeyFingerprintStyle::DefPathHash);
|
||||||
DepNode { kind, hash: def_path_hash.0.into() }
|
DepNode { kind, key_fingerprint: def_path_hash.0.into() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -184,10 +185,10 @@ impl fmt::Debug for DepNode {
|
||||||
} else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(*self) {
|
} else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(*self) {
|
||||||
write!(f, "{s}")?;
|
write!(f, "{s}")?;
|
||||||
} else {
|
} else {
|
||||||
write!(f, "{}", self.hash)?;
|
write!(f, "{}", self.key_fingerprint)?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
write!(f, "{}", self.hash)?;
|
write!(f, "{}", self.key_fingerprint)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
|
|
@ -198,7 +199,7 @@ impl fmt::Debug for DepNode {
|
||||||
|
|
||||||
/// Trait for query keys as seen by dependency-node tracking.
|
/// Trait for query keys as seen by dependency-node tracking.
|
||||||
pub trait DepNodeKey<'tcx>: fmt::Debug + Sized {
|
pub trait DepNodeKey<'tcx>: fmt::Debug + Sized {
|
||||||
fn fingerprint_style() -> FingerprintStyle;
|
fn key_fingerprint_style() -> KeyFingerprintStyle;
|
||||||
|
|
||||||
/// This method turns a query key into an opaque `Fingerprint` to be used
|
/// This method turns a query key into an opaque `Fingerprint` to be used
|
||||||
/// in `DepNode`.
|
/// in `DepNode`.
|
||||||
|
|
@ -212,7 +213,7 @@ pub trait DepNodeKey<'tcx>: fmt::Debug + Sized {
|
||||||
/// `fingerprint_style()` is not `FingerprintStyle::Opaque`.
|
/// `fingerprint_style()` is not `FingerprintStyle::Opaque`.
|
||||||
/// It is always valid to return `None` here, in which case incremental
|
/// It is always valid to return `None` here, in which case incremental
|
||||||
/// compilation will treat the query as having changed instead of forcing it.
|
/// compilation will treat the query as having changed instead of forcing it.
|
||||||
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self>;
|
fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Blanket impl of `DepNodeKey`, which is specialized by other impls elsewhere.
|
// Blanket impl of `DepNodeKey`, which is specialized by other impls elsewhere.
|
||||||
|
|
@ -221,8 +222,8 @@ where
|
||||||
T: for<'a> HashStable<StableHashingContext<'a>> + fmt::Debug,
|
T: for<'a> HashStable<StableHashingContext<'a>> + fmt::Debug,
|
||||||
{
|
{
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
default fn fingerprint_style() -> FingerprintStyle {
|
default fn key_fingerprint_style() -> KeyFingerprintStyle {
|
||||||
FingerprintStyle::Opaque
|
KeyFingerprintStyle::Opaque
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
|
@ -243,7 +244,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
default fn recover(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> {
|
default fn try_recover_key(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -264,10 +265,11 @@ pub struct DepKindVTable<'tcx> {
|
||||||
/// cached within one compiler invocation.
|
/// cached within one compiler invocation.
|
||||||
pub is_eval_always: bool,
|
pub is_eval_always: bool,
|
||||||
|
|
||||||
/// Indicates whether and how the query key can be recovered from its hashed fingerprint.
|
/// Indicates whether and how a query key can be reconstructed from the
|
||||||
|
/// key fingerprint of a dep node with this [`DepKind`].
|
||||||
///
|
///
|
||||||
/// The [`DepNodeKey`] trait determines the fingerprint style for each key type.
|
/// The [`DepNodeKey`] trait determines the fingerprint style for each key type.
|
||||||
pub fingerprint_style: FingerprintStyle,
|
pub key_fingerprint_style: KeyFingerprintStyle,
|
||||||
|
|
||||||
/// The red/green evaluation system will try to mark a specific DepNode in the
|
/// The red/green evaluation system will try to mark a specific DepNode in the
|
||||||
/// dependency graph as green by recursively trying to mark the dependencies of
|
/// dependency graph as green by recursively trying to mark the dependencies of
|
||||||
|
|
@ -279,7 +281,7 @@ pub struct DepKindVTable<'tcx> {
|
||||||
/// `force_from_dep_node()` implements.
|
/// `force_from_dep_node()` implements.
|
||||||
///
|
///
|
||||||
/// In the general case, a `DepNode` consists of a `DepKind` and an opaque
|
/// In the general case, a `DepNode` consists of a `DepKind` and an opaque
|
||||||
/// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint
|
/// "key fingerprint" that will uniquely identify the node. This key fingerprint
|
||||||
/// is usually constructed by computing a stable hash of the query-key that the
|
/// is usually constructed by computing a stable hash of the query-key that the
|
||||||
/// `DepNode` corresponds to. Consequently, it is not in general possible to go
|
/// `DepNode` corresponds to. Consequently, it is not in general possible to go
|
||||||
/// back from hash to query-key (since hash functions are not reversible). For
|
/// back from hash to query-key (since hash functions are not reversible). For
|
||||||
|
|
@ -293,7 +295,7 @@ pub struct DepKindVTable<'tcx> {
|
||||||
/// Now, if `force_from_dep_node()` would always fail, it would be pretty useless.
|
/// Now, if `force_from_dep_node()` would always fail, it would be pretty useless.
|
||||||
/// Fortunately, we can use some contextual information that will allow us to
|
/// Fortunately, we can use some contextual information that will allow us to
|
||||||
/// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we
|
/// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we
|
||||||
/// enforce by construction that the GUID/fingerprint of certain `DepNode`s is a
|
/// enforce by construction that the key fingerprint of certain `DepNode`s is a
|
||||||
/// valid `DefPathHash`. Since we also always build a huge table that maps every
|
/// valid `DefPathHash`. Since we also always build a huge table that maps every
|
||||||
/// `DefPathHash` in the current codebase to the corresponding `DefId`, we have
|
/// `DefPathHash` in the current codebase to the corresponding `DefId`, we have
|
||||||
/// everything we need to re-run the query.
|
/// everything we need to re-run the query.
|
||||||
|
|
@ -301,7 +303,7 @@ pub struct DepKindVTable<'tcx> {
|
||||||
/// Take the `mir_promoted` query as an example. Like many other queries, it
|
/// Take the `mir_promoted` query as an example. Like many other queries, it
|
||||||
/// just has a single parameter: the `DefId` of the item it will compute the
|
/// just has a single parameter: the `DefId` of the item it will compute the
|
||||||
/// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode`
|
/// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode`
|
||||||
/// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode`
|
/// with kind `mir_promoted`, we know that the key fingerprint of the `DepNode`
|
||||||
/// is actually a `DefPathHash`, and can therefore just look up the corresponding
|
/// is actually a `DefPathHash`, and can therefore just look up the corresponding
|
||||||
/// `DefId` in `tcx.def_path_hash_to_def_id`.
|
/// `DefId` in `tcx.def_path_hash_to_def_id`.
|
||||||
pub force_from_dep_node: Option<
|
pub force_from_dep_node: Option<
|
||||||
|
|
@ -472,8 +474,8 @@ impl DepNode {
|
||||||
/// refers to something from the previous compilation session that
|
/// refers to something from the previous compilation session that
|
||||||
/// has been removed.
|
/// has been removed.
|
||||||
pub fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
|
pub fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
|
||||||
if tcx.fingerprint_style(self.kind) == FingerprintStyle::DefPathHash {
|
if tcx.key_fingerprint_style(self.kind) == KeyFingerprintStyle::DefPathHash {
|
||||||
tcx.def_path_hash_to_def_id(DefPathHash(self.hash.into()))
|
tcx.def_path_hash_to_def_id(DefPathHash(self.key_fingerprint.into()))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
@ -486,10 +488,10 @@ impl DepNode {
|
||||||
) -> Result<DepNode, ()> {
|
) -> Result<DepNode, ()> {
|
||||||
let kind = dep_kind_from_label_string(label)?;
|
let kind = dep_kind_from_label_string(label)?;
|
||||||
|
|
||||||
match tcx.fingerprint_style(kind) {
|
match tcx.key_fingerprint_style(kind) {
|
||||||
FingerprintStyle::Opaque | FingerprintStyle::HirId => Err(()),
|
KeyFingerprintStyle::Opaque | KeyFingerprintStyle::HirId => Err(()),
|
||||||
FingerprintStyle::Unit => Ok(DepNode::new_no_params(tcx, kind)),
|
KeyFingerprintStyle::Unit => Ok(DepNode::new_no_params(tcx, kind)),
|
||||||
FingerprintStyle::DefPathHash => {
|
KeyFingerprintStyle::DefPathHash => {
|
||||||
Ok(DepNode::from_def_path_hash(tcx, def_path_hash, kind))
|
Ok(DepNode::from_def_path_hash(tcx, def_path_hash, kind))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,13 @@ use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalModDefId,
|
||||||
use rustc_hir::definitions::DefPathHash;
|
use rustc_hir::definitions::DefPathHash;
|
||||||
use rustc_hir::{HirId, ItemLocalId, OwnerId};
|
use rustc_hir::{HirId, ItemLocalId, OwnerId};
|
||||||
|
|
||||||
use crate::dep_graph::{DepNode, DepNodeKey, FingerprintStyle};
|
use crate::dep_graph::{DepNode, DepNodeKey, KeyFingerprintStyle};
|
||||||
use crate::ty::TyCtxt;
|
use crate::ty::TyCtxt;
|
||||||
|
|
||||||
impl<'tcx> DepNodeKey<'tcx> for () {
|
impl<'tcx> DepNodeKey<'tcx> for () {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn fingerprint_style() -> FingerprintStyle {
|
fn key_fingerprint_style() -> KeyFingerprintStyle {
|
||||||
FingerprintStyle::Unit
|
KeyFingerprintStyle::Unit
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
|
@ -18,15 +18,15 @@ impl<'tcx> DepNodeKey<'tcx> for () {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn recover(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> {
|
fn try_recover_key(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> {
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> DepNodeKey<'tcx> for DefId {
|
impl<'tcx> DepNodeKey<'tcx> for DefId {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn fingerprint_style() -> FingerprintStyle {
|
fn key_fingerprint_style() -> KeyFingerprintStyle {
|
||||||
FingerprintStyle::DefPathHash
|
KeyFingerprintStyle::DefPathHash
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
|
@ -40,15 +40,15 @@ impl<'tcx> DepNodeKey<'tcx> for DefId {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
|
fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
|
||||||
dep_node.extract_def_id(tcx)
|
dep_node.extract_def_id(tcx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> DepNodeKey<'tcx> for LocalDefId {
|
impl<'tcx> DepNodeKey<'tcx> for LocalDefId {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn fingerprint_style() -> FingerprintStyle {
|
fn key_fingerprint_style() -> KeyFingerprintStyle {
|
||||||
FingerprintStyle::DefPathHash
|
KeyFingerprintStyle::DefPathHash
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
|
@ -62,15 +62,15 @@ impl<'tcx> DepNodeKey<'tcx> for LocalDefId {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
|
fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
|
||||||
dep_node.extract_def_id(tcx).map(|id| id.expect_local())
|
dep_node.extract_def_id(tcx).map(|id| id.expect_local())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> DepNodeKey<'tcx> for OwnerId {
|
impl<'tcx> DepNodeKey<'tcx> for OwnerId {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn fingerprint_style() -> FingerprintStyle {
|
fn key_fingerprint_style() -> KeyFingerprintStyle {
|
||||||
FingerprintStyle::DefPathHash
|
KeyFingerprintStyle::DefPathHash
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
|
@ -84,15 +84,15 @@ impl<'tcx> DepNodeKey<'tcx> for OwnerId {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
|
fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
|
||||||
dep_node.extract_def_id(tcx).map(|id| OwnerId { def_id: id.expect_local() })
|
dep_node.extract_def_id(tcx).map(|id| OwnerId { def_id: id.expect_local() })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> DepNodeKey<'tcx> for CrateNum {
|
impl<'tcx> DepNodeKey<'tcx> for CrateNum {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn fingerprint_style() -> FingerprintStyle {
|
fn key_fingerprint_style() -> KeyFingerprintStyle {
|
||||||
FingerprintStyle::DefPathHash
|
KeyFingerprintStyle::DefPathHash
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
|
@ -107,15 +107,15 @@ impl<'tcx> DepNodeKey<'tcx> for CrateNum {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
|
fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
|
||||||
dep_node.extract_def_id(tcx).map(|id| id.krate)
|
dep_node.extract_def_id(tcx).map(|id| id.krate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> DepNodeKey<'tcx> for (DefId, DefId) {
|
impl<'tcx> DepNodeKey<'tcx> for (DefId, DefId) {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn fingerprint_style() -> FingerprintStyle {
|
fn key_fingerprint_style() -> KeyFingerprintStyle {
|
||||||
FingerprintStyle::Opaque
|
KeyFingerprintStyle::Opaque
|
||||||
}
|
}
|
||||||
|
|
||||||
// We actually would not need to specialize the implementation of this
|
// We actually would not need to specialize the implementation of this
|
||||||
|
|
@ -141,8 +141,8 @@ impl<'tcx> DepNodeKey<'tcx> for (DefId, DefId) {
|
||||||
|
|
||||||
impl<'tcx> DepNodeKey<'tcx> for HirId {
|
impl<'tcx> DepNodeKey<'tcx> for HirId {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn fingerprint_style() -> FingerprintStyle {
|
fn key_fingerprint_style() -> KeyFingerprintStyle {
|
||||||
FingerprintStyle::HirId
|
KeyFingerprintStyle::HirId
|
||||||
}
|
}
|
||||||
|
|
||||||
// We actually would not need to specialize the implementation of this
|
// We actually would not need to specialize the implementation of this
|
||||||
|
|
@ -166,9 +166,9 @@ impl<'tcx> DepNodeKey<'tcx> for HirId {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
|
fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
|
||||||
if tcx.fingerprint_style(dep_node.kind) == FingerprintStyle::HirId {
|
if tcx.key_fingerprint_style(dep_node.kind) == KeyFingerprintStyle::HirId {
|
||||||
let (local_hash, local_id) = Fingerprint::from(dep_node.hash).split();
|
let (local_hash, local_id) = Fingerprint::from(dep_node.key_fingerprint).split();
|
||||||
let def_path_hash = DefPathHash::new(tcx.stable_crate_id(LOCAL_CRATE), local_hash);
|
let def_path_hash = DefPathHash::new(tcx.stable_crate_id(LOCAL_CRATE), local_hash);
|
||||||
let def_id = tcx.def_path_hash_to_def_id(def_path_hash)?.expect_local();
|
let def_id = tcx.def_path_hash_to_def_id(def_path_hash)?.expect_local();
|
||||||
let local_id = local_id
|
let local_id = local_id
|
||||||
|
|
@ -184,8 +184,8 @@ impl<'tcx> DepNodeKey<'tcx> for HirId {
|
||||||
|
|
||||||
impl<'tcx> DepNodeKey<'tcx> for ModDefId {
|
impl<'tcx> DepNodeKey<'tcx> for ModDefId {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn fingerprint_style() -> FingerprintStyle {
|
fn key_fingerprint_style() -> KeyFingerprintStyle {
|
||||||
FingerprintStyle::DefPathHash
|
KeyFingerprintStyle::DefPathHash
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
|
@ -199,15 +199,15 @@ impl<'tcx> DepNodeKey<'tcx> for ModDefId {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
|
fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
|
||||||
DefId::recover(tcx, dep_node).map(ModDefId::new_unchecked)
|
DefId::try_recover_key(tcx, dep_node).map(ModDefId::new_unchecked)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> DepNodeKey<'tcx> for LocalModDefId {
|
impl<'tcx> DepNodeKey<'tcx> for LocalModDefId {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn fingerprint_style() -> FingerprintStyle {
|
fn key_fingerprint_style() -> KeyFingerprintStyle {
|
||||||
FingerprintStyle::DefPathHash
|
KeyFingerprintStyle::DefPathHash
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
|
@ -221,7 +221,7 @@ impl<'tcx> DepNodeKey<'tcx> for LocalModDefId {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
|
fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
|
||||||
LocalDefId::recover(tcx, dep_node).map(LocalModDefId::new_unchecked)
|
LocalDefId::try_recover_key(tcx, dep_node).map(LocalModDefId::new_unchecked)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -142,15 +142,17 @@ impl DepGraph {
|
||||||
|
|
||||||
// Instantiate a node with zero dependencies only once for anonymous queries.
|
// Instantiate a node with zero dependencies only once for anonymous queries.
|
||||||
let _green_node_index = current.alloc_new_node(
|
let _green_node_index = current.alloc_new_node(
|
||||||
DepNode { kind: DepKind::ANON_ZERO_DEPS, hash: current.anon_id_seed.into() },
|
DepNode { kind: DepKind::ANON_ZERO_DEPS, key_fingerprint: current.anon_id_seed.into() },
|
||||||
EdgesVec::new(),
|
EdgesVec::new(),
|
||||||
Fingerprint::ZERO,
|
Fingerprint::ZERO,
|
||||||
);
|
);
|
||||||
assert_eq!(_green_node_index, DepNodeIndex::SINGLETON_ZERO_DEPS_ANON_NODE);
|
assert_eq!(_green_node_index, DepNodeIndex::SINGLETON_ZERO_DEPS_ANON_NODE);
|
||||||
|
|
||||||
// Instantiate a dependy-less red node only once for anonymous queries.
|
// Create a single always-red node, with no dependencies of its own.
|
||||||
|
// Other nodes can use the always-red node as a fake dependency, to
|
||||||
|
// ensure that their dependency list will never be all-green.
|
||||||
let red_node_index = current.alloc_new_node(
|
let red_node_index = current.alloc_new_node(
|
||||||
DepNode { kind: DepKind::RED, hash: Fingerprint::ZERO.into() },
|
DepNode { kind: DepKind::RED, key_fingerprint: Fingerprint::ZERO.into() },
|
||||||
EdgesVec::new(),
|
EdgesVec::new(),
|
||||||
Fingerprint::ZERO,
|
Fingerprint::ZERO,
|
||||||
);
|
);
|
||||||
|
|
@ -418,7 +420,7 @@ impl DepGraphData {
|
||||||
// Fingerprint::combine() is faster than sending Fingerprint
|
// Fingerprint::combine() is faster than sending Fingerprint
|
||||||
// through the StableHasher (at least as long as StableHasher
|
// through the StableHasher (at least as long as StableHasher
|
||||||
// is so slow).
|
// is so slow).
|
||||||
hash: self.current.anon_id_seed.combine(hasher.finish()).into(),
|
key_fingerprint: self.current.anon_id_seed.combine(hasher.finish()).into(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// The DepNodes generated by the process above are not unique. 2 queries could
|
// The DepNodes generated by the process above are not unique. 2 queries could
|
||||||
|
|
@ -585,7 +587,7 @@ impl DepGraph {
|
||||||
data.current.record_edge(
|
data.current.record_edge(
|
||||||
dep_node_index,
|
dep_node_index,
|
||||||
node,
|
node,
|
||||||
data.prev_fingerprint_of(prev_index),
|
data.prev_value_fingerprint_of(prev_index),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -658,8 +660,8 @@ impl DepGraphData {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn prev_fingerprint_of(&self, prev_index: SerializedDepNodeIndex) -> Fingerprint {
|
pub fn prev_value_fingerprint_of(&self, prev_index: SerializedDepNodeIndex) -> Fingerprint {
|
||||||
self.previous.fingerprint_by_index(prev_index)
|
self.previous.value_fingerprint_for_index(prev_index)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
@ -679,7 +681,7 @@ impl DepGraphData {
|
||||||
let dep_node_index = self.current.encoder.send_new(
|
let dep_node_index = self.current.encoder.send_new(
|
||||||
DepNode {
|
DepNode {
|
||||||
kind: DepKind::SIDE_EFFECT,
|
kind: DepKind::SIDE_EFFECT,
|
||||||
hash: PackedFingerprint::from(Fingerprint::ZERO),
|
key_fingerprint: PackedFingerprint::from(Fingerprint::ZERO),
|
||||||
},
|
},
|
||||||
Fingerprint::ZERO,
|
Fingerprint::ZERO,
|
||||||
// We want the side effect node to always be red so it will be forced and emit the
|
// We want the side effect node to always be red so it will be forced and emit the
|
||||||
|
|
@ -712,7 +714,7 @@ impl DepGraphData {
|
||||||
&self.colors,
|
&self.colors,
|
||||||
DepNode {
|
DepNode {
|
||||||
kind: DepKind::SIDE_EFFECT,
|
kind: DepKind::SIDE_EFFECT,
|
||||||
hash: PackedFingerprint::from(Fingerprint::ZERO),
|
key_fingerprint: PackedFingerprint::from(Fingerprint::ZERO),
|
||||||
},
|
},
|
||||||
Fingerprint::ZERO,
|
Fingerprint::ZERO,
|
||||||
std::iter::once(DepNodeIndex::FOREVER_RED_NODE).collect(),
|
std::iter::once(DepNodeIndex::FOREVER_RED_NODE).collect(),
|
||||||
|
|
@ -727,12 +729,12 @@ impl DepGraphData {
|
||||||
&self,
|
&self,
|
||||||
key: DepNode,
|
key: DepNode,
|
||||||
edges: EdgesVec,
|
edges: EdgesVec,
|
||||||
fingerprint: Option<Fingerprint>,
|
value_fingerprint: Option<Fingerprint>,
|
||||||
) -> DepNodeIndex {
|
) -> DepNodeIndex {
|
||||||
if let Some(prev_index) = self.previous.node_to_index_opt(&key) {
|
if let Some(prev_index) = self.previous.node_to_index_opt(&key) {
|
||||||
// Determine the color and index of the new `DepNode`.
|
// Determine the color and index of the new `DepNode`.
|
||||||
let is_green = if let Some(fingerprint) = fingerprint {
|
let is_green = if let Some(value_fingerprint) = value_fingerprint {
|
||||||
if fingerprint == self.previous.fingerprint_by_index(prev_index) {
|
if value_fingerprint == self.previous.value_fingerprint_for_index(prev_index) {
|
||||||
// This is a green node: it existed in the previous compilation,
|
// This is a green node: it existed in the previous compilation,
|
||||||
// its query was re-executed, and it has the same result as before.
|
// its query was re-executed, and it has the same result as before.
|
||||||
true
|
true
|
||||||
|
|
@ -749,22 +751,22 @@ impl DepGraphData {
|
||||||
false
|
false
|
||||||
};
|
};
|
||||||
|
|
||||||
let fingerprint = fingerprint.unwrap_or(Fingerprint::ZERO);
|
let value_fingerprint = value_fingerprint.unwrap_or(Fingerprint::ZERO);
|
||||||
|
|
||||||
let dep_node_index = self.current.encoder.send_and_color(
|
let dep_node_index = self.current.encoder.send_and_color(
|
||||||
prev_index,
|
prev_index,
|
||||||
&self.colors,
|
&self.colors,
|
||||||
key,
|
key,
|
||||||
fingerprint,
|
value_fingerprint,
|
||||||
edges,
|
edges,
|
||||||
is_green,
|
is_green,
|
||||||
);
|
);
|
||||||
|
|
||||||
self.current.record_node(dep_node_index, key, fingerprint);
|
self.current.record_node(dep_node_index, key, value_fingerprint);
|
||||||
|
|
||||||
dep_node_index
|
dep_node_index
|
||||||
} else {
|
} else {
|
||||||
self.current.alloc_new_node(key, edges, fingerprint.unwrap_or(Fingerprint::ZERO))
|
self.current.alloc_new_node(key, edges, value_fingerprint.unwrap_or(Fingerprint::ZERO))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -781,7 +783,7 @@ impl DepGraphData {
|
||||||
self.current.record_edge(
|
self.current.record_edge(
|
||||||
dep_node_index,
|
dep_node_index,
|
||||||
*self.previous.index_to_node(prev_index),
|
*self.previous.index_to_node(prev_index),
|
||||||
self.previous.fingerprint_by_index(prev_index),
|
self.previous.value_fingerprint_for_index(prev_index),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -925,7 +927,7 @@ impl DepGraphData {
|
||||||
if !tcx.is_eval_always(dep_dep_node.kind) {
|
if !tcx.is_eval_always(dep_dep_node.kind) {
|
||||||
debug!(
|
debug!(
|
||||||
"state of dependency {:?} ({}) is unknown, trying to mark it green",
|
"state of dependency {:?} ({}) is unknown, trying to mark it green",
|
||||||
dep_dep_node, dep_dep_node.hash,
|
dep_dep_node, dep_dep_node.key_fingerprint,
|
||||||
);
|
);
|
||||||
|
|
||||||
let node_index = self.try_mark_previous_green(tcx, parent_dep_node_index, Some(frame));
|
let node_index = self.try_mark_previous_green(tcx, parent_dep_node_index, Some(frame));
|
||||||
|
|
@ -1154,10 +1156,10 @@ pub(super) struct CurrentDepGraph {
|
||||||
encoder: GraphEncoder,
|
encoder: GraphEncoder,
|
||||||
anon_node_to_index: ShardedHashMap<DepNode, DepNodeIndex>,
|
anon_node_to_index: ShardedHashMap<DepNode, DepNodeIndex>,
|
||||||
|
|
||||||
/// This is used to verify that fingerprints do not change between the creation of a node
|
/// This is used to verify that value fingerprints do not change between the
|
||||||
/// and its recomputation.
|
/// creation of a node and its recomputation.
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
fingerprints: Lock<IndexVec<DepNodeIndex, Option<Fingerprint>>>,
|
value_fingerprints: Lock<IndexVec<DepNodeIndex, Option<Fingerprint>>>,
|
||||||
|
|
||||||
/// Used to trap when a specific edge is added to the graph.
|
/// Used to trap when a specific edge is added to the graph.
|
||||||
/// This is used for debug purposes and is only active with `debug_assertions`.
|
/// This is used for debug purposes and is only active with `debug_assertions`.
|
||||||
|
|
@ -1224,7 +1226,7 @@ impl CurrentDepGraph {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
forbidden_edge,
|
forbidden_edge,
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
fingerprints: Lock::new(IndexVec::from_elem_n(None, new_node_count_estimate)),
|
value_fingerprints: Lock::new(IndexVec::from_elem_n(None, new_node_count_estimate)),
|
||||||
nodes_in_current_session: new_node_dbg.then(|| {
|
nodes_in_current_session: new_node_dbg.then(|| {
|
||||||
Lock::new(FxHashMap::with_capacity_and_hasher(
|
Lock::new(FxHashMap::with_capacity_and_hasher(
|
||||||
new_node_count_estimate,
|
new_node_count_estimate,
|
||||||
|
|
@ -1237,12 +1239,20 @@ impl CurrentDepGraph {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
fn record_edge(&self, dep_node_index: DepNodeIndex, key: DepNode, fingerprint: Fingerprint) {
|
fn record_edge(
|
||||||
|
&self,
|
||||||
|
dep_node_index: DepNodeIndex,
|
||||||
|
key: DepNode,
|
||||||
|
value_fingerprint: Fingerprint,
|
||||||
|
) {
|
||||||
if let Some(forbidden_edge) = &self.forbidden_edge {
|
if let Some(forbidden_edge) = &self.forbidden_edge {
|
||||||
forbidden_edge.index_to_node.lock().insert(dep_node_index, key);
|
forbidden_edge.index_to_node.lock().insert(dep_node_index, key);
|
||||||
}
|
}
|
||||||
let previous = *self.fingerprints.lock().get_or_insert_with(dep_node_index, || fingerprint);
|
let prior_value_fingerprint = *self
|
||||||
assert_eq!(previous, fingerprint, "Unstable fingerprints for {:?}", key);
|
.value_fingerprints
|
||||||
|
.lock()
|
||||||
|
.get_or_insert_with(dep_node_index, || value_fingerprint);
|
||||||
|
assert_eq!(prior_value_fingerprint, value_fingerprint, "Unstable fingerprints for {key:?}");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
|
@ -1250,10 +1260,10 @@ impl CurrentDepGraph {
|
||||||
&self,
|
&self,
|
||||||
dep_node_index: DepNodeIndex,
|
dep_node_index: DepNodeIndex,
|
||||||
key: DepNode,
|
key: DepNode,
|
||||||
_current_fingerprint: Fingerprint,
|
_value_fingerprint: Fingerprint,
|
||||||
) {
|
) {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
self.record_edge(dep_node_index, key, _current_fingerprint);
|
self.record_edge(dep_node_index, key, _value_fingerprint);
|
||||||
|
|
||||||
if let Some(ref nodes_in_current_session) = self.nodes_in_current_session {
|
if let Some(ref nodes_in_current_session) = self.nodes_in_current_session {
|
||||||
outline(|| {
|
outline(|| {
|
||||||
|
|
@ -1271,11 +1281,11 @@ impl CurrentDepGraph {
|
||||||
&self,
|
&self,
|
||||||
key: DepNode,
|
key: DepNode,
|
||||||
edges: EdgesVec,
|
edges: EdgesVec,
|
||||||
current_fingerprint: Fingerprint,
|
value_fingerprint: Fingerprint,
|
||||||
) -> DepNodeIndex {
|
) -> DepNodeIndex {
|
||||||
let dep_node_index = self.encoder.send_new(key, current_fingerprint, edges);
|
let dep_node_index = self.encoder.send_new(key, value_fingerprint, edges);
|
||||||
|
|
||||||
self.record_node(dep_node_index, key, current_fingerprint);
|
self.record_node(dep_node_index, key, value_fingerprint);
|
||||||
|
|
||||||
dep_node_index
|
dep_node_index
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ mod serialized;
|
||||||
/// This is mainly for determining whether and how we can reconstruct a key
|
/// This is mainly for determining whether and how we can reconstruct a key
|
||||||
/// from the fingerprint.
|
/// from the fingerprint.
|
||||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||||
pub enum FingerprintStyle {
|
pub enum KeyFingerprintStyle {
|
||||||
/// The fingerprint is actually a DefPathHash.
|
/// The fingerprint is actually a DefPathHash.
|
||||||
DefPathHash,
|
DefPathHash,
|
||||||
/// The fingerprint is actually a HirId.
|
/// The fingerprint is actually a HirId.
|
||||||
|
|
@ -41,14 +41,14 @@ pub enum FingerprintStyle {
|
||||||
Opaque,
|
Opaque,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FingerprintStyle {
|
impl KeyFingerprintStyle {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn reconstructible(self) -> bool {
|
pub const fn reconstructible(self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
FingerprintStyle::DefPathHash | FingerprintStyle::Unit | FingerprintStyle::HirId => {
|
KeyFingerprintStyle::DefPathHash
|
||||||
true
|
| KeyFingerprintStyle::Unit
|
||||||
}
|
| KeyFingerprintStyle::HirId => true,
|
||||||
FingerprintStyle::Opaque => false,
|
KeyFingerprintStyle::Opaque => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -86,8 +86,8 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn fingerprint_style(self, kind: DepKind) -> FingerprintStyle {
|
pub fn key_fingerprint_style(self, kind: DepKind) -> KeyFingerprintStyle {
|
||||||
self.dep_kind_vtable(kind).fingerprint_style
|
self.dep_kind_vtable(kind).key_fingerprint_style
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try to force a dep node to execute and see if it's green.
|
/// Try to force a dep node to execute and see if it's green.
|
||||||
|
|
|
||||||
|
|
@ -90,9 +90,13 @@ const DEP_NODE_WIDTH_BITS: usize = DEP_NODE_SIZE / 2;
|
||||||
pub struct SerializedDepGraph {
|
pub struct SerializedDepGraph {
|
||||||
/// The set of all DepNodes in the graph
|
/// The set of all DepNodes in the graph
|
||||||
nodes: IndexVec<SerializedDepNodeIndex, DepNode>,
|
nodes: IndexVec<SerializedDepNodeIndex, DepNode>,
|
||||||
/// The set of all Fingerprints in the graph. Each Fingerprint corresponds to
|
/// A value fingerprint associated with each [`DepNode`] in [`Self::nodes`],
|
||||||
/// the DepNode at the same index in the nodes vector.
|
/// typically a hash of the value returned by the node's query in the
|
||||||
fingerprints: IndexVec<SerializedDepNodeIndex, Fingerprint>,
|
/// previous incremental-compilation session.
|
||||||
|
///
|
||||||
|
/// Some nodes don't have a meaningful value hash (e.g. queries with `no_hash`),
|
||||||
|
/// so they store a dummy value here instead (e.g. [`Fingerprint::ZERO`]).
|
||||||
|
value_fingerprints: IndexVec<SerializedDepNodeIndex, Fingerprint>,
|
||||||
/// For each DepNode, stores the list of edges originating from that
|
/// For each DepNode, stores the list of edges originating from that
|
||||||
/// DepNode. Encoded as a [start, end) pair indexing into edge_list_data,
|
/// DepNode. Encoded as a [start, end) pair indexing into edge_list_data,
|
||||||
/// which holds the actual DepNodeIndices of the target nodes.
|
/// which holds the actual DepNodeIndices of the target nodes.
|
||||||
|
|
@ -100,8 +104,8 @@ pub struct SerializedDepGraph {
|
||||||
/// A flattened list of all edge targets in the graph, stored in the same
|
/// A flattened list of all edge targets in the graph, stored in the same
|
||||||
/// varint encoding that we use on disk. Edge sources are implicit in edge_list_indices.
|
/// varint encoding that we use on disk. Edge sources are implicit in edge_list_indices.
|
||||||
edge_list_data: Vec<u8>,
|
edge_list_data: Vec<u8>,
|
||||||
/// Stores a map from fingerprints to nodes per dep node kind.
|
/// For each dep kind, stores a map from key fingerprints back to the index
|
||||||
/// This is the reciprocal of `nodes`.
|
/// of the corresponding node. This is the inverse of `nodes`.
|
||||||
index: Vec<UnhashMap<PackedFingerprint, SerializedDepNodeIndex>>,
|
index: Vec<UnhashMap<PackedFingerprint, SerializedDepNodeIndex>>,
|
||||||
/// The number of previous compilation sessions. This is used to generate
|
/// The number of previous compilation sessions. This is used to generate
|
||||||
/// unique anon dep nodes per session.
|
/// unique anon dep nodes per session.
|
||||||
|
|
@ -138,12 +142,15 @@ impl SerializedDepGraph {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn node_to_index_opt(&self, dep_node: &DepNode) -> Option<SerializedDepNodeIndex> {
|
pub fn node_to_index_opt(&self, dep_node: &DepNode) -> Option<SerializedDepNodeIndex> {
|
||||||
self.index.get(dep_node.kind.as_usize())?.get(&dep_node.hash).cloned()
|
self.index.get(dep_node.kind.as_usize())?.get(&dep_node.key_fingerprint).copied()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn fingerprint_by_index(&self, dep_node_index: SerializedDepNodeIndex) -> Fingerprint {
|
pub fn value_fingerprint_for_index(
|
||||||
self.fingerprints[dep_node_index]
|
&self,
|
||||||
|
dep_node_index: SerializedDepNodeIndex,
|
||||||
|
) -> Fingerprint {
|
||||||
|
self.value_fingerprints[dep_node_index]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
@ -212,10 +219,13 @@ impl SerializedDepGraph {
|
||||||
let graph_bytes = d.len() - (3 * IntEncodedWithFixedSize::ENCODED_SIZE) - d.position();
|
let graph_bytes = d.len() - (3 * IntEncodedWithFixedSize::ENCODED_SIZE) - d.position();
|
||||||
|
|
||||||
let mut nodes = IndexVec::from_elem_n(
|
let mut nodes = IndexVec::from_elem_n(
|
||||||
DepNode { kind: DepKind::NULL, hash: PackedFingerprint::from(Fingerprint::ZERO) },
|
DepNode {
|
||||||
|
kind: DepKind::NULL,
|
||||||
|
key_fingerprint: PackedFingerprint::from(Fingerprint::ZERO),
|
||||||
|
},
|
||||||
node_max,
|
node_max,
|
||||||
);
|
);
|
||||||
let mut fingerprints = IndexVec::from_elem_n(Fingerprint::ZERO, node_max);
|
let mut value_fingerprints = IndexVec::from_elem_n(Fingerprint::ZERO, node_max);
|
||||||
let mut edge_list_indices =
|
let mut edge_list_indices =
|
||||||
IndexVec::from_elem_n(EdgeHeader { repr: 0, num_edges: 0 }, node_max);
|
IndexVec::from_elem_n(EdgeHeader { repr: 0, num_edges: 0 }, node_max);
|
||||||
|
|
||||||
|
|
@ -243,7 +253,7 @@ impl SerializedDepGraph {
|
||||||
assert!(node_header.node().kind != DepKind::NULL && node.kind == DepKind::NULL);
|
assert!(node_header.node().kind != DepKind::NULL && node.kind == DepKind::NULL);
|
||||||
*node = node_header.node();
|
*node = node_header.node();
|
||||||
|
|
||||||
fingerprints[index] = node_header.fingerprint();
|
value_fingerprints[index] = node_header.value_fingerprint();
|
||||||
|
|
||||||
// If the length of this node's edge list is small, the length is stored in the header.
|
// If the length of this node's edge list is small, the length is stored in the header.
|
||||||
// If it is not, we fall back to another decoder call.
|
// If it is not, we fall back to another decoder call.
|
||||||
|
|
@ -275,7 +285,7 @@ impl SerializedDepGraph {
|
||||||
let session_count = d.read_u64();
|
let session_count = d.read_u64();
|
||||||
|
|
||||||
for (idx, node) in nodes.iter_enumerated() {
|
for (idx, node) in nodes.iter_enumerated() {
|
||||||
if index[node.kind.as_usize()].insert(node.hash, idx).is_some() {
|
if index[node.kind.as_usize()].insert(node.key_fingerprint, idx).is_some() {
|
||||||
// Empty nodes and side effect nodes can have duplicates
|
// Empty nodes and side effect nodes can have duplicates
|
||||||
if node.kind != DepKind::NULL && node.kind != DepKind::SIDE_EFFECT {
|
if node.kind != DepKind::NULL && node.kind != DepKind::SIDE_EFFECT {
|
||||||
let name = node.kind.name();
|
let name = node.kind.name();
|
||||||
|
|
@ -291,7 +301,7 @@ impl SerializedDepGraph {
|
||||||
|
|
||||||
Arc::new(SerializedDepGraph {
|
Arc::new(SerializedDepGraph {
|
||||||
nodes,
|
nodes,
|
||||||
fingerprints,
|
value_fingerprints,
|
||||||
edge_list_indices,
|
edge_list_indices,
|
||||||
edge_list_data,
|
edge_list_data,
|
||||||
index,
|
index,
|
||||||
|
|
@ -303,8 +313,8 @@ impl SerializedDepGraph {
|
||||||
/// A packed representation of all the fixed-size fields in a `NodeInfo`.
|
/// A packed representation of all the fixed-size fields in a `NodeInfo`.
|
||||||
///
|
///
|
||||||
/// This stores in one byte array:
|
/// This stores in one byte array:
|
||||||
/// * The `Fingerprint` in the `NodeInfo`
|
/// * The value `Fingerprint` in the `NodeInfo`
|
||||||
/// * The `Fingerprint` in `DepNode` that is in this `NodeInfo`
|
/// * The key `Fingerprint` in `DepNode` that is in this `NodeInfo`
|
||||||
/// * The `DepKind`'s discriminant (a u16, but not all bits are used...)
|
/// * The `DepKind`'s discriminant (a u16, but not all bits are used...)
|
||||||
/// * The byte width of the encoded edges for this node
|
/// * The byte width of the encoded edges for this node
|
||||||
/// * In whatever bits remain, the length of the edge list for this node, if it fits
|
/// * In whatever bits remain, the length of the edge list for this node, if it fits
|
||||||
|
|
@ -323,8 +333,8 @@ struct Unpacked {
|
||||||
bytes_per_index: usize,
|
bytes_per_index: usize,
|
||||||
kind: DepKind,
|
kind: DepKind,
|
||||||
index: SerializedDepNodeIndex,
|
index: SerializedDepNodeIndex,
|
||||||
hash: PackedFingerprint,
|
key_fingerprint: PackedFingerprint,
|
||||||
fingerprint: Fingerprint,
|
value_fingerprint: Fingerprint,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bit fields, where
|
// Bit fields, where
|
||||||
|
|
@ -345,7 +355,7 @@ impl SerializedNodeHeader {
|
||||||
fn new(
|
fn new(
|
||||||
node: &DepNode,
|
node: &DepNode,
|
||||||
index: DepNodeIndex,
|
index: DepNodeIndex,
|
||||||
fingerprint: Fingerprint,
|
value_fingerprint: Fingerprint,
|
||||||
edge_max_index: u32,
|
edge_max_index: u32,
|
||||||
edge_count: usize,
|
edge_count: usize,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
|
@ -363,19 +373,19 @@ impl SerializedNodeHeader {
|
||||||
head |= (edge_count as u16 + 1) << (Self::KIND_BITS + Self::WIDTH_BITS);
|
head |= (edge_count as u16 + 1) << (Self::KIND_BITS + Self::WIDTH_BITS);
|
||||||
}
|
}
|
||||||
|
|
||||||
let hash: Fingerprint = node.hash.into();
|
let hash: Fingerprint = node.key_fingerprint.into();
|
||||||
|
|
||||||
// Using half-open ranges ensures an unconditional panic if we get the magic numbers wrong.
|
// Using half-open ranges ensures an unconditional panic if we get the magic numbers wrong.
|
||||||
let mut bytes = [0u8; 38];
|
let mut bytes = [0u8; 38];
|
||||||
bytes[..2].copy_from_slice(&head.to_le_bytes());
|
bytes[..2].copy_from_slice(&head.to_le_bytes());
|
||||||
bytes[2..6].copy_from_slice(&index.as_u32().to_le_bytes());
|
bytes[2..6].copy_from_slice(&index.as_u32().to_le_bytes());
|
||||||
bytes[6..22].copy_from_slice(&hash.to_le_bytes());
|
bytes[6..22].copy_from_slice(&hash.to_le_bytes());
|
||||||
bytes[22..].copy_from_slice(&fingerprint.to_le_bytes());
|
bytes[22..].copy_from_slice(&value_fingerprint.to_le_bytes());
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
{
|
{
|
||||||
let res = Self { bytes };
|
let res = Self { bytes };
|
||||||
assert_eq!(fingerprint, res.fingerprint());
|
assert_eq!(value_fingerprint, res.value_fingerprint());
|
||||||
assert_eq!(*node, res.node());
|
assert_eq!(*node, res.node());
|
||||||
if let Some(len) = res.len() {
|
if let Some(len) = res.len() {
|
||||||
assert_eq!(edge_count, len as usize);
|
assert_eq!(edge_count, len as usize);
|
||||||
|
|
@ -388,8 +398,8 @@ impl SerializedNodeHeader {
|
||||||
fn unpack(&self) -> Unpacked {
|
fn unpack(&self) -> Unpacked {
|
||||||
let head = u16::from_le_bytes(self.bytes[..2].try_into().unwrap());
|
let head = u16::from_le_bytes(self.bytes[..2].try_into().unwrap());
|
||||||
let index = u32::from_le_bytes(self.bytes[2..6].try_into().unwrap());
|
let index = u32::from_le_bytes(self.bytes[2..6].try_into().unwrap());
|
||||||
let hash = self.bytes[6..22].try_into().unwrap();
|
let key_fingerprint = self.bytes[6..22].try_into().unwrap();
|
||||||
let fingerprint = self.bytes[22..].try_into().unwrap();
|
let value_fingerprint = self.bytes[22..].try_into().unwrap();
|
||||||
|
|
||||||
let kind = head & mask(Self::KIND_BITS) as u16;
|
let kind = head & mask(Self::KIND_BITS) as u16;
|
||||||
let bytes_per_index = (head >> Self::KIND_BITS) & mask(Self::WIDTH_BITS) as u16;
|
let bytes_per_index = (head >> Self::KIND_BITS) & mask(Self::WIDTH_BITS) as u16;
|
||||||
|
|
@ -400,8 +410,8 @@ impl SerializedNodeHeader {
|
||||||
bytes_per_index: bytes_per_index as usize + 1,
|
bytes_per_index: bytes_per_index as usize + 1,
|
||||||
kind: DepKind::new(kind),
|
kind: DepKind::new(kind),
|
||||||
index: SerializedDepNodeIndex::from_u32(index),
|
index: SerializedDepNodeIndex::from_u32(index),
|
||||||
hash: Fingerprint::from_le_bytes(hash).into(),
|
key_fingerprint: Fingerprint::from_le_bytes(key_fingerprint).into(),
|
||||||
fingerprint: Fingerprint::from_le_bytes(fingerprint),
|
value_fingerprint: Fingerprint::from_le_bytes(value_fingerprint),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -421,14 +431,14 @@ impl SerializedNodeHeader {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn fingerprint(&self) -> Fingerprint {
|
fn value_fingerprint(&self) -> Fingerprint {
|
||||||
self.unpack().fingerprint
|
self.unpack().value_fingerprint
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn node(&self) -> DepNode {
|
fn node(&self) -> DepNode {
|
||||||
let Unpacked { kind, hash, .. } = self.unpack();
|
let Unpacked { kind, key_fingerprint, .. } = self.unpack();
|
||||||
DepNode { kind, hash }
|
DepNode { kind, key_fingerprint }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
@ -443,15 +453,20 @@ impl SerializedNodeHeader {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct NodeInfo {
|
struct NodeInfo {
|
||||||
node: DepNode,
|
node: DepNode,
|
||||||
fingerprint: Fingerprint,
|
value_fingerprint: Fingerprint,
|
||||||
edges: EdgesVec,
|
edges: EdgesVec,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NodeInfo {
|
impl NodeInfo {
|
||||||
fn encode(&self, e: &mut MemEncoder, index: DepNodeIndex) {
|
fn encode(&self, e: &mut MemEncoder, index: DepNodeIndex) {
|
||||||
let NodeInfo { ref node, fingerprint, ref edges } = *self;
|
let NodeInfo { ref node, value_fingerprint, ref edges } = *self;
|
||||||
let header =
|
let header = SerializedNodeHeader::new(
|
||||||
SerializedNodeHeader::new(node, index, fingerprint, edges.max_index(), edges.len());
|
node,
|
||||||
|
index,
|
||||||
|
value_fingerprint,
|
||||||
|
edges.max_index(),
|
||||||
|
edges.len(),
|
||||||
|
);
|
||||||
e.write_array(header.bytes);
|
e.write_array(header.bytes);
|
||||||
|
|
||||||
if header.len().is_none() {
|
if header.len().is_none() {
|
||||||
|
|
@ -476,7 +491,7 @@ impl NodeInfo {
|
||||||
e: &mut MemEncoder,
|
e: &mut MemEncoder,
|
||||||
node: &DepNode,
|
node: &DepNode,
|
||||||
index: DepNodeIndex,
|
index: DepNodeIndex,
|
||||||
fingerprint: Fingerprint,
|
value_fingerprint: Fingerprint,
|
||||||
prev_index: SerializedDepNodeIndex,
|
prev_index: SerializedDepNodeIndex,
|
||||||
colors: &DepNodeColorMap,
|
colors: &DepNodeColorMap,
|
||||||
previous: &SerializedDepGraph,
|
previous: &SerializedDepGraph,
|
||||||
|
|
@ -488,7 +503,8 @@ impl NodeInfo {
|
||||||
let edge_max =
|
let edge_max =
|
||||||
edges.clone().map(|i| colors.current(i).unwrap().as_u32()).max().unwrap_or(0);
|
edges.clone().map(|i| colors.current(i).unwrap().as_u32()).max().unwrap_or(0);
|
||||||
|
|
||||||
let header = SerializedNodeHeader::new(node, index, fingerprint, edge_max, edge_count);
|
let header =
|
||||||
|
SerializedNodeHeader::new(node, index, value_fingerprint, edge_max, edge_count);
|
||||||
e.write_array(header.bytes);
|
e.write_array(header.bytes);
|
||||||
|
|
||||||
if header.len().is_none() {
|
if header.len().is_none() {
|
||||||
|
|
@ -676,12 +692,12 @@ impl EncoderState {
|
||||||
local: &mut LocalEncoderState,
|
local: &mut LocalEncoderState,
|
||||||
) {
|
) {
|
||||||
let node = self.previous.index_to_node(prev_index);
|
let node = self.previous.index_to_node(prev_index);
|
||||||
let fingerprint = self.previous.fingerprint_by_index(prev_index);
|
let value_fingerprint = self.previous.value_fingerprint_for_index(prev_index);
|
||||||
let edge_count = NodeInfo::encode_promoted(
|
let edge_count = NodeInfo::encode_promoted(
|
||||||
&mut local.encoder,
|
&mut local.encoder,
|
||||||
node,
|
node,
|
||||||
index,
|
index,
|
||||||
fingerprint,
|
value_fingerprint,
|
||||||
prev_index,
|
prev_index,
|
||||||
colors,
|
colors,
|
||||||
&self.previous,
|
&self.previous,
|
||||||
|
|
@ -857,11 +873,11 @@ impl GraphEncoder {
|
||||||
pub(crate) fn send_new(
|
pub(crate) fn send_new(
|
||||||
&self,
|
&self,
|
||||||
node: DepNode,
|
node: DepNode,
|
||||||
fingerprint: Fingerprint,
|
value_fingerprint: Fingerprint,
|
||||||
edges: EdgesVec,
|
edges: EdgesVec,
|
||||||
) -> DepNodeIndex {
|
) -> DepNodeIndex {
|
||||||
let _prof_timer = self.profiler.generic_activity("incr_comp_encode_dep_graph");
|
let _prof_timer = self.profiler.generic_activity("incr_comp_encode_dep_graph");
|
||||||
let node = NodeInfo { node, fingerprint, edges };
|
let node = NodeInfo { node, value_fingerprint, edges };
|
||||||
let mut local = self.status.local.borrow_mut();
|
let mut local = self.status.local.borrow_mut();
|
||||||
let index = self.status.next_index(&mut *local);
|
let index = self.status.next_index(&mut *local);
|
||||||
self.status.bump_index(&mut *local);
|
self.status.bump_index(&mut *local);
|
||||||
|
|
@ -877,12 +893,12 @@ impl GraphEncoder {
|
||||||
prev_index: SerializedDepNodeIndex,
|
prev_index: SerializedDepNodeIndex,
|
||||||
colors: &DepNodeColorMap,
|
colors: &DepNodeColorMap,
|
||||||
node: DepNode,
|
node: DepNode,
|
||||||
fingerprint: Fingerprint,
|
value_fingerprint: Fingerprint,
|
||||||
edges: EdgesVec,
|
edges: EdgesVec,
|
||||||
is_green: bool,
|
is_green: bool,
|
||||||
) -> DepNodeIndex {
|
) -> DepNodeIndex {
|
||||||
let _prof_timer = self.profiler.generic_activity("incr_comp_encode_dep_graph");
|
let _prof_timer = self.profiler.generic_activity("incr_comp_encode_dep_graph");
|
||||||
let node = NodeInfo { node, fingerprint, edges };
|
let node = NodeInfo { node, value_fingerprint, edges };
|
||||||
|
|
||||||
let mut local = self.status.local.borrow_mut();
|
let mut local = self.status.local.borrow_mut();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1237,10 +1237,6 @@ impl<'tcx> Debug for Rvalue<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ShallowInitBox(ref place, ref ty) => {
|
|
||||||
with_no_trimmed_paths!(write!(fmt, "ShallowInitBox({place:?}, {ty})"))
|
|
||||||
}
|
|
||||||
|
|
||||||
WrapUnsafeBinder(ref op, ty) => {
|
WrapUnsafeBinder(ref op, ty) => {
|
||||||
with_no_trimmed_paths!(write!(fmt, "wrap_binder!({op:?}; {ty})"))
|
with_no_trimmed_paths!(write!(fmt, "wrap_binder!({op:?}; {ty})"))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -747,11 +747,6 @@ impl<'tcx> ConstOperand<'tcx> {
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Rvalues
|
// Rvalues
|
||||||
|
|
||||||
pub enum RvalueInitializationState {
|
|
||||||
Shallow,
|
|
||||||
Deep,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> Rvalue<'tcx> {
|
impl<'tcx> Rvalue<'tcx> {
|
||||||
/// Returns true if rvalue can be safely removed when the result is unused.
|
/// Returns true if rvalue can be safely removed when the result is unused.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
@ -786,7 +781,6 @@ impl<'tcx> Rvalue<'tcx> {
|
||||||
| Rvalue::UnaryOp(_, _)
|
| Rvalue::UnaryOp(_, _)
|
||||||
| Rvalue::Discriminant(_)
|
| Rvalue::Discriminant(_)
|
||||||
| Rvalue::Aggregate(_, _)
|
| Rvalue::Aggregate(_, _)
|
||||||
| Rvalue::ShallowInitBox(_, _)
|
|
||||||
| Rvalue::WrapUnsafeBinder(_, _) => true,
|
| Rvalue::WrapUnsafeBinder(_, _) => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -833,21 +827,10 @@ impl<'tcx> Rvalue<'tcx> {
|
||||||
}
|
}
|
||||||
AggregateKind::RawPtr(ty, mutability) => Ty::new_ptr(tcx, ty, mutability),
|
AggregateKind::RawPtr(ty, mutability) => Ty::new_ptr(tcx, ty, mutability),
|
||||||
},
|
},
|
||||||
Rvalue::ShallowInitBox(_, ty) => Ty::new_box(tcx, ty),
|
|
||||||
Rvalue::CopyForDeref(ref place) => place.ty(local_decls, tcx).ty,
|
Rvalue::CopyForDeref(ref place) => place.ty(local_decls, tcx).ty,
|
||||||
Rvalue::WrapUnsafeBinder(_, ty) => ty,
|
Rvalue::WrapUnsafeBinder(_, ty) => ty,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Returns `true` if this rvalue is deeply initialized (most rvalues) or
|
|
||||||
/// whether its only shallowly initialized (`Rvalue::Box`).
|
|
||||||
pub fn initialization_state(&self) -> RvalueInitializationState {
|
|
||||||
match *self {
|
|
||||||
Rvalue::ShallowInitBox(_, _) => RvalueInitializationState::Shallow,
|
|
||||||
_ => RvalueInitializationState::Deep,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BorrowKind {
|
impl BorrowKind {
|
||||||
|
|
|
||||||
|
|
@ -1458,13 +1458,6 @@ pub enum Rvalue<'tcx> {
|
||||||
/// coroutine lowering, `Coroutine` aggregate kinds are disallowed too.
|
/// coroutine lowering, `Coroutine` aggregate kinds are disallowed too.
|
||||||
Aggregate(Box<AggregateKind<'tcx>>, IndexVec<FieldIdx, Operand<'tcx>>),
|
Aggregate(Box<AggregateKind<'tcx>>, IndexVec<FieldIdx, Operand<'tcx>>),
|
||||||
|
|
||||||
/// Transmutes a `*mut u8` into shallow-initialized `Box<T>`.
|
|
||||||
///
|
|
||||||
/// This is different from a normal transmute because dataflow analysis will treat the box as
|
|
||||||
/// initialized but its content as uninitialized. Like other pointer casts, this in general
|
|
||||||
/// affects alias analysis.
|
|
||||||
ShallowInitBox(Operand<'tcx>, Ty<'tcx>),
|
|
||||||
|
|
||||||
/// A CopyForDeref is equivalent to a read from a place at the
|
/// A CopyForDeref is equivalent to a read from a place at the
|
||||||
/// codegen level, but is treated specially by drop elaboration. When such a read happens, it
|
/// codegen level, but is treated specially by drop elaboration. When such a read happens, it
|
||||||
/// is guaranteed (via nature of the mir_opt `Derefer` in rustc_mir_transform/src/deref_separator)
|
/// is guaranteed (via nature of the mir_opt `Derefer` in rustc_mir_transform/src/deref_separator)
|
||||||
|
|
|
||||||
|
|
@ -810,11 +810,6 @@ macro_rules! make_mir_visitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rvalue::ShallowInitBox(operand, ty) => {
|
|
||||||
self.visit_operand(operand, location);
|
|
||||||
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
|
|
||||||
}
|
|
||||||
|
|
||||||
Rvalue::WrapUnsafeBinder(op, ty) => {
|
Rvalue::WrapUnsafeBinder(op, ty) => {
|
||||||
self.visit_operand(op, location);
|
self.visit_operand(op, location);
|
||||||
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
|
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ where
|
||||||
#[inline]
|
#[inline]
|
||||||
fn complete(&self, key: K, value: V, index: DepNodeIndex) {
|
fn complete(&self, key: K, value: V, index: DepNodeIndex) {
|
||||||
// We may be overwriting another value. This is all right, since the dep-graph
|
// We may be overwriting another value. This is all right, since the dep-graph
|
||||||
// will check that the fingerprint matches.
|
// will check that the value fingerprint matches.
|
||||||
self.cache.insert(key, (value, index));
|
self.cache.insert(key, (value, index));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ pub fn incremental_verify_ich<'tcx, V>(
|
||||||
tcx.with_stable_hashing_context(|mut hcx| f(&mut hcx, result))
|
tcx.with_stable_hashing_context(|mut hcx| f(&mut hcx, result))
|
||||||
});
|
});
|
||||||
|
|
||||||
let old_hash = dep_graph_data.prev_fingerprint_of(prev_index);
|
let old_hash = dep_graph_data.prev_value_fingerprint_of(prev_index);
|
||||||
|
|
||||||
if new_hash != old_hash {
|
if new_hash != old_hash {
|
||||||
incremental_verify_ich_failed(tcx, prev_index, &|| format_value(result));
|
incremental_verify_ich_failed(tcx, prev_index, &|| format_value(result));
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,6 @@ where
|
||||||
|
|
||||||
Rvalue::Cast(..)
|
Rvalue::Cast(..)
|
||||||
| Rvalue::Ref(_, BorrowKind::Fake(_), _)
|
| Rvalue::Ref(_, BorrowKind::Fake(_), _)
|
||||||
| Rvalue::ShallowInitBox(..)
|
|
||||||
| Rvalue::Use(..)
|
| Rvalue::Use(..)
|
||||||
| Rvalue::ThreadLocalRef(..)
|
| Rvalue::ThreadLocalRef(..)
|
||||||
| Rvalue::Repeat(..)
|
| Rvalue::Repeat(..)
|
||||||
|
|
|
||||||
|
|
@ -391,15 +391,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
|
||||||
}
|
}
|
||||||
StatementKind::Assign(box (place, rval)) => {
|
StatementKind::Assign(box (place, rval)) => {
|
||||||
self.create_move_path(*place);
|
self.create_move_path(*place);
|
||||||
if let RvalueInitializationState::Shallow = rval.initialization_state() {
|
self.gather_init(place.as_ref(), InitKind::Deep);
|
||||||
// Box starts out uninitialized - need to create a separate
|
|
||||||
// move-path for the interior so it will be separate from
|
|
||||||
// the exterior.
|
|
||||||
self.create_move_path(self.tcx.mk_place_deref(*place));
|
|
||||||
self.gather_init(place.as_ref(), InitKind::Shallow);
|
|
||||||
} else {
|
|
||||||
self.gather_init(place.as_ref(), InitKind::Deep);
|
|
||||||
}
|
|
||||||
self.gather_rvalue(rval);
|
self.gather_rvalue(rval);
|
||||||
}
|
}
|
||||||
StatementKind::FakeRead(box (_, place)) => {
|
StatementKind::FakeRead(box (_, place)) => {
|
||||||
|
|
@ -435,7 +427,6 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
|
||||||
Rvalue::Use(ref operand)
|
Rvalue::Use(ref operand)
|
||||||
| Rvalue::Repeat(ref operand, _)
|
| Rvalue::Repeat(ref operand, _)
|
||||||
| Rvalue::Cast(_, ref operand, _)
|
| Rvalue::Cast(_, ref operand, _)
|
||||||
| Rvalue::ShallowInitBox(ref operand, _)
|
|
||||||
| Rvalue::UnaryOp(_, ref operand)
|
| Rvalue::UnaryOp(_, ref operand)
|
||||||
| Rvalue::WrapUnsafeBinder(ref operand, _) => self.gather_operand(operand),
|
| Rvalue::WrapUnsafeBinder(ref operand, _) => self.gather_operand(operand),
|
||||||
Rvalue::BinaryOp(ref _binop, box (ref lhs, ref rhs)) => {
|
Rvalue::BinaryOp(ref _binop, box (ref lhs, ref rhs)) => {
|
||||||
|
|
|
||||||
|
|
@ -467,7 +467,6 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
|
||||||
Rvalue::Discriminant(place) => state.get_discr(place.as_ref(), &self.map),
|
Rvalue::Discriminant(place) => state.get_discr(place.as_ref(), &self.map),
|
||||||
Rvalue::Use(operand) => return self.handle_operand(operand, state),
|
Rvalue::Use(operand) => return self.handle_operand(operand, state),
|
||||||
Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in runtime MIR"),
|
Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in runtime MIR"),
|
||||||
Rvalue::ShallowInitBox(..) => bug!("`ShallowInitBox` in runtime MIR"),
|
|
||||||
Rvalue::Ref(..) | Rvalue::RawPtr(..) => {
|
Rvalue::Ref(..) | Rvalue::RawPtr(..) => {
|
||||||
// We don't track such places.
|
// We don't track such places.
|
||||||
return ValueOrPlace::TOP;
|
return ValueOrPlace::TOP;
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,8 @@
|
||||||
//! This pass transforms derefs of Box into a deref of the pointer inside Box.
|
//! This pass transforms derefs of Box into a deref of the pointer inside Box.
|
||||||
//!
|
//!
|
||||||
//! Box is not actually a pointer so it is incorrect to dereference it directly.
|
//! Box is not actually a pointer so it is incorrect to dereference it directly.
|
||||||
//!
|
|
||||||
//! `ShallowInitBox` being a device for drop elaboration to understand deferred assignment to box
|
|
||||||
//! contents, we do not need this any more on runtime MIR.
|
|
||||||
|
|
||||||
use rustc_abi::{FieldIdx, VariantIdx};
|
use rustc_abi::FieldIdx;
|
||||||
use rustc_index::{IndexVec, indexvec};
|
|
||||||
use rustc_middle::mir::visit::MutVisitor;
|
use rustc_middle::mir::visit::MutVisitor;
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
use rustc_middle::span_bug;
|
use rustc_middle::span_bug;
|
||||||
|
|
@ -89,68 +85,6 @@ impl<'a, 'tcx> MutVisitor<'tcx> for ElaborateBoxDerefVisitor<'a, 'tcx> {
|
||||||
|
|
||||||
self.super_place(place, context, location);
|
self.super_place(place, context, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_statement(&mut self, stmt: &mut Statement<'tcx>, location: Location) {
|
|
||||||
self.super_statement(stmt, location);
|
|
||||||
|
|
||||||
let tcx = self.tcx;
|
|
||||||
let source_info = stmt.source_info;
|
|
||||||
|
|
||||||
if let StatementKind::Assign(box (_, ref mut rvalue)) = stmt.kind
|
|
||||||
&& let Rvalue::ShallowInitBox(ref mut mutptr_to_u8, pointee) = *rvalue
|
|
||||||
&& let ty::Adt(box_adt, box_args) = Ty::new_box(tcx, pointee).kind()
|
|
||||||
{
|
|
||||||
let args = tcx.mk_args(&[pointee.into()]);
|
|
||||||
let (unique_ty, nonnull_ty, ptr_ty) =
|
|
||||||
build_ptr_tys(tcx, pointee, self.unique_def, self.nonnull_def);
|
|
||||||
let adt_kind = |def: ty::AdtDef<'tcx>, args| {
|
|
||||||
Box::new(AggregateKind::Adt(def.did(), VariantIdx::ZERO, args, None, None))
|
|
||||||
};
|
|
||||||
let zst = |ty| {
|
|
||||||
Operand::Constant(Box::new(ConstOperand {
|
|
||||||
span: source_info.span,
|
|
||||||
user_ty: None,
|
|
||||||
const_: Const::zero_sized(ty),
|
|
||||||
}))
|
|
||||||
};
|
|
||||||
|
|
||||||
let constptr = self.patch.new_temp(ptr_ty, source_info.span);
|
|
||||||
self.patch.add_assign(
|
|
||||||
location,
|
|
||||||
constptr.into(),
|
|
||||||
Rvalue::Cast(CastKind::Transmute, mutptr_to_u8.clone(), ptr_ty),
|
|
||||||
);
|
|
||||||
|
|
||||||
let nonnull = self.patch.new_temp(nonnull_ty, source_info.span);
|
|
||||||
self.patch.add_assign(
|
|
||||||
location,
|
|
||||||
nonnull.into(),
|
|
||||||
Rvalue::Aggregate(
|
|
||||||
adt_kind(self.nonnull_def, args),
|
|
||||||
indexvec![Operand::Move(constptr.into())],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
let unique = self.patch.new_temp(unique_ty, source_info.span);
|
|
||||||
let phantomdata_ty =
|
|
||||||
self.unique_def.non_enum_variant().fields[FieldIdx::ONE].ty(tcx, args);
|
|
||||||
self.patch.add_assign(
|
|
||||||
location,
|
|
||||||
unique.into(),
|
|
||||||
Rvalue::Aggregate(
|
|
||||||
adt_kind(self.unique_def, args),
|
|
||||||
indexvec![Operand::Move(nonnull.into()), zst(phantomdata_ty)],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
let global_alloc_ty =
|
|
||||||
box_adt.non_enum_variant().fields[FieldIdx::ONE].ty(tcx, box_args);
|
|
||||||
*rvalue = Rvalue::Aggregate(
|
|
||||||
adt_kind(*box_adt, box_args),
|
|
||||||
indexvec![Operand::Move(unique.into()), zst(global_alloc_ty)],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct ElaborateBoxDerefs;
|
pub(super) struct ElaborateBoxDerefs;
|
||||||
|
|
|
||||||
|
|
@ -1069,7 +1069,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
|
||||||
|
|
||||||
// Unsupported values.
|
// Unsupported values.
|
||||||
Rvalue::ThreadLocalRef(..) => return None,
|
Rvalue::ThreadLocalRef(..) => return None,
|
||||||
Rvalue::CopyForDeref(_) | Rvalue::ShallowInitBox(..) => {
|
Rvalue::CopyForDeref(_) => {
|
||||||
bug!("forbidden in runtime MIR: {rvalue:?}")
|
bug!("forbidden in runtime MIR: {rvalue:?}")
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -443,7 +443,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
||||||
| Rvalue::CopyForDeref(..)
|
| Rvalue::CopyForDeref(..)
|
||||||
| Rvalue::Repeat(..)
|
| Rvalue::Repeat(..)
|
||||||
| Rvalue::Cast(..)
|
| Rvalue::Cast(..)
|
||||||
| Rvalue::ShallowInitBox(..)
|
|
||||||
| Rvalue::Discriminant(..)
|
| Rvalue::Discriminant(..)
|
||||||
| Rvalue::WrapUnsafeBinder(..) => {}
|
| Rvalue::WrapUnsafeBinder(..) => {}
|
||||||
}
|
}
|
||||||
|
|
@ -605,8 +604,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
||||||
|
|
||||||
Ref(..) | RawPtr(..) => return None,
|
Ref(..) | RawPtr(..) => return None,
|
||||||
|
|
||||||
ShallowInitBox(..) => return None,
|
|
||||||
|
|
||||||
Cast(ref kind, ref value, to) => match kind {
|
Cast(ref kind, ref value, to) => match kind {
|
||||||
CastKind::IntToInt | CastKind::IntToFloat => {
|
CastKind::IntToInt | CastKind::IntToFloat => {
|
||||||
let value = self.eval_operand(value)?;
|
let value = self.eval_operand(value)?;
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Lint<'a, 'tcx> {
|
||||||
| Rvalue::Repeat(..)
|
| Rvalue::Repeat(..)
|
||||||
| Rvalue::Aggregate(..)
|
| Rvalue::Aggregate(..)
|
||||||
| Rvalue::Cast(..)
|
| Rvalue::Cast(..)
|
||||||
| Rvalue::ShallowInitBox(..)
|
|
||||||
| Rvalue::WrapUnsafeBinder(..) => true,
|
| Rvalue::WrapUnsafeBinder(..) => true,
|
||||||
Rvalue::ThreadLocalRef(..)
|
Rvalue::ThreadLocalRef(..)
|
||||||
| Rvalue::UnaryOp(..)
|
| Rvalue::UnaryOp(..)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
|
use std::sync::atomic::Ordering;
|
||||||
|
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
|
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
|
||||||
use rustc_middle::mir::{Body, MirDumper, MirPhase, RuntimePhase};
|
use rustc_middle::mir::{Body, MirDumper, MirPhase, RuntimePhase};
|
||||||
|
|
@ -285,6 +286,19 @@ fn run_passes_inner<'tcx>(
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if is_optimization_stage(body, phase_change, optimizations)
|
||||||
|
&& let Some(limit) = &tcx.sess.opts.unstable_opts.mir_opt_bisect_limit
|
||||||
|
{
|
||||||
|
if limited_by_opt_bisect(
|
||||||
|
tcx,
|
||||||
|
tcx.def_path_debug_str(body.source.def_id()),
|
||||||
|
*limit,
|
||||||
|
*pass,
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let dumper = if pass.is_mir_dump_enabled()
|
let dumper = if pass.is_mir_dump_enabled()
|
||||||
&& let Some(dumper) = MirDumper::new(tcx, pass_name, body)
|
&& let Some(dumper) = MirDumper::new(tcx, pass_name, body)
|
||||||
{
|
{
|
||||||
|
|
@ -356,3 +370,46 @@ pub(super) fn dump_mir_for_phase_change<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tc
|
||||||
dumper.set_show_pass_num().set_disambiguator(&"after").dump_mir(body)
|
dumper.set_show_pass_num().set_disambiguator(&"after").dump_mir(body)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_optimization_stage(
|
||||||
|
body: &Body<'_>,
|
||||||
|
phase_change: Option<MirPhase>,
|
||||||
|
optimizations: Optimizations,
|
||||||
|
) -> bool {
|
||||||
|
optimizations == Optimizations::Allowed
|
||||||
|
&& body.phase == MirPhase::Runtime(RuntimePhase::PostCleanup)
|
||||||
|
&& phase_change == Some(MirPhase::Runtime(RuntimePhase::Optimized))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn limited_by_opt_bisect<'tcx, P>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
def_path: String,
|
||||||
|
limit: usize,
|
||||||
|
pass: &P,
|
||||||
|
) -> bool
|
||||||
|
where
|
||||||
|
P: MirPass<'tcx> + ?Sized,
|
||||||
|
{
|
||||||
|
let current_opt_bisect_count =
|
||||||
|
tcx.sess.mir_opt_bisect_eval_count.fetch_add(1, Ordering::Relaxed);
|
||||||
|
|
||||||
|
let can_run = current_opt_bisect_count < limit;
|
||||||
|
|
||||||
|
if can_run {
|
||||||
|
eprintln!(
|
||||||
|
"BISECT: running pass ({}) {} on {}",
|
||||||
|
current_opt_bisect_count + 1,
|
||||||
|
pass.name(),
|
||||||
|
def_path
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
eprintln!(
|
||||||
|
"BISECT: NOT running pass ({}) {} on {}",
|
||||||
|
current_opt_bisect_count + 1,
|
||||||
|
pass.name(),
|
||||||
|
def_path
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
!can_run
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -449,8 +449,6 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||||
self.validate_operand(operand)?;
|
self.validate_operand(operand)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Rvalue::ShallowInitBox(_, _) => return Err(Unpromotable),
|
|
||||||
|
|
||||||
Rvalue::UnaryOp(op, operand) => {
|
Rvalue::UnaryOp(op, operand) => {
|
||||||
match op {
|
match op {
|
||||||
// These operations can never fail.
|
// These operations can never fail.
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ impl<'tcx> crate::MirPass<'tcx> for SingleUseConsts {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_required(&self) -> bool {
|
fn is_required(&self) -> bool {
|
||||||
true
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1259,14 +1259,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Rvalue::ShallowInitBox(operand, _) => {
|
|
||||||
if self.body.phase >= MirPhase::Runtime(RuntimePhase::Initial) {
|
|
||||||
self.fail(location, format!("ShallowInitBox after ElaborateBoxDerefs"))
|
|
||||||
}
|
|
||||||
|
|
||||||
let a = operand.ty(&self.body.local_decls, self.tcx);
|
|
||||||
check_kinds!(a, "Cannot shallow init type {:?}", ty::RawPtr(..));
|
|
||||||
}
|
|
||||||
Rvalue::Cast(kind, operand, target_type) => {
|
Rvalue::Cast(kind, operand, target_type) => {
|
||||||
let op_ty = operand.ty(self.body, self.tcx);
|
let op_ty = operand.ty(self.body, self.tcx);
|
||||||
match kind {
|
match kind {
|
||||||
|
|
|
||||||
|
|
@ -567,13 +567,6 @@ pub enum Rvalue {
|
||||||
/// [#74836]: https://github.com/rust-lang/rust/issues/74836
|
/// [#74836]: https://github.com/rust-lang/rust/issues/74836
|
||||||
Repeat(Operand, TyConst),
|
Repeat(Operand, TyConst),
|
||||||
|
|
||||||
/// Transmutes a `*mut u8` into shallow-initialized `Box<T>`.
|
|
||||||
///
|
|
||||||
/// This is different from a normal transmute because dataflow analysis will treat the box as
|
|
||||||
/// initialized but its content as uninitialized. Like other pointer casts, this in general
|
|
||||||
/// affects alias analysis.
|
|
||||||
ShallowInitBox(Operand, Ty),
|
|
||||||
|
|
||||||
/// Creates a pointer/reference to the given thread local.
|
/// Creates a pointer/reference to the given thread local.
|
||||||
///
|
///
|
||||||
/// The yielded type is a `*mut T` if the static is mutable, otherwise if the static is extern a
|
/// The yielded type is a `*mut T` if the static is mutable, otherwise if the static is extern a
|
||||||
|
|
@ -651,7 +644,6 @@ impl Rvalue {
|
||||||
}
|
}
|
||||||
AggregateKind::RawPtr(ty, mutability) => Ok(Ty::new_ptr(ty, mutability)),
|
AggregateKind::RawPtr(ty, mutability) => Ok(Ty::new_ptr(ty, mutability)),
|
||||||
},
|
},
|
||||||
Rvalue::ShallowInitBox(_, ty) => Ok(Ty::new_box(*ty)),
|
|
||||||
Rvalue::CopyForDeref(place) => place.ty(locals),
|
Rvalue::CopyForDeref(place) => place.ty(locals),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -383,7 +383,6 @@ fn pretty_rvalue<W: Write>(writer: &mut W, rval: &Rvalue) -> io::Result<()> {
|
||||||
Rvalue::Repeat(op, cnst) => {
|
Rvalue::Repeat(op, cnst) => {
|
||||||
write!(writer, "[{}; {}]", pretty_operand(op), pretty_ty_const(cnst))
|
write!(writer, "[{}; {}]", pretty_operand(op), pretty_ty_const(cnst))
|
||||||
}
|
}
|
||||||
Rvalue::ShallowInitBox(_, _) => Ok(()),
|
|
||||||
Rvalue::ThreadLocalRef(item) => {
|
Rvalue::ThreadLocalRef(item) => {
|
||||||
write!(writer, "thread_local_ref{item:?}")
|
write!(writer, "thread_local_ref{item:?}")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -277,10 +277,6 @@ macro_rules! make_mir_visitor {
|
||||||
self.visit_operand(op, location);
|
self.visit_operand(op, location);
|
||||||
self.visit_ty_const(constant, location);
|
self.visit_ty_const(constant, location);
|
||||||
}
|
}
|
||||||
Rvalue::ShallowInitBox(op, ty) => {
|
|
||||||
self.visit_ty(ty, location);
|
|
||||||
self.visit_operand(op, location)
|
|
||||||
}
|
|
||||||
Rvalue::ThreadLocalRef(_) => {}
|
Rvalue::ThreadLocalRef(_) => {}
|
||||||
Rvalue::UnaryOp(_, op) | Rvalue::Use(op) => {
|
Rvalue::UnaryOp(_, op) | Rvalue::Use(op) => {
|
||||||
self.visit_operand(op, location);
|
self.visit_operand(op, location);
|
||||||
|
|
|
||||||
|
|
@ -240,9 +240,6 @@ impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> {
|
||||||
let operands = operands.iter().map(|op| op.stable(tables, cx)).collect();
|
let operands = operands.iter().map(|op| op.stable(tables, cx)).collect();
|
||||||
crate::mir::Rvalue::Aggregate(agg_kind.stable(tables, cx), operands)
|
crate::mir::Rvalue::Aggregate(agg_kind.stable(tables, cx), operands)
|
||||||
}
|
}
|
||||||
ShallowInitBox(op, ty) => {
|
|
||||||
crate::mir::Rvalue::ShallowInitBox(op.stable(tables, cx), ty.stable(tables, cx))
|
|
||||||
}
|
|
||||||
CopyForDeref(place) => crate::mir::Rvalue::CopyForDeref(place.stable(tables, cx)),
|
CopyForDeref(place) => crate::mir::Rvalue::CopyForDeref(place.stable(tables, cx)),
|
||||||
WrapUnsafeBinder(..) => todo!("FIXME(unsafe_binders):"),
|
WrapUnsafeBinder(..) => todo!("FIXME(unsafe_binders):"),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use rustc_middle::bug;
|
use rustc_middle::bug;
|
||||||
use rustc_middle::dep_graph::{DepKindVTable, DepNodeKey, FingerprintStyle};
|
use rustc_middle::dep_graph::{DepKindVTable, DepNodeKey, KeyFingerprintStyle};
|
||||||
use rustc_middle::query::QueryCache;
|
use rustc_middle::query::QueryCache;
|
||||||
|
|
||||||
use crate::plumbing::{force_from_dep_node_inner, try_load_from_on_disk_cache_inner};
|
use crate::plumbing::{force_from_dep_node_inner, try_load_from_on_disk_cache_inner};
|
||||||
|
|
@ -15,7 +15,7 @@ mod non_query {
|
||||||
DepKindVTable {
|
DepKindVTable {
|
||||||
is_anon: false,
|
is_anon: false,
|
||||||
is_eval_always: false,
|
is_eval_always: false,
|
||||||
fingerprint_style: FingerprintStyle::Unit,
|
key_fingerprint_style: KeyFingerprintStyle::Unit,
|
||||||
force_from_dep_node: Some(|_, dep_node, _| {
|
force_from_dep_node: Some(|_, dep_node, _| {
|
||||||
bug!("force_from_dep_node: encountered {dep_node:?}")
|
bug!("force_from_dep_node: encountered {dep_node:?}")
|
||||||
}),
|
}),
|
||||||
|
|
@ -29,7 +29,7 @@ mod non_query {
|
||||||
DepKindVTable {
|
DepKindVTable {
|
||||||
is_anon: false,
|
is_anon: false,
|
||||||
is_eval_always: false,
|
is_eval_always: false,
|
||||||
fingerprint_style: FingerprintStyle::Unit,
|
key_fingerprint_style: KeyFingerprintStyle::Unit,
|
||||||
force_from_dep_node: Some(|_, dep_node, _| {
|
force_from_dep_node: Some(|_, dep_node, _| {
|
||||||
bug!("force_from_dep_node: encountered {dep_node:?}")
|
bug!("force_from_dep_node: encountered {dep_node:?}")
|
||||||
}),
|
}),
|
||||||
|
|
@ -42,7 +42,7 @@ mod non_query {
|
||||||
DepKindVTable {
|
DepKindVTable {
|
||||||
is_anon: false,
|
is_anon: false,
|
||||||
is_eval_always: false,
|
is_eval_always: false,
|
||||||
fingerprint_style: FingerprintStyle::Unit,
|
key_fingerprint_style: KeyFingerprintStyle::Unit,
|
||||||
force_from_dep_node: Some(|tcx, _, prev_index| {
|
force_from_dep_node: Some(|tcx, _, prev_index| {
|
||||||
tcx.dep_graph.force_diagnostic_node(tcx, prev_index);
|
tcx.dep_graph.force_diagnostic_node(tcx, prev_index);
|
||||||
true
|
true
|
||||||
|
|
@ -56,7 +56,7 @@ mod non_query {
|
||||||
DepKindVTable {
|
DepKindVTable {
|
||||||
is_anon: true,
|
is_anon: true,
|
||||||
is_eval_always: false,
|
is_eval_always: false,
|
||||||
fingerprint_style: FingerprintStyle::Opaque,
|
key_fingerprint_style: KeyFingerprintStyle::Opaque,
|
||||||
force_from_dep_node: Some(|_, _, _| bug!("cannot force an anon node")),
|
force_from_dep_node: Some(|_, _, _| bug!("cannot force an anon node")),
|
||||||
try_load_from_on_disk_cache: None,
|
try_load_from_on_disk_cache: None,
|
||||||
name: &"AnonZeroDeps",
|
name: &"AnonZeroDeps",
|
||||||
|
|
@ -67,7 +67,7 @@ mod non_query {
|
||||||
DepKindVTable {
|
DepKindVTable {
|
||||||
is_anon: true,
|
is_anon: true,
|
||||||
is_eval_always: false,
|
is_eval_always: false,
|
||||||
fingerprint_style: FingerprintStyle::Unit,
|
key_fingerprint_style: KeyFingerprintStyle::Unit,
|
||||||
force_from_dep_node: None,
|
force_from_dep_node: None,
|
||||||
try_load_from_on_disk_cache: None,
|
try_load_from_on_disk_cache: None,
|
||||||
name: &"TraitSelect",
|
name: &"TraitSelect",
|
||||||
|
|
@ -78,7 +78,7 @@ mod non_query {
|
||||||
DepKindVTable {
|
DepKindVTable {
|
||||||
is_anon: false,
|
is_anon: false,
|
||||||
is_eval_always: false,
|
is_eval_always: false,
|
||||||
fingerprint_style: FingerprintStyle::Opaque,
|
key_fingerprint_style: KeyFingerprintStyle::Opaque,
|
||||||
force_from_dep_node: None,
|
force_from_dep_node: None,
|
||||||
try_load_from_on_disk_cache: None,
|
try_load_from_on_disk_cache: None,
|
||||||
name: &"CompileCodegenUnit",
|
name: &"CompileCodegenUnit",
|
||||||
|
|
@ -89,7 +89,7 @@ mod non_query {
|
||||||
DepKindVTable {
|
DepKindVTable {
|
||||||
is_anon: false,
|
is_anon: false,
|
||||||
is_eval_always: false,
|
is_eval_always: false,
|
||||||
fingerprint_style: FingerprintStyle::Opaque,
|
key_fingerprint_style: KeyFingerprintStyle::Opaque,
|
||||||
force_from_dep_node: None,
|
force_from_dep_node: None,
|
||||||
try_load_from_on_disk_cache: None,
|
try_load_from_on_disk_cache: None,
|
||||||
name: &"CompileMonoItem",
|
name: &"CompileMonoItem",
|
||||||
|
|
@ -100,7 +100,7 @@ mod non_query {
|
||||||
DepKindVTable {
|
DepKindVTable {
|
||||||
is_anon: false,
|
is_anon: false,
|
||||||
is_eval_always: false,
|
is_eval_always: false,
|
||||||
fingerprint_style: FingerprintStyle::Unit,
|
key_fingerprint_style: KeyFingerprintStyle::Unit,
|
||||||
force_from_dep_node: None,
|
force_from_dep_node: None,
|
||||||
try_load_from_on_disk_cache: None,
|
try_load_from_on_disk_cache: None,
|
||||||
name: &"Metadata",
|
name: &"Metadata",
|
||||||
|
|
@ -118,17 +118,17 @@ where
|
||||||
Cache: QueryCache + 'tcx,
|
Cache: QueryCache + 'tcx,
|
||||||
{
|
{
|
||||||
let is_anon = FLAGS.is_anon;
|
let is_anon = FLAGS.is_anon;
|
||||||
let fingerprint_style = if is_anon {
|
let key_fingerprint_style = if is_anon {
|
||||||
FingerprintStyle::Opaque
|
KeyFingerprintStyle::Opaque
|
||||||
} else {
|
} else {
|
||||||
<Cache::Key as DepNodeKey<'tcx>>::fingerprint_style()
|
<Cache::Key as DepNodeKey<'tcx>>::key_fingerprint_style()
|
||||||
};
|
};
|
||||||
|
|
||||||
if is_anon || !fingerprint_style.reconstructible() {
|
if is_anon || !key_fingerprint_style.reconstructible() {
|
||||||
return DepKindVTable {
|
return DepKindVTable {
|
||||||
is_anon,
|
is_anon,
|
||||||
is_eval_always,
|
is_eval_always,
|
||||||
fingerprint_style,
|
key_fingerprint_style,
|
||||||
force_from_dep_node: None,
|
force_from_dep_node: None,
|
||||||
try_load_from_on_disk_cache: None,
|
try_load_from_on_disk_cache: None,
|
||||||
name: Q::NAME,
|
name: Q::NAME,
|
||||||
|
|
@ -138,7 +138,7 @@ where
|
||||||
DepKindVTable {
|
DepKindVTable {
|
||||||
is_anon,
|
is_anon,
|
||||||
is_eval_always,
|
is_eval_always,
|
||||||
fingerprint_style,
|
key_fingerprint_style,
|
||||||
force_from_dep_node: Some(|tcx, dep_node, _| {
|
force_from_dep_node: Some(|tcx, dep_node, _| {
|
||||||
force_from_dep_node_inner(Q::query_dispatcher(tcx), tcx, dep_node)
|
force_from_dep_node_inner(Q::query_dispatcher(tcx), tcx, dep_node)
|
||||||
}),
|
}),
|
||||||
|
|
|
||||||
|
|
@ -509,7 +509,7 @@ fn try_load_from_disk_and_cache_in_memory<'tcx, C: QueryCache, const FLAGS: Quer
|
||||||
dep_graph_data.mark_debug_loaded_from_disk(*dep_node)
|
dep_graph_data.mark_debug_loaded_from_disk(*dep_node)
|
||||||
}
|
}
|
||||||
|
|
||||||
let prev_fingerprint = dep_graph_data.prev_fingerprint_of(prev_dep_node_index);
|
let prev_fingerprint = dep_graph_data.prev_value_fingerprint_of(prev_dep_node_index);
|
||||||
// If `-Zincremental-verify-ich` is specified, re-hash results from
|
// If `-Zincremental-verify-ich` is specified, re-hash results from
|
||||||
// the cache and make sure that they have the expected fingerprint.
|
// the cache and make sure that they have the expected fingerprint.
|
||||||
//
|
//
|
||||||
|
|
@ -538,7 +538,7 @@ fn try_load_from_disk_and_cache_in_memory<'tcx, C: QueryCache, const FLAGS: Quer
|
||||||
// can be forced from `DepNode`.
|
// can be forced from `DepNode`.
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
!query.will_cache_on_disk_for_key(tcx, key)
|
!query.will_cache_on_disk_for_key(tcx, key)
|
||||||
|| !tcx.fingerprint_style(dep_node.kind).reconstructible(),
|
|| !tcx.key_fingerprint_style(dep_node.kind).reconstructible(),
|
||||||
"missing on-disk cache entry for {dep_node:?}"
|
"missing on-disk cache entry for {dep_node:?}"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -396,8 +396,11 @@ pub(crate) fn try_load_from_on_disk_cache_inner<'tcx, C: QueryCache, const FLAGS
|
||||||
) {
|
) {
|
||||||
debug_assert!(tcx.dep_graph.is_green(&dep_node));
|
debug_assert!(tcx.dep_graph.is_green(&dep_node));
|
||||||
|
|
||||||
let key = C::Key::recover(tcx, &dep_node).unwrap_or_else(|| {
|
let key = C::Key::try_recover_key(tcx, &dep_node).unwrap_or_else(|| {
|
||||||
panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash)
|
panic!(
|
||||||
|
"Failed to recover key for {dep_node:?} with key fingerprint {}",
|
||||||
|
dep_node.key_fingerprint
|
||||||
|
)
|
||||||
});
|
});
|
||||||
if query.will_cache_on_disk_for_key(tcx, &key) {
|
if query.will_cache_on_disk_for_key(tcx, &key) {
|
||||||
// Call `tcx.$query(key)` for its side-effect of loading the disk-cached
|
// Call `tcx.$query(key)` for its side-effect of loading the disk-cached
|
||||||
|
|
@ -462,7 +465,7 @@ pub(crate) fn force_from_dep_node_inner<'tcx, C: QueryCache, const FLAGS: QueryF
|
||||||
"calling force_from_dep_node() on dep_kinds::codegen_unit"
|
"calling force_from_dep_node() on dep_kinds::codegen_unit"
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Some(key) = C::Key::recover(tcx, &dep_node) {
|
if let Some(key) = C::Key::try_recover_key(tcx, &dep_node) {
|
||||||
force_query(query, tcx, key, dep_node);
|
force_query(query, tcx, key, dep_node);
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -469,9 +469,15 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
|
||||||
PathResult::NonModule(partial_res) => {
|
PathResult::NonModule(partial_res) => {
|
||||||
expected_found_error(partial_res.expect_full_res())
|
expected_found_error(partial_res.expect_full_res())
|
||||||
}
|
}
|
||||||
PathResult::Failed { span, label, suggestion, .. } => {
|
PathResult::Failed {
|
||||||
Err(VisResolutionError::FailedToResolve(span, label, suggestion))
|
span, label, suggestion, message, segment_name, ..
|
||||||
}
|
} => Err(VisResolutionError::FailedToResolve(
|
||||||
|
span,
|
||||||
|
segment_name,
|
||||||
|
label,
|
||||||
|
suggestion,
|
||||||
|
message,
|
||||||
|
)),
|
||||||
PathResult::Indeterminate => Err(VisResolutionError::Indeterminate(path.span)),
|
PathResult::Indeterminate => Err(VisResolutionError::Indeterminate(path.span)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ use rustc_span::edit_distance::find_best_match_for_name;
|
||||||
use rustc_span::edition::Edition;
|
use rustc_span::edition::Edition;
|
||||||
use rustc_span::hygiene::MacroKind;
|
use rustc_span::hygiene::MacroKind;
|
||||||
use rustc_span::source_map::{SourceMap, Spanned};
|
use rustc_span::source_map::{SourceMap, Spanned};
|
||||||
use rustc_span::{BytePos, Ident, Span, Symbol, SyntaxContext, kw, sym};
|
use rustc_span::{BytePos, Ident, RemapPathScopeComponents, Span, Symbol, SyntaxContext, kw, sym};
|
||||||
use thin_vec::{ThinVec, thin_vec};
|
use thin_vec::{ThinVec, thin_vec};
|
||||||
use tracing::{debug, instrument};
|
use tracing::{debug, instrument};
|
||||||
|
|
||||||
|
|
@ -899,9 +899,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||||
ResolutionError::SelfImportOnlyInImportListWithNonEmptyPrefix => {
|
ResolutionError::SelfImportOnlyInImportListWithNonEmptyPrefix => {
|
||||||
self.dcx().create_err(errs::SelfImportOnlyInImportListWithNonEmptyPrefix { span })
|
self.dcx().create_err(errs::SelfImportOnlyInImportListWithNonEmptyPrefix { span })
|
||||||
}
|
}
|
||||||
ResolutionError::FailedToResolve { segment, label, suggestion, module } => {
|
ResolutionError::FailedToResolve { segment, label, suggestion, module, message } => {
|
||||||
let mut err =
|
let mut err = struct_span_code_err!(self.dcx(), span, E0433, "{message}");
|
||||||
struct_span_code_err!(self.dcx(), span, E0433, "failed to resolve: {label}");
|
|
||||||
err.span_label(span, label);
|
err.span_label(span, label);
|
||||||
|
|
||||||
if let Some((suggestions, msg, applicability)) = suggestion {
|
if let Some((suggestions, msg, applicability)) = suggestion {
|
||||||
|
|
@ -909,16 +908,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||||
err.help(msg);
|
err.help(msg);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
err.multipart_suggestion(msg, suggestions, applicability);
|
err.multipart_suggestion_verbose(msg, suggestions, applicability);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(segment) = segment {
|
let module = match module {
|
||||||
let module = match module {
|
Some(ModuleOrUniformRoot::Module(m)) if let Some(id) = m.opt_def_id() => id,
|
||||||
Some(ModuleOrUniformRoot::Module(m)) if let Some(id) = m.opt_def_id() => id,
|
_ => CRATE_DEF_ID.to_def_id(),
|
||||||
_ => CRATE_DEF_ID.to_def_id(),
|
};
|
||||||
};
|
self.find_cfg_stripped(&mut err, &segment, module);
|
||||||
self.find_cfg_stripped(&mut err, &segment, module);
|
|
||||||
}
|
|
||||||
|
|
||||||
err
|
err
|
||||||
}
|
}
|
||||||
|
|
@ -1108,10 +1105,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||||
VisResolutionError::AncestorOnly(span) => {
|
VisResolutionError::AncestorOnly(span) => {
|
||||||
self.dcx().create_err(errs::AncestorOnly(span))
|
self.dcx().create_err(errs::AncestorOnly(span))
|
||||||
}
|
}
|
||||||
VisResolutionError::FailedToResolve(span, label, suggestion) => self.into_struct_error(
|
VisResolutionError::FailedToResolve(span, segment, label, suggestion, message) => self
|
||||||
span,
|
.into_struct_error(
|
||||||
ResolutionError::FailedToResolve { segment: None, label, suggestion, module: None },
|
span,
|
||||||
),
|
ResolutionError::FailedToResolve {
|
||||||
|
segment,
|
||||||
|
label,
|
||||||
|
suggestion,
|
||||||
|
module: None,
|
||||||
|
message,
|
||||||
|
},
|
||||||
|
),
|
||||||
VisResolutionError::ExpectedFound(span, path_str, res) => {
|
VisResolutionError::ExpectedFound(span, path_str, res) => {
|
||||||
self.dcx().create_err(errs::ExpectedModuleFound { span, res, path_str })
|
self.dcx().create_err(errs::ExpectedModuleFound { span, res, path_str })
|
||||||
}
|
}
|
||||||
|
|
@ -2438,13 +2442,25 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||||
failed_segment_idx: usize,
|
failed_segment_idx: usize,
|
||||||
ident: Ident,
|
ident: Ident,
|
||||||
diag_metadata: Option<&DiagMetadata<'_>>,
|
diag_metadata: Option<&DiagMetadata<'_>>,
|
||||||
) -> (String, Option<Suggestion>) {
|
) -> (String, String, Option<Suggestion>) {
|
||||||
let is_last = failed_segment_idx == path.len() - 1;
|
let is_last = failed_segment_idx == path.len() - 1;
|
||||||
let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS };
|
let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS };
|
||||||
let module_res = match module {
|
let module_res = match module {
|
||||||
Some(ModuleOrUniformRoot::Module(module)) => module.res(),
|
Some(ModuleOrUniformRoot::Module(module)) => module.res(),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
let scope = match &path[..failed_segment_idx] {
|
||||||
|
[.., prev] => {
|
||||||
|
if prev.ident.name == kw::PathRoot {
|
||||||
|
format!("the crate root")
|
||||||
|
} else {
|
||||||
|
format!("`{}`", prev.ident)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => format!("this scope"),
|
||||||
|
};
|
||||||
|
let message = format!("cannot find `{ident}` in {scope}");
|
||||||
|
|
||||||
if module_res == self.graph_root.res() {
|
if module_res == self.graph_root.res() {
|
||||||
let is_mod = |res| matches!(res, Res::Def(DefKind::Mod, _));
|
let is_mod = |res| matches!(res, Res::Def(DefKind::Mod, _));
|
||||||
let mut candidates = self.lookup_import_candidates(ident, TypeNS, parent_scope, is_mod);
|
let mut candidates = self.lookup_import_candidates(ident, TypeNS, parent_scope, is_mod);
|
||||||
|
|
@ -2462,6 +2478,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||||
Path { segments, span: Span::default(), tokens: None }
|
Path { segments, span: Span::default(), tokens: None }
|
||||||
};
|
};
|
||||||
(
|
(
|
||||||
|
message,
|
||||||
String::from("unresolved import"),
|
String::from("unresolved import"),
|
||||||
Some((
|
Some((
|
||||||
vec![(ident.span, pprust::path_to_string(&path))],
|
vec![(ident.span, pprust::path_to_string(&path))],
|
||||||
|
|
@ -2471,6 +2488,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||||
)
|
)
|
||||||
} else if ident.name == sym::core {
|
} else if ident.name == sym::core {
|
||||||
(
|
(
|
||||||
|
message,
|
||||||
format!("you might be missing crate `{ident}`"),
|
format!("you might be missing crate `{ident}`"),
|
||||||
Some((
|
Some((
|
||||||
vec![(ident.span, "std".to_string())],
|
vec![(ident.span, "std".to_string())],
|
||||||
|
|
@ -2479,9 +2497,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||||
)),
|
)),
|
||||||
)
|
)
|
||||||
} else if ident.name == kw::Underscore {
|
} else if ident.name == kw::Underscore {
|
||||||
(format!("`_` is not a valid crate or module name"), None)
|
(
|
||||||
|
"invalid crate or module name `_`".to_string(),
|
||||||
|
"`_` is not a valid crate or module name".to_string(),
|
||||||
|
None,
|
||||||
|
)
|
||||||
} else if self.tcx.sess.is_rust_2015() {
|
} else if self.tcx.sess.is_rust_2015() {
|
||||||
(
|
(
|
||||||
|
format!("cannot find module or crate `{ident}` in {scope}"),
|
||||||
format!("use of unresolved module or unlinked crate `{ident}`"),
|
format!("use of unresolved module or unlinked crate `{ident}`"),
|
||||||
Some((
|
Some((
|
||||||
vec![(
|
vec![(
|
||||||
|
|
@ -2490,8 +2513,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||||
)],
|
)],
|
||||||
if was_invoked_from_cargo() {
|
if was_invoked_from_cargo() {
|
||||||
format!(
|
format!(
|
||||||
"if you wanted to use a crate named `{ident}`, use `cargo add {ident}` \
|
"if you wanted to use a crate named `{ident}`, use `cargo add \
|
||||||
to add it to your `Cargo.toml` and import it in your code",
|
{ident}` to add it to your `Cargo.toml` and import it in your \
|
||||||
|
code",
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
format!(
|
format!(
|
||||||
|
|
@ -2503,7 +2527,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||||
)),
|
)),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
(format!("could not find `{ident}` in the crate root"), None)
|
(message, format!("could not find `{ident}` in the crate root"), None)
|
||||||
}
|
}
|
||||||
} else if failed_segment_idx > 0 {
|
} else if failed_segment_idx > 0 {
|
||||||
let parent = path[failed_segment_idx - 1].ident.name;
|
let parent = path[failed_segment_idx - 1].ident.name;
|
||||||
|
|
@ -2569,15 +2593,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
(msg, None)
|
(message, msg, None)
|
||||||
} else if ident.name == kw::SelfUpper {
|
} else if ident.name == kw::SelfUpper {
|
||||||
// As mentioned above, `opt_ns` being `None` indicates a module path in import.
|
// As mentioned above, `opt_ns` being `None` indicates a module path in import.
|
||||||
// We can use this to improve a confusing error for, e.g. `use Self::Variant` in an
|
// We can use this to improve a confusing error for, e.g. `use Self::Variant` in an
|
||||||
// impl
|
// impl
|
||||||
if opt_ns.is_none() {
|
if opt_ns.is_none() {
|
||||||
("`Self` cannot be used in imports".to_string(), None)
|
(message, "`Self` cannot be used in imports".to_string(), None)
|
||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
|
message,
|
||||||
"`Self` is only available in impls, traits, and type definitions".to_string(),
|
"`Self` is only available in impls, traits, and type definitions".to_string(),
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
|
|
@ -2608,12 +2633,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||||
// }
|
// }
|
||||||
// ```
|
// ```
|
||||||
Some(LateDecl::RibDef(Res::Local(id))) => {
|
Some(LateDecl::RibDef(Res::Local(id))) => {
|
||||||
Some(*self.pat_span_map.get(&id).unwrap())
|
Some((*self.pat_span_map.get(&id).unwrap(), "a", "local binding"))
|
||||||
}
|
}
|
||||||
// Name matches item from a local name binding
|
// Name matches item from a local name binding
|
||||||
// created by `use` declaration. For example:
|
// created by `use` declaration. For example:
|
||||||
// ```
|
// ```
|
||||||
// pub Foo: &str = "";
|
// pub const Foo: &str = "";
|
||||||
//
|
//
|
||||||
// mod submod {
|
// mod submod {
|
||||||
// use super::Foo;
|
// use super::Foo;
|
||||||
|
|
@ -2621,18 +2646,27 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||||
// // binding `Foo`.
|
// // binding `Foo`.
|
||||||
// }
|
// }
|
||||||
// ```
|
// ```
|
||||||
Some(LateDecl::Decl(name_binding)) => Some(name_binding.span),
|
Some(LateDecl::Decl(name_binding)) => Some((
|
||||||
|
name_binding.span,
|
||||||
|
name_binding.res().article(),
|
||||||
|
name_binding.res().descr(),
|
||||||
|
)),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
let suggestion = match_span.map(|span| {
|
|
||||||
(
|
|
||||||
vec![(span, String::from(""))],
|
|
||||||
format!("`{ident}` is defined here, but is not a type"),
|
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
(format!("use of undeclared type `{ident}`"), suggestion)
|
let message = format!("cannot find type `{ident}` in {scope}");
|
||||||
|
let label = if let Some((span, article, descr)) = match_span {
|
||||||
|
format!(
|
||||||
|
"`{ident}` is declared as {article} {descr} at `{}`, not a type",
|
||||||
|
self.tcx
|
||||||
|
.sess
|
||||||
|
.source_map()
|
||||||
|
.span_to_short_string(span, RemapPathScopeComponents::DIAGNOSTICS)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
format!("use of undeclared type `{ident}`")
|
||||||
|
};
|
||||||
|
(message, label, None)
|
||||||
} else {
|
} else {
|
||||||
let mut suggestion = None;
|
let mut suggestion = None;
|
||||||
if ident.name == sym::alloc {
|
if ident.name == sym::alloc {
|
||||||
|
|
@ -2663,7 +2697,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||||
ignore_import,
|
ignore_import,
|
||||||
) {
|
) {
|
||||||
let descr = binding.res().descr();
|
let descr = binding.res().descr();
|
||||||
(format!("{descr} `{ident}` is not a crate or module"), suggestion)
|
let message = format!("cannot find module or crate `{ident}` in {scope}");
|
||||||
|
(message, format!("{descr} `{ident}` is not a crate or module"), suggestion)
|
||||||
} else {
|
} else {
|
||||||
let suggestion = if suggestion.is_some() {
|
let suggestion = if suggestion.is_some() {
|
||||||
suggestion
|
suggestion
|
||||||
|
|
@ -2685,7 +2720,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
))
|
))
|
||||||
};
|
};
|
||||||
(format!("use of unresolved module or unlinked crate `{ident}`"), suggestion)
|
let message = format!("cannot find module or crate `{ident}` in {scope}");
|
||||||
|
(
|
||||||
|
message,
|
||||||
|
format!("use of unresolved module or unlinked crate `{ident}`"),
|
||||||
|
suggestion,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1775,7 +1775,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||||
finalize.is_some(),
|
finalize.is_some(),
|
||||||
module_had_parse_errors,
|
module_had_parse_errors,
|
||||||
module,
|
module,
|
||||||
|| ("there are too many leading `super` keywords".to_string(), None),
|
|| {
|
||||||
|
(
|
||||||
|
"too many leading `super` keywords".to_string(),
|
||||||
|
"there are too many leading `super` keywords".to_string(),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if segment_idx == 0 {
|
if segment_idx == 0 {
|
||||||
|
|
@ -1823,16 +1829,24 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||||
module,
|
module,
|
||||||
|| {
|
|| {
|
||||||
let name_str = if name == kw::PathRoot {
|
let name_str = if name == kw::PathRoot {
|
||||||
"crate root".to_string()
|
"the crate root".to_string()
|
||||||
} else {
|
} else {
|
||||||
format!("`{name}`")
|
format!("`{name}`")
|
||||||
};
|
};
|
||||||
let label = if segment_idx == 1 && path[0].ident.name == kw::PathRoot {
|
let (message, label) = if segment_idx == 1
|
||||||
format!("global paths cannot start with {name_str}")
|
&& path[0].ident.name == kw::PathRoot
|
||||||
|
{
|
||||||
|
(
|
||||||
|
format!("global paths cannot start with {name_str}"),
|
||||||
|
"cannot start with this".to_string(),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
format!("{name_str} in paths can only be used in start position")
|
(
|
||||||
|
format!("{name_str} in paths can only be used in start position"),
|
||||||
|
"can only be used in path start position".to_string(),
|
||||||
|
)
|
||||||
};
|
};
|
||||||
(label, None)
|
(message, label, None)
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -1948,7 +1962,20 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||||
res.article(),
|
res.article(),
|
||||||
res.descr()
|
res.descr()
|
||||||
);
|
);
|
||||||
(label, None)
|
let scope = match &path[..segment_idx] {
|
||||||
|
[.., prev] => {
|
||||||
|
if prev.ident.name == kw::PathRoot {
|
||||||
|
format!("the crate root")
|
||||||
|
} else {
|
||||||
|
format!("`{}`", prev.ident)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => format!("this scope"),
|
||||||
|
};
|
||||||
|
// FIXME: reword, as the reason we expected a module is because of
|
||||||
|
// the following path segment.
|
||||||
|
let message = format!("cannot find module `{ident}` in {scope}");
|
||||||
|
(message, label, None)
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -371,6 +371,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||||
// - A glob decl is overwritten by its clone after setting ambiguity in it.
|
// - A glob decl is overwritten by its clone after setting ambiguity in it.
|
||||||
// FIXME: avoid this by removing `warn_ambiguity`, or by triggering glob re-fetch
|
// FIXME: avoid this by removing `warn_ambiguity`, or by triggering glob re-fetch
|
||||||
// with the same decl in some way.
|
// with the same decl in some way.
|
||||||
|
// - A glob decl is overwritten by a glob decl with larger visibility.
|
||||||
|
// FIXME: avoid this by updating this visibility in place.
|
||||||
// - A glob decl is overwritten by a glob decl re-fetching an
|
// - A glob decl is overwritten by a glob decl re-fetching an
|
||||||
// overwritten decl from other module (the recursive case).
|
// overwritten decl from other module (the recursive case).
|
||||||
// Here we are detecting all such re-fetches and overwrite old decls
|
// Here we are detecting all such re-fetches and overwrite old decls
|
||||||
|
|
@ -384,7 +386,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||||
// FIXME: reenable the asserts when `warn_ambiguity` is removed (#149195).
|
// FIXME: reenable the asserts when `warn_ambiguity` is removed (#149195).
|
||||||
// assert_ne!(old_deep_decl, deep_decl);
|
// assert_ne!(old_deep_decl, deep_decl);
|
||||||
// assert!(old_deep_decl.is_glob_import());
|
// assert!(old_deep_decl.is_glob_import());
|
||||||
assert!(!deep_decl.is_glob_import());
|
// FIXME: reenable the assert when visibility is updated in place.
|
||||||
|
// assert!(!deep_decl.is_glob_import());
|
||||||
if old_glob_decl.ambiguity.get().is_some() && glob_decl.ambiguity.get().is_none() {
|
if old_glob_decl.ambiguity.get().is_some() && glob_decl.ambiguity.get().is_none() {
|
||||||
// Do not lose glob ambiguities when re-fetching the glob.
|
// Do not lose glob ambiguities when re-fetching the glob.
|
||||||
glob_decl.ambiguity.set_unchecked(old_glob_decl.ambiguity.get());
|
glob_decl.ambiguity.set_unchecked(old_glob_decl.ambiguity.get());
|
||||||
|
|
@ -1042,16 +1045,18 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||||
suggestion,
|
suggestion,
|
||||||
module,
|
module,
|
||||||
error_implied_by_parse_error: _,
|
error_implied_by_parse_error: _,
|
||||||
|
message,
|
||||||
} => {
|
} => {
|
||||||
if no_ambiguity {
|
if no_ambiguity {
|
||||||
assert!(import.imported_module.get().is_none());
|
assert!(import.imported_module.get().is_none());
|
||||||
self.report_error(
|
self.report_error(
|
||||||
span,
|
span,
|
||||||
ResolutionError::FailedToResolve {
|
ResolutionError::FailedToResolve {
|
||||||
segment: Some(segment_name),
|
segment: segment_name,
|
||||||
label,
|
label,
|
||||||
suggestion,
|
suggestion,
|
||||||
module,
|
module,
|
||||||
|
message,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4890,14 +4890,16 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
||||||
module,
|
module,
|
||||||
segment_name,
|
segment_name,
|
||||||
error_implied_by_parse_error: _,
|
error_implied_by_parse_error: _,
|
||||||
|
message,
|
||||||
} => {
|
} => {
|
||||||
return Err(respan(
|
return Err(respan(
|
||||||
span,
|
span,
|
||||||
ResolutionError::FailedToResolve {
|
ResolutionError::FailedToResolve {
|
||||||
segment: Some(segment_name),
|
segment: segment_name,
|
||||||
label,
|
label,
|
||||||
suggestion,
|
suggestion,
|
||||||
module,
|
module,
|
||||||
|
message,
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4060,25 +4060,32 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||||
"instead, you are more likely to want"
|
"instead, you are more likely to want"
|
||||||
};
|
};
|
||||||
let mut owned_sugg = lt.kind == MissingLifetimeKind::Ampersand;
|
let mut owned_sugg = lt.kind == MissingLifetimeKind::Ampersand;
|
||||||
|
let mut sugg_is_str_to_string = false;
|
||||||
let mut sugg = vec![(lt.span, String::new())];
|
let mut sugg = vec![(lt.span, String::new())];
|
||||||
if let Some((kind, _span)) = self.diag_metadata.current_function
|
if let Some((kind, _span)) = self.diag_metadata.current_function
|
||||||
&& let FnKind::Fn(_, _, ast::Fn { sig, .. }) = kind
|
&& let FnKind::Fn(_, _, ast::Fn { sig, .. }) = kind
|
||||||
&& let ast::FnRetTy::Ty(ty) = &sig.decl.output
|
|
||||||
{
|
{
|
||||||
let mut lt_finder =
|
let mut lt_finder =
|
||||||
LifetimeFinder { lifetime: lt.span, found: None, seen: vec![] };
|
LifetimeFinder { lifetime: lt.span, found: None, seen: vec![] };
|
||||||
lt_finder.visit_ty(&ty);
|
for param in &sig.decl.inputs {
|
||||||
|
lt_finder.visit_ty(¶m.ty);
|
||||||
if let [Ty { span, kind: TyKind::Ref(_, mut_ty), .. }] =
|
}
|
||||||
<_finder.seen[..]
|
if let ast::FnRetTy::Ty(ret_ty) = &sig.decl.output {
|
||||||
{
|
lt_finder.visit_ty(ret_ty);
|
||||||
// We might have a situation like
|
let mut ret_lt_finder =
|
||||||
// fn g(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()>
|
LifetimeFinder { lifetime: lt.span, found: None, seen: vec![] };
|
||||||
// but `lt.span` only points at `'_`, so to suggest `-> Option<()>`
|
ret_lt_finder.visit_ty(ret_ty);
|
||||||
// we need to find a more accurate span to end up with
|
if let [Ty { span, kind: TyKind::Ref(_, mut_ty), .. }] =
|
||||||
// fn g<'a>(mut x: impl Iterator<Item = &'_ ()>) -> Option<()>
|
&ret_lt_finder.seen[..]
|
||||||
sugg = vec![(span.with_hi(mut_ty.ty.span.lo()), String::new())];
|
{
|
||||||
owned_sugg = true;
|
// We might have a situation like
|
||||||
|
// fn g(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()>
|
||||||
|
// but `lt.span` only points at `'_`, so to suggest `-> Option<()>`
|
||||||
|
// we need to find a more accurate span to end up with
|
||||||
|
// fn g<'a>(mut x: impl Iterator<Item = &'_ ()>) -> Option<()>
|
||||||
|
sugg = vec![(span.with_hi(mut_ty.ty.span.lo()), String::new())];
|
||||||
|
owned_sugg = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if let Some(ty) = lt_finder.found {
|
if let Some(ty) = lt_finder.found {
|
||||||
if let TyKind::Path(None, path) = &ty.kind {
|
if let TyKind::Path(None, path) = &ty.kind {
|
||||||
|
|
@ -4098,6 +4105,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||||
lt.span.with_hi(ty.span.hi()),
|
lt.span.with_hi(ty.span.hi()),
|
||||||
"String".to_string(),
|
"String".to_string(),
|
||||||
)];
|
)];
|
||||||
|
sugg_is_str_to_string = true;
|
||||||
}
|
}
|
||||||
Some(Res::PrimTy(..)) => {}
|
Some(Res::PrimTy(..)) => {}
|
||||||
Some(Res::Def(
|
Some(Res::Def(
|
||||||
|
|
@ -4124,6 +4132,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||||
lt.span.with_hi(ty.span.hi()),
|
lt.span.with_hi(ty.span.hi()),
|
||||||
"String".to_string(),
|
"String".to_string(),
|
||||||
)];
|
)];
|
||||||
|
sugg_is_str_to_string = true;
|
||||||
}
|
}
|
||||||
Res::PrimTy(..) => {}
|
Res::PrimTy(..) => {}
|
||||||
Res::Def(
|
Res::Def(
|
||||||
|
|
@ -4158,6 +4167,12 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if owned_sugg {
|
if owned_sugg {
|
||||||
|
if let Some(span) =
|
||||||
|
self.find_ref_prefix_span_for_owned_suggestion(lt.span)
|
||||||
|
&& !sugg_is_str_to_string
|
||||||
|
{
|
||||||
|
sugg = vec![(span, String::new())];
|
||||||
|
}
|
||||||
err.multipart_suggestion_verbose(
|
err.multipart_suggestion_verbose(
|
||||||
format!("{pre} to return an owned value"),
|
format!("{pre} to return an owned value"),
|
||||||
sugg,
|
sugg,
|
||||||
|
|
@ -4184,6 +4199,23 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn find_ref_prefix_span_for_owned_suggestion(&self, lifetime: Span) -> Option<Span> {
|
||||||
|
let mut finder = RefPrefixSpanFinder { lifetime, span: None };
|
||||||
|
if let Some(item) = self.diag_metadata.current_item {
|
||||||
|
finder.visit_item(item);
|
||||||
|
} else if let Some((kind, _span)) = self.diag_metadata.current_function
|
||||||
|
&& let FnKind::Fn(_, _, ast::Fn { sig, .. }) = kind
|
||||||
|
{
|
||||||
|
for param in &sig.decl.inputs {
|
||||||
|
finder.visit_ty(¶m.ty);
|
||||||
|
}
|
||||||
|
if let ast::FnRetTy::Ty(ret_ty) = &sig.decl.output {
|
||||||
|
finder.visit_ty(ret_ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finder.span
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mk_where_bound_predicate(
|
fn mk_where_bound_predicate(
|
||||||
|
|
@ -4285,6 +4317,26 @@ impl<'ast> Visitor<'ast> for LifetimeFinder<'ast> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct RefPrefixSpanFinder {
|
||||||
|
lifetime: Span,
|
||||||
|
span: Option<Span>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ast> Visitor<'ast> for RefPrefixSpanFinder {
|
||||||
|
fn visit_ty(&mut self, t: &'ast Ty) {
|
||||||
|
if self.span.is_some() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if let TyKind::Ref(_, mut_ty) | TyKind::PinnedRef(_, mut_ty) = &t.kind
|
||||||
|
&& t.span.lo() == self.lifetime.lo()
|
||||||
|
{
|
||||||
|
self.span = Some(t.span.with_hi(mut_ty.ty.span.lo()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
walk_ty(self, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Shadowing involving a label is only a warning for historical reasons.
|
/// Shadowing involving a label is only a warning for historical reasons.
|
||||||
//FIXME: make this a proper lint.
|
//FIXME: make this a proper lint.
|
||||||
pub(super) fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident) {
|
pub(super) fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident) {
|
||||||
|
|
|
||||||
|
|
@ -280,10 +280,11 @@ enum ResolutionError<'ra> {
|
||||||
SelfImportOnlyInImportListWithNonEmptyPrefix,
|
SelfImportOnlyInImportListWithNonEmptyPrefix,
|
||||||
/// Error E0433: failed to resolve.
|
/// Error E0433: failed to resolve.
|
||||||
FailedToResolve {
|
FailedToResolve {
|
||||||
segment: Option<Symbol>,
|
segment: Symbol,
|
||||||
label: String,
|
label: String,
|
||||||
suggestion: Option<Suggestion>,
|
suggestion: Option<Suggestion>,
|
||||||
module: Option<ModuleOrUniformRoot<'ra>>,
|
module: Option<ModuleOrUniformRoot<'ra>>,
|
||||||
|
message: String,
|
||||||
},
|
},
|
||||||
/// Error E0434: can't capture dynamic environment in a fn item.
|
/// Error E0434: can't capture dynamic environment in a fn item.
|
||||||
CannotCaptureDynamicEnvironmentInFnItem,
|
CannotCaptureDynamicEnvironmentInFnItem,
|
||||||
|
|
@ -342,7 +343,7 @@ enum ResolutionError<'ra> {
|
||||||
enum VisResolutionError<'a> {
|
enum VisResolutionError<'a> {
|
||||||
Relative2018(Span, &'a ast::Path),
|
Relative2018(Span, &'a ast::Path),
|
||||||
AncestorOnly(Span),
|
AncestorOnly(Span),
|
||||||
FailedToResolve(Span, String, Option<Suggestion>),
|
FailedToResolve(Span, Symbol, String, Option<Suggestion>, String),
|
||||||
ExpectedFound(Span, String, Res),
|
ExpectedFound(Span, String, Res),
|
||||||
Indeterminate(Span),
|
Indeterminate(Span),
|
||||||
ModuleOnly(Span),
|
ModuleOnly(Span),
|
||||||
|
|
@ -486,6 +487,7 @@ enum PathResult<'ra> {
|
||||||
/// The segment name of target
|
/// The segment name of target
|
||||||
segment_name: Symbol,
|
segment_name: Symbol,
|
||||||
error_implied_by_parse_error: bool,
|
error_implied_by_parse_error: bool,
|
||||||
|
message: String,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -496,10 +498,14 @@ impl<'ra> PathResult<'ra> {
|
||||||
finalize: bool,
|
finalize: bool,
|
||||||
error_implied_by_parse_error: bool,
|
error_implied_by_parse_error: bool,
|
||||||
module: Option<ModuleOrUniformRoot<'ra>>,
|
module: Option<ModuleOrUniformRoot<'ra>>,
|
||||||
label_and_suggestion: impl FnOnce() -> (String, Option<Suggestion>),
|
label_and_suggestion: impl FnOnce() -> (String, String, Option<Suggestion>),
|
||||||
) -> PathResult<'ra> {
|
) -> PathResult<'ra> {
|
||||||
let (label, suggestion) =
|
let (message, label, suggestion) = if finalize {
|
||||||
if finalize { label_and_suggestion() } else { (String::new(), None) };
|
label_and_suggestion()
|
||||||
|
} else {
|
||||||
|
// FIXME: this output isn't actually present in the test suite.
|
||||||
|
(format!("cannot find `{ident}` in this scope"), String::new(), None)
|
||||||
|
};
|
||||||
PathResult::Failed {
|
PathResult::Failed {
|
||||||
span: ident.span,
|
span: ident.span,
|
||||||
segment_name: ident.name,
|
segment_name: ident.name,
|
||||||
|
|
@ -508,6 +514,7 @@ impl<'ra> PathResult<'ra> {
|
||||||
is_error_from_last_segment,
|
is_error_from_last_segment,
|
||||||
module,
|
module,
|
||||||
error_implied_by_parse_error,
|
error_implied_by_parse_error,
|
||||||
|
message,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -908,10 +908,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||||
),
|
),
|
||||||
path_res @ (PathResult::NonModule(..) | PathResult::Failed { .. }) => {
|
path_res @ (PathResult::NonModule(..) | PathResult::Failed { .. }) => {
|
||||||
let mut suggestion = None;
|
let mut suggestion = None;
|
||||||
let (span, label, module, segment) =
|
let (span, message, label, module, segment) = match path_res {
|
||||||
if let PathResult::Failed { span, label, module, segment_name, .. } =
|
PathResult::Failed {
|
||||||
path_res
|
span, label, module, segment_name, message, ..
|
||||||
{
|
} => {
|
||||||
// try to suggest if it's not a macro, maybe a function
|
// try to suggest if it's not a macro, maybe a function
|
||||||
if let PathResult::NonModule(partial_res) = self
|
if let PathResult::NonModule(partial_res) = self
|
||||||
.cm()
|
.cm()
|
||||||
|
|
@ -930,26 +930,52 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
(span, label, module, segment_name)
|
(span, message, label, module, segment_name)
|
||||||
} else {
|
}
|
||||||
|
PathResult::NonModule(partial_res) => {
|
||||||
|
let found_an = partial_res.base_res().article();
|
||||||
|
let found_descr = partial_res.base_res().descr();
|
||||||
|
let scope = match &path[..partial_res.unresolved_segments()] {
|
||||||
|
[.., prev] => {
|
||||||
|
format!("{found_descr} `{}`", prev.ident)
|
||||||
|
}
|
||||||
|
_ => found_descr.to_string(),
|
||||||
|
};
|
||||||
|
let expected_an = kind.article();
|
||||||
|
let expected_descr = kind.descr();
|
||||||
|
let expected_name = path[partial_res.unresolved_segments()].ident;
|
||||||
|
|
||||||
(
|
(
|
||||||
path_span,
|
path_span,
|
||||||
format!(
|
format!(
|
||||||
"partially resolved path in {} {}",
|
"cannot find {expected_descr} `{expected_name}` in {scope}"
|
||||||
kind.article(),
|
|
||||||
kind.descr()
|
|
||||||
),
|
),
|
||||||
|
match partial_res.base_res() {
|
||||||
|
Res::Def(
|
||||||
|
DefKind::Mod | DefKind::Macro(..) | DefKind::ExternCrate,
|
||||||
|
_,
|
||||||
|
) => format!(
|
||||||
|
"partially resolved path in {expected_an} {expected_descr}",
|
||||||
|
),
|
||||||
|
_ => format!(
|
||||||
|
"{expected_an} {expected_descr} can't exist within \
|
||||||
|
{found_an} {found_descr}"
|
||||||
|
),
|
||||||
|
},
|
||||||
None,
|
None,
|
||||||
path.last().map(|segment| segment.ident.name).unwrap(),
|
path.last().map(|segment| segment.ident.name).unwrap(),
|
||||||
)
|
)
|
||||||
};
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
self.report_error(
|
self.report_error(
|
||||||
span,
|
span,
|
||||||
ResolutionError::FailedToResolve {
|
ResolutionError::FailedToResolve {
|
||||||
segment: Some(segment),
|
segment,
|
||||||
label,
|
label,
|
||||||
suggestion,
|
suggestion,
|
||||||
module,
|
module,
|
||||||
|
message,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2481,6 +2481,9 @@ options! {
|
||||||
mir_include_spans: MirIncludeSpans = (MirIncludeSpans::default(), parse_mir_include_spans, [UNTRACKED],
|
mir_include_spans: MirIncludeSpans = (MirIncludeSpans::default(), parse_mir_include_spans, [UNTRACKED],
|
||||||
"include extra comments in mir pretty printing, like line numbers and statement indices, \
|
"include extra comments in mir pretty printing, like line numbers and statement indices, \
|
||||||
details about types, etc. (boolean for all passes, 'nll' to enable in NLL MIR only, default: 'nll')"),
|
details about types, etc. (boolean for all passes, 'nll' to enable in NLL MIR only, default: 'nll')"),
|
||||||
|
mir_opt_bisect_limit: Option<usize> = (None, parse_opt_number, [TRACKED],
|
||||||
|
"limit the number of MIR optimization pass executions (global across all bodies). \
|
||||||
|
Pass executions after this limit are skipped and reported. (default: no limit)"),
|
||||||
#[rustc_lint_opt_deny_field_access("use `Session::mir_opt_level` instead of this field")]
|
#[rustc_lint_opt_deny_field_access("use `Session::mir_opt_level` instead of this field")]
|
||||||
mir_opt_level: Option<usize> = (None, parse_opt_number, [TRACKED],
|
mir_opt_level: Option<usize> = (None, parse_opt_number, [TRACKED],
|
||||||
"MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)"),
|
"MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)"),
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use std::any::Any;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::atomic::AtomicBool;
|
use std::sync::atomic::{AtomicBool, AtomicUsize};
|
||||||
use std::{env, io};
|
use std::{env, io};
|
||||||
|
|
||||||
use rand::{RngCore, rng};
|
use rand::{RngCore, rng};
|
||||||
|
|
@ -161,6 +161,12 @@ pub struct Session {
|
||||||
|
|
||||||
/// Does the codegen backend support ThinLTO?
|
/// Does the codegen backend support ThinLTO?
|
||||||
pub thin_lto_supported: bool,
|
pub thin_lto_supported: bool,
|
||||||
|
|
||||||
|
/// Global per-session counter for MIR optimization pass applications.
|
||||||
|
///
|
||||||
|
/// Used by `-Zmir-opt-bisect-limit` to assign an index to each
|
||||||
|
/// optimization-pass execution candidate during this compilation.
|
||||||
|
pub mir_opt_bisect_eval_count: AtomicUsize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
|
@ -1101,6 +1107,7 @@ pub fn build_session(
|
||||||
invocation_temp,
|
invocation_temp,
|
||||||
replaced_intrinsics: FxHashSet::default(), // filled by `run_compiler`
|
replaced_intrinsics: FxHashSet::default(), // filled by `run_compiler`
|
||||||
thin_lto_supported: true, // filled by `run_compiler`
|
thin_lto_supported: true, // filled by `run_compiler`
|
||||||
|
mir_opt_bisect_eval_count: AtomicUsize::new(0),
|
||||||
};
|
};
|
||||||
|
|
||||||
validate_commandline_args_with_session_available(&sess);
|
validate_commandline_args_with_session_available(&sess);
|
||||||
|
|
|
||||||
|
|
@ -327,7 +327,6 @@ symbols! {
|
||||||
Pointer,
|
Pointer,
|
||||||
Poll,
|
Poll,
|
||||||
ProcMacro,
|
ProcMacro,
|
||||||
ProceduralMasqueradeDummyType,
|
|
||||||
Range,
|
Range,
|
||||||
RangeBounds,
|
RangeBounds,
|
||||||
RangeCopy,
|
RangeCopy,
|
||||||
|
|
|
||||||
|
|
@ -300,6 +300,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||||
let rebased_args = alias.args.rebase_onto(tcx, trait_def_id, impl_substs);
|
let rebased_args = alias.args.rebase_onto(tcx, trait_def_id, impl_substs);
|
||||||
|
|
||||||
let impl_item_def_id = leaf_def.item.def_id;
|
let impl_item_def_id = leaf_def.item.def_id;
|
||||||
|
if !tcx.check_args_compatible(impl_item_def_id, rebased_args) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
let impl_assoc_ty = tcx.type_of(impl_item_def_id).instantiate(tcx, rebased_args);
|
let impl_assoc_ty = tcx.type_of(impl_item_def_id).instantiate(tcx, rebased_args);
|
||||||
|
|
||||||
self.infcx.can_eq(param_env, impl_assoc_ty, concrete)
|
self.infcx.can_eq(param_env, impl_assoc_ty, concrete)
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ use rustc_middle::traits::ObligationCauseCode;
|
||||||
use rustc_middle::ty::error::ExpectedFound;
|
use rustc_middle::ty::error::ExpectedFound;
|
||||||
use rustc_middle::ty::print::RegionHighlightMode;
|
use rustc_middle::ty::print::RegionHighlightMode;
|
||||||
use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
|
use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
|
||||||
use rustc_span::Span;
|
use rustc_span::{Ident, Span};
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
use crate::error_reporting::infer::nice_region_error::NiceRegionError;
|
use crate::error_reporting::infer::nice_region_error::NiceRegionError;
|
||||||
|
|
@ -99,7 +99,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
||||||
|
|
||||||
// Get the span of all the used type parameters in the method.
|
// Get the span of all the used type parameters in the method.
|
||||||
let assoc_item = self.tcx().associated_item(trait_item_def_id);
|
let assoc_item = self.tcx().associated_item(trait_item_def_id);
|
||||||
let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] };
|
let mut visitor =
|
||||||
|
TypeParamSpanVisitor { tcx: self.tcx(), types: vec![], elided_lifetime_paths: vec![] };
|
||||||
match assoc_item.kind {
|
match assoc_item.kind {
|
||||||
ty::AssocKind::Fn { .. } => {
|
ty::AssocKind::Fn { .. } => {
|
||||||
if let Some(hir_id) =
|
if let Some(hir_id) =
|
||||||
|
|
@ -122,13 +123,49 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
||||||
found,
|
found,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.tcx().dcx().emit_err(diag)
|
let mut diag = self.tcx().dcx().create_err(diag);
|
||||||
|
// A limit not to make diag verbose.
|
||||||
|
const ELIDED_LIFETIME_NOTE_LIMIT: usize = 5;
|
||||||
|
let elided_lifetime_paths = visitor.elided_lifetime_paths;
|
||||||
|
let total_elided_lifetime_paths = elided_lifetime_paths.len();
|
||||||
|
let shown_elided_lifetime_paths = if tcx.sess.opts.verbose {
|
||||||
|
total_elided_lifetime_paths
|
||||||
|
} else {
|
||||||
|
ELIDED_LIFETIME_NOTE_LIMIT
|
||||||
|
};
|
||||||
|
|
||||||
|
for elided in elided_lifetime_paths.into_iter().take(shown_elided_lifetime_paths) {
|
||||||
|
diag.span_note(
|
||||||
|
elided.span,
|
||||||
|
format!("`{}` here is elided as `{}`", elided.ident, elided.shorthand),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if total_elided_lifetime_paths > shown_elided_lifetime_paths {
|
||||||
|
diag.note(format!(
|
||||||
|
"and {} more elided lifetime{} in type paths",
|
||||||
|
total_elided_lifetime_paths - shown_elided_lifetime_paths,
|
||||||
|
if total_elided_lifetime_paths - shown_elided_lifetime_paths == 1 {
|
||||||
|
""
|
||||||
|
} else {
|
||||||
|
"s"
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
diag.emit()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct ElidedLifetimeInPath {
|
||||||
|
span: Span,
|
||||||
|
ident: Ident,
|
||||||
|
shorthand: String,
|
||||||
|
}
|
||||||
|
|
||||||
struct TypeParamSpanVisitor<'tcx> {
|
struct TypeParamSpanVisitor<'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
types: Vec<Span>,
|
types: Vec<Span>,
|
||||||
|
elided_lifetime_paths: Vec<ElidedLifetimeInPath>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
|
impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
|
||||||
|
|
@ -138,6 +175,83 @@ impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
|
||||||
self.tcx
|
self.tcx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_qpath(&mut self, qpath: &'tcx hir::QPath<'tcx>, id: hir::HirId, _span: Span) {
|
||||||
|
fn record_elided_lifetimes(
|
||||||
|
tcx: TyCtxt<'_>,
|
||||||
|
elided_lifetime_paths: &mut Vec<ElidedLifetimeInPath>,
|
||||||
|
segment: &hir::PathSegment<'_>,
|
||||||
|
) {
|
||||||
|
let Some(args) = segment.args else { return };
|
||||||
|
if args.parenthesized != hir::GenericArgsParentheses::No {
|
||||||
|
// Our diagnostic rendering below uses `<...>` syntax; skip cases like `Fn(..) -> ..`.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let elided_count = args
|
||||||
|
.args
|
||||||
|
.iter()
|
||||||
|
.filter(|arg| {
|
||||||
|
let hir::GenericArg::Lifetime(l) = arg else { return false };
|
||||||
|
l.syntax == hir::LifetimeSyntax::Implicit
|
||||||
|
&& matches!(l.source, hir::LifetimeSource::Path { .. })
|
||||||
|
})
|
||||||
|
.count();
|
||||||
|
if elided_count == 0
|
||||||
|
|| elided_lifetime_paths.iter().any(|p| p.span == segment.ident.span)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let sm = tcx.sess.source_map();
|
||||||
|
let mut parts = args
|
||||||
|
.args
|
||||||
|
.iter()
|
||||||
|
.map(|arg| match arg {
|
||||||
|
hir::GenericArg::Lifetime(l) => {
|
||||||
|
if l.syntax == hir::LifetimeSyntax::Implicit
|
||||||
|
&& matches!(l.source, hir::LifetimeSource::Path { .. })
|
||||||
|
{
|
||||||
|
"'_".to_string()
|
||||||
|
} else {
|
||||||
|
sm.span_to_snippet(l.ident.span)
|
||||||
|
.unwrap_or_else(|_| format!("'{}", l.ident.name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hir::GenericArg::Type(ty) => {
|
||||||
|
sm.span_to_snippet(ty.span).unwrap_or_else(|_| "..".to_string())
|
||||||
|
}
|
||||||
|
hir::GenericArg::Const(ct) => {
|
||||||
|
sm.span_to_snippet(ct.span).unwrap_or_else(|_| "..".to_string())
|
||||||
|
}
|
||||||
|
hir::GenericArg::Infer(_) => "_".to_string(),
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
parts.extend(args.constraints.iter().map(|constraint| {
|
||||||
|
sm.span_to_snippet(constraint.span)
|
||||||
|
.unwrap_or_else(|_| format!("{} = ..", constraint.ident))
|
||||||
|
}));
|
||||||
|
let shorthand = format!("{}<{}>", segment.ident, parts.join(", "));
|
||||||
|
|
||||||
|
elided_lifetime_paths.push(ElidedLifetimeInPath {
|
||||||
|
span: segment.ident.span,
|
||||||
|
ident: segment.ident,
|
||||||
|
shorthand,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
match qpath {
|
||||||
|
hir::QPath::Resolved(_, path) => {
|
||||||
|
for segment in path.segments {
|
||||||
|
record_elided_lifetimes(self.tcx, &mut self.elided_lifetime_paths, segment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hir::QPath::TypeRelative(_, segment) => {
|
||||||
|
record_elided_lifetimes(self.tcx, &mut self.elided_lifetime_paths, segment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hir::intravisit::walk_qpath(self, qpath, id);
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx, AmbigArg>) {
|
fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx, AmbigArg>) {
|
||||||
match arg.kind {
|
match arg.kind {
|
||||||
hir::TyKind::Ref(_, ref mut_ty) => {
|
hir::TyKind::Ref(_, ref mut_ty) => {
|
||||||
|
|
|
||||||
|
|
@ -182,7 +182,6 @@
|
||||||
#![feature(negative_impls)]
|
#![feature(negative_impls)]
|
||||||
#![feature(never_type)]
|
#![feature(never_type)]
|
||||||
#![feature(optimize_attribute)]
|
#![feature(optimize_attribute)]
|
||||||
#![feature(rustc_allow_const_fn_unstable)]
|
|
||||||
#![feature(rustc_attrs)]
|
#![feature(rustc_attrs)]
|
||||||
#![feature(slice_internals)]
|
#![feature(slice_internals)]
|
||||||
#![feature(staged_api)]
|
#![feature(staged_api)]
|
||||||
|
|
|
||||||
|
|
@ -159,7 +159,6 @@
|
||||||
#![feature(pattern_types)]
|
#![feature(pattern_types)]
|
||||||
#![feature(prelude_import)]
|
#![feature(prelude_import)]
|
||||||
#![feature(repr_simd)]
|
#![feature(repr_simd)]
|
||||||
#![feature(rustc_allow_const_fn_unstable)]
|
|
||||||
#![feature(rustc_attrs)]
|
#![feature(rustc_attrs)]
|
||||||
#![feature(rustdoc_internals)]
|
#![feature(rustdoc_internals)]
|
||||||
#![feature(simd_ffi)]
|
#![feature(simd_ffi)]
|
||||||
|
|
|
||||||
|
|
@ -2481,7 +2481,8 @@ macro_rules! int_impl {
|
||||||
///
|
///
|
||||||
/// Returns a tuple of the addition along with a boolean indicating
|
/// Returns a tuple of the addition along with a boolean indicating
|
||||||
/// whether an arithmetic overflow would occur. If an overflow would have
|
/// whether an arithmetic overflow would occur. If an overflow would have
|
||||||
/// occurred then the wrapped value is returned.
|
/// occurred then the wrapped value is returned (negative if overflowed
|
||||||
|
/// above [`MAX`](Self::MAX), non-negative if below [`MIN`](Self::MIN)).
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
|
@ -2516,6 +2517,9 @@ macro_rules! int_impl {
|
||||||
/// The output boolean returned by this method is *not* a carry flag,
|
/// The output boolean returned by this method is *not* a carry flag,
|
||||||
/// and should *not* be added to a more significant word.
|
/// and should *not* be added to a more significant word.
|
||||||
///
|
///
|
||||||
|
/// If overflow occurred, the wrapped value is returned (negative if overflowed
|
||||||
|
/// above [`MAX`](Self::MAX), non-negative if below [`MIN`](Self::MIN)).
|
||||||
|
///
|
||||||
/// If the input carry is false, this method is equivalent to
|
/// If the input carry is false, this method is equivalent to
|
||||||
/// [`overflowing_add`](Self::overflowing_add).
|
/// [`overflowing_add`](Self::overflowing_add).
|
||||||
///
|
///
|
||||||
|
|
@ -2583,7 +2587,8 @@ macro_rules! int_impl {
|
||||||
/// Calculates `self` - `rhs`.
|
/// Calculates `self` - `rhs`.
|
||||||
///
|
///
|
||||||
/// Returns a tuple of the subtraction along with a boolean indicating whether an arithmetic overflow
|
/// Returns a tuple of the subtraction along with a boolean indicating whether an arithmetic overflow
|
||||||
/// would occur. If an overflow would have occurred then the wrapped value is returned.
|
/// would occur. If an overflow would have occurred then the wrapped value is returned
|
||||||
|
/// (negative if overflowed above [`MAX`](Self::MAX), non-negative if below [`MIN`](Self::MIN)).
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
|
@ -2619,6 +2624,9 @@ macro_rules! int_impl {
|
||||||
/// The output boolean returned by this method is *not* a borrow flag,
|
/// The output boolean returned by this method is *not* a borrow flag,
|
||||||
/// and should *not* be subtracted from a more significant word.
|
/// and should *not* be subtracted from a more significant word.
|
||||||
///
|
///
|
||||||
|
/// If overflow occurred, the wrapped value is returned (negative if overflowed
|
||||||
|
/// above [`MAX`](Self::MAX), non-negative if below [`MIN`](Self::MIN)).
|
||||||
|
///
|
||||||
/// If the input borrow is false, this method is equivalent to
|
/// If the input borrow is false, this method is equivalent to
|
||||||
/// [`overflowing_sub`](Self::overflowing_sub).
|
/// [`overflowing_sub`](Self::overflowing_sub).
|
||||||
///
|
///
|
||||||
|
|
|
||||||
|
|
@ -487,8 +487,8 @@ macro_rules! uint_impl {
|
||||||
|
|
||||||
/// Performs a carry-less multiplication, returning the lower bits.
|
/// Performs a carry-less multiplication, returning the lower bits.
|
||||||
///
|
///
|
||||||
/// This operation is similar to long multiplication, except that exclusive or is used
|
/// This operation is similar to long multiplication in base 2, except that exclusive or is
|
||||||
/// instead of addition. The implementation is equivalent to:
|
/// used instead of addition. The implementation is equivalent to:
|
||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
#[doc = concat!("pub fn carryless_mul(lhs: ", stringify!($SelfT), ", rhs: ", stringify!($SelfT), ") -> ", stringify!($SelfT), "{")]
|
#[doc = concat!("pub fn carryless_mul(lhs: ", stringify!($SelfT), ", rhs: ", stringify!($SelfT), ") -> ", stringify!($SelfT), "{")]
|
||||||
|
|
|
||||||
|
|
@ -164,7 +164,7 @@ mod imp {
|
||||||
// of this used `[[NSProcessInfo processInfo] arguments]`.
|
// of this used `[[NSProcessInfo processInfo] arguments]`.
|
||||||
#[cfg(target_vendor = "apple")]
|
#[cfg(target_vendor = "apple")]
|
||||||
mod imp {
|
mod imp {
|
||||||
use crate::ffi::{c_char, c_int};
|
use crate::ffi::c_char;
|
||||||
|
|
||||||
pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
|
pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
|
||||||
// No need to initialize anything in here, `libdyld.dylib` has already
|
// No need to initialize anything in here, `libdyld.dylib` has already
|
||||||
|
|
@ -172,12 +172,6 @@ mod imp {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn argc_argv() -> (isize, *const *const c_char) {
|
pub fn argc_argv() -> (isize, *const *const c_char) {
|
||||||
unsafe extern "C" {
|
|
||||||
// These functions are in crt_externs.h.
|
|
||||||
fn _NSGetArgc() -> *mut c_int;
|
|
||||||
fn _NSGetArgv() -> *mut *mut *mut c_char;
|
|
||||||
}
|
|
||||||
|
|
||||||
// SAFETY: The returned pointer points to a static initialized early
|
// SAFETY: The returned pointer points to a static initialized early
|
||||||
// in the program lifetime by `libdyld.dylib`, and as such is always
|
// in the program lifetime by `libdyld.dylib`, and as such is always
|
||||||
// valid.
|
// valid.
|
||||||
|
|
@ -187,9 +181,9 @@ mod imp {
|
||||||
// doesn't exist a lock that we can take. Instead, it is generally
|
// doesn't exist a lock that we can take. Instead, it is generally
|
||||||
// expected that it's only modified in `main` / before other code
|
// expected that it's only modified in `main` / before other code
|
||||||
// runs, so reading this here should be fine.
|
// runs, so reading this here should be fine.
|
||||||
let argc = unsafe { _NSGetArgc().read() };
|
let argc = unsafe { libc::_NSGetArgc().read() };
|
||||||
// SAFETY: Same as above.
|
// SAFETY: Same as above.
|
||||||
let argv = unsafe { _NSGetArgv().read() };
|
let argv = unsafe { libc::_NSGetArgv().read() };
|
||||||
|
|
||||||
// Cast from `*mut *mut c_char` to `*const *const c_char`
|
// Cast from `*mut *mut c_char` to `*const *const c_char`
|
||||||
(argc as isize, argv.cast())
|
(argc as isize, argv.cast())
|
||||||
|
|
|
||||||
|
|
@ -393,7 +393,7 @@ Here’s how these different lint controls interact:
|
||||||
warning: 1 warning emitted
|
warning: 1 warning emitted
|
||||||
```
|
```
|
||||||
|
|
||||||
3. [CLI level flags](#via-compiler-flag) take precedence over attributes.
|
3. [CLI level flags](#via-compiler-flag) override the default level of a lint. They essentially behave like crate-level attributes. Attributes within the source code take precedence over CLI flags, except for `-F`/`--forbid`, which cannot be overridden.
|
||||||
|
|
||||||
The order of the flags matter; flags on the right take precedence over earlier flags.
|
The order of the flags matter; flags on the right take precedence over earlier flags.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -194,7 +194,6 @@ fn check_rvalue<'tcx>(
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Rvalue::ShallowInitBox(_, _) => Ok(()),
|
|
||||||
Rvalue::UnaryOp(_, operand) => {
|
Rvalue::UnaryOp(_, operand) => {
|
||||||
let ty = operand.ty(body, cx.tcx);
|
let ty = operand.ty(body, cx.tcx);
|
||||||
if ty.is_integral() || ty.is_bool() {
|
if ty.is_integral() || ty.is_bool() {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ struct Foo(isize, isize, isize, isize);
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
let Self::anything_here_kills_it(a, b, ..) = Foo(5, 5, 5, 5);
|
let Self::anything_here_kills_it(a, b, ..) = Foo(5, 5, 5, 5);
|
||||||
//~^ ERROR: failed to resolve
|
//~^ ERROR: cannot find `Self` in this scope
|
||||||
match [5, 5, 5, 5] {
|
match [5, 5, 5, 5] {
|
||||||
[..] => {},
|
[..] => {},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
error[E0433]: failed to resolve: `Self` is only available in impls, traits, and type definitions
|
error[E0433]: cannot find `Self` in this scope
|
||||||
--> tests/ui/crashes/unreachable-array-or-slice.rs:4:9
|
--> tests/ui/crashes/unreachable-array-or-slice.rs:4:9
|
||||||
|
|
|
|
||||||
LL | let Self::anything_here_kills_it(a, b, ..) = Foo(5, 5, 5, 5);
|
LL | let Self::anything_here_kills_it(a, b, ..) = Foo(5, 5, 5, 5);
|
||||||
|
|
|
||||||
|
|
@ -343,8 +343,8 @@ impl VisitProvenance for Thread<'_> {
|
||||||
|
|
||||||
impl VisitProvenance for Frame<'_, Provenance, FrameExtra<'_>> {
|
impl VisitProvenance for Frame<'_, Provenance, FrameExtra<'_>> {
|
||||||
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
|
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
|
||||||
|
let return_place = self.return_place();
|
||||||
let Frame {
|
let Frame {
|
||||||
return_place,
|
|
||||||
locals,
|
locals,
|
||||||
extra,
|
extra,
|
||||||
// There are some private fields we cannot access; they contain no tags.
|
// There are some private fields we cannot access; they contain no tags.
|
||||||
|
|
|
||||||
|
|
@ -493,7 +493,7 @@ pub fn report_result<'tcx>(
|
||||||
for (i, frame) in ecx.active_thread_stack().iter().enumerate() {
|
for (i, frame) in ecx.active_thread_stack().iter().enumerate() {
|
||||||
trace!("-------------------");
|
trace!("-------------------");
|
||||||
trace!("Frame {}", i);
|
trace!("Frame {}", i);
|
||||||
trace!(" return: {:?}", frame.return_place);
|
trace!(" return: {:?}", frame.return_place());
|
||||||
for (i, local) in frame.locals.iter().enumerate() {
|
for (i, local) in frame.locals.iter().enumerate() {
|
||||||
trace!(" local {}: {:?}", i, local);
|
trace!(" local {}: {:?}", i, local);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1235,7 +1235,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
|
||||||
// to run extra MIR), and Ok(Some(body)) if we found MIR to run for the
|
// to run extra MIR), and Ok(Some(body)) if we found MIR to run for the
|
||||||
// foreign function
|
// foreign function
|
||||||
// Any needed call to `goto_block` will be performed by `emulate_foreign_item`.
|
// Any needed call to `goto_block` will be performed by `emulate_foreign_item`.
|
||||||
let args = ecx.copy_fn_args(args); // FIXME: Should `InPlace` arguments be reset to uninit?
|
let args = MiriInterpCx::copy_fn_args(args); // FIXME: Should `InPlace` arguments be reset to uninit?
|
||||||
let link_name = Symbol::intern(ecx.tcx.symbol_name(instance).name);
|
let link_name = Symbol::intern(ecx.tcx.symbol_name(instance).name);
|
||||||
return ecx.emulate_foreign_item(link_name, abi, &args, dest, ret, unwind);
|
return ecx.emulate_foreign_item(link_name, abi, &args, dest, ret, unwind);
|
||||||
}
|
}
|
||||||
|
|
@ -1262,7 +1262,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
|
||||||
ret: Option<mir::BasicBlock>,
|
ret: Option<mir::BasicBlock>,
|
||||||
unwind: mir::UnwindAction,
|
unwind: mir::UnwindAction,
|
||||||
) -> InterpResult<'tcx> {
|
) -> InterpResult<'tcx> {
|
||||||
let args = ecx.copy_fn_args(args); // FIXME: Should `InPlace` arguments be reset to uninit?
|
let args = MiriInterpCx::copy_fn_args(args); // FIXME: Should `InPlace` arguments be reset to uninit?
|
||||||
ecx.emulate_dyn_sym(fn_val, abi, &args, dest, ret, unwind)
|
ecx.emulate_dyn_sym(fn_val, abi, &args, dest, ret, unwind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ struct Struct<T>(T);
|
||||||
impl<T> std::ops::Deref for Struct<T> {
|
impl<T> std::ops::Deref for Struct<T> {
|
||||||
type Target = dyn Fn(T);
|
type Target = dyn Fn(T);
|
||||||
fn deref(&self) -> &assert_mem_uninitialized_valid::Target {
|
fn deref(&self) -> &assert_mem_uninitialized_valid::Target {
|
||||||
//~^ERROR: use of unresolved module or unlinked crate
|
//~^ERROR: cannot find module or crate `assert_mem_uninitialized_valid` in this scope
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
error[E0433]: failed to resolve: use of unresolved module or unlinked crate `assert_mem_uninitialized_valid`
|
error[E0433]: cannot find module or crate `assert_mem_uninitialized_valid` in this scope
|
||||||
--> tests/fail/rustc-error2.rs:LL:CC
|
--> tests/fail/rustc-error2.rs:LL:CC
|
||||||
|
|
|
|
||||||
LL | fn deref(&self) -> &assert_mem_uninitialized_valid::Target {
|
LL | fn deref(&self) -> &assert_mem_uninitialized_valid::Target {
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@ LL | let local = 0;
|
||||||
help: ALLOC was deallocated here:
|
help: ALLOC was deallocated here:
|
||||||
--> tests/fail/tail_calls/dangling-local-var.rs:LL:CC
|
--> tests/fail/tail_calls/dangling-local-var.rs:LL:CC
|
||||||
|
|
|
|
||||||
LL | f(std::ptr::null());
|
LL | let _val = unsafe { *x };
|
||||||
| ^^^^^^^^^^^^^^^^^^^
|
| ^^^^
|
||||||
= note: stack backtrace:
|
= note: stack backtrace:
|
||||||
0: g
|
0: g
|
||||||
at tests/fail/tail_calls/dangling-local-var.rs:LL:CC
|
at tests/fail/tail_calls/dangling-local-var.rs:LL:CC
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
//@compile-flags: -Zmiri-recursive-validation
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = 3u8;
|
||||||
|
let xref = &x;
|
||||||
|
let xref_wrong_type: Box<bool> = unsafe { std::mem::transmute(xref) }; //~ERROR: encountered 0x03, but expected a boolean
|
||||||
|
let _val = *xref_wrong_type;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
error: Undefined Behavior: constructing invalid value at .<deref>: encountered 0x03, but expected a boolean
|
||||||
|
--> tests/fail/validity/recursive-validity-box-bool.rs:LL:CC
|
||||||
|
|
|
||||||
|
LL | let xref_wrong_type: Box<bool> = unsafe { std::mem::transmute(xref) };
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
|
||||||
|
|
|
||||||
|
= 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: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
fn main() {
|
fn main() {
|
||||||
assert_eq!(factorial(10), 3_628_800);
|
assert_eq!(factorial(10), 3_628_800);
|
||||||
assert_eq!(mutually_recursive_identity(1000), 1000);
|
assert_eq!(mutually_recursive_identity(1000), 1000);
|
||||||
|
non_scalar();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn factorial(n: u32) -> u32 {
|
fn factorial(n: u32) -> u32 {
|
||||||
|
|
@ -37,3 +38,14 @@ fn mutually_recursive_identity(x: u32) -> u32 {
|
||||||
|
|
||||||
switch(x, 0)
|
switch(x, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn non_scalar() {
|
||||||
|
fn f(x: [usize; 2], i: u32) {
|
||||||
|
if i == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
become f(x, i - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
f([5, 5], 2);
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
//@ compile-flags: -Copt-level=3
|
//@ compile-flags: -Copt-level=3
|
||||||
#![feature(panic_internals, const_eval_select, rustc_allow_const_fn_unstable, core_intrinsics)]
|
#![feature(panic_internals, const_eval_select, rustc_attrs, core_intrinsics)]
|
||||||
#![crate_type = "lib"]
|
#![crate_type = "lib"]
|
||||||
|
|
||||||
// check that assert! and const_assert! emit branch weights
|
// check that assert! and const_assert! emit branch weights
|
||||||
|
|
|
||||||
|
|
@ -15,13 +15,14 @@ pub fn add_noopt() -> i32 {
|
||||||
#[optimize(none)]
|
#[optimize(none)]
|
||||||
pub fn const_branch() -> i32 {
|
pub fn const_branch() -> i32 {
|
||||||
// CHECK-LABEL: fn const_branch(
|
// CHECK-LABEL: fn const_branch(
|
||||||
// CHECK: switchInt(const true) -> [0: [[FALSE:bb[0-9]+]], otherwise: [[TRUE:bb[0-9]+]]];
|
// CHECK: [[BOOL:_[0-9]+]] = const true;
|
||||||
|
// CHECK: switchInt(move [[BOOL]]) -> [0: [[BB_FALSE:bb[0-9]+]], otherwise: [[BB_TRUE:bb[0-9]+]]];
|
||||||
// CHECK-NEXT: }
|
// CHECK-NEXT: }
|
||||||
// CHECK: [[FALSE]]: {
|
// CHECK: [[BB_FALSE]]: {
|
||||||
// CHECK-NEXT: _0 = const 0
|
// CHECK-NEXT: _0 = const 0
|
||||||
// CHECK-NEXT: goto
|
// CHECK-NEXT: goto
|
||||||
// CHECK-NEXT: }
|
// CHECK-NEXT: }
|
||||||
// CHECK: [[TRUE]]: {
|
// CHECK: [[BB_TRUE]]: {
|
||||||
// CHECK-NEXT: _0 = const 1
|
// CHECK-NEXT: _0 = const 1
|
||||||
// CHECK-NEXT: goto
|
// CHECK-NEXT: goto
|
||||||
// CHECK-NEXT: }
|
// CHECK-NEXT: }
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
error[E0433]: failed to resolve: use of undeclared type `Complete`
|
error[E0433]: cannot find type `Complete` in this scope
|
||||||
--> foo.rs:3:12
|
--> foo.rs:3:12
|
||||||
|
|
|
|
||||||
3 | x.push(Complete::Item { name: "hello" });
|
3 | x.push(Complete::Item { name: "hello" });
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
error[E0433]: failed to resolve: use of undeclared type `Complete`
|
error[E0433]: cannot find type `Complete` in this scope
|
||||||
--> foo.rs:3:12
|
--> foo.rs:3:12
|
||||||
|
|
|
|
||||||
3 | x.push(Complete::Item { name: "hello" });
|
3 | x.push(Complete::Item { name: "hello" });
|
||||||
|
|
|
||||||
11
tests/run-make/mir-opt-bisect-limit/main.rs
Normal file
11
tests/run-make/mir-opt-bisect-limit/main.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
#[inline(never)]
|
||||||
|
pub fn callee(x: u64) -> u64 {
|
||||||
|
x.wrapping_mul(3).wrapping_add(7)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn caller(a: u64, b: u64) -> u64 {
|
||||||
|
callee(a) + callee(b)
|
||||||
|
}
|
||||||
119
tests/run-make/mir-opt-bisect-limit/rmake.rs
Normal file
119
tests/run-make/mir-opt-bisect-limit/rmake.rs
Normal file
|
|
@ -0,0 +1,119 @@
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use run_make_support::{CompletedProcess, rfs, rustc};
|
||||||
|
|
||||||
|
struct Case {
|
||||||
|
name: &'static str,
|
||||||
|
flags: &'static [&'static str],
|
||||||
|
expect_inline_dump: bool,
|
||||||
|
expect_running: ExpectedCount,
|
||||||
|
expect_not_running: ExpectedCount,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ExpectedCount {
|
||||||
|
Exactly(usize),
|
||||||
|
AtLeastOne,
|
||||||
|
Zero,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let cases = [
|
||||||
|
Case {
|
||||||
|
name: "limit0",
|
||||||
|
flags: &["-Zmir-opt-bisect-limit=0"],
|
||||||
|
expect_inline_dump: false,
|
||||||
|
expect_running: ExpectedCount::Exactly(0),
|
||||||
|
expect_not_running: ExpectedCount::AtLeastOne,
|
||||||
|
},
|
||||||
|
Case {
|
||||||
|
name: "limit1",
|
||||||
|
flags: &["-Zmir-opt-bisect-limit=1"],
|
||||||
|
expect_inline_dump: false,
|
||||||
|
expect_running: ExpectedCount::Exactly(1),
|
||||||
|
expect_not_running: ExpectedCount::AtLeastOne,
|
||||||
|
},
|
||||||
|
Case {
|
||||||
|
name: "huge_limit",
|
||||||
|
flags: &["-Zmir-opt-bisect-limit=1000000000"],
|
||||||
|
expect_inline_dump: true,
|
||||||
|
expect_running: ExpectedCount::AtLeastOne,
|
||||||
|
expect_not_running: ExpectedCount::Zero,
|
||||||
|
},
|
||||||
|
Case {
|
||||||
|
name: "limit0_with_force_enable_inline",
|
||||||
|
flags: &["-Zmir-opt-bisect-limit=0", "-Zmir-enable-passes=+Inline"],
|
||||||
|
expect_inline_dump: false,
|
||||||
|
expect_running: ExpectedCount::Exactly(0),
|
||||||
|
expect_not_running: ExpectedCount::AtLeastOne,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
for case in cases {
|
||||||
|
let (inline_dumped, running_count, not_running_count, output) =
|
||||||
|
compile_case(case.name, case.flags);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
inline_dumped, case.expect_inline_dump,
|
||||||
|
"{}: unexpected Inline dump presence",
|
||||||
|
case.name
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_expected_count(
|
||||||
|
running_count,
|
||||||
|
case.expect_running,
|
||||||
|
&format!("{}: running count", case.name),
|
||||||
|
);
|
||||||
|
assert_expected_count(
|
||||||
|
not_running_count,
|
||||||
|
case.expect_not_running,
|
||||||
|
&format!("{}: NOT running count", case.name),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compile_case(dump_dir: &str, extra_flags: &[&str]) -> (bool, usize, usize, CompletedProcess) {
|
||||||
|
if Path::new(dump_dir).exists() {
|
||||||
|
rfs::remove_dir_all(dump_dir);
|
||||||
|
}
|
||||||
|
rfs::create_dir_all(dump_dir);
|
||||||
|
|
||||||
|
let mut cmd = rustc();
|
||||||
|
cmd.input("main.rs")
|
||||||
|
.arg("--emit=mir")
|
||||||
|
.arg("-Zmir-opt-level=2")
|
||||||
|
.arg("-Copt-level=2")
|
||||||
|
.arg("-Zthreads=1")
|
||||||
|
.arg("-Zdump-mir=Inline")
|
||||||
|
.arg(format!("-Zdump-mir-dir={dump_dir}"));
|
||||||
|
|
||||||
|
for &flag in extra_flags {
|
||||||
|
cmd.arg(flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
let output = cmd.run();
|
||||||
|
let (running_count, not_running_count) = bisect_line_counts(&output);
|
||||||
|
(has_inline_dump_file(dump_dir), running_count, not_running_count, output)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assert_expected_count(actual: usize, expected: ExpectedCount, context: &str) {
|
||||||
|
match expected {
|
||||||
|
ExpectedCount::Exactly(n) => assert_eq!(actual, n, "{context}"),
|
||||||
|
ExpectedCount::AtLeastOne => assert!(actual > 0, "{context}"),
|
||||||
|
ExpectedCount::Zero => assert_eq!(actual, 0, "{context}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_inline_dump_file(dir: &str) -> bool {
|
||||||
|
rfs::read_dir(dir)
|
||||||
|
.flatten()
|
||||||
|
.any(|entry| entry.file_name().to_string_lossy().contains(".Inline."))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bisect_line_counts(output: &CompletedProcess) -> (usize, usize) {
|
||||||
|
let stderr = output.stderr_utf8();
|
||||||
|
let running_count =
|
||||||
|
stderr.lines().filter(|line| line.starts_with("BISECT: running pass (")).count();
|
||||||
|
let not_running_count =
|
||||||
|
stderr.lines().filter(|line| line.starts_with("BISECT: NOT running pass (")).count();
|
||||||
|
(running_count, not_running_count)
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Regression test for issue #95879.
|
// Regression test for issue #95879.
|
||||||
|
|
||||||
use unresolved_crate::module::Name; //~ ERROR failed to resolve
|
use unresolved_crate::module::Name; //~ ERROR cannot find
|
||||||
|
|
||||||
/// [Name]
|
/// [Name]
|
||||||
pub struct S;
|
pub struct S;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
error[E0433]: failed to resolve: use of unresolved module or unlinked crate `unresolved_crate`
|
error[E0433]: cannot find module or crate `unresolved_crate` in the crate root
|
||||||
--> $DIR/unresolved-import-recovery.rs:3:5
|
--> $DIR/unresolved-import-recovery.rs:3:5
|
||||||
|
|
|
|
||||||
LL | use unresolved_crate::module::Name;
|
LL | use unresolved_crate::module::Name;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// This previously triggered an ICE.
|
// This previously triggered an ICE.
|
||||||
|
|
||||||
pub(in crate::r#mod) fn main() {}
|
pub(in crate::r#mod) fn main() {}
|
||||||
//~^ ERROR failed to resolve: use of unresolved module or unlinked crate `r#mod`
|
//~^ ERROR cannot find module or crate `r#mod` in `crate`
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
error[E0433]: failed to resolve: use of unresolved module or unlinked crate `r#mod`
|
error[E0433]: cannot find module or crate `r#mod` in `crate`
|
||||||
--> $DIR/issue-61732.rs:3:15
|
--> $DIR/issue-61732.rs:3:15
|
||||||
|
|
|
|
||||||
LL | pub(in crate::r#mod) fn main() {}
|
LL | pub(in crate::r#mod) fn main() {}
|
||||||
|
|
|
||||||
|
|
@ -137,7 +137,7 @@ struct MessageWrongType {
|
||||||
struct InvalidPathFieldAttr {
|
struct InvalidPathFieldAttr {
|
||||||
#[nonsense]
|
#[nonsense]
|
||||||
//~^ ERROR `#[nonsense]` is not a valid attribute
|
//~^ ERROR `#[nonsense]` is not a valid attribute
|
||||||
//~^^ ERROR cannot find attribute `nonsense` in this scope
|
//~| ERROR cannot find attribute `nonsense` in this scope
|
||||||
foo: String,
|
foo: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,14 @@ struct G {
|
||||||
var: String,
|
var: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
#[label("...")]
|
||||||
|
struct H {
|
||||||
|
#[primary_span]
|
||||||
|
span: Span,
|
||||||
|
var: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
#[label(slug = 4)]
|
#[label(slug = 4)]
|
||||||
//~^ ERROR no nested attribute expected here
|
//~^ ERROR no nested attribute expected here
|
||||||
|
|
|
||||||
|
|
@ -35,109 +35,109 @@ LL | #[label(bug = "...")]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: derive(Diagnostic): no nested attribute expected here
|
error: derive(Diagnostic): no nested attribute expected here
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:94:9
|
--> $DIR/subdiagnostic-derive-inline.rs:102:9
|
||||||
|
|
|
|
||||||
LL | #[label(slug = 4)]
|
LL | #[label(slug = 4)]
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
||||||
error: derive(Diagnostic): diagnostic message must be first argument of a `#[label(...)]` attribute
|
error: derive(Diagnostic): diagnostic message must be first argument of a `#[label(...)]` attribute
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:94:1
|
--> $DIR/subdiagnostic-derive-inline.rs:102:1
|
||||||
|
|
|
|
||||||
LL | #[label(slug = 4)]
|
LL | #[label(slug = 4)]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: derive(Diagnostic): no nested attribute expected here
|
error: derive(Diagnostic): no nested attribute expected here
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:104:9
|
--> $DIR/subdiagnostic-derive-inline.rs:112:9
|
||||||
|
|
|
|
||||||
LL | #[label(slug("..."))]
|
LL | #[label(slug("..."))]
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
||||||
error: derive(Diagnostic): diagnostic message must be first argument of a `#[label(...)]` attribute
|
error: derive(Diagnostic): diagnostic message must be first argument of a `#[label(...)]` attribute
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:104:1
|
--> $DIR/subdiagnostic-derive-inline.rs:112:1
|
||||||
|
|
|
|
||||||
LL | #[label(slug("..."))]
|
LL | #[label(slug("..."))]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: derive(Diagnostic): diagnostic message must be first argument of a `#[label(...)]` attribute
|
error: derive(Diagnostic): diagnostic message must be first argument of a `#[label(...)]` attribute
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:114:1
|
--> $DIR/subdiagnostic-derive-inline.rs:122:1
|
||||||
|
|
|
|
||||||
LL | #[label()]
|
LL | #[label()]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: derive(Diagnostic): no nested attribute expected here
|
error: derive(Diagnostic): no nested attribute expected here
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:123:28
|
--> $DIR/subdiagnostic-derive-inline.rs:131:28
|
||||||
|
|
|
|
||||||
LL | #[label("example message", code = "...")]
|
LL | #[label("example message", code = "...")]
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
||||||
error: derive(Diagnostic): no nested attribute expected here
|
error: derive(Diagnostic): no nested attribute expected here
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:132:28
|
--> $DIR/subdiagnostic-derive-inline.rs:140:28
|
||||||
|
|
|
|
||||||
LL | #[label("example message", applicability = "machine-applicable")]
|
LL | #[label("example message", applicability = "machine-applicable")]
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: derive(Diagnostic): unsupported type attribute for subdiagnostic enum
|
error: derive(Diagnostic): unsupported type attribute for subdiagnostic enum
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:141:1
|
--> $DIR/subdiagnostic-derive-inline.rs:149:1
|
||||||
|
|
|
|
||||||
LL | #[foo]
|
LL | #[foo]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: derive(Diagnostic): `#[bar]` is not a valid attribute
|
error: derive(Diagnostic): `#[bar]` is not a valid attribute
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:155:5
|
--> $DIR/subdiagnostic-derive-inline.rs:163:5
|
||||||
|
|
|
|
||||||
LL | #[bar]
|
LL | #[bar]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: derive(Diagnostic): `#[bar = ...]` is not a valid attribute
|
error: derive(Diagnostic): `#[bar = ...]` is not a valid attribute
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:167:5
|
--> $DIR/subdiagnostic-derive-inline.rs:175:5
|
||||||
|
|
|
|
||||||
LL | #[bar = "..."]
|
LL | #[bar = "..."]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: derive(Diagnostic): `#[bar = ...]` is not a valid attribute
|
error: derive(Diagnostic): `#[bar = ...]` is not a valid attribute
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:179:5
|
--> $DIR/subdiagnostic-derive-inline.rs:187:5
|
||||||
|
|
|
|
||||||
LL | #[bar = 4]
|
LL | #[bar = 4]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: derive(Diagnostic): `#[bar(...)]` is not a valid attribute
|
error: derive(Diagnostic): `#[bar(...)]` is not a valid attribute
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:191:5
|
--> $DIR/subdiagnostic-derive-inline.rs:199:5
|
||||||
|
|
|
|
||||||
LL | #[bar("...")]
|
LL | #[bar("...")]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: derive(Diagnostic): no nested attribute expected here
|
error: derive(Diagnostic): no nested attribute expected here
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:203:13
|
--> $DIR/subdiagnostic-derive-inline.rs:211:13
|
||||||
|
|
|
|
||||||
LL | #[label(code = "...")]
|
LL | #[label(code = "...")]
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
||||||
error: derive(Diagnostic): diagnostic message must be first argument of a `#[label(...)]` attribute
|
error: derive(Diagnostic): diagnostic message must be first argument of a `#[label(...)]` attribute
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:203:5
|
--> $DIR/subdiagnostic-derive-inline.rs:211:5
|
||||||
|
|
|
|
||||||
LL | #[label(code = "...")]
|
LL | #[label(code = "...")]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: derive(Diagnostic): the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan`
|
error: derive(Diagnostic): the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan`
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:232:5
|
--> $DIR/subdiagnostic-derive-inline.rs:240:5
|
||||||
|
|
|
|
||||||
LL | #[primary_span]
|
LL | #[primary_span]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: derive(Diagnostic): label without `#[primary_span]` field
|
error: derive(Diagnostic): label without `#[primary_span]` field
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:229:1
|
--> $DIR/subdiagnostic-derive-inline.rs:237:1
|
||||||
|
|
|
|
||||||
LL | #[label("example message")]
|
LL | #[label("example message")]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: derive(Diagnostic): `#[applicability]` is only valid on suggestions
|
error: derive(Diagnostic): `#[applicability]` is only valid on suggestions
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:242:5
|
--> $DIR/subdiagnostic-derive-inline.rs:250:5
|
||||||
|
|
|
|
||||||
LL | #[applicability]
|
LL | #[applicability]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: derive(Diagnostic): `#[bar]` is not a valid attribute
|
error: derive(Diagnostic): `#[bar]` is not a valid attribute
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:252:5
|
--> $DIR/subdiagnostic-derive-inline.rs:260:5
|
||||||
|
|
|
|
||||||
LL | #[bar]
|
LL | #[bar]
|
||||||
| ^
|
| ^
|
||||||
|
|
@ -145,13 +145,13 @@ LL | #[bar]
|
||||||
= help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes
|
= help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes
|
||||||
|
|
||||||
error: derive(Diagnostic): `#[bar = ...]` is not a valid attribute
|
error: derive(Diagnostic): `#[bar = ...]` is not a valid attribute
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:263:5
|
--> $DIR/subdiagnostic-derive-inline.rs:271:5
|
||||||
|
|
|
|
||||||
LL | #[bar = "..."]
|
LL | #[bar = "..."]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: derive(Diagnostic): `#[bar(...)]` is not a valid attribute
|
error: derive(Diagnostic): `#[bar(...)]` is not a valid attribute
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:274:5
|
--> $DIR/subdiagnostic-derive-inline.rs:282:5
|
||||||
|
|
|
|
||||||
LL | #[bar("...")]
|
LL | #[bar("...")]
|
||||||
| ^
|
| ^
|
||||||
|
|
@ -159,7 +159,7 @@ LL | #[bar("...")]
|
||||||
= help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes
|
= help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes
|
||||||
|
|
||||||
error: unexpected unsupported untagged union
|
error: unexpected unsupported untagged union
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:290:1
|
--> $DIR/subdiagnostic-derive-inline.rs:298:1
|
||||||
|
|
|
|
||||||
LL | / union AC {
|
LL | / union AC {
|
||||||
LL | |
|
LL | |
|
||||||
|
|
@ -169,97 +169,97 @@ LL | | }
|
||||||
| |_^
|
| |_^
|
||||||
|
|
||||||
error: expected this path to be an identifier
|
error: expected this path to be an identifier
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:305:28
|
--> $DIR/subdiagnostic-derive-inline.rs:313:28
|
||||||
|
|
|
|
||||||
LL | #[label("example message", no_crate::example)]
|
LL | #[label("example message", no_crate::example)]
|
||||||
| ^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: derive(Diagnostic): attribute specified multiple times
|
error: derive(Diagnostic): attribute specified multiple times
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:318:5
|
--> $DIR/subdiagnostic-derive-inline.rs:326:5
|
||||||
|
|
|
|
||||||
LL | #[primary_span]
|
LL | #[primary_span]
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
note: previously specified here
|
note: previously specified here
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:315:5
|
--> $DIR/subdiagnostic-derive-inline.rs:323:5
|
||||||
|
|
|
|
||||||
LL | #[primary_span]
|
LL | #[primary_span]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: derive(Diagnostic): subdiagnostic kind not specified
|
error: derive(Diagnostic): subdiagnostic kind not specified
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:324:8
|
--> $DIR/subdiagnostic-derive-inline.rs:332:8
|
||||||
|
|
|
|
||||||
LL | struct AG {
|
LL | struct AG {
|
||||||
| ^^
|
| ^^
|
||||||
|
|
||||||
error: derive(Diagnostic): attribute specified multiple times
|
error: derive(Diagnostic): attribute specified multiple times
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:361:47
|
--> $DIR/subdiagnostic-derive-inline.rs:369:47
|
||||||
|
|
|
|
||||||
LL | #[suggestion("example message", code = "...", code = "...")]
|
LL | #[suggestion("example message", code = "...", code = "...")]
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
|
|
||||||
note: previously specified here
|
note: previously specified here
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:361:33
|
--> $DIR/subdiagnostic-derive-inline.rs:369:33
|
||||||
|
|
|
|
||||||
LL | #[suggestion("example message", code = "...", code = "...")]
|
LL | #[suggestion("example message", code = "...", code = "...")]
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
||||||
error: derive(Diagnostic): attribute specified multiple times
|
error: derive(Diagnostic): attribute specified multiple times
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:379:5
|
--> $DIR/subdiagnostic-derive-inline.rs:387:5
|
||||||
|
|
|
|
||||||
LL | #[applicability]
|
LL | #[applicability]
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
note: previously specified here
|
note: previously specified here
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:376:5
|
--> $DIR/subdiagnostic-derive-inline.rs:384:5
|
||||||
|
|
|
|
||||||
LL | #[applicability]
|
LL | #[applicability]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: derive(Diagnostic): the `#[applicability]` attribute can only be applied to fields of type `Applicability`
|
error: derive(Diagnostic): the `#[applicability]` attribute can only be applied to fields of type `Applicability`
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:389:5
|
--> $DIR/subdiagnostic-derive-inline.rs:397:5
|
||||||
|
|
|
|
||||||
LL | #[applicability]
|
LL | #[applicability]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: derive(Diagnostic): suggestion without `code = "..."`
|
error: derive(Diagnostic): suggestion without `code = "..."`
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:402:1
|
--> $DIR/subdiagnostic-derive-inline.rs:410:1
|
||||||
|
|
|
|
||||||
LL | #[suggestion("example message")]
|
LL | #[suggestion("example message")]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: derive(Diagnostic): invalid applicability
|
error: derive(Diagnostic): invalid applicability
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:412:63
|
--> $DIR/subdiagnostic-derive-inline.rs:420:63
|
||||||
|
|
|
|
||||||
LL | #[suggestion("example message", code = "...", applicability = "foo")]
|
LL | #[suggestion("example message", code = "...", applicability = "foo")]
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error: derive(Diagnostic): suggestion without `#[primary_span]` field
|
error: derive(Diagnostic): suggestion without `#[primary_span]` field
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:430:1
|
--> $DIR/subdiagnostic-derive-inline.rs:438:1
|
||||||
|
|
|
|
||||||
LL | #[suggestion("example message", code = "...")]
|
LL | #[suggestion("example message", code = "...")]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: derive(Diagnostic): unsupported type attribute for subdiagnostic enum
|
error: derive(Diagnostic): unsupported type attribute for subdiagnostic enum
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:444:1
|
--> $DIR/subdiagnostic-derive-inline.rs:452:1
|
||||||
|
|
|
|
||||||
LL | #[label]
|
LL | #[label]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: derive(Diagnostic): `var` doesn't refer to a field on this type
|
error: derive(Diagnostic): `var` doesn't refer to a field on this type
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:464:40
|
--> $DIR/subdiagnostic-derive-inline.rs:472:40
|
||||||
|
|
|
|
||||||
LL | #[suggestion("example message", code = "{var}", applicability = "machine-applicable")]
|
LL | #[suggestion("example message", code = "{var}", applicability = "machine-applicable")]
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: derive(Diagnostic): `var` doesn't refer to a field on this type
|
error: derive(Diagnostic): `var` doesn't refer to a field on this type
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:483:44
|
--> $DIR/subdiagnostic-derive-inline.rs:491:44
|
||||||
|
|
|
|
||||||
LL | #[suggestion("example message", code = "{var}", applicability = "machine-applicable")]
|
LL | #[suggestion("example message", code = "{var}", applicability = "machine-applicable")]
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: derive(Diagnostic): `#[suggestion_part]` is not a valid attribute
|
error: derive(Diagnostic): `#[suggestion_part]` is not a valid attribute
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:506:5
|
--> $DIR/subdiagnostic-derive-inline.rs:514:5
|
||||||
|
|
|
|
||||||
LL | #[suggestion_part]
|
LL | #[suggestion_part]
|
||||||
| ^
|
| ^
|
||||||
|
|
@ -267,7 +267,7 @@ LL | #[suggestion_part]
|
||||||
= help: `#[suggestion_part(...)]` is only valid in multipart suggestions, use `#[primary_span]` instead
|
= help: `#[suggestion_part(...)]` is only valid in multipart suggestions, use `#[primary_span]` instead
|
||||||
|
|
||||||
error: derive(Diagnostic): `#[suggestion_part(...)]` is not a valid attribute
|
error: derive(Diagnostic): `#[suggestion_part(...)]` is not a valid attribute
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:509:5
|
--> $DIR/subdiagnostic-derive-inline.rs:517:5
|
||||||
|
|
|
|
||||||
LL | #[suggestion_part(code = "...")]
|
LL | #[suggestion_part(code = "...")]
|
||||||
| ^
|
| ^
|
||||||
|
|
@ -275,13 +275,13 @@ LL | #[suggestion_part(code = "...")]
|
||||||
= help: `#[suggestion_part(...)]` is only valid in multipart suggestions
|
= help: `#[suggestion_part(...)]` is only valid in multipart suggestions
|
||||||
|
|
||||||
error: derive(Diagnostic): suggestion without `#[primary_span]` field
|
error: derive(Diagnostic): suggestion without `#[primary_span]` field
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:503:1
|
--> $DIR/subdiagnostic-derive-inline.rs:511:1
|
||||||
|
|
|
|
||||||
LL | #[suggestion("example message", code = "...")]
|
LL | #[suggestion("example message", code = "...")]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: derive(Diagnostic): invalid nested attribute
|
error: derive(Diagnostic): invalid nested attribute
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:518:43
|
--> $DIR/subdiagnostic-derive-inline.rs:526:43
|
||||||
|
|
|
|
||||||
LL | #[multipart_suggestion("example message", code = "...", applicability = "machine-applicable")]
|
LL | #[multipart_suggestion("example message", code = "...", applicability = "machine-applicable")]
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
@ -289,25 +289,25 @@ LL | #[multipart_suggestion("example message", code = "...", applicability = "ma
|
||||||
= help: only `style` and `applicability` are valid nested attributes
|
= help: only `style` and `applicability` are valid nested attributes
|
||||||
|
|
||||||
error: derive(Diagnostic): multipart suggestion without any `#[suggestion_part(...)]` fields
|
error: derive(Diagnostic): multipart suggestion without any `#[suggestion_part(...)]` fields
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:518:1
|
--> $DIR/subdiagnostic-derive-inline.rs:526:1
|
||||||
|
|
|
|
||||||
LL | #[multipart_suggestion("example message", code = "...", applicability = "machine-applicable")]
|
LL | #[multipart_suggestion("example message", code = "...", applicability = "machine-applicable")]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."`
|
error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."`
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:528:5
|
--> $DIR/subdiagnostic-derive-inline.rs:536:5
|
||||||
|
|
|
|
||||||
LL | #[suggestion_part]
|
LL | #[suggestion_part]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."`
|
error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."`
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:536:5
|
--> $DIR/subdiagnostic-derive-inline.rs:544:5
|
||||||
|
|
|
|
||||||
LL | #[suggestion_part()]
|
LL | #[suggestion_part()]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: derive(Diagnostic): `#[primary_span]` is not a valid attribute
|
error: derive(Diagnostic): `#[primary_span]` is not a valid attribute
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:545:5
|
--> $DIR/subdiagnostic-derive-inline.rs:553:5
|
||||||
|
|
|
|
||||||
LL | #[primary_span]
|
LL | #[primary_span]
|
||||||
| ^
|
| ^
|
||||||
|
|
@ -315,127 +315,127 @@ LL | #[primary_span]
|
||||||
= help: multipart suggestions use one or more `#[suggestion_part]`s rather than one `#[primary_span]`
|
= help: multipart suggestions use one or more `#[suggestion_part]`s rather than one `#[primary_span]`
|
||||||
|
|
||||||
error: derive(Diagnostic): multipart suggestion without any `#[suggestion_part(...)]` fields
|
error: derive(Diagnostic): multipart suggestion without any `#[suggestion_part(...)]` fields
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:542:1
|
--> $DIR/subdiagnostic-derive-inline.rs:550:1
|
||||||
|
|
|
|
||||||
LL | #[multipart_suggestion("example message")]
|
LL | #[multipart_suggestion("example message")]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."`
|
error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."`
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:553:5
|
--> $DIR/subdiagnostic-derive-inline.rs:561:5
|
||||||
|
|
|
|
||||||
LL | #[suggestion_part]
|
LL | #[suggestion_part]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."`
|
error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."`
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:556:5
|
--> $DIR/subdiagnostic-derive-inline.rs:564:5
|
||||||
|
|
|
|
||||||
LL | #[suggestion_part()]
|
LL | #[suggestion_part()]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: derive(Diagnostic): `code` is the only valid nested attribute
|
error: derive(Diagnostic): `code` is the only valid nested attribute
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:559:23
|
--> $DIR/subdiagnostic-derive-inline.rs:567:23
|
||||||
|
|
|
|
||||||
LL | #[suggestion_part(foo = "bar")]
|
LL | #[suggestion_part(foo = "bar")]
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
||||||
error: derive(Diagnostic): the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
|
error: derive(Diagnostic): the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:563:5
|
--> $DIR/subdiagnostic-derive-inline.rs:571:5
|
||||||
|
|
|
|
||||||
LL | #[suggestion_part(code = "...")]
|
LL | #[suggestion_part(code = "...")]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: derive(Diagnostic): the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
|
error: derive(Diagnostic): the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:566:5
|
--> $DIR/subdiagnostic-derive-inline.rs:574:5
|
||||||
|
|
|
|
||||||
LL | #[suggestion_part()]
|
LL | #[suggestion_part()]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: expected `,`
|
error: expected `,`
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:559:27
|
--> $DIR/subdiagnostic-derive-inline.rs:567:27
|
||||||
|
|
|
|
||||||
LL | #[suggestion_part(foo = "bar")]
|
LL | #[suggestion_part(foo = "bar")]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: derive(Diagnostic): attribute specified multiple times
|
error: derive(Diagnostic): attribute specified multiple times
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:574:37
|
--> $DIR/subdiagnostic-derive-inline.rs:582:37
|
||||||
|
|
|
|
||||||
LL | #[suggestion_part(code = "...", code = ",,,")]
|
LL | #[suggestion_part(code = "...", code = ",,,")]
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
|
|
||||||
note: previously specified here
|
note: previously specified here
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:574:23
|
--> $DIR/subdiagnostic-derive-inline.rs:582:23
|
||||||
|
|
|
|
||||||
LL | #[suggestion_part(code = "...", code = ",,,")]
|
LL | #[suggestion_part(code = "...", code = ",,,")]
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
||||||
error: derive(Diagnostic): `#[applicability]` has no effect if all `#[suggestion]`/`#[multipart_suggestion]` attributes have a static `applicability = "..."`
|
error: derive(Diagnostic): `#[applicability]` has no effect if all `#[suggestion]`/`#[multipart_suggestion]` attributes have a static `applicability = "..."`
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:603:5
|
--> $DIR/subdiagnostic-derive-inline.rs:611:5
|
||||||
|
|
|
|
||||||
LL | #[applicability]
|
LL | #[applicability]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: derive(Diagnostic): expected exactly one string literal for `code = ...`
|
error: derive(Diagnostic): expected exactly one string literal for `code = ...`
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:651:28
|
--> $DIR/subdiagnostic-derive-inline.rs:659:28
|
||||||
|
|
|
|
||||||
LL | #[suggestion_part(code("foo"))]
|
LL | #[suggestion_part(code("foo"))]
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error: unexpected token, expected `)`
|
error: unexpected token, expected `)`
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:651:28
|
--> $DIR/subdiagnostic-derive-inline.rs:659:28
|
||||||
|
|
|
|
||||||
LL | #[suggestion_part(code("foo"))]
|
LL | #[suggestion_part(code("foo"))]
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error: derive(Diagnostic): expected exactly one string literal for `code = ...`
|
error: derive(Diagnostic): expected exactly one string literal for `code = ...`
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:661:28
|
--> $DIR/subdiagnostic-derive-inline.rs:669:28
|
||||||
|
|
|
|
||||||
LL | #[suggestion_part(code("foo", "bar"))]
|
LL | #[suggestion_part(code("foo", "bar"))]
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error: unexpected token, expected `)`
|
error: unexpected token, expected `)`
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:661:28
|
--> $DIR/subdiagnostic-derive-inline.rs:669:28
|
||||||
|
|
|
|
||||||
LL | #[suggestion_part(code("foo", "bar"))]
|
LL | #[suggestion_part(code("foo", "bar"))]
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error: derive(Diagnostic): expected exactly one string literal for `code = ...`
|
error: derive(Diagnostic): expected exactly one string literal for `code = ...`
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:671:28
|
--> $DIR/subdiagnostic-derive-inline.rs:679:28
|
||||||
|
|
|
|
||||||
LL | #[suggestion_part(code(3))]
|
LL | #[suggestion_part(code(3))]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: unexpected token, expected `)`
|
error: unexpected token, expected `)`
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:671:28
|
--> $DIR/subdiagnostic-derive-inline.rs:679:28
|
||||||
|
|
|
|
||||||
LL | #[suggestion_part(code(3))]
|
LL | #[suggestion_part(code(3))]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: derive(Diagnostic): expected exactly one string literal for `code = ...`
|
error: derive(Diagnostic): expected exactly one string literal for `code = ...`
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:681:28
|
--> $DIR/subdiagnostic-derive-inline.rs:689:28
|
||||||
|
|
|
|
||||||
LL | #[suggestion_part(code())]
|
LL | #[suggestion_part(code())]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: expected string literal
|
error: expected string literal
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:690:30
|
--> $DIR/subdiagnostic-derive-inline.rs:698:30
|
||||||
|
|
|
|
||||||
LL | #[suggestion_part(code = 3)]
|
LL | #[suggestion_part(code = 3)]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: derive(Diagnostic): attribute specified multiple times
|
error: derive(Diagnostic): attribute specified multiple times
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:732:1
|
--> $DIR/subdiagnostic-derive-inline.rs:740:1
|
||||||
|
|
|
|
||||||
LL | #[suggestion("example message", code = "", style = "hidden", style = "normal")]
|
LL | #[suggestion("example message", code = "", style = "hidden", style = "normal")]
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
note: previously specified here
|
note: previously specified here
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:732:1
|
--> $DIR/subdiagnostic-derive-inline.rs:740:1
|
||||||
|
|
|
|
||||||
LL | #[suggestion("example message", code = "", style = "hidden", style = "normal")]
|
LL | #[suggestion("example message", code = "", style = "hidden", style = "normal")]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: derive(Diagnostic): `#[suggestion_hidden(...)]` is not a valid attribute
|
error: derive(Diagnostic): `#[suggestion_hidden(...)]` is not a valid attribute
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:741:1
|
--> $DIR/subdiagnostic-derive-inline.rs:749:1
|
||||||
|
|
|
|
||||||
LL | #[suggestion_hidden("example message", code = "")]
|
LL | #[suggestion_hidden("example message", code = "")]
|
||||||
| ^
|
| ^
|
||||||
|
|
@ -443,7 +443,7 @@ LL | #[suggestion_hidden("example message", code = "")]
|
||||||
= help: Use `#[suggestion(..., style = "hidden")]` instead
|
= help: Use `#[suggestion(..., style = "hidden")]` instead
|
||||||
|
|
||||||
error: derive(Diagnostic): `#[suggestion_hidden(...)]` is not a valid attribute
|
error: derive(Diagnostic): `#[suggestion_hidden(...)]` is not a valid attribute
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:749:1
|
--> $DIR/subdiagnostic-derive-inline.rs:757:1
|
||||||
|
|
|
|
||||||
LL | #[suggestion_hidden("example message", code = "", style = "normal")]
|
LL | #[suggestion_hidden("example message", code = "", style = "normal")]
|
||||||
| ^
|
| ^
|
||||||
|
|
@ -451,7 +451,7 @@ LL | #[suggestion_hidden("example message", code = "", style = "normal")]
|
||||||
= help: Use `#[suggestion(..., style = "hidden")]` instead
|
= help: Use `#[suggestion(..., style = "hidden")]` instead
|
||||||
|
|
||||||
error: derive(Diagnostic): invalid suggestion style
|
error: derive(Diagnostic): invalid suggestion style
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:757:52
|
--> $DIR/subdiagnostic-derive-inline.rs:765:52
|
||||||
|
|
|
|
||||||
LL | #[suggestion("example message", code = "", style = "foo")]
|
LL | #[suggestion("example message", code = "", style = "foo")]
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
@ -459,25 +459,25 @@ LL | #[suggestion("example message", code = "", style = "foo")]
|
||||||
= help: valid styles are `normal`, `short`, `hidden`, `verbose` and `tool-only`
|
= help: valid styles are `normal`, `short`, `hidden`, `verbose` and `tool-only`
|
||||||
|
|
||||||
error: expected string literal
|
error: expected string literal
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:765:52
|
--> $DIR/subdiagnostic-derive-inline.rs:773:52
|
||||||
|
|
|
|
||||||
LL | #[suggestion("example message", code = "", style = 42)]
|
LL | #[suggestion("example message", code = "", style = 42)]
|
||||||
| ^^
|
| ^^
|
||||||
|
|
||||||
error: expected `=`
|
error: expected `=`
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:773:49
|
--> $DIR/subdiagnostic-derive-inline.rs:781:49
|
||||||
|
|
|
|
||||||
LL | #[suggestion("example message", code = "", style)]
|
LL | #[suggestion("example message", code = "", style)]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: expected `=`
|
error: expected `=`
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:781:49
|
--> $DIR/subdiagnostic-derive-inline.rs:789:49
|
||||||
|
|
|
|
||||||
LL | #[suggestion("example message", code = "", style("foo"))]
|
LL | #[suggestion("example message", code = "", style("foo"))]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: derive(Diagnostic): `#[primary_span]` is not a valid attribute
|
error: derive(Diagnostic): `#[primary_span]` is not a valid attribute
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:792:5
|
--> $DIR/subdiagnostic-derive-inline.rs:800:5
|
||||||
|
|
|
|
||||||
LL | #[primary_span]
|
LL | #[primary_span]
|
||||||
| ^
|
| ^
|
||||||
|
|
@ -486,7 +486,7 @@ LL | #[primary_span]
|
||||||
= help: to create a suggestion with multiple spans, use `#[multipart_suggestion]` instead
|
= help: to create a suggestion with multiple spans, use `#[multipart_suggestion]` instead
|
||||||
|
|
||||||
error: derive(Diagnostic): suggestion without `#[primary_span]` field
|
error: derive(Diagnostic): suggestion without `#[primary_span]` field
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:789:1
|
--> $DIR/subdiagnostic-derive-inline.rs:797:1
|
||||||
|
|
|
|
||||||
LL | #[suggestion("example message", code = "")]
|
LL | #[suggestion("example message", code = "")]
|
||||||
| ^
|
| ^
|
||||||
|
|
@ -498,49 +498,49 @@ LL | #[foo]
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
||||||
error: cannot find attribute `foo` in this scope
|
error: cannot find attribute `foo` in this scope
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:141:3
|
--> $DIR/subdiagnostic-derive-inline.rs:149:3
|
||||||
|
|
|
|
||||||
LL | #[foo]
|
LL | #[foo]
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
||||||
error: cannot find attribute `bar` in this scope
|
error: cannot find attribute `bar` in this scope
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:155:7
|
--> $DIR/subdiagnostic-derive-inline.rs:163:7
|
||||||
|
|
|
|
||||||
LL | #[bar]
|
LL | #[bar]
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
||||||
error: cannot find attribute `bar` in this scope
|
error: cannot find attribute `bar` in this scope
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:167:7
|
--> $DIR/subdiagnostic-derive-inline.rs:175:7
|
||||||
|
|
|
|
||||||
LL | #[bar = "..."]
|
LL | #[bar = "..."]
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
||||||
error: cannot find attribute `bar` in this scope
|
error: cannot find attribute `bar` in this scope
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:179:7
|
--> $DIR/subdiagnostic-derive-inline.rs:187:7
|
||||||
|
|
|
|
||||||
LL | #[bar = 4]
|
LL | #[bar = 4]
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
||||||
error: cannot find attribute `bar` in this scope
|
error: cannot find attribute `bar` in this scope
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:191:7
|
--> $DIR/subdiagnostic-derive-inline.rs:199:7
|
||||||
|
|
|
|
||||||
LL | #[bar("...")]
|
LL | #[bar("...")]
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
||||||
error: cannot find attribute `bar` in this scope
|
error: cannot find attribute `bar` in this scope
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:252:7
|
--> $DIR/subdiagnostic-derive-inline.rs:260:7
|
||||||
|
|
|
|
||||||
LL | #[bar]
|
LL | #[bar]
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
||||||
error: cannot find attribute `bar` in this scope
|
error: cannot find attribute `bar` in this scope
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:263:7
|
--> $DIR/subdiagnostic-derive-inline.rs:271:7
|
||||||
|
|
|
|
||||||
LL | #[bar = "..."]
|
LL | #[bar = "..."]
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
||||||
error: cannot find attribute `bar` in this scope
|
error: cannot find attribute `bar` in this scope
|
||||||
--> $DIR/subdiagnostic-derive-inline.rs:274:7
|
--> $DIR/subdiagnostic-derive-inline.rs:282:7
|
||||||
|
|
|
|
||||||
LL | #[bar("...")]
|
LL | #[bar("...")]
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ fn main() {
|
||||||
// Check that the path of an attribute without a name is printed correctly (issue #140082)
|
// Check that the path of an attribute without a name is printed correctly (issue #140082)
|
||||||
#[::a]
|
#[::a]
|
||||||
//~^ ERROR attribute incompatible with `#[unsafe(naked)]`
|
//~^ ERROR attribute incompatible with `#[unsafe(naked)]`
|
||||||
//~| ERROR failed to resolve: use of unresolved module or unlinked crate `a`
|
//~| ERROR cannot find module or crate `a` in the crate root
|
||||||
#[unsafe(naked)]
|
#[unsafe(naked)]
|
||||||
extern "C" fn issue_140082() {
|
extern "C" fn issue_140082() {
|
||||||
naked_asm!("")
|
naked_asm!("")
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
error[E0433]: failed to resolve: use of unresolved module or unlinked crate `a`
|
error[E0433]: cannot find module or crate `a` in the crate root
|
||||||
--> $DIR/naked-invalid-attr.rs:57:5
|
--> $DIR/naked-invalid-attr.rs:57:5
|
||||||
|
|
|
|
||||||
LL | #[::a]
|
LL | #[::a]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
//@ compile-flags: -Znext-solver=globally
|
||||||
|
|
||||||
|
// Regression test for https://github.com/rust-lang/rust/issues/152684.
|
||||||
|
|
||||||
|
#![feature(associated_type_defaults)]
|
||||||
|
|
||||||
|
trait Foo {
|
||||||
|
type Assoc<T = u8> = T;
|
||||||
|
//~^ ERROR defaults for generic parameters are not allowed here
|
||||||
|
fn foo() -> Self::Assoc;
|
||||||
|
}
|
||||||
|
impl Foo for () {
|
||||||
|
fn foo() -> Self::Assoc {
|
||||||
|
[] //~ ERROR mismatched types
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
error: defaults for generic parameters are not allowed here
|
||||||
|
--> $DIR/suggest-param-env-shadowing-incompatible-args.rs:8:16
|
||||||
|
|
|
||||||
|
LL | type Assoc<T = u8> = T;
|
||||||
|
| ^^^^^^
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/suggest-param-env-shadowing-incompatible-args.rs:14:9
|
||||||
|
|
|
||||||
|
LL | fn foo() -> Self::Assoc {
|
||||||
|
| ----------- expected `<() as Foo>::Assoc` because of return type
|
||||||
|
LL | []
|
||||||
|
| ^^ expected `u8`, found `[_; 0]`
|
||||||
|
|
|
||||||
|
= note: expected type `u8`
|
||||||
|
found array `[_; 0]`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
// Regression test for https://github.com/rust-lang/rust/issues/143789
|
// Regression test for https://github.com/rust-lang/rust/issues/143789
|
||||||
#[must_use::skip]
|
#[must_use::skip]
|
||||||
//~^ ERROR failed to resolve: use of unresolved module or unlinked crate `must_use`
|
//~^ ERROR: cannot find module or crate `must_use`
|
||||||
fn main() { }
|
fn main() { }
|
||||||
|
|
||||||
// Regression test for https://github.com/rust-lang/rust/issues/137590
|
// Regression test for https://github.com/rust-lang/rust/issues/137590
|
||||||
struct S(#[stable::skip] u8, u16, u32);
|
struct S(#[stable::skip] u8, u16, u32);
|
||||||
//~^ ERROR failed to resolve: use of unresolved module or unlinked crate `stable`
|
//~^ ERROR: cannot find module or crate `stable`
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
error[E0433]: failed to resolve: use of unresolved module or unlinked crate `stable`
|
error[E0433]: cannot find module or crate `stable` in this scope
|
||||||
--> $DIR/builtin-attribute-prefix.rs:7:12
|
--> $DIR/builtin-attribute-prefix.rs:7:12
|
||||||
|
|
|
|
||||||
LL | struct S(#[stable::skip] u8, u16, u32);
|
LL | struct S(#[stable::skip] u8, u16, u32);
|
||||||
| ^^^^^^ use of unresolved module or unlinked crate `stable`
|
| ^^^^^^ use of unresolved module or unlinked crate `stable`
|
||||||
|
|
||||||
error[E0433]: failed to resolve: use of unresolved module or unlinked crate `must_use`
|
error[E0433]: cannot find module or crate `must_use` in this scope
|
||||||
--> $DIR/builtin-attribute-prefix.rs:2:3
|
--> $DIR/builtin-attribute-prefix.rs:2:3
|
||||||
|
|
|
|
||||||
LL | #[must_use::skip]
|
LL | #[must_use::skip]
|
||||||
|
|
|
||||||
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