Compare commits

..

1 commit

Author SHA1 Message Date
Rust timing bot
d060fad6ee
Unrolled build for #145399
Rollup merge of #145399 - estebank:resolve-error-wording-2, r=petrochenkov

Unify wording of resolve error

Remove "failed to resolve" from the main error message and use the same format we use in other resolution errors "cannot find `name`":

```
error[E0433]: cannot find `nonexistent` in `existent`
  --> $DIR/custom_attr_multisegment_error.rs:5:13
   |
LL | #[existent::nonexistent]
   |             ^^^^^^^^^^^ could not find `nonexistent` in `existent`
```

The intent behind this is to end up with all resolve errors eventually be on the form of

```
error[ECODE]: cannot find `{NAME}` in {SCOPE}
  --> $DIR/file.rs:5:13
   |
LL | #[existent::nonexistent]
   |             ^^^^^^^^^^^ {SPECIFIC LABEL}
```

A category of errors that is interest are those that involve keywords. For example:

```
error[E0433]: cannot find `Self` in this scope
  --> $DIR/issue-97194.rs:2:35
   |
LL |     fn bget(&self, index: [usize; Self::DIM]) -> bool {
   |                                   ^^^^ `Self` is only available in impls, traits, and type definitions
```
and

```
error[E0433]: cannot find `super` in this scope
  --> $DIR/keyword-super.rs:2:9
   |
LL |     let super: isize;
   |         ^^^^^ there are too many leading `super` keywords
```

For these the label provides the actual help, while the message is less informative beyond telling you "couldn't find `name`".

This is an off-shoot of https://github.com/rust-lang/rust/pull/126810 and https://github.com/rust-lang/rust/pull/128086, a subset of the intended changes there with review comments applied.

r? @petrochenkov
2026-02-18 18:17:37 +01:00
116 changed files with 847 additions and 1217 deletions

View file

@ -1544,7 +1544,8 @@ 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)
} }

View file

@ -297,9 +297,8 @@ 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*/)
self.consume_operand(location, operand) | Rvalue::ShallowInitBox(operand, _ /*ty*/) => self.consume_operand(location, operand),
}
&Rvalue::Discriminant(place) => { &Rvalue::Discriminant(place) => {
self.access_place( self.access_place(

View file

@ -1004,6 +1004,17 @@ 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(
@ -2220,6 +2231,7 @@ 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(..)

View file

@ -902,6 +902,7 @@ 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(_)

View file

@ -710,6 +710,7 @@ 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"),
} }
} }

View file

@ -646,6 +646,8 @@ 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 {

View file

@ -237,7 +237,8 @@ where
Rvalue::Use(operand) Rvalue::Use(operand)
| Rvalue::Repeat(operand, _) | Rvalue::Repeat(operand, _)
| Rvalue::UnaryOp(_, operand) | Rvalue::UnaryOp(_, operand)
| Rvalue::Cast(_, operand, _) => in_operand::<Q, _>(cx, in_local, operand), | Rvalue::Cast(_, 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)

View file

@ -192,6 +192,7 @@ 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(..)

View file

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

View file

@ -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, interp_ok, throw_ub, Projectable, Provenance, ReturnAction, ReturnContinuation, Scalar, StackPopInfo, interp_ok,
throw_ub_custom, throw_ub, throw_ub_custom,
}; };
use crate::enter_trace_span; use crate::enter_trace_span;
use crate::interpret::EnteredTraceSpan; use crate::interpret::EnteredTraceSpan;
@ -43,22 +43,25 @@ 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) -> OpTy<'tcx, Prov> { pub fn copy_fn_arg(&self, arg: &FnArg<'tcx, M::Provenance>) -> OpTy<'tcx, M::Provenance> {
match self { match arg {
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(args: &[FnArg<'tcx, M::Provenance>]) -> Vec<OpTy<'tcx, M::Provenance>> { pub fn copy_fn_args(
args.iter().map(|fn_arg| fn_arg.copy_fn_arg()).collect() &self,
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.
@ -316,7 +319,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 = caller_arg.copy_fn_arg(); let caller_arg_copy = self.copy_fn_arg(caller_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();
@ -613,7 +616,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,
@ -700,7 +703,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 = args[0].copy_fn_arg(); let mut receiver = self.copy_fn_arg(&args[0]);
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(..) => {
@ -821,50 +824,41 @@ 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 cannot use `return_from_current_stack_frame`, // Note that we are using `pop_stack_frame_raw` and not `return_from_current_stack_frame`,
// as that "executes" the goto to the return block, but we don't want to, // as the latter "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(())
})?;
// The arguments need to all be copied since the current stack frame will be removed assert_eq!(return_action, ReturnAction::Normal);
// before the callee even starts executing.
// FIXME(explicit_tail_calls,#144855): does this match what codegen does? // Take the "stack pop cleanup" info, and use that to initiate the next call.
let args = args.iter().map(|fn_arg| FnArg::Copy(fn_arg.copy_fn_arg())).collect::<Vec<_>>(); let ReturnContinuation::Goto { ret, unwind } = return_cont else {
// Remove the frame from the stack. bug!("can't tailcall as root");
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,
frame.return_place(), &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(
@ -959,18 +953,14 @@ 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");
// Remove the frame from the stack. // Do the actual pop + copy.
let frame = self.pop_stack_frame_raw()?; let stack_pop_info = self.pop_stack_frame_raw(unwinding, |this, return_place| {
// Copy the return value and remember the return continuation. this.copy_op_allow_transmute(&return_op, return_place)?;
if !unwinding { trace!("return value: {:?}", this.dump_place(return_place));
self.copy_op_allow_transmute(&return_op, frame.return_place())?; interp_ok(())
trace!("return value: {:?}", self.dump_place(frame.return_place())); })?;
}
let return_cont = frame.return_cont(); match stack_pop_info.return_action {
// 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.
@ -988,7 +978,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 return_cont { match stack_pop_info.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)
@ -999,7 +989,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
} }
} else { } else {
// Follow the normal return edge. // Follow the normal return edge.
match return_cont { match stack_pop_info.return_cont {
ReturnContinuation::Goto { ret, .. } => self.return_to_block(ret), ReturnContinuation::Goto { ret, .. } => self.return_to_block(ret),
ReturnContinuation::Stop { .. } => { ReturnContinuation::Stop { .. } => {
assert!( assert!(

View file

@ -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}; pub use self::stack::{Frame, FrameInfo, LocalState, ReturnContinuation, StackPopInfo};
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};

View file

@ -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.
return_place: PlaceTy<'tcx, Prov>, pub 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,6 +127,19 @@ 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> {
@ -279,14 +292,6 @@ 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))
@ -412,26 +417,35 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
interp_ok(()) interp_ok(())
} }
/// Low-level helper that pops a stack frame from the stack without any cleanup. /// Low-level helper that pops a stack frame from the stack and returns some information about
/// This invokes `before_stack_pop`. /// it.
/// After calling this function, you need to deal with the return value, and then ///
/// invoke `cleanup_stack_frame`. /// This also deallocates locals, if necessary.
/// `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,
) -> InterpResult<'tcx, Frame<'tcx, M::Provenance, M::FrameExtra>> { unwinding: bool,
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)
}
/// Deallocate local variables in the stack frame, and invoke `after_stack_pop`. // Copy return value (unless we are unwinding).
pub(super) fn cleanup_stack_frame( if !unwinding {
&mut self, copy_ret_val(self, &frame.return_place)?;
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.
@ -441,7 +455,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
ReturnContinuation::Stop { cleanup, .. } => cleanup, ReturnContinuation::Stop { cleanup, .. } => cleanup,
}; };
if cleanup { let return_action = if cleanup {
for local in &frame.locals { for local in &frame.locals {
self.deallocate_local(local.value)?; self.deallocate_local(local.value)?;
} }
@ -452,11 +466,13 @@ 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);
interp_ok(return_action) 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.
interp_ok(ReturnAction::NoCleanup) 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
@ -639,7 +655,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 = fn_arg.copy_fn_arg(); let op = self.copy_fn_arg(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)?;

View file

@ -249,6 +249,12 @@ 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 =

View file

@ -647,8 +647,13 @@ 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: should we also `UnsafeCell` behind shared references? Currently that is not // FIXME: we do *not* check behind boxes, since creating a new box first creates it uninitialized
// 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, || {

View file

@ -2,11 +2,12 @@ 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::PathBuf; use std::path::{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};
@ -21,14 +22,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::Parser; use rustc_parse::parser::{AllowConstBlockItems, ForceCollect, 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, Ident, Span, Symbol, kw}; use rustc_span::{DUMMY_SP, FileName, Ident, Span, Symbol, kw, sym};
use smallvec::{SmallVec, smallvec}; use smallvec::{SmallVec, smallvec};
use thin_vec::ThinVec; use thin_vec::ThinVec;
@ -1420,3 +1421,80 @@ 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)
}

View file

@ -446,6 +446,18 @@ 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::*;

View file

@ -105,6 +105,11 @@ 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;

View file

@ -103,8 +103,8 @@ impl ToInternal<token::LitKind> for LitKind {
} }
} }
impl FromInternal<TokenStream> for Vec<TokenTree<TokenStream, Span, Symbol>> { impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStream, Span, Symbol>> {
fn from_internal(stream: TokenStream) -> Self { fn from_internal((stream, rustc): (TokenStream, &mut Rustc<'_, '_>)) -> 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,6 +115,22 @@ impl FromInternal<TokenStream> for Vec<TokenTree<TokenStream, Span, Symbol>> {
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
@ -671,7 +687,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) FromInternal::from_internal((stream, self))
} }
fn span_debug(&mut self, span: Self::Span) -> String { fn span_debug(&mut self, span: Self::Span) -> String {

View file

@ -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",
), ),
rustc_attr!( gated!(
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"

View file

@ -287,6 +287,10 @@ 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)`.
@ -489,7 +493,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(131179)), (unstable, final_associated_functions, "CURRENT_RUSTC_VERSION", Some(1)),
/// 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

View file

@ -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.key_fingerprint) format!("{:?}({:?})", dep_node.kind, dep_node.hash)
} }
} }

View file

@ -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 "key fingerprint", a 128-bit hash value, the exact meaning of which //! and a [`Fingerprint`], a 128-bit hash value, the exact meaning of which
//! depends on the node's `DepKind`. Together, the kind and the key fingerprint //! depends on the node's `DepKind`. Together, the kind and the 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 key fingerprint does not depend on anything //! In other words, the value of the 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,9 +41,17 @@
//! `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 key fingerprint back to the //! in which case it is possible to map the node's 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 when computing a key fingerprint. //! lost during fingerprint computation.
//!
//! `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
@ -57,7 +65,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::{KeyFingerprintStyle, SerializedDepNodeIndex}; use super::{FingerprintStyle, 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};
@ -117,20 +125,10 @@ 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 {
@ -138,23 +136,24 @@ 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.key_fingerprint_style(kind), KeyFingerprintStyle::Unit); debug_assert_eq!(tcx.fingerprint_style(kind), FingerprintStyle::Unit);
DepNode { kind, key_fingerprint: Fingerprint::ZERO.into() } DepNode { kind, hash: Fingerprint::ZERO.into() }
} }
pub fn construct<'tcx, Key>(tcx: TyCtxt<'tcx>, kind: DepKind, key: &Key) -> DepNode pub fn construct<'tcx, Key>(tcx: TyCtxt<'tcx>, kind: DepKind, arg: &Key) -> DepNode
where where
Key: DepNodeKey<'tcx>, Key: DepNodeKey<'tcx>,
{ {
let dep_node = DepNode { kind, key_fingerprint: key.to_fingerprint(tcx).into() }; let hash = arg.to_fingerprint(tcx);
let dep_node = DepNode { kind, hash: hash.into() };
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
{ {
if !tcx.key_fingerprint_style(kind).reconstructible() if !tcx.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, || key.to_debug_str(tcx)); tcx.dep_graph.register_dep_node_debug_str(dep_node, || arg.to_debug_str(tcx));
} }
} }
@ -169,8 +168,8 @@ impl DepNode {
def_path_hash: DefPathHash, def_path_hash: DefPathHash,
kind: DepKind, kind: DepKind,
) -> Self { ) -> Self {
debug_assert!(tcx.key_fingerprint_style(kind) == KeyFingerprintStyle::DefPathHash); debug_assert!(tcx.fingerprint_style(kind) == FingerprintStyle::DefPathHash);
DepNode { kind, key_fingerprint: def_path_hash.0.into() } DepNode { kind, hash: def_path_hash.0.into() }
} }
} }
@ -185,10 +184,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.key_fingerprint)?; write!(f, "{}", self.hash)?;
} }
} else { } else {
write!(f, "{}", self.key_fingerprint)?; write!(f, "{}", self.hash)?;
} }
Ok(()) Ok(())
})?; })?;
@ -199,7 +198,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 key_fingerprint_style() -> KeyFingerprintStyle; fn fingerprint_style() -> FingerprintStyle;
/// 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`.
@ -213,7 +212,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 try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self>; fn recover(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.
@ -222,8 +221,8 @@ where
T: for<'a> HashStable<StableHashingContext<'a>> + fmt::Debug, T: for<'a> HashStable<StableHashingContext<'a>> + fmt::Debug,
{ {
#[inline(always)] #[inline(always)]
default fn key_fingerprint_style() -> KeyFingerprintStyle { default fn fingerprint_style() -> FingerprintStyle {
KeyFingerprintStyle::Opaque FingerprintStyle::Opaque
} }
#[inline(always)] #[inline(always)]
@ -244,7 +243,7 @@ where
} }
#[inline(always)] #[inline(always)]
default fn try_recover_key(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> { default fn recover(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> {
None None
} }
} }
@ -265,11 +264,10 @@ 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 a query key can be reconstructed from the /// Indicates whether and how the query key can be recovered from its hashed fingerprint.
/// 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 key_fingerprint_style: KeyFingerprintStyle, pub fingerprint_style: FingerprintStyle,
/// 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
@ -281,7 +279,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
/// "key fingerprint" that will uniquely identify the node. This key fingerprint /// GUID/fingerprint that will uniquely identify the node. This GUID/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
@ -295,7 +293,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 key fingerprint of certain `DepNode`s is a /// enforce by construction that the GUID/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.
@ -303,7 +301,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 `mir_promoted`, we know that the key fingerprint of the `DepNode` /// with kind `MirValidated`, we know that the GUID/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<
@ -474,8 +472,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.key_fingerprint_style(self.kind) == KeyFingerprintStyle::DefPathHash { if tcx.fingerprint_style(self.kind) == FingerprintStyle::DefPathHash {
tcx.def_path_hash_to_def_id(DefPathHash(self.key_fingerprint.into())) tcx.def_path_hash_to_def_id(DefPathHash(self.hash.into()))
} else { } else {
None None
} }
@ -488,10 +486,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.key_fingerprint_style(kind) { match tcx.fingerprint_style(kind) {
KeyFingerprintStyle::Opaque | KeyFingerprintStyle::HirId => Err(()), FingerprintStyle::Opaque | FingerprintStyle::HirId => Err(()),
KeyFingerprintStyle::Unit => Ok(DepNode::new_no_params(tcx, kind)), FingerprintStyle::Unit => Ok(DepNode::new_no_params(tcx, kind)),
KeyFingerprintStyle::DefPathHash => { FingerprintStyle::DefPathHash => {
Ok(DepNode::from_def_path_hash(tcx, def_path_hash, kind)) Ok(DepNode::from_def_path_hash(tcx, def_path_hash, kind))
} }
} }

View file

@ -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, KeyFingerprintStyle}; use crate::dep_graph::{DepNode, DepNodeKey, FingerprintStyle};
use crate::ty::TyCtxt; use crate::ty::TyCtxt;
impl<'tcx> DepNodeKey<'tcx> for () { impl<'tcx> DepNodeKey<'tcx> for () {
#[inline(always)] #[inline(always)]
fn key_fingerprint_style() -> KeyFingerprintStyle { fn fingerprint_style() -> FingerprintStyle {
KeyFingerprintStyle::Unit FingerprintStyle::Unit
} }
#[inline(always)] #[inline(always)]
@ -18,15 +18,15 @@ impl<'tcx> DepNodeKey<'tcx> for () {
} }
#[inline(always)] #[inline(always)]
fn try_recover_key(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> { fn recover(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> {
Some(()) Some(())
} }
} }
impl<'tcx> DepNodeKey<'tcx> for DefId { impl<'tcx> DepNodeKey<'tcx> for DefId {
#[inline(always)] #[inline(always)]
fn key_fingerprint_style() -> KeyFingerprintStyle { fn fingerprint_style() -> FingerprintStyle {
KeyFingerprintStyle::DefPathHash FingerprintStyle::DefPathHash
} }
#[inline(always)] #[inline(always)]
@ -40,15 +40,15 @@ impl<'tcx> DepNodeKey<'tcx> for DefId {
} }
#[inline(always)] #[inline(always)]
fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> { fn recover(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 key_fingerprint_style() -> KeyFingerprintStyle { fn fingerprint_style() -> FingerprintStyle {
KeyFingerprintStyle::DefPathHash FingerprintStyle::DefPathHash
} }
#[inline(always)] #[inline(always)]
@ -62,15 +62,15 @@ impl<'tcx> DepNodeKey<'tcx> for LocalDefId {
} }
#[inline(always)] #[inline(always)]
fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> { fn recover(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 key_fingerprint_style() -> KeyFingerprintStyle { fn fingerprint_style() -> FingerprintStyle {
KeyFingerprintStyle::DefPathHash FingerprintStyle::DefPathHash
} }
#[inline(always)] #[inline(always)]
@ -84,15 +84,15 @@ impl<'tcx> DepNodeKey<'tcx> for OwnerId {
} }
#[inline(always)] #[inline(always)]
fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> { fn recover(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 key_fingerprint_style() -> KeyFingerprintStyle { fn fingerprint_style() -> FingerprintStyle {
KeyFingerprintStyle::DefPathHash FingerprintStyle::DefPathHash
} }
#[inline(always)] #[inline(always)]
@ -107,15 +107,15 @@ impl<'tcx> DepNodeKey<'tcx> for CrateNum {
} }
#[inline(always)] #[inline(always)]
fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> { fn recover(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 key_fingerprint_style() -> KeyFingerprintStyle { fn fingerprint_style() -> FingerprintStyle {
KeyFingerprintStyle::Opaque FingerprintStyle::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 key_fingerprint_style() -> KeyFingerprintStyle { fn fingerprint_style() -> FingerprintStyle {
KeyFingerprintStyle::HirId FingerprintStyle::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 try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> { fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
if tcx.key_fingerprint_style(dep_node.kind) == KeyFingerprintStyle::HirId { if tcx.fingerprint_style(dep_node.kind) == FingerprintStyle::HirId {
let (local_hash, local_id) = Fingerprint::from(dep_node.key_fingerprint).split(); let (local_hash, local_id) = Fingerprint::from(dep_node.hash).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 key_fingerprint_style() -> KeyFingerprintStyle { fn fingerprint_style() -> FingerprintStyle {
KeyFingerprintStyle::DefPathHash FingerprintStyle::DefPathHash
} }
#[inline(always)] #[inline(always)]
@ -199,15 +199,15 @@ impl<'tcx> DepNodeKey<'tcx> for ModDefId {
} }
#[inline(always)] #[inline(always)]
fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> { fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
DefId::try_recover_key(tcx, dep_node).map(ModDefId::new_unchecked) DefId::recover(tcx, dep_node).map(ModDefId::new_unchecked)
} }
} }
impl<'tcx> DepNodeKey<'tcx> for LocalModDefId { impl<'tcx> DepNodeKey<'tcx> for LocalModDefId {
#[inline(always)] #[inline(always)]
fn key_fingerprint_style() -> KeyFingerprintStyle { fn fingerprint_style() -> FingerprintStyle {
KeyFingerprintStyle::DefPathHash FingerprintStyle::DefPathHash
} }
#[inline(always)] #[inline(always)]
@ -221,7 +221,7 @@ impl<'tcx> DepNodeKey<'tcx> for LocalModDefId {
} }
#[inline(always)] #[inline(always)]
fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> { fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
LocalDefId::try_recover_key(tcx, dep_node).map(LocalModDefId::new_unchecked) LocalDefId::recover(tcx, dep_node).map(LocalModDefId::new_unchecked)
} }
} }

View file

@ -142,17 +142,15 @@ 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, key_fingerprint: current.anon_id_seed.into() }, DepNode { kind: DepKind::ANON_ZERO_DEPS, hash: 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);
// Create a single always-red node, with no dependencies of its own. // Instantiate a dependy-less red node only once for anonymous queries.
// 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, key_fingerprint: Fingerprint::ZERO.into() }, DepNode { kind: DepKind::RED, hash: Fingerprint::ZERO.into() },
EdgesVec::new(), EdgesVec::new(),
Fingerprint::ZERO, Fingerprint::ZERO,
); );
@ -420,7 +418,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).
key_fingerprint: self.current.anon_id_seed.combine(hasher.finish()).into(), hash: 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
@ -587,7 +585,7 @@ impl DepGraph {
data.current.record_edge( data.current.record_edge(
dep_node_index, dep_node_index,
node, node,
data.prev_value_fingerprint_of(prev_index), data.prev_fingerprint_of(prev_index),
); );
} }
@ -660,8 +658,8 @@ impl DepGraphData {
} }
#[inline] #[inline]
pub fn prev_value_fingerprint_of(&self, prev_index: SerializedDepNodeIndex) -> Fingerprint { pub fn prev_fingerprint_of(&self, prev_index: SerializedDepNodeIndex) -> Fingerprint {
self.previous.value_fingerprint_for_index(prev_index) self.previous.fingerprint_by_index(prev_index)
} }
#[inline] #[inline]
@ -681,7 +679,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,
key_fingerprint: PackedFingerprint::from(Fingerprint::ZERO), hash: 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
@ -714,7 +712,7 @@ impl DepGraphData {
&self.colors, &self.colors,
DepNode { DepNode {
kind: DepKind::SIDE_EFFECT, kind: DepKind::SIDE_EFFECT,
key_fingerprint: PackedFingerprint::from(Fingerprint::ZERO), hash: PackedFingerprint::from(Fingerprint::ZERO),
}, },
Fingerprint::ZERO, Fingerprint::ZERO,
std::iter::once(DepNodeIndex::FOREVER_RED_NODE).collect(), std::iter::once(DepNodeIndex::FOREVER_RED_NODE).collect(),
@ -729,12 +727,12 @@ impl DepGraphData {
&self, &self,
key: DepNode, key: DepNode,
edges: EdgesVec, edges: EdgesVec,
value_fingerprint: Option<Fingerprint>, 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(value_fingerprint) = value_fingerprint { let is_green = if let Some(fingerprint) = fingerprint {
if value_fingerprint == self.previous.value_fingerprint_for_index(prev_index) { if fingerprint == self.previous.fingerprint_by_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
@ -751,22 +749,22 @@ impl DepGraphData {
false false
}; };
let value_fingerprint = value_fingerprint.unwrap_or(Fingerprint::ZERO); let fingerprint = 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,
value_fingerprint, fingerprint,
edges, edges,
is_green, is_green,
); );
self.current.record_node(dep_node_index, key, value_fingerprint); self.current.record_node(dep_node_index, key, fingerprint);
dep_node_index dep_node_index
} else { } else {
self.current.alloc_new_node(key, edges, value_fingerprint.unwrap_or(Fingerprint::ZERO)) self.current.alloc_new_node(key, edges, fingerprint.unwrap_or(Fingerprint::ZERO))
} }
} }
@ -783,7 +781,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.value_fingerprint_for_index(prev_index), self.previous.fingerprint_by_index(prev_index),
); );
} }
@ -927,7 +925,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.key_fingerprint, dep_dep_node, dep_dep_node.hash,
); );
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));
@ -1156,10 +1154,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 value fingerprints do not change between the /// This is used to verify that fingerprints do not change between the creation of a node
/// creation of a node and its recomputation. /// and its recomputation.
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
value_fingerprints: Lock<IndexVec<DepNodeIndex, Option<Fingerprint>>>, 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`.
@ -1226,7 +1224,7 @@ impl CurrentDepGraph {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
forbidden_edge, forbidden_edge,
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
value_fingerprints: Lock::new(IndexVec::from_elem_n(None, new_node_count_estimate)), 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,
@ -1239,20 +1237,12 @@ impl CurrentDepGraph {
} }
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
fn record_edge( fn record_edge(&self, dep_node_index: DepNodeIndex, key: DepNode, fingerprint: Fingerprint) {
&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 prior_value_fingerprint = *self let previous = *self.fingerprints.lock().get_or_insert_with(dep_node_index, || fingerprint);
.value_fingerprints assert_eq!(previous, fingerprint, "Unstable fingerprints for {:?}", key);
.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)]
@ -1260,10 +1250,10 @@ impl CurrentDepGraph {
&self, &self,
dep_node_index: DepNodeIndex, dep_node_index: DepNodeIndex,
key: DepNode, key: DepNode,
_value_fingerprint: Fingerprint, _current_fingerprint: Fingerprint,
) { ) {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
self.record_edge(dep_node_index, key, _value_fingerprint); self.record_edge(dep_node_index, key, _current_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(|| {
@ -1281,11 +1271,11 @@ impl CurrentDepGraph {
&self, &self,
key: DepNode, key: DepNode,
edges: EdgesVec, edges: EdgesVec,
value_fingerprint: Fingerprint, current_fingerprint: Fingerprint,
) -> DepNodeIndex { ) -> DepNodeIndex {
let dep_node_index = self.encoder.send_new(key, value_fingerprint, edges); let dep_node_index = self.encoder.send_new(key, current_fingerprint, edges);
self.record_node(dep_node_index, key, value_fingerprint); self.record_node(dep_node_index, key, current_fingerprint);
dep_node_index dep_node_index
} }

View file

@ -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 KeyFingerprintStyle { pub enum FingerprintStyle {
/// 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 KeyFingerprintStyle {
Opaque, Opaque,
} }
impl KeyFingerprintStyle { impl FingerprintStyle {
#[inline] #[inline]
pub const fn reconstructible(self) -> bool { pub const fn reconstructible(self) -> bool {
match self { match self {
KeyFingerprintStyle::DefPathHash FingerprintStyle::DefPathHash | FingerprintStyle::Unit | FingerprintStyle::HirId => {
| KeyFingerprintStyle::Unit true
| KeyFingerprintStyle::HirId => true, }
KeyFingerprintStyle::Opaque => false, FingerprintStyle::Opaque => false,
} }
} }
} }
@ -86,8 +86,8 @@ impl<'tcx> TyCtxt<'tcx> {
} }
#[inline(always)] #[inline(always)]
pub fn key_fingerprint_style(self, kind: DepKind) -> KeyFingerprintStyle { pub fn fingerprint_style(self, kind: DepKind) -> FingerprintStyle {
self.dep_kind_vtable(kind).key_fingerprint_style self.dep_kind_vtable(kind).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.

View file

@ -90,13 +90,9 @@ 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>,
/// A value fingerprint associated with each [`DepNode`] in [`Self::nodes`], /// The set of all Fingerprints in the graph. Each Fingerprint corresponds to
/// typically a hash of the value returned by the node's query in the /// the DepNode at the same index in the nodes vector.
/// previous incremental-compilation session. fingerprints: IndexVec<SerializedDepNodeIndex, Fingerprint>,
///
/// 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.
@ -104,8 +100,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>,
/// For each dep kind, stores a map from key fingerprints back to the index /// Stores a map from fingerprints to nodes per dep node kind.
/// of the corresponding node. This is the inverse of `nodes`. /// This is the reciprocal 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.
@ -142,15 +138,12 @@ 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.key_fingerprint).copied() self.index.get(dep_node.kind.as_usize())?.get(&dep_node.hash).cloned()
} }
#[inline] #[inline]
pub fn value_fingerprint_for_index( pub fn fingerprint_by_index(&self, dep_node_index: SerializedDepNodeIndex) -> Fingerprint {
&self, self.fingerprints[dep_node_index]
dep_node_index: SerializedDepNodeIndex,
) -> Fingerprint {
self.value_fingerprints[dep_node_index]
} }
#[inline] #[inline]
@ -219,13 +212,10 @@ 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 { DepNode { kind: DepKind::NULL, hash: PackedFingerprint::from(Fingerprint::ZERO) },
kind: DepKind::NULL,
key_fingerprint: PackedFingerprint::from(Fingerprint::ZERO),
},
node_max, node_max,
); );
let mut value_fingerprints = IndexVec::from_elem_n(Fingerprint::ZERO, node_max); let mut 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);
@ -253,7 +243,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();
value_fingerprints[index] = node_header.value_fingerprint(); fingerprints[index] = node_header.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.
@ -285,7 +275,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.key_fingerprint, idx).is_some() { if index[node.kind.as_usize()].insert(node.hash, 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();
@ -301,7 +291,7 @@ impl SerializedDepGraph {
Arc::new(SerializedDepGraph { Arc::new(SerializedDepGraph {
nodes, nodes,
value_fingerprints, fingerprints,
edge_list_indices, edge_list_indices,
edge_list_data, edge_list_data,
index, index,
@ -313,8 +303,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 value `Fingerprint` in the `NodeInfo` /// * The `Fingerprint` in the `NodeInfo`
/// * The key `Fingerprint` in `DepNode` that is in this `NodeInfo` /// * The `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
@ -333,8 +323,8 @@ struct Unpacked {
bytes_per_index: usize, bytes_per_index: usize,
kind: DepKind, kind: DepKind,
index: SerializedDepNodeIndex, index: SerializedDepNodeIndex,
key_fingerprint: PackedFingerprint, hash: PackedFingerprint,
value_fingerprint: Fingerprint, fingerprint: Fingerprint,
} }
// Bit fields, where // Bit fields, where
@ -355,7 +345,7 @@ impl SerializedNodeHeader {
fn new( fn new(
node: &DepNode, node: &DepNode,
index: DepNodeIndex, index: DepNodeIndex,
value_fingerprint: Fingerprint, fingerprint: Fingerprint,
edge_max_index: u32, edge_max_index: u32,
edge_count: usize, edge_count: usize,
) -> Self { ) -> Self {
@ -373,19 +363,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.key_fingerprint.into(); let hash: Fingerprint = node.hash.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(&value_fingerprint.to_le_bytes()); bytes[22..].copy_from_slice(&fingerprint.to_le_bytes());
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
{ {
let res = Self { bytes }; let res = Self { bytes };
assert_eq!(value_fingerprint, res.value_fingerprint()); assert_eq!(fingerprint, res.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);
@ -398,8 +388,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 key_fingerprint = self.bytes[6..22].try_into().unwrap(); let hash = self.bytes[6..22].try_into().unwrap();
let value_fingerprint = self.bytes[22..].try_into().unwrap(); let 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;
@ -410,8 +400,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),
key_fingerprint: Fingerprint::from_le_bytes(key_fingerprint).into(), hash: Fingerprint::from_le_bytes(hash).into(),
value_fingerprint: Fingerprint::from_le_bytes(value_fingerprint), fingerprint: Fingerprint::from_le_bytes(fingerprint),
} }
} }
@ -431,14 +421,14 @@ impl SerializedNodeHeader {
} }
#[inline] #[inline]
fn value_fingerprint(&self) -> Fingerprint { fn fingerprint(&self) -> Fingerprint {
self.unpack().value_fingerprint self.unpack().fingerprint
} }
#[inline] #[inline]
fn node(&self) -> DepNode { fn node(&self) -> DepNode {
let Unpacked { kind, key_fingerprint, .. } = self.unpack(); let Unpacked { kind, hash, .. } = self.unpack();
DepNode { kind, key_fingerprint } DepNode { kind, hash }
} }
#[inline] #[inline]
@ -453,20 +443,15 @@ impl SerializedNodeHeader {
#[derive(Debug)] #[derive(Debug)]
struct NodeInfo { struct NodeInfo {
node: DepNode, node: DepNode,
value_fingerprint: Fingerprint, 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, value_fingerprint, ref edges } = *self; let NodeInfo { ref node, fingerprint, ref edges } = *self;
let header = SerializedNodeHeader::new( let header =
node, SerializedNodeHeader::new(node, index, fingerprint, edges.max_index(), edges.len());
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() {
@ -491,7 +476,7 @@ impl NodeInfo {
e: &mut MemEncoder, e: &mut MemEncoder,
node: &DepNode, node: &DepNode,
index: DepNodeIndex, index: DepNodeIndex,
value_fingerprint: Fingerprint, fingerprint: Fingerprint,
prev_index: SerializedDepNodeIndex, prev_index: SerializedDepNodeIndex,
colors: &DepNodeColorMap, colors: &DepNodeColorMap,
previous: &SerializedDepGraph, previous: &SerializedDepGraph,
@ -503,8 +488,7 @@ 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 = let header = SerializedNodeHeader::new(node, index, fingerprint, edge_max, edge_count);
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() {
@ -692,12 +676,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 value_fingerprint = self.previous.value_fingerprint_for_index(prev_index); let fingerprint = self.previous.fingerprint_by_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,
value_fingerprint, fingerprint,
prev_index, prev_index,
colors, colors,
&self.previous, &self.previous,
@ -873,11 +857,11 @@ impl GraphEncoder {
pub(crate) fn send_new( pub(crate) fn send_new(
&self, &self,
node: DepNode, node: DepNode,
value_fingerprint: Fingerprint, 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, value_fingerprint, edges }; let node = NodeInfo { node, 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);
@ -893,12 +877,12 @@ impl GraphEncoder {
prev_index: SerializedDepNodeIndex, prev_index: SerializedDepNodeIndex,
colors: &DepNodeColorMap, colors: &DepNodeColorMap,
node: DepNode, node: DepNode,
value_fingerprint: Fingerprint, 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, value_fingerprint, edges }; let node = NodeInfo { node, fingerprint, edges };
let mut local = self.status.local.borrow_mut(); let mut local = self.status.local.borrow_mut();

View file

@ -1237,6 +1237,10 @@ 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})"))
} }

View file

@ -747,6 +747,11 @@ 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]
@ -781,6 +786,7 @@ impl<'tcx> Rvalue<'tcx> {
| Rvalue::UnaryOp(_, _) | Rvalue::UnaryOp(_, _)
| Rvalue::Discriminant(_) | Rvalue::Discriminant(_)
| Rvalue::Aggregate(_, _) | Rvalue::Aggregate(_, _)
| Rvalue::ShallowInitBox(_, _)
| Rvalue::WrapUnsafeBinder(_, _) => true, | Rvalue::WrapUnsafeBinder(_, _) => true,
} }
} }
@ -827,10 +833,21 @@ 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 {

View file

@ -1458,6 +1458,13 @@ 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)

View file

@ -810,6 +810,11 @@ 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));

View file

@ -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 value fingerprint matches. // will check that the fingerprint matches.
self.cache.insert(key, (value, index)); self.cache.insert(key, (value, index));
} }

View file

@ -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_value_fingerprint_of(prev_index); let old_hash = dep_graph_data.prev_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));

View file

@ -86,6 +86,7 @@ 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(..)

View file

@ -391,7 +391,15 @@ 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);
self.gather_init(place.as_ref(), InitKind::Deep); if let RvalueInitializationState::Shallow = rval.initialization_state() {
// 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)) => {
@ -427,6 +435,7 @@ 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)) => {

View file

@ -467,6 +467,7 @@ 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;

View file

@ -1,8 +1,12 @@
//! 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; use rustc_abi::{FieldIdx, VariantIdx};
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;
@ -85,6 +89,68 @@ 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;

View file

@ -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::CopyForDeref(_) | Rvalue::ShallowInitBox(..) => {
bug!("forbidden in runtime MIR: {rvalue:?}") bug!("forbidden in runtime MIR: {rvalue:?}")
} }
}; };

View file

@ -443,6 +443,7 @@ 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(..) => {}
} }
@ -604,6 +605,8 @@ 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)?;

View file

@ -85,6 +85,7 @@ 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(..)

View file

@ -1,6 +1,5 @@
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};
@ -286,19 +285,6 @@ 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)
{ {
@ -370,46 +356,3 @@ 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
}

View file

@ -449,6 +449,8 @@ 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.

View file

@ -85,7 +85,7 @@ impl<'tcx> crate::MirPass<'tcx> for SingleUseConsts {
} }
fn is_required(&self) -> bool { fn is_required(&self) -> bool {
false true
} }
} }

View file

@ -1259,6 +1259,14 @@ 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 {

View file

@ -567,6 +567,13 @@ 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
@ -644,6 +651,7 @@ 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),
} }
} }

View file

@ -383,6 +383,7 @@ 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:?}")
} }

View file

@ -277,6 +277,10 @@ 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);

View file

@ -240,6 +240,9 @@ 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):"),
} }

View file

@ -1,5 +1,5 @@
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::dep_graph::{DepKindVTable, DepNodeKey, KeyFingerprintStyle}; use rustc_middle::dep_graph::{DepKindVTable, DepNodeKey, FingerprintStyle};
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,
key_fingerprint_style: KeyFingerprintStyle::Unit, fingerprint_style: FingerprintStyle::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,
key_fingerprint_style: KeyFingerprintStyle::Unit, fingerprint_style: FingerprintStyle::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,
key_fingerprint_style: KeyFingerprintStyle::Unit, fingerprint_style: FingerprintStyle::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,
key_fingerprint_style: KeyFingerprintStyle::Opaque, fingerprint_style: FingerprintStyle::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,
key_fingerprint_style: KeyFingerprintStyle::Unit, fingerprint_style: FingerprintStyle::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,
key_fingerprint_style: KeyFingerprintStyle::Opaque, fingerprint_style: FingerprintStyle::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,
key_fingerprint_style: KeyFingerprintStyle::Opaque, fingerprint_style: FingerprintStyle::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,
key_fingerprint_style: KeyFingerprintStyle::Unit, fingerprint_style: FingerprintStyle::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 key_fingerprint_style = if is_anon { let fingerprint_style = if is_anon {
KeyFingerprintStyle::Opaque FingerprintStyle::Opaque
} else { } else {
<Cache::Key as DepNodeKey<'tcx>>::key_fingerprint_style() <Cache::Key as DepNodeKey<'tcx>>::fingerprint_style()
}; };
if is_anon || !key_fingerprint_style.reconstructible() { if is_anon || !fingerprint_style.reconstructible() {
return DepKindVTable { return DepKindVTable {
is_anon, is_anon,
is_eval_always, is_eval_always,
key_fingerprint_style, 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,
key_fingerprint_style, 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)
}), }),

View file

@ -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_value_fingerprint_of(prev_dep_node_index); let prev_fingerprint = dep_graph_data.prev_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.key_fingerprint_style(dep_node.kind).reconstructible(), || !tcx.fingerprint_style(dep_node.kind).reconstructible(),
"missing on-disk cache entry for {dep_node:?}" "missing on-disk cache entry for {dep_node:?}"
); );

View file

@ -396,11 +396,8 @@ 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::try_recover_key(tcx, &dep_node).unwrap_or_else(|| { let key = C::Key::recover(tcx, &dep_node).unwrap_or_else(|| {
panic!( panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash)
"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
@ -465,7 +462,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::try_recover_key(tcx, &dep_node) { if let Some(key) = C::Key::recover(tcx, &dep_node) {
force_query(query, tcx, key, dep_node); force_query(query, tcx, key, dep_node);
true true
} else { } else {

View file

@ -371,8 +371,6 @@ 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
@ -386,8 +384,7 @@ 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());
// FIXME: reenable the assert when visibility is updated in place. assert!(!deep_decl.is_glob_import());
// 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());

View file

@ -4060,32 +4060,25 @@ 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![] };
for param in &sig.decl.inputs { lt_finder.visit_ty(&ty);
lt_finder.visit_ty(&param.ty);
} if let [Ty { span, kind: TyKind::Ref(_, mut_ty), .. }] =
if let ast::FnRetTy::Ty(ret_ty) = &sig.decl.output { &lt_finder.seen[..]
lt_finder.visit_ty(ret_ty); {
let mut ret_lt_finder = // We might have a situation like
LifetimeFinder { lifetime: lt.span, found: None, seen: vec![] }; // fn g(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()>
ret_lt_finder.visit_ty(ret_ty); // but `lt.span` only points at `'_`, so to suggest `-> Option<()>`
if let [Ty { span, kind: TyKind::Ref(_, mut_ty), .. }] = // we need to find a more accurate span to end up with
&ret_lt_finder.seen[..] // fn g<'a>(mut x: impl Iterator<Item = &'_ ()>) -> Option<()>
{ sugg = vec![(span.with_hi(mut_ty.ty.span.lo()), String::new())];
// We might have a situation like owned_sugg = true;
// 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 {
@ -4105,7 +4098,6 @@ 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(
@ -4132,7 +4124,6 @@ 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(
@ -4167,12 +4158,6 @@ 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,
@ -4199,23 +4184,6 @@ 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(&param.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(
@ -4317,26 +4285,6 @@ 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) {

View file

@ -2481,9 +2481,6 @@ 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)"),

View file

@ -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, AtomicUsize}; use std::sync::atomic::AtomicBool;
use std::{env, io}; use std::{env, io};
use rand::{RngCore, rng}; use rand::{RngCore, rng};
@ -161,12 +161,6 @@ 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)]
@ -1107,7 +1101,6 @@ 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);

View file

@ -327,6 +327,7 @@ symbols! {
Pointer, Pointer,
Poll, Poll,
ProcMacro, ProcMacro,
ProceduralMasqueradeDummyType,
Range, Range,
RangeBounds, RangeBounds,
RangeCopy, RangeCopy,

View file

@ -300,9 +300,6 @@ 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)

View file

@ -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::{Ident, Span}; use rustc_span::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,8 +99,7 @@ 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 = let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] };
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) =
@ -123,49 +122,13 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
found, found,
}; };
let mut diag = self.tcx().dcx().create_err(diag); self.tcx().dcx().emit_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> {
@ -175,83 +138,6 @@ 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) => {

View file

@ -182,6 +182,7 @@
#![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)]

View file

@ -159,6 +159,7 @@
#![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)]

View file

@ -2481,8 +2481,7 @@ 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 (negative if overflowed /// occurred then the wrapped value is returned.
/// above [`MAX`](Self::MAX), non-negative if below [`MIN`](Self::MIN)).
/// ///
/// # Examples /// # Examples
/// ///
@ -2517,9 +2516,6 @@ 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).
/// ///
@ -2587,8 +2583,7 @@ 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
/// ///
@ -2624,9 +2619,6 @@ 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).
/// ///

View file

@ -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 in base 2, except that exclusive or is /// This operation is similar to long multiplication, except that exclusive or is used
/// used instead of addition. The implementation is equivalent to: /// 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), "{")]

View file

@ -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; use crate::ffi::{c_char, c_int};
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,6 +172,12 @@ 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.
@ -181,9 +187,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 { libc::_NSGetArgc().read() }; let argc = unsafe { _NSGetArgc().read() };
// SAFETY: Same as above. // SAFETY: Same as above.
let argv = unsafe { libc::_NSGetArgv().read() }; let argv = unsafe { _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())

View file

@ -393,7 +393,7 @@ Heres how these different lint controls interact:
warning: 1 warning emitted warning: 1 warning emitted
``` ```
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. 3. [CLI level flags](#via-compiler-flag) take precedence over attributes.
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.

View file

@ -194,6 +194,7 @@ 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() {

View file

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

View file

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

View file

@ -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 = MiriInterpCx::copy_fn_args(args); // FIXME: Should `InPlace` arguments be reset to uninit? let args = ecx.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 = MiriInterpCx::copy_fn_args(args); // FIXME: Should `InPlace` arguments be reset to uninit? let args = ecx.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)
} }

View file

@ -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 | let _val = unsafe { *x }; LL | f(std::ptr::null());
| ^^^^ | ^^^^^^^^^^^^^^^^^^^
= 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

View file

@ -1,8 +0,0 @@
//@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;
}

View file

@ -1,13 +0,0 @@
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

View file

@ -4,7 +4,6 @@
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 {
@ -38,14 +37,3 @@ 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);
}

View file

@ -1,5 +1,5 @@
//@ compile-flags: -Copt-level=3 //@ compile-flags: -Copt-level=3
#![feature(panic_internals, const_eval_select, rustc_attrs, core_intrinsics)] #![feature(panic_internals, const_eval_select, rustc_allow_const_fn_unstable, 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

View file

@ -15,14 +15,13 @@ 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: [[BOOL:_[0-9]+]] = const true; // CHECK: switchInt(const true) -> [0: [[FALSE:bb[0-9]+]], otherwise: [[TRUE:bb[0-9]+]]];
// CHECK: switchInt(move [[BOOL]]) -> [0: [[BB_FALSE:bb[0-9]+]], otherwise: [[BB_TRUE:bb[0-9]+]]];
// CHECK-NEXT: } // CHECK-NEXT: }
// CHECK: [[BB_FALSE]]: { // CHECK: [[FALSE]]: {
// CHECK-NEXT: _0 = const 0 // CHECK-NEXT: _0 = const 0
// CHECK-NEXT: goto // CHECK-NEXT: goto
// CHECK-NEXT: } // CHECK-NEXT: }
// CHECK: [[BB_TRUE]]: { // CHECK: [[TRUE]]: {
// CHECK-NEXT: _0 = const 1 // CHECK-NEXT: _0 = const 1
// CHECK-NEXT: goto // CHECK-NEXT: goto
// CHECK-NEXT: } // CHECK-NEXT: }

View file

@ -1,11 +0,0 @@
#![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)
}

View file

@ -1,119 +0,0 @@
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)
}

View file

@ -1,18 +0,0 @@
//@ 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() {}

View file

@ -1,20 +0,0 @@
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`.

View file

@ -2,6 +2,7 @@
// We enable a bunch of features to not get feature-gate errs in this test. // We enable a bunch of features to not get feature-gate errs in this test.
#![deny(invalid_doc_attributes)] #![deny(invalid_doc_attributes)]
#![feature(rustc_attrs)] #![feature(rustc_attrs)]
#![feature(rustc_allow_const_fn_unstable)]
#![feature(allow_internal_unstable)] #![feature(allow_internal_unstable)]
// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity // FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity
#![feature(fn_align)] #![feature(fn_align)]

View file

@ -1,5 +1,5 @@
error[E0539]: malformed `cfg` attribute input error[E0539]: malformed `cfg` attribute input
--> $DIR/malformed-attrs.rs:106:1 --> $DIR/malformed-attrs.rs:107:1
| |
LL | #[cfg] LL | #[cfg]
| ^^^^^^ | ^^^^^^
@ -10,7 +10,7 @@ LL | #[cfg]
= note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute> = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute>
error[E0539]: malformed `cfg_attr` attribute input error[E0539]: malformed `cfg_attr` attribute input
--> $DIR/malformed-attrs.rs:108:1 --> $DIR/malformed-attrs.rs:109:1
| |
LL | #[cfg_attr] LL | #[cfg_attr]
| ^^^^^^^^^^^ | ^^^^^^^^^^^
@ -21,13 +21,13 @@ LL | #[cfg_attr]
= note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute> = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
error[E0463]: can't find crate for `wloop` error[E0463]: can't find crate for `wloop`
--> $DIR/malformed-attrs.rs:214:1 --> $DIR/malformed-attrs.rs:215:1
| |
LL | extern crate wloop; LL | extern crate wloop;
| ^^^^^^^^^^^^^^^^^^^ can't find crate | ^^^^^^^^^^^^^^^^^^^ can't find crate
error: malformed `allow` attribute input error: malformed `allow` attribute input
--> $DIR/malformed-attrs.rs:180:1 --> $DIR/malformed-attrs.rs:181:1
| |
LL | #[allow] LL | #[allow]
| ^^^^^^^^ | ^^^^^^^^
@ -43,7 +43,7 @@ LL | #[allow(lint1, lint2, lint3, reason = "...")]
| +++++++++++++++++++++++++++++++++++++ | +++++++++++++++++++++++++++++++++++++
error: malformed `expect` attribute input error: malformed `expect` attribute input
--> $DIR/malformed-attrs.rs:182:1 --> $DIR/malformed-attrs.rs:183:1
| |
LL | #[expect] LL | #[expect]
| ^^^^^^^^^ | ^^^^^^^^^
@ -59,7 +59,7 @@ LL | #[expect(lint1, lint2, lint3, reason = "...")]
| +++++++++++++++++++++++++++++++++++++ | +++++++++++++++++++++++++++++++++++++
error: malformed `warn` attribute input error: malformed `warn` attribute input
--> $DIR/malformed-attrs.rs:184:1 --> $DIR/malformed-attrs.rs:185:1
| |
LL | #[warn] LL | #[warn]
| ^^^^^^^ | ^^^^^^^
@ -75,7 +75,7 @@ LL | #[warn(lint1, lint2, lint3, reason = "...")]
| +++++++++++++++++++++++++++++++++++++ | +++++++++++++++++++++++++++++++++++++
error: malformed `deny` attribute input error: malformed `deny` attribute input
--> $DIR/malformed-attrs.rs:186:1 --> $DIR/malformed-attrs.rs:187:1
| |
LL | #[deny] LL | #[deny]
| ^^^^^^^ | ^^^^^^^
@ -91,7 +91,7 @@ LL | #[deny(lint1, lint2, lint3, reason = "...")]
| +++++++++++++++++++++++++++++++++++++ | +++++++++++++++++++++++++++++++++++++
error: malformed `forbid` attribute input error: malformed `forbid` attribute input
--> $DIR/malformed-attrs.rs:188:1 --> $DIR/malformed-attrs.rs:189:1
| |
LL | #[forbid] LL | #[forbid]
| ^^^^^^^^^ | ^^^^^^^^^
@ -107,25 +107,25 @@ LL | #[forbid(lint1, lint2, lint3, reason = "...")]
| +++++++++++++++++++++++++++++++++++++ | +++++++++++++++++++++++++++++++++++++
error: the `#[proc_macro]` attribute is only usable with crates of the `proc-macro` crate type error: the `#[proc_macro]` attribute is only usable with crates of the `proc-macro` crate type
--> $DIR/malformed-attrs.rs:103:1 --> $DIR/malformed-attrs.rs:104:1
| |
LL | #[proc_macro = 18] LL | #[proc_macro = 18]
| ^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^
error: the `#[proc_macro_attribute]` attribute is only usable with crates of the `proc-macro` crate type error: the `#[proc_macro_attribute]` attribute is only usable with crates of the `proc-macro` crate type
--> $DIR/malformed-attrs.rs:120:1 --> $DIR/malformed-attrs.rs:121:1
| |
LL | #[proc_macro_attribute = 19] LL | #[proc_macro_attribute = 19]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type error: the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type
--> $DIR/malformed-attrs.rs:127:1 --> $DIR/malformed-attrs.rs:128:1
| |
LL | #[proc_macro_derive] LL | #[proc_macro_derive]
| ^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^
error[E0658]: allow_internal_unsafe side-steps the unsafe_code lint error[E0658]: allow_internal_unsafe side-steps the unsafe_code lint
--> $DIR/malformed-attrs.rs:219:1 --> $DIR/malformed-attrs.rs:220:1
| |
LL | #[allow_internal_unsafe = 1] LL | #[allow_internal_unsafe = 1]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -134,7 +134,7 @@ LL | #[allow_internal_unsafe = 1]
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0539]: malformed `windows_subsystem` attribute input error[E0539]: malformed `windows_subsystem` attribute input
--> $DIR/malformed-attrs.rs:26:1 --> $DIR/malformed-attrs.rs:27:1
| |
LL | #![windows_subsystem] LL | #![windows_subsystem]
| ^^^-----------------^ | ^^^-----------------^
@ -150,25 +150,25 @@ LL | #![windows_subsystem = "windows"]
| +++++++++++ | +++++++++++
error[E0539]: malformed `export_name` attribute input error[E0539]: malformed `export_name` attribute input
--> $DIR/malformed-attrs.rs:29:1 --> $DIR/malformed-attrs.rs:30:1
| |
LL | #[unsafe(export_name)] LL | #[unsafe(export_name)]
| ^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[export_name = "name"]` | ^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[export_name = "name"]`
error: `rustc_allow_const_fn_unstable` expects a list of feature names error: `rustc_allow_const_fn_unstable` expects a list of feature names
--> $DIR/malformed-attrs.rs:31:1 --> $DIR/malformed-attrs.rs:32:1
| |
LL | #[rustc_allow_const_fn_unstable] LL | #[rustc_allow_const_fn_unstable]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `allow_internal_unstable` expects a list of feature names error: `allow_internal_unstable` expects a list of feature names
--> $DIR/malformed-attrs.rs:34:1 --> $DIR/malformed-attrs.rs:35:1
| |
LL | #[allow_internal_unstable] LL | #[allow_internal_unstable]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0539]: malformed `rustc_confusables` attribute input error[E0539]: malformed `rustc_confusables` attribute input
--> $DIR/malformed-attrs.rs:36:1 --> $DIR/malformed-attrs.rs:37:1
| |
LL | #[rustc_confusables] LL | #[rustc_confusables]
| ^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^
@ -177,7 +177,7 @@ LL | #[rustc_confusables]
| help: must be of the form: `#[rustc_confusables("name1", "name2", ...)]` | help: must be of the form: `#[rustc_confusables("name1", "name2", ...)]`
error: `#[rustc_confusables]` attribute cannot be used on functions error: `#[rustc_confusables]` attribute cannot be used on functions
--> $DIR/malformed-attrs.rs:36:1 --> $DIR/malformed-attrs.rs:37:1
| |
LL | #[rustc_confusables] LL | #[rustc_confusables]
| ^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^
@ -185,7 +185,7 @@ LL | #[rustc_confusables]
= help: `#[rustc_confusables]` can only be applied to inherent methods = help: `#[rustc_confusables]` can only be applied to inherent methods
error[E0539]: malformed `deprecated` attribute input error[E0539]: malformed `deprecated` attribute input
--> $DIR/malformed-attrs.rs:39:1 --> $DIR/malformed-attrs.rs:40:1
| |
LL | #[deprecated = 5] LL | #[deprecated = 5]
| ^^^^^^^^^^^^^^^-^ | ^^^^^^^^^^^^^^^-^
@ -193,7 +193,7 @@ LL | #[deprecated = 5]
| expected a string literal here | expected a string literal here
error[E0539]: malformed `rustc_macro_transparency` attribute input error[E0539]: malformed `rustc_macro_transparency` attribute input
--> $DIR/malformed-attrs.rs:43:1 --> $DIR/malformed-attrs.rs:44:1
| |
LL | #[rustc_macro_transparency] LL | #[rustc_macro_transparency]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -208,7 +208,7 @@ LL | #[rustc_macro_transparency = "transparent"]
| +++++++++++++++ | +++++++++++++++
error: `#[rustc_macro_transparency]` attribute cannot be used on functions error: `#[rustc_macro_transparency]` attribute cannot be used on functions
--> $DIR/malformed-attrs.rs:43:1 --> $DIR/malformed-attrs.rs:44:1
| |
LL | #[rustc_macro_transparency] LL | #[rustc_macro_transparency]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -216,7 +216,7 @@ LL | #[rustc_macro_transparency]
= help: `#[rustc_macro_transparency]` can only be applied to macro defs = help: `#[rustc_macro_transparency]` can only be applied to macro defs
error[E0539]: malformed `repr` attribute input error[E0539]: malformed `repr` attribute input
--> $DIR/malformed-attrs.rs:46:1 --> $DIR/malformed-attrs.rs:47:1
| |
LL | #[repr] LL | #[repr]
| ^^^^^^^ expected this to be a list | ^^^^^^^ expected this to be a list
@ -224,7 +224,7 @@ LL | #[repr]
= note: for more information, visit <https://doc.rust-lang.org/reference/type-layout.html#representations> = note: for more information, visit <https://doc.rust-lang.org/reference/type-layout.html#representations>
error[E0565]: malformed `rustc_as_ptr` attribute input error[E0565]: malformed `rustc_as_ptr` attribute input
--> $DIR/malformed-attrs.rs:49:1 --> $DIR/malformed-attrs.rs:50:1
| |
LL | #[rustc_as_ptr = 5] LL | #[rustc_as_ptr = 5]
| ^^^^^^^^^^^^^^^---^ | ^^^^^^^^^^^^^^^---^
@ -233,7 +233,7 @@ LL | #[rustc_as_ptr = 5]
| help: must be of the form: `#[rustc_as_ptr]` | help: must be of the form: `#[rustc_as_ptr]`
error[E0539]: malformed `rustc_align` attribute input error[E0539]: malformed `rustc_align` attribute input
--> $DIR/malformed-attrs.rs:54:1 --> $DIR/malformed-attrs.rs:55:1
| |
LL | #[rustc_align] LL | #[rustc_align]
| ^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^
@ -242,7 +242,7 @@ LL | #[rustc_align]
| help: must be of the form: `#[rustc_align(<alignment in bytes>)]` | help: must be of the form: `#[rustc_align(<alignment in bytes>)]`
error[E0539]: malformed `optimize` attribute input error[E0539]: malformed `optimize` attribute input
--> $DIR/malformed-attrs.rs:56:1 --> $DIR/malformed-attrs.rs:57:1
| |
LL | #[optimize] LL | #[optimize]
| ^^^^^^^^^^^ expected this to be a list | ^^^^^^^^^^^ expected this to be a list
@ -257,7 +257,7 @@ LL | #[optimize(speed)]
| +++++++ | +++++++
error[E0565]: malformed `cold` attribute input error[E0565]: malformed `cold` attribute input
--> $DIR/malformed-attrs.rs:58:1 --> $DIR/malformed-attrs.rs:59:1
| |
LL | #[cold = 1] LL | #[cold = 1]
| ^^^^^^^---^ | ^^^^^^^---^
@ -266,7 +266,7 @@ LL | #[cold = 1]
| help: must be of the form: `#[cold]` | help: must be of the form: `#[cold]`
error[E0539]: malformed `must_use` attribute input error[E0539]: malformed `must_use` attribute input
--> $DIR/malformed-attrs.rs:60:1 --> $DIR/malformed-attrs.rs:61:1
| |
LL | #[must_use()] LL | #[must_use()]
| ^^^^^^^^^^--^ | ^^^^^^^^^^--^
@ -284,7 +284,7 @@ LL + #[must_use]
| |
error[E0565]: malformed `no_mangle` attribute input error[E0565]: malformed `no_mangle` attribute input
--> $DIR/malformed-attrs.rs:62:1 --> $DIR/malformed-attrs.rs:63:1
| |
LL | #[no_mangle = 1] LL | #[no_mangle = 1]
| ^^^^^^^^^^^^---^ | ^^^^^^^^^^^^---^
@ -293,7 +293,7 @@ LL | #[no_mangle = 1]
| help: must be of the form: `#[no_mangle]` | help: must be of the form: `#[no_mangle]`
error[E0565]: malformed `naked` attribute input error[E0565]: malformed `naked` attribute input
--> $DIR/malformed-attrs.rs:64:1 --> $DIR/malformed-attrs.rs:65:1
| |
LL | #[unsafe(naked())] LL | #[unsafe(naked())]
| ^^^^^^^^^^^^^^--^^ | ^^^^^^^^^^^^^^--^^
@ -302,7 +302,7 @@ LL | #[unsafe(naked())]
| help: must be of the form: `#[naked]` | help: must be of the form: `#[naked]`
error[E0565]: malformed `track_caller` attribute input error[E0565]: malformed `track_caller` attribute input
--> $DIR/malformed-attrs.rs:66:1 --> $DIR/malformed-attrs.rs:67:1
| |
LL | #[track_caller()] LL | #[track_caller()]
| ^^^^^^^^^^^^^^--^ | ^^^^^^^^^^^^^^--^
@ -311,13 +311,13 @@ LL | #[track_caller()]
| help: must be of the form: `#[track_caller]` | help: must be of the form: `#[track_caller]`
error[E0539]: malformed `export_name` attribute input error[E0539]: malformed `export_name` attribute input
--> $DIR/malformed-attrs.rs:68:1 --> $DIR/malformed-attrs.rs:69:1
| |
LL | #[export_name()] LL | #[export_name()]
| ^^^^^^^^^^^^^^^^ help: must be of the form: `#[export_name = "name"]` | ^^^^^^^^^^^^^^^^ help: must be of the form: `#[export_name = "name"]`
error[E0805]: malformed `used` attribute input error[E0805]: malformed `used` attribute input
--> $DIR/malformed-attrs.rs:70:1 --> $DIR/malformed-attrs.rs:71:1
| |
LL | #[used()] LL | #[used()]
| ^^^^^^--^ | ^^^^^^--^
@ -335,7 +335,7 @@ LL + #[used]
| |
error: `#[used]` attribute cannot be used on functions error: `#[used]` attribute cannot be used on functions
--> $DIR/malformed-attrs.rs:70:1 --> $DIR/malformed-attrs.rs:71:1
| |
LL | #[used()] LL | #[used()]
| ^^^^^^^^^ | ^^^^^^^^^
@ -343,13 +343,13 @@ LL | #[used()]
= help: `#[used]` can only be applied to statics = help: `#[used]` can only be applied to statics
error[E0539]: malformed `crate_name` attribute input error[E0539]: malformed `crate_name` attribute input
--> $DIR/malformed-attrs.rs:73:1 --> $DIR/malformed-attrs.rs:74:1
| |
LL | #[crate_name] LL | #[crate_name]
| ^^^^^^^^^^^^^ help: must be of the form: `#[crate_name = "name"]` | ^^^^^^^^^^^^^ help: must be of the form: `#[crate_name = "name"]`
error[E0539]: malformed `target_feature` attribute input error[E0539]: malformed `target_feature` attribute input
--> $DIR/malformed-attrs.rs:78:1 --> $DIR/malformed-attrs.rs:79:1
| |
LL | #[target_feature] LL | #[target_feature]
| ^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^
@ -358,7 +358,7 @@ LL | #[target_feature]
| help: must be of the form: `#[target_feature(enable = "feat1, feat2")]` | help: must be of the form: `#[target_feature(enable = "feat1, feat2")]`
error[E0565]: malformed `export_stable` attribute input error[E0565]: malformed `export_stable` attribute input
--> $DIR/malformed-attrs.rs:80:1 --> $DIR/malformed-attrs.rs:81:1
| |
LL | #[export_stable = 1] LL | #[export_stable = 1]
| ^^^^^^^^^^^^^^^^---^ | ^^^^^^^^^^^^^^^^---^
@ -367,7 +367,7 @@ LL | #[export_stable = 1]
| help: must be of the form: `#[export_stable]` | help: must be of the form: `#[export_stable]`
error[E0539]: malformed `link` attribute input error[E0539]: malformed `link` attribute input
--> $DIR/malformed-attrs.rs:82:1 --> $DIR/malformed-attrs.rs:83:1
| |
LL | #[link] LL | #[link]
| ^^^^^^^ expected this to be a list | ^^^^^^^ expected this to be a list
@ -375,7 +375,7 @@ LL | #[link]
= note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute> = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute>
error[E0539]: malformed `link_name` attribute input error[E0539]: malformed `link_name` attribute input
--> $DIR/malformed-attrs.rs:86:1 --> $DIR/malformed-attrs.rs:87:1
| |
LL | #[link_name] LL | #[link_name]
| ^^^^^^^^^^^^ help: must be of the form: `#[link_name = "name"]` | ^^^^^^^^^^^^ help: must be of the form: `#[link_name = "name"]`
@ -383,7 +383,7 @@ LL | #[link_name]
= note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_name-attribute> = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_name-attribute>
error[E0539]: malformed `link_section` attribute input error[E0539]: malformed `link_section` attribute input
--> $DIR/malformed-attrs.rs:90:1 --> $DIR/malformed-attrs.rs:91:1
| |
LL | #[link_section] LL | #[link_section]
| ^^^^^^^^^^^^^^^ help: must be of the form: `#[link_section = "name"]` | ^^^^^^^^^^^^^^^ help: must be of the form: `#[link_section = "name"]`
@ -391,7 +391,7 @@ LL | #[link_section]
= note: for more information, visit <https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute> = note: for more information, visit <https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute>
error[E0539]: malformed `coverage` attribute input error[E0539]: malformed `coverage` attribute input
--> $DIR/malformed-attrs.rs:92:1 --> $DIR/malformed-attrs.rs:93:1
| |
LL | #[coverage] LL | #[coverage]
| ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
@ -404,13 +404,13 @@ LL | #[coverage(on)]
| ++++ | ++++
error[E0539]: malformed `sanitize` attribute input error[E0539]: malformed `sanitize` attribute input
--> $DIR/malformed-attrs.rs:94:1 --> $DIR/malformed-attrs.rs:95:1
| |
LL | #[sanitize] LL | #[sanitize]
| ^^^^^^^^^^^ expected this to be a list | ^^^^^^^^^^^ expected this to be a list
error[E0565]: malformed `no_implicit_prelude` attribute input error[E0565]: malformed `no_implicit_prelude` attribute input
--> $DIR/malformed-attrs.rs:99:1 --> $DIR/malformed-attrs.rs:100:1
| |
LL | #[no_implicit_prelude = 23] LL | #[no_implicit_prelude = 23]
| ^^^^^^^^^^^^^^^^^^^^^^----^ | ^^^^^^^^^^^^^^^^^^^^^^----^
@ -419,7 +419,7 @@ LL | #[no_implicit_prelude = 23]
| help: must be of the form: `#[no_implicit_prelude]` | help: must be of the form: `#[no_implicit_prelude]`
error[E0565]: malformed `proc_macro` attribute input error[E0565]: malformed `proc_macro` attribute input
--> $DIR/malformed-attrs.rs:103:1 --> $DIR/malformed-attrs.rs:104:1
| |
LL | #[proc_macro = 18] LL | #[proc_macro = 18]
| ^^^^^^^^^^^^^----^ | ^^^^^^^^^^^^^----^
@ -428,7 +428,7 @@ LL | #[proc_macro = 18]
| help: must be of the form: `#[proc_macro]` | help: must be of the form: `#[proc_macro]`
error[E0539]: malformed `instruction_set` attribute input error[E0539]: malformed `instruction_set` attribute input
--> $DIR/malformed-attrs.rs:110:1 --> $DIR/malformed-attrs.rs:111:1
| |
LL | #[instruction_set] LL | #[instruction_set]
| ^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^
@ -439,7 +439,7 @@ LL | #[instruction_set]
= note: for more information, visit <https://doc.rust-lang.org/reference/attributes/codegen.html#the-instruction_set-attribute> = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/codegen.html#the-instruction_set-attribute>
error[E0539]: malformed `patchable_function_entry` attribute input error[E0539]: malformed `patchable_function_entry` attribute input
--> $DIR/malformed-attrs.rs:112:1 --> $DIR/malformed-attrs.rs:113:1
| |
LL | #[patchable_function_entry] LL | #[patchable_function_entry]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -448,7 +448,7 @@ LL | #[patchable_function_entry]
| help: must be of the form: `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]` | help: must be of the form: `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]`
error[E0565]: malformed `coroutine` attribute input error[E0565]: malformed `coroutine` attribute input
--> $DIR/malformed-attrs.rs:115:5 --> $DIR/malformed-attrs.rs:116:5
| |
LL | #[coroutine = 63] || {} LL | #[coroutine = 63] || {}
| ^^^^^^^^^^^^----^ | ^^^^^^^^^^^^----^
@ -457,7 +457,7 @@ LL | #[coroutine = 63] || {}
| help: must be of the form: `#[coroutine]` | help: must be of the form: `#[coroutine]`
error[E0565]: malformed `proc_macro_attribute` attribute input error[E0565]: malformed `proc_macro_attribute` attribute input
--> $DIR/malformed-attrs.rs:120:1 --> $DIR/malformed-attrs.rs:121:1
| |
LL | #[proc_macro_attribute = 19] LL | #[proc_macro_attribute = 19]
| ^^^^^^^^^^^^^^^^^^^^^^^----^ | ^^^^^^^^^^^^^^^^^^^^^^^----^
@ -466,7 +466,7 @@ LL | #[proc_macro_attribute = 19]
| help: must be of the form: `#[proc_macro_attribute]` | help: must be of the form: `#[proc_macro_attribute]`
error[E0539]: malformed `must_use` attribute input error[E0539]: malformed `must_use` attribute input
--> $DIR/malformed-attrs.rs:123:1 --> $DIR/malformed-attrs.rs:124:1
| |
LL | #[must_use = 1] LL | #[must_use = 1]
| ^^^^^^^^^^^^^-^ | ^^^^^^^^^^^^^-^
@ -484,7 +484,7 @@ LL + #[must_use]
| |
error[E0539]: malformed `proc_macro_derive` attribute input error[E0539]: malformed `proc_macro_derive` attribute input
--> $DIR/malformed-attrs.rs:127:1 --> $DIR/malformed-attrs.rs:128:1
| |
LL | #[proc_macro_derive] LL | #[proc_macro_derive]
| ^^^^^^^^^^^^^^^^^^^^ expected this to be a list | ^^^^^^^^^^^^^^^^^^^^ expected this to be a list
@ -498,7 +498,7 @@ LL | #[proc_macro_derive(TraitName, attributes(name1, name2, ...))]
| ++++++++++++++++++++++++++++++++++++++++++ | ++++++++++++++++++++++++++++++++++++++++++
error[E0539]: malformed `rustc_layout_scalar_valid_range_start` attribute input error[E0539]: malformed `rustc_layout_scalar_valid_range_start` attribute input
--> $DIR/malformed-attrs.rs:132:1 --> $DIR/malformed-attrs.rs:133:1
| |
LL | #[rustc_layout_scalar_valid_range_start] LL | #[rustc_layout_scalar_valid_range_start]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -507,7 +507,7 @@ LL | #[rustc_layout_scalar_valid_range_start]
| help: must be of the form: `#[rustc_layout_scalar_valid_range_start(start)]` | help: must be of the form: `#[rustc_layout_scalar_valid_range_start(start)]`
error[E0539]: malformed `rustc_layout_scalar_valid_range_end` attribute input error[E0539]: malformed `rustc_layout_scalar_valid_range_end` attribute input
--> $DIR/malformed-attrs.rs:134:1 --> $DIR/malformed-attrs.rs:135:1
| |
LL | #[rustc_layout_scalar_valid_range_end] LL | #[rustc_layout_scalar_valid_range_end]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -516,7 +516,7 @@ LL | #[rustc_layout_scalar_valid_range_end]
| help: must be of the form: `#[rustc_layout_scalar_valid_range_end(end)]` | help: must be of the form: `#[rustc_layout_scalar_valid_range_end(end)]`
error[E0539]: malformed `must_not_suspend` attribute input error[E0539]: malformed `must_not_suspend` attribute input
--> $DIR/malformed-attrs.rs:136:1 --> $DIR/malformed-attrs.rs:137:1
| |
LL | #[must_not_suspend()] LL | #[must_not_suspend()]
| ^^^^^^^^^^^^^^^^^^--^ | ^^^^^^^^^^^^^^^^^^--^
@ -532,7 +532,7 @@ LL + #[must_not_suspend]
| |
error[E0539]: malformed `cfi_encoding` attribute input error[E0539]: malformed `cfi_encoding` attribute input
--> $DIR/malformed-attrs.rs:138:1 --> $DIR/malformed-attrs.rs:139:1
| |
LL | #[cfi_encoding = ""] LL | #[cfi_encoding = ""]
| ^^^^^^^^^^^^^^^^^--^ | ^^^^^^^^^^^^^^^^^--^
@ -541,7 +541,7 @@ LL | #[cfi_encoding = ""]
| help: must be of the form: `#[cfi_encoding = "encoding"]` | help: must be of the form: `#[cfi_encoding = "encoding"]`
error[E0565]: malformed `marker` attribute input error[E0565]: malformed `marker` attribute input
--> $DIR/malformed-attrs.rs:157:1 --> $DIR/malformed-attrs.rs:158:1
| |
LL | #[marker = 3] LL | #[marker = 3]
| ^^^^^^^^^---^ | ^^^^^^^^^---^
@ -550,7 +550,7 @@ LL | #[marker = 3]
| help: must be of the form: `#[marker]` | help: must be of the form: `#[marker]`
error[E0565]: malformed `fundamental` attribute input error[E0565]: malformed `fundamental` attribute input
--> $DIR/malformed-attrs.rs:159:1 --> $DIR/malformed-attrs.rs:160:1
| |
LL | #[fundamental()] LL | #[fundamental()]
| ^^^^^^^^^^^^^--^ | ^^^^^^^^^^^^^--^
@ -559,7 +559,7 @@ LL | #[fundamental()]
| help: must be of the form: `#[fundamental]` | help: must be of the form: `#[fundamental]`
error[E0565]: malformed `ffi_pure` attribute input error[E0565]: malformed `ffi_pure` attribute input
--> $DIR/malformed-attrs.rs:167:5 --> $DIR/malformed-attrs.rs:168:5
| |
LL | #[unsafe(ffi_pure = 1)] LL | #[unsafe(ffi_pure = 1)]
| ^^^^^^^^^^^^^^^^^^---^^ | ^^^^^^^^^^^^^^^^^^---^^
@ -568,7 +568,7 @@ LL | #[unsafe(ffi_pure = 1)]
| help: must be of the form: `#[ffi_pure]` | help: must be of the form: `#[ffi_pure]`
error[E0539]: malformed `link_ordinal` attribute input error[E0539]: malformed `link_ordinal` attribute input
--> $DIR/malformed-attrs.rs:169:5 --> $DIR/malformed-attrs.rs:170:5
| |
LL | #[link_ordinal] LL | #[link_ordinal]
| ^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^
@ -579,7 +579,7 @@ LL | #[link_ordinal]
= note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute> = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute>
error[E0565]: malformed `ffi_const` attribute input error[E0565]: malformed `ffi_const` attribute input
--> $DIR/malformed-attrs.rs:173:5 --> $DIR/malformed-attrs.rs:174:5
| |
LL | #[unsafe(ffi_const = 1)] LL | #[unsafe(ffi_const = 1)]
| ^^^^^^^^^^^^^^^^^^^---^^ | ^^^^^^^^^^^^^^^^^^^---^^
@ -588,13 +588,13 @@ LL | #[unsafe(ffi_const = 1)]
| help: must be of the form: `#[ffi_const]` | help: must be of the form: `#[ffi_const]`
error[E0539]: malformed `linkage` attribute input error[E0539]: malformed `linkage` attribute input
--> $DIR/malformed-attrs.rs:175:5 --> $DIR/malformed-attrs.rs:176:5
| |
LL | #[linkage] LL | #[linkage]
| ^^^^^^^^^^ expected this to be of the form `linkage = "..."` | ^^^^^^^^^^ expected this to be of the form `linkage = "..."`
error[E0539]: malformed `debugger_visualizer` attribute input error[E0539]: malformed `debugger_visualizer` attribute input
--> $DIR/malformed-attrs.rs:190:1 --> $DIR/malformed-attrs.rs:191:1
| |
LL | #[debugger_visualizer] LL | #[debugger_visualizer]
| ^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^
@ -605,7 +605,7 @@ LL | #[debugger_visualizer]
= note: for more information, visit <https://doc.rust-lang.org/reference/attributes/debugger.html#the-debugger_visualizer-attribute> = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/debugger.html#the-debugger_visualizer-attribute>
error[E0565]: malformed `automatically_derived` attribute input error[E0565]: malformed `automatically_derived` attribute input
--> $DIR/malformed-attrs.rs:192:1 --> $DIR/malformed-attrs.rs:193:1
| |
LL | #[automatically_derived = 18] LL | #[automatically_derived = 18]
| ^^^^^^^^^^^^^^^^^^^^^^^^----^ | ^^^^^^^^^^^^^^^^^^^^^^^^----^
@ -614,7 +614,7 @@ LL | #[automatically_derived = 18]
| help: must be of the form: `#[automatically_derived]` | help: must be of the form: `#[automatically_derived]`
error[E0565]: malformed `non_exhaustive` attribute input error[E0565]: malformed `non_exhaustive` attribute input
--> $DIR/malformed-attrs.rs:200:1 --> $DIR/malformed-attrs.rs:201:1
| |
LL | #[non_exhaustive = 1] LL | #[non_exhaustive = 1]
| ^^^^^^^^^^^^^^^^^---^ | ^^^^^^^^^^^^^^^^^---^
@ -623,7 +623,7 @@ LL | #[non_exhaustive = 1]
| help: must be of the form: `#[non_exhaustive]` | help: must be of the form: `#[non_exhaustive]`
error[E0565]: malformed `thread_local` attribute input error[E0565]: malformed `thread_local` attribute input
--> $DIR/malformed-attrs.rs:206:1 --> $DIR/malformed-attrs.rs:207:1
| |
LL | #[thread_local()] LL | #[thread_local()]
| ^^^^^^^^^^^^^^--^ | ^^^^^^^^^^^^^^--^
@ -632,7 +632,7 @@ LL | #[thread_local()]
| help: must be of the form: `#[thread_local]` | help: must be of the form: `#[thread_local]`
error[E0565]: malformed `no_link` attribute input error[E0565]: malformed `no_link` attribute input
--> $DIR/malformed-attrs.rs:210:1 --> $DIR/malformed-attrs.rs:211:1
| |
LL | #[no_link()] LL | #[no_link()]
| ^^^^^^^^^--^ | ^^^^^^^^^--^
@ -641,7 +641,7 @@ LL | #[no_link()]
| help: must be of the form: `#[no_link]` | help: must be of the form: `#[no_link]`
error[E0539]: malformed `macro_use` attribute input error[E0539]: malformed `macro_use` attribute input
--> $DIR/malformed-attrs.rs:212:1 --> $DIR/malformed-attrs.rs:213:1
| |
LL | #[macro_use = 1] LL | #[macro_use = 1]
| ^^^^^^^^^^^^---^ | ^^^^^^^^^^^^---^
@ -659,7 +659,7 @@ LL + #[macro_use]
| |
error[E0539]: malformed `macro_export` attribute input error[E0539]: malformed `macro_export` attribute input
--> $DIR/malformed-attrs.rs:217:1 --> $DIR/malformed-attrs.rs:218:1
| |
LL | #[macro_export = 18] LL | #[macro_export = 18]
| ^^^^^^^^^^^^^^^----^ | ^^^^^^^^^^^^^^^----^
@ -676,7 +676,7 @@ LL + #[macro_export]
| |
error[E0565]: malformed `allow_internal_unsafe` attribute input error[E0565]: malformed `allow_internal_unsafe` attribute input
--> $DIR/malformed-attrs.rs:219:1 --> $DIR/malformed-attrs.rs:220:1
| |
LL | #[allow_internal_unsafe = 1] LL | #[allow_internal_unsafe = 1]
| ^^^^^^^^^^^^^^^^^^^^^^^^---^ | ^^^^^^^^^^^^^^^^^^^^^^^^---^
@ -685,7 +685,7 @@ LL | #[allow_internal_unsafe = 1]
| help: must be of the form: `#[allow_internal_unsafe]` | help: must be of the form: `#[allow_internal_unsafe]`
error: attribute should be applied to `const fn` error: attribute should be applied to `const fn`
--> $DIR/malformed-attrs.rs:31:1 --> $DIR/malformed-attrs.rs:32:1
| |
LL | #[rustc_allow_const_fn_unstable] LL | #[rustc_allow_const_fn_unstable]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -697,7 +697,7 @@ LL | | }
| |_- not a `const fn` | |_- not a `const fn`
warning: attribute should be applied to an `extern` block with non-Rust ABI warning: attribute should be applied to an `extern` block with non-Rust ABI
--> $DIR/malformed-attrs.rs:82:1 --> $DIR/malformed-attrs.rs:83:1
| |
LL | #[link] LL | #[link]
| ^^^^^^^ | ^^^^^^^
@ -712,19 +712,19 @@ LL | | }
= note: requested on the command line with `-W unused-attributes` = note: requested on the command line with `-W unused-attributes`
error: `#[repr(align(...))]` is not supported on functions error: `#[repr(align(...))]` is not supported on functions
--> $DIR/malformed-attrs.rs:46:1 --> $DIR/malformed-attrs.rs:47:1
| |
LL | #[repr] LL | #[repr]
| ^^^^^^^ | ^^^^^^^
| |
help: use `#[rustc_align(...)]` instead help: use `#[rustc_align(...)]` instead
--> $DIR/malformed-attrs.rs:46:1 --> $DIR/malformed-attrs.rs:47:1
| |
LL | #[repr] LL | #[repr]
| ^^^^^^^ | ^^^^^^^
warning: missing options for `on_unimplemented` attribute warning: missing options for `on_unimplemented` attribute
--> $DIR/malformed-attrs.rs:142:1 --> $DIR/malformed-attrs.rs:143:1
| |
LL | #[diagnostic::on_unimplemented] LL | #[diagnostic::on_unimplemented]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -733,7 +733,7 @@ LL | #[diagnostic::on_unimplemented]
= note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
warning: malformed `on_unimplemented` attribute warning: malformed `on_unimplemented` attribute
--> $DIR/malformed-attrs.rs:144:1 --> $DIR/malformed-attrs.rs:145:1
| |
LL | #[diagnostic::on_unimplemented = 1] LL | #[diagnostic::on_unimplemented = 1]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here
@ -741,7 +741,7 @@ LL | #[diagnostic::on_unimplemented = 1]
= help: only `message`, `note` and `label` are allowed as options = help: only `message`, `note` and `label` are allowed as options
error: valid forms for the attribute are `#[doc = "string"]`, `#[doc(alias)]`, `#[doc(attribute)]`, `#[doc(auto_cfg)]`, `#[doc(cfg)]`, `#[doc(fake_variadic)]`, `#[doc(hidden)]`, `#[doc(html_favicon_url)]`, `#[doc(html_logo_url)]`, `#[doc(html_no_source)]`, `#[doc(html_playground_url)]`, `#[doc(html_root_url)]`, `#[doc(include)]`, `#[doc(inline)]`, `#[doc(issue_tracker_base_url)]`, `#[doc(keyword)]`, `#[doc(masked)]`, `#[doc(no_default_passes)]`, `#[doc(no_inline)]`, `#[doc(notable_trait)]`, `#[doc(passes)]`, `#[doc(plugins)]`, `#[doc(rust_logo)]`, `#[doc(search_unbox)]`, `#[doc(spotlight)]`, and `#[doc(test)]` error: valid forms for the attribute are `#[doc = "string"]`, `#[doc(alias)]`, `#[doc(attribute)]`, `#[doc(auto_cfg)]`, `#[doc(cfg)]`, `#[doc(fake_variadic)]`, `#[doc(hidden)]`, `#[doc(html_favicon_url)]`, `#[doc(html_logo_url)]`, `#[doc(html_no_source)]`, `#[doc(html_playground_url)]`, `#[doc(html_root_url)]`, `#[doc(include)]`, `#[doc(inline)]`, `#[doc(issue_tracker_base_url)]`, `#[doc(keyword)]`, `#[doc(masked)]`, `#[doc(no_default_passes)]`, `#[doc(no_inline)]`, `#[doc(notable_trait)]`, `#[doc(passes)]`, `#[doc(plugins)]`, `#[doc(rust_logo)]`, `#[doc(search_unbox)]`, `#[doc(spotlight)]`, and `#[doc(test)]`
--> $DIR/malformed-attrs.rs:41:1 --> $DIR/malformed-attrs.rs:42:1
| |
LL | #[doc] LL | #[doc]
| ^^^^^^ | ^^^^^^
@ -753,7 +753,7 @@ LL | #![deny(invalid_doc_attributes)]
| ^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^
error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]` error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]`
--> $DIR/malformed-attrs.rs:51:1 --> $DIR/malformed-attrs.rs:52:1
| |
LL | #[inline = 5] LL | #[inline = 5]
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
@ -763,13 +763,13 @@ LL | #[inline = 5]
= note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]` warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]`
--> $DIR/malformed-attrs.rs:73:1 --> $DIR/malformed-attrs.rs:74:1
| |
LL | #[crate_name] LL | #[crate_name]
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
| |
note: this attribute does not have an `!`, which means it is applied to this function note: this attribute does not have an `!`, which means it is applied to this function
--> $DIR/malformed-attrs.rs:114:1 --> $DIR/malformed-attrs.rs:115:1
| |
LL | / fn test() { LL | / fn test() {
LL | | #[coroutine = 63] || {} LL | | #[coroutine = 63] || {}
@ -778,13 +778,13 @@ LL | | }
| |_^ | |_^
error: valid forms for the attribute are `#[doc = "string"]`, `#[doc(alias)]`, `#[doc(attribute)]`, `#[doc(auto_cfg)]`, `#[doc(cfg)]`, `#[doc(fake_variadic)]`, `#[doc(hidden)]`, `#[doc(html_favicon_url)]`, `#[doc(html_logo_url)]`, `#[doc(html_no_source)]`, `#[doc(html_playground_url)]`, `#[doc(html_root_url)]`, `#[doc(include)]`, `#[doc(inline)]`, `#[doc(issue_tracker_base_url)]`, `#[doc(keyword)]`, `#[doc(masked)]`, `#[doc(no_default_passes)]`, `#[doc(no_inline)]`, `#[doc(notable_trait)]`, `#[doc(passes)]`, `#[doc(plugins)]`, `#[doc(rust_logo)]`, `#[doc(search_unbox)]`, `#[doc(spotlight)]`, and `#[doc(test)]` error: valid forms for the attribute are `#[doc = "string"]`, `#[doc(alias)]`, `#[doc(attribute)]`, `#[doc(auto_cfg)]`, `#[doc(cfg)]`, `#[doc(fake_variadic)]`, `#[doc(hidden)]`, `#[doc(html_favicon_url)]`, `#[doc(html_logo_url)]`, `#[doc(html_no_source)]`, `#[doc(html_playground_url)]`, `#[doc(html_root_url)]`, `#[doc(include)]`, `#[doc(inline)]`, `#[doc(issue_tracker_base_url)]`, `#[doc(keyword)]`, `#[doc(masked)]`, `#[doc(no_default_passes)]`, `#[doc(no_inline)]`, `#[doc(notable_trait)]`, `#[doc(passes)]`, `#[doc(plugins)]`, `#[doc(rust_logo)]`, `#[doc(search_unbox)]`, `#[doc(spotlight)]`, and `#[doc(test)]`
--> $DIR/malformed-attrs.rs:76:1 --> $DIR/malformed-attrs.rs:77:1
| |
LL | #[doc] LL | #[doc]
| ^^^^^^ | ^^^^^^
warning: `#[link_name]` attribute cannot be used on functions warning: `#[link_name]` attribute cannot be used on functions
--> $DIR/malformed-attrs.rs:86:1 --> $DIR/malformed-attrs.rs:87:1
| |
LL | #[link_name] LL | #[link_name]
| ^^^^^^^^^^^^ | ^^^^^^^^^^^^
@ -793,7 +793,7 @@ LL | #[link_name]
= help: `#[link_name]` can be applied to foreign functions and foreign statics = help: `#[link_name]` can be applied to foreign functions and foreign statics
error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]` error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]`
--> $DIR/malformed-attrs.rs:96:1 --> $DIR/malformed-attrs.rs:97:1
| |
LL | #[ignore()] LL | #[ignore()]
| ^^^^^^^^^^^ | ^^^^^^^^^^^
@ -802,7 +802,7 @@ LL | #[ignore()]
= note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571> = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
warning: `#[no_implicit_prelude]` attribute cannot be used on functions warning: `#[no_implicit_prelude]` attribute cannot be used on functions
--> $DIR/malformed-attrs.rs:99:1 --> $DIR/malformed-attrs.rs:100:1
| |
LL | #[no_implicit_prelude = 23] LL | #[no_implicit_prelude = 23]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -811,13 +811,13 @@ LL | #[no_implicit_prelude = 23]
= help: `#[no_implicit_prelude]` can be applied to crates and modules = help: `#[no_implicit_prelude]` can be applied to crates and modules
warning: `#[diagnostic::do_not_recommend]` does not expect any arguments warning: `#[diagnostic::do_not_recommend]` does not expect any arguments
--> $DIR/malformed-attrs.rs:151:1 --> $DIR/malformed-attrs.rs:152:1
| |
LL | #[diagnostic::do_not_recommend()] LL | #[diagnostic::do_not_recommend()]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: `#[automatically_derived]` attribute cannot be used on modules warning: `#[automatically_derived]` attribute cannot be used on modules
--> $DIR/malformed-attrs.rs:192:1 --> $DIR/malformed-attrs.rs:193:1
| |
LL | #[automatically_derived = 18] LL | #[automatically_derived = 18]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -826,7 +826,7 @@ LL | #[automatically_derived = 18]
= help: `#[automatically_derived]` can only be applied to trait impl blocks = help: `#[automatically_derived]` can only be applied to trait impl blocks
error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]` error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]`
--> $DIR/malformed-attrs.rs:226:1 --> $DIR/malformed-attrs.rs:227:1
| |
LL | #[ignore = 1] LL | #[ignore = 1]
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
@ -835,7 +835,7 @@ LL | #[ignore = 1]
= note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571> = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/malformed-attrs.rs:115:23 --> $DIR/malformed-attrs.rs:116:23
| |
LL | fn test() { LL | fn test() {
| - help: a return type might be missing here: `-> _` | - help: a return type might be missing here: `-> _`
@ -843,7 +843,7 @@ LL | #[coroutine = 63] || {}
| ^^^^^ expected `()`, found coroutine | ^^^^^ expected `()`, found coroutine
| |
= note: expected unit type `()` = note: expected unit type `()`
found coroutine `{coroutine@$DIR/malformed-attrs.rs:115:23: 115:25}` found coroutine `{coroutine@$DIR/malformed-attrs.rs:116:23: 116:25}`
error: aborting due to 75 previous errors; 8 warnings emitted error: aborting due to 75 previous errors; 8 warnings emitted
@ -851,7 +851,7 @@ Some errors have detailed explanations: E0308, E0463, E0539, E0565, E0658, E0805
For more information about an error, try `rustc --explain E0308`. For more information about an error, try `rustc --explain E0308`.
Future incompatibility report: Future breakage diagnostic: Future incompatibility report: Future breakage diagnostic:
error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]` error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]`
--> $DIR/malformed-attrs.rs:51:1 --> $DIR/malformed-attrs.rs:52:1
| |
LL | #[inline = 5] LL | #[inline = 5]
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
@ -862,7 +862,7 @@ LL | #[inline = 5]
Future breakage diagnostic: Future breakage diagnostic:
error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]` error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]`
--> $DIR/malformed-attrs.rs:96:1 --> $DIR/malformed-attrs.rs:97:1
| |
LL | #[ignore()] LL | #[ignore()]
| ^^^^^^^^^^^ | ^^^^^^^^^^^
@ -873,7 +873,7 @@ LL | #[ignore()]
Future breakage diagnostic: Future breakage diagnostic:
error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]` error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]`
--> $DIR/malformed-attrs.rs:226:1 --> $DIR/malformed-attrs.rs:227:1
| |
LL | #[ignore = 1] LL | #[ignore = 1]
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^

View file

@ -2,7 +2,7 @@
//@ compile-flags: --crate-type=lib -Cinstrument-coverage -Zno-profiler-runtime //@ compile-flags: --crate-type=lib -Cinstrument-coverage -Zno-profiler-runtime
//@[allow] check-pass //@[allow] check-pass
#![feature(staged_api, rustc_attrs)] #![feature(staged_api, rustc_allow_const_fn_unstable)]
#![stable(feature = "rust_test", since = "1.0.0")] #![stable(feature = "rust_test", since = "1.0.0")]
#[stable(feature = "rust_test", since = "1.0.0")] #[stable(feature = "rust_test", since = "1.0.0")]

View file

@ -4,7 +4,7 @@ error[E0658]: `final` on trait functions is experimental
LL | final fn bar() {} LL | final fn bar() {}
| ^^^^^ | ^^^^^
| |
= note: see issue #131179 <https://github.com/rust-lang/rust/issues/131179> for more information = note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
= help: add `#![feature(final_associated_functions)]` to the crate attributes to enable = help: add `#![feature(final_associated_functions)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

View file

@ -1,6 +1,6 @@
#![allow(unused_macros)] #![allow(unused_macros)]
#[rustc_allow_const_fn_unstable()] //~ ERROR use of an internal attribute #[rustc_allow_const_fn_unstable()] //~ ERROR rustc_allow_const_fn_unstable side-steps
const fn foo() { } const fn foo() { }
fn main() {} fn main() {}

View file

@ -1,12 +1,12 @@
error[E0658]: use of an internal attribute error[E0658]: rustc_allow_const_fn_unstable side-steps feature gating and stability checks
--> $DIR/feature-gate-rustc-allow-const-fn-unstable.rs:3:1 --> $DIR/feature-gate-rustc-allow-const-fn-unstable.rs:3:1
| |
LL | #[rustc_allow_const_fn_unstable()] LL | #[rustc_allow_const_fn_unstable()]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable = note: see issue #69399 <https://github.com/rust-lang/rust/issues/69399> for more information
= note: the `#[rustc_allow_const_fn_unstable]` attribute is an internal implementation detail that will never be stable = help: add `#![feature(rustc_allow_const_fn_unstable)]` to the crate attributes to enable
= note: rustc_allow_const_fn_unstable side-steps feature gating and stability checks = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error: aborting due to 1 previous error error: aborting due to 1 previous error

View file

@ -1,14 +0,0 @@
// Regression test for issue #152606.
//@ check-pass
mod outer {
mod inner {
use super::*; // should go before the ambiguous glob imports
}
use crate::*;
pub use crate::*;
}
fn main() {}

View file

@ -1,29 +0,0 @@
//! Regression test for <https://github.com/rust-lang/rust/issues/150077>
//! Tests that `&mut T` suggests `T`, not `mut T`, `&mut str` suggests `String`, not `str`,
//! when recommending an owned value.
fn with_fn(_f: impl Fn() -> &mut ()) {}
//~^ ERROR: missing lifetime specifier
fn with_ref_mut_str(_f: impl Fn() -> &mut str) {}
//~^ ERROR: missing lifetime specifier
fn with_fn_has_return(_f: impl Fn() -> &mut ()) -> i32 {
//~^ ERROR: missing lifetime specifier
2
}
fn with_dyn(_f: Box<dyn Fn() -> &mut i32>) {}
//~^ ERROR: missing lifetime specifier
fn trait_bound<F: Fn() -> &mut i32>(_f: F) {}
//~^ ERROR: missing lifetime specifier
fn nested_result(_f: impl Fn() -> Result<&mut i32, ()>) {}
//~^ ERROR: missing lifetime specifier
struct Holder<F: Fn() -> &mut i32> {
//~^ ERROR: missing lifetime specifier
f: F,
}
fn main() {}

View file

@ -1,137 +0,0 @@
error[E0106]: missing lifetime specifier
--> $DIR/mut-ref-owned-suggestion.rs:4:29
|
LL | fn with_fn(_f: impl Fn() -> &mut ()) {}
| ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
|
LL | fn with_fn(_f: impl Fn() -> &'static mut ()) {}
| +++++++
help: instead, you are more likely to want to return an owned value
|
LL - fn with_fn(_f: impl Fn() -> &mut ()) {}
LL + fn with_fn(_f: impl Fn() -> ()) {}
|
error[E0106]: missing lifetime specifier
--> $DIR/mut-ref-owned-suggestion.rs:7:38
|
LL | fn with_ref_mut_str(_f: impl Fn() -> &mut str) {}
| ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
|
LL | fn with_ref_mut_str(_f: impl Fn() -> &'static mut str) {}
| +++++++
help: instead, you are more likely to want to return an owned value
|
LL - fn with_ref_mut_str(_f: impl Fn() -> &mut str) {}
LL + fn with_ref_mut_str(_f: impl Fn() -> String) {}
|
error[E0106]: missing lifetime specifier
--> $DIR/mut-ref-owned-suggestion.rs:10:40
|
LL | fn with_fn_has_return(_f: impl Fn() -> &mut ()) -> i32 {
| ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
= note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
|
LL | fn with_fn_has_return(_f: impl Fn() -> &'static mut ()) -> i32 {
| +++++++
help: consider making the bound lifetime-generic with a new `'a` lifetime
|
LL - fn with_fn_has_return(_f: impl Fn() -> &mut ()) -> i32 {
LL + fn with_fn_has_return(_f: impl for<'a> Fn() -> &'a ()) -> i32 {
|
help: consider introducing a named lifetime parameter
|
LL - fn with_fn_has_return(_f: impl Fn() -> &mut ()) -> i32 {
LL + fn with_fn_has_return<'a>(_f: impl Fn() -> &'a ()) -> i32 {
|
help: alternatively, you might want to return an owned value
|
LL - fn with_fn_has_return(_f: impl Fn() -> &mut ()) -> i32 {
LL + fn with_fn_has_return(_f: impl Fn() -> ()) -> i32 {
|
error[E0106]: missing lifetime specifier
--> $DIR/mut-ref-owned-suggestion.rs:15:33
|
LL | fn with_dyn(_f: Box<dyn Fn() -> &mut i32>) {}
| ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
|
LL | fn with_dyn(_f: Box<dyn Fn() -> &'static mut i32>) {}
| +++++++
help: instead, you are more likely to want to return an owned value
|
LL - fn with_dyn(_f: Box<dyn Fn() -> &mut i32>) {}
LL + fn with_dyn(_f: Box<dyn Fn() -> i32>) {}
|
error[E0106]: missing lifetime specifier
--> $DIR/mut-ref-owned-suggestion.rs:18:27
|
LL | fn trait_bound<F: Fn() -> &mut i32>(_f: F) {}
| ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
|
LL | fn trait_bound<F: Fn() -> &'static mut i32>(_f: F) {}
| +++++++
help: instead, you are more likely to want to change the argument to be borrowed...
|
LL | fn trait_bound<F: Fn() -> &mut i32>(_f: &F) {}
| +
help: ...or alternatively, you might want to return an owned value
|
LL - fn trait_bound<F: Fn() -> &mut i32>(_f: F) {}
LL + fn trait_bound<F: Fn() -> i32>(_f: F) {}
|
error[E0106]: missing lifetime specifier
--> $DIR/mut-ref-owned-suggestion.rs:21:42
|
LL | fn nested_result(_f: impl Fn() -> Result<&mut i32, ()>) {}
| ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
|
LL | fn nested_result(_f: impl Fn() -> Result<&'static mut i32, ()>) {}
| +++++++
help: instead, you are more likely to want to return an owned value
|
LL - fn nested_result(_f: impl Fn() -> Result<&mut i32, ()>) {}
LL + fn nested_result(_f: impl Fn() -> Result<i32, ()>) {}
|
error[E0106]: missing lifetime specifier
--> $DIR/mut-ref-owned-suggestion.rs:24:26
|
LL | struct Holder<F: Fn() -> &mut i32> {
| ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
|
LL | struct Holder<F: Fn() -> &'static mut i32> {
| +++++++
help: instead, you are more likely to want to return an owned value
|
LL - struct Holder<F: Fn() -> &mut i32> {
LL + struct Holder<F: Fn() -> i32> {
|
error: aborting due to 7 previous errors
For more information about this error, try `rustc --explain E0106`.

View file

@ -1,49 +0,0 @@
// Regression test for https://github.com/rust-lang/rust/issues/65866.
mod plain {
struct Foo;
struct Re<'a> {
_data: &'a u16,
}
trait Bar {
fn bar(&self, r: &mut Re);
//~^ NOTE expected
//~| NOTE `Re` here is elided as `Re<'_>`
}
impl Bar for Foo {
fn bar<'a, 'b>(&'a self, _r: &'b mut Re<'a>) {}
//~^ ERROR `impl` item signature doesn't match `trait` item signature
//~| NOTE expected signature
//~| NOTE found
//~| HELP the lifetime requirements
//~| HELP verify the lifetime relationships
}
}
mod with_type_args {
struct Foo;
struct Re<'a, T> {
_data: (&'a u16, T),
}
trait Bar {
fn bar(&self, r: &mut Re<u8>);
//~^ NOTE expected
//~| NOTE `Re` here is elided as `Re<'_, u8>`
}
impl Bar for Foo {
fn bar<'a, 'b>(&'a self, _r: &'b mut Re<'a, u8>) {}
//~^ ERROR `impl` item signature doesn't match `trait` item signature
//~| NOTE expected signature
//~| NOTE found
//~| HELP the lifetime requirements
//~| HELP verify the lifetime relationships
}
}
fn main() {}

View file

@ -1,40 +0,0 @@
error: `impl` item signature doesn't match `trait` item signature
--> $DIR/trait-impl-mismatch-elided-lifetime-issue-65866.rs:17:9
|
LL | fn bar(&self, r: &mut Re);
| -------------------------- expected `fn(&'1 plain::Foo, &'2 mut plain::Re<'3>)`
...
LL | fn bar<'a, 'b>(&'a self, _r: &'b mut Re<'a>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 plain::Foo, &'2 mut plain::Re<'1>)`
|
= note: expected signature `fn(&'1 plain::Foo, &'2 mut plain::Re<'3>)`
found signature `fn(&'1 plain::Foo, &'2 mut plain::Re<'1>)`
= help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
= help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
note: `Re` here is elided as `Re<'_>`
--> $DIR/trait-impl-mismatch-elided-lifetime-issue-65866.rs:11:31
|
LL | fn bar(&self, r: &mut Re);
| ^^
error: `impl` item signature doesn't match `trait` item signature
--> $DIR/trait-impl-mismatch-elided-lifetime-issue-65866.rs:40:9
|
LL | fn bar(&self, r: &mut Re<u8>);
| ------------------------------ expected `fn(&'1 with_type_args::Foo, &'2 mut with_type_args::Re<'3, u8>)`
...
LL | fn bar<'a, 'b>(&'a self, _r: &'b mut Re<'a, u8>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 with_type_args::Foo, &'2 mut with_type_args::Re<'1, u8>)`
|
= note: expected signature `fn(&'1 with_type_args::Foo, &'2 mut with_type_args::Re<'3, u8>)`
found signature `fn(&'1 with_type_args::Foo, &'2 mut with_type_args::Re<'1, u8>)`
= help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
= help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
note: `Re` here is elided as `Re<'_, u8>`
--> $DIR/trait-impl-mismatch-elided-lifetime-issue-65866.rs:34:31
|
LL | fn bar(&self, r: &mut Re<u8>);
| ^^
error: aborting due to 2 previous errors

View file

@ -0,0 +1,12 @@
//@ proc-macro: test-macros.rs
//@ compile-flags: -Z span-debug
//@ check-pass
#![no_std] // Don't load unnecessary hygiene information from std
extern crate std;
#[macro_use] extern crate test_macros;
include!("pretty-print-hack/rental-0.5.6/src/lib.rs");
fn main() {}

View file

@ -0,0 +1,21 @@
PRINT-DERIVE INPUT (DISPLAY): enum ProceduralMasqueradeDummyType { Input }
PRINT-DERIVE INPUT (DEBUG): TokenStream [
Ident {
ident: "enum",
span: $DIR/pretty-print-hack/rental-0.5.6/src/lib.rs:4:1: 4:5 (#0),
},
Ident {
ident: "ProceduralMasqueradeDummyType",
span: $DIR/pretty-print-hack/rental-0.5.6/src/lib.rs:4:6: 4:35 (#0),
},
Group {
delimiter: Brace,
stream: TokenStream [
Ident {
ident: "Input",
span: $DIR/pretty-print-hack/rental-0.5.6/src/lib.rs:13:5: 13:10 (#0),
},
],
span: $DIR/pretty-print-hack/rental-0.5.6/src/lib.rs:4:36: 14:2 (#0),
},
]

View file

@ -0,0 +1,6 @@
error: using an old version of `rental`
|
= note: older versions of the `rental` crate no longer compile; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
error: aborting due to 1 previous error

View file

@ -0,0 +1,6 @@
error: using an old version of `rental`
|
= note: older versions of the `rental` crate no longer compile; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
error: aborting due to 1 previous error

View file

@ -0,0 +1,21 @@
//@ proc-macro: test-macros.rs
//@ compile-flags: -Z span-debug
//@ revisions: local remapped
//@ [remapped] remap-src-base
#![no_std] // Don't load unnecessary hygiene information from std
extern crate std;
#[macro_use] extern crate test_macros;
mod first {
include!("pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs");
}
mod second {
include!("pretty-print-hack/rental-0.5.5/src/lib.rs");
}
fn main() {}
//~? ERROR using an old version of `rental`

View file

@ -0,0 +1,14 @@
//@ ignore-auxiliary (used by `../../../pretty-print-hack-show.rs`)
#[derive(Print)]
enum ProceduralMasqueradeDummyType {
//~^ ERROR using
//~| WARN this was previously
//~| ERROR using
//~| WARN this was previously
//~| ERROR using
//~| WARN this was previously
//~| ERROR using
//~| WARN this was previously
Input
}

View file

@ -0,0 +1,14 @@
//@ ignore-auxiliary (used by `../../../pretty-print-hack-show.rs`)
#[derive(Print)]
enum ProceduralMasqueradeDummyType {
//~^ ERROR using
//~| WARN this was previously
//~| ERROR using
//~| WARN this was previously
//~| ERROR using
//~| WARN this was previously
//~| ERROR using
//~| WARN this was previously
Input
}

View file

@ -0,0 +1,14 @@
//@ ignore-auxiliary (used by `../../../pretty-print-hack/hide.rs`)
#[derive(Print)]
enum ProceduralMasqueradeDummyType {
//~^ ERROR using
//~| WARN this was previously
//~| ERROR using
//~| WARN this was previously
//~| ERROR using
//~| WARN this was previously
//~| ERROR using
//~| WARN this was previously
Input
}

View file

@ -1,21 +0,0 @@
//! Regression test for <https://github.com/rust-lang/rust/issues/147958>
//@ check-pass
#![feature(decl_macro)]
macro_rules! exported {
() => {
#[macro_export]
macro_rules! exported {
() => {};
}
};
}
use inner1::*;
exported!();
mod inner1 {
pub macro exported() {}
}
fn main() {}

View file

@ -1,5 +1,4 @@
//@ compile-flags: --test //@ compile-flags: --test
//@ reference: attributes.testing.test.allowed-positions
fn align_offset_weird_strides() { fn align_offset_weird_strides() {
#[test] #[test]

View file

@ -1,5 +1,5 @@
error: the `#[test]` attribute may only be used on a free function error: the `#[test]` attribute may only be used on a free function
--> $DIR/issue-109816.rs:5:5 --> $DIR/issue-109816.rs:4:5
| |
LL | #[test] LL | #[test]
| ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions | ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions

View file

@ -1,5 +1,4 @@
//@ compile-flags:--test //@ compile-flags:--test
//@ reference: attributes.testing.test.allowed-positions
struct A {} struct A {}

Some files were not shown because too many files have changed in this diff Show more