diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index b52cc873f2e69..f2e3c620cb039 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -24,12 +24,12 @@ const NOTE_ON_UNDEFINED_BEHAVIOR_ERROR: &str = "The rules on what exactly is und repository if you believe it should not be considered undefined behavior."; // Returns a pointer to where the result lives +#[instrument(level = "debug", skip(ecx, body), fields(?param_env=ecx.param_env()), ret)] fn eval_body_using_ecx<'mir, 'tcx>( ecx: &mut CompileTimeEvalContext<'mir, 'tcx>, cid: GlobalId<'tcx>, body: &'mir mir::Body<'tcx>, ) -> InterpResult<'tcx, MPlaceTy<'tcx>> { - debug!("eval_body_using_ecx: {:?}, {:?}", cid, ecx.param_env); let tcx = *ecx.tcx; assert!( cid.promoted.is_some() @@ -78,7 +78,6 @@ fn eval_body_using_ecx<'mir, 'tcx>( intern_const_alloc_recursive(ecx, intern_kind, &ret)?; // we leave alignment checks off, since this `ecx` will not be used for further evaluation anyway - debug!("eval_body_using_ecx done: {:?}", *ret); Ok(ret) } diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index a964fe8465eec..62761ca2695bf 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -162,7 +162,7 @@ fn create_mplace_from_layout<'tcx>( ty: Ty<'tcx>, ) -> MPlaceTy<'tcx> { let tcx = ecx.tcx; - let param_env = ecx.param_env; + let param_env = ecx.param_env(); let layout = tcx.layout_of(param_env.and(ty)).unwrap(); debug!(?layout); diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index cbe98548025bc..115094749c109 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -64,7 +64,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let instance = ty::Instance::resolve_for_fn_ptr( *self.tcx, - self.param_env, + self.param_env(), def_id, substs, ) @@ -301,14 +301,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ) -> InterpResult<'tcx> { // A -> A conversion let (src_pointee_ty, dest_pointee_ty) = - self.tcx.struct_lockstep_tails_erasing_lifetimes(source_ty, cast_ty, self.param_env); + self.tcx.struct_lockstep_tails_erasing_lifetimes(source_ty, cast_ty, self.param_env()); match (&src_pointee_ty.kind(), &dest_pointee_ty.kind()) { (&ty::Array(_, length), &ty::Slice(_)) => { let ptr = self.read_scalar(src)?; // u64 cast is from usize to u64, which is always good let val = - Immediate::new_slice(ptr, length.eval_usize(*self.tcx, self.param_env), self); + Immediate::new_slice(ptr, length.eval_usize(*self.tcx, self.param_env()), self); self.write_immediate(val, dest) } (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => { diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index bdebfbb3ff510..f98a99313a68a 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -37,7 +37,9 @@ pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> { pub tcx: TyCtxtAt<'tcx>, /// Bounds in scope for polymorphic evaluations. - pub(crate) param_env: ty::ParamEnv<'tcx>, + /// + /// This has to be mutable as we may only lazily reveal opaque types. + pub(crate) param_env: Cell>, /// The virtual memory system. pub memory: Memory<'mir, 'tcx, M>, @@ -298,7 +300,7 @@ where M: Machine<'mir, 'tcx>, { fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.param_env + self.param_env.get() } } @@ -405,7 +407,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { InterpCx { machine, tcx: tcx.at(root_span), - param_env, + param_env: Cell::new(param_env), memory: Memory::new(), recursion_limit: tcx.recursion_limit(), } @@ -418,6 +420,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.stack().last().map_or(self.tcx.span, |f| f.current_span()) } + #[inline(always)] + pub fn param_env(&self) -> ParamEnv<'tcx> { + self.param_env.get() + } + #[inline(always)] pub(crate) fn stack(&self) -> &[Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>] { M::stack(self) @@ -465,7 +472,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { #[inline] pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool { - ty.is_freeze(self.tcx, self.param_env) + ty.is_freeze(self.tcx, self.param_env()) + } + + pub fn reveal_opaque_types_in_value>(&self, value: T) -> T { + let (param_env, value) = self.tcx.reveal_opaque_types_in_value(self.param_env.get(), value); + self.param_env.set(param_env); + value } pub fn load_mir( @@ -505,7 +518,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ) -> Result> { frame .instance - .try_subst_mir_and_normalize_erasing_regions(*self.tcx, self.param_env, value) + .try_subst_mir_and_normalize_erasing_regions(*self.tcx, self.param_env(), value) + .map(|value| { + let (param_env, value) = + self.tcx.reveal_opaque_types_in_value(self.param_env.get(), value); + self.param_env.set(param_env); + value + }) .map_err(|e| { self.tcx.sess.delay_span_bug( self.cur_span(), @@ -517,15 +536,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } /// The `substs` are assumed to already be in our interpreter "universe" (param_env). + #[instrument(level = "trace", skip(self), fields(param_env = ?self.param_env), ret)] pub(super) fn resolve( &self, def: ty::WithOptConstParam, substs: SubstsRef<'tcx>, ) -> InterpResult<'tcx, ty::Instance<'tcx>> { - trace!("resolve: {:?}, {:#?}", def, substs); - trace!("param_env: {:#?}", self.param_env); - trace!("substs: {:#?}", substs); - match ty::Instance::resolve_opt_const_arg(*self.tcx, self.param_env, def, substs) { + match ty::Instance::resolve_opt_const_arg(*self.tcx, self.param_env(), def, substs) { Ok(Some(instance)) => Ok(instance), Ok(None) => throw_inval!(TooGeneric), @@ -545,7 +562,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // have to support that case (mostly by skipping all caching). match frame.locals.get(local).and_then(|state| state.layout.get()) { None => { - let layout = from_known_layout(self.tcx, self.param_env, layout, || { + let layout = from_known_layout(self.tcx, self.param_env(), layout, || { let local_ty = frame.body.local_decls[local].ty; let local_ty = self.subst_from_frame_and_normalize_erasing_regions(frame, local_ty)?; @@ -914,7 +931,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let param_env = if self.tcx.is_static(gid.instance.def_id()) { ty::ParamEnv::reveal_all() } else { - self.param_env + self.param_env() }; let param_env = param_env.with_const(); // Use a precise span for better cycle errors. diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 24dbc769529c3..63adae82df872 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -114,7 +114,7 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval: if let InternMode::Static(mutability) = mode { // For this, we need to take into account `UnsafeCell`. When `ty` is `None`, we assume // no interior mutability. - let frozen = ty.map_or(true, |ty| ty.is_freeze(ecx.tcx, ecx.param_env)); + let frozen = ty.map_or(true, |ty| ty.is_freeze(ecx.tcx, ecx.param_env.get())); // For statics, allocation mutability is the combination of place mutability and // type mutability. // The entire allocation needs to be mutable if it contains an `UnsafeCell` anywhere. @@ -243,7 +243,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory assert_eq!(mplace.layout.ty, referenced_ty); // Handle trait object vtables. if let ty::Dynamic(..) = - tcx.struct_tail_erasing_lifetimes(referenced_ty, self.ecx.param_env).kind() + tcx.struct_tail_erasing_lifetimes(referenced_ty, self.ecx.param_env()).kind() { let ptr = mplace.meta.unwrap_meta().to_pointer(&tcx)?; if let Some(alloc_id) = ptr.provenance { diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 8637d6a7767e4..cece911088d5c 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -170,7 +170,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { _ => bug!(), }; let val = - self.tcx.const_eval_global_id(self.param_env, gid, Some(self.tcx.span))?; + self.tcx.const_eval_global_id(self.param_env(), gid, Some(self.tcx.span))?; let val = self.const_val_to_op(val, ty, Some(dest.layout))?; self.copy_op(&val, dest, /*allow_transmute*/ false)?; } diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 510adde62962b..9b780a3e577ca 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -499,7 +499,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { debug_assert!( mir_assign_valid_types( *self.tcx, - self.param_env, + self.param_env(), self.layout_of(self.subst_from_current_frame_and_normalize_erasing_regions( mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty )?)?, @@ -570,7 +570,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let cid = GlobalId { instance, promoted: None }; let _valtree = self .tcx - .eval_to_valtree(self.param_env.and(cid))? + .eval_to_valtree(self.param_env().and(cid))? .unwrap_or_else(|| bug!("unable to create ValTree for {uv:?}")); Ok(self.eval_to_allocation(cid)?.into()) @@ -606,7 +606,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Scalar::Int(int) => Scalar::Int(int), }) }; - let layout = from_known_layout(self.tcx, self.param_env, layout, || self.layout_of(ty))?; + let layout = from_known_layout(self.tcx, self.param_env(), layout, || self.layout_of(ty))?; let op = match val_val { ConstValue::ByRef { alloc, offset } => { let id = self.tcx.create_memory_alloc(alloc); diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 7a01b85381a3f..31b6169bd3e69 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -426,7 +426,7 @@ where debug_assert!( mir_assign_valid_types( *self.tcx, - self.param_env, + self.param_env(), self.layout_of(self.subst_from_current_frame_and_normalize_erasing_regions( mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty )?)?, @@ -626,7 +626,7 @@ where // We do NOT compare the types for equality, because well-typed code can // actually "transmute" `&mut T` to `&T` in an assignment without a cast. let layout_compat = - mir_assign_valid_types(*self.tcx, self.param_env, src.layout, dest.layout); + mir_assign_valid_types(*self.tcx, self.param_env(), src.layout, dest.layout); if !allow_transmute && !layout_compat { span_bug!( self.cur_span(), diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index 50a82aa0e72c9..94332f9e8b870 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -73,7 +73,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let fn_sig_binder = func.layout.ty.fn_sig(*self.tcx); let fn_sig = - self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig_binder); + self.tcx.normalize_erasing_late_bound_regions(self.param_env(), fn_sig_binder); let extra_args = &args[fn_sig.inputs().len()..]; let extra_args = self.tcx.mk_type_list(extra_args.iter().map(|arg| arg.layout.ty)); @@ -86,6 +86,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ty::FnDef(def_id, substs) => { let instance = self.resolve(ty::WithOptConstParam::unknown(def_id), substs)?; + let instance = self.reveal_opaque_types_in_value(instance); ( FnVal::Instance(instance), self.fn_abi_of_instance(instance, extra_args)?, @@ -563,7 +564,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Obtain the underlying trait we are working on. let receiver_tail = self .tcx - .struct_tail_erasing_lifetimes(receiver_place.layout.ty, self.param_env); + .struct_tail_erasing_lifetimes(receiver_place.layout.ty, self.param_env()); let ty::Dynamic(data, ..) = receiver_tail.kind() else { span_bug!(self.cur_span(), "dynamic call on non-`dyn` type {}", receiver_tail) }; @@ -599,7 +600,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let concrete_method = Instance::resolve_for_vtable( tcx, - self.param_env, + self.param_env(), def_id, instance.substs.rebase_onto(tcx, trait_def_id, concrete_trait_ref.substs), ) diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index 2bc521d5bbe0b..4bb5b4a54afe7 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -13,7 +13,7 @@ where T: TypeVisitable<'tcx>, { debug!("ensure_monomorphic_enough: ty={:?}", ty); - if !ty.needs_subst() { + if !(ty.needs_subst() || ty.has_opaque_types()) { return Ok(()); } @@ -31,7 +31,7 @@ where } match *ty.kind() { - ty::Param(_) => ControlFlow::Break(FoundParam), + ty::Param(_) | ty::Opaque(..) => ControlFlow::Break(FoundParam), ty::Closure(def_id, substs) | ty::Generator(def_id, substs, ..) | ty::FnDef(def_id, substs) => { diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 14aaee6ac3f9e..3e56237dede9e 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -333,7 +333,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' meta: MemPlaceMeta, pointee: TyAndLayout<'tcx>, ) -> InterpResult<'tcx> { - let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(pointee.ty, self.ecx.param_env); + let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(pointee.ty, self.ecx.param_env()); match tail.kind() { ty::Dynamic(..) => { let vtable = meta.unwrap_meta().to_pointer(self.ecx)?; @@ -726,7 +726,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> ) -> InterpResult<'tcx> { // Special check preventing `UnsafeCell` inside unions in the inner part of constants. if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true, .. })) { - if !op.layout.ty.is_freeze(self.ecx.tcx.at(DUMMY_SP), self.ecx.param_env) { + if !op.layout.ty.is_freeze(self.ecx.tcx.at(DUMMY_SP), self.ecx.param_env()) { throw_validation_failure!(self.path, { "`UnsafeCell` in a `const`" }); } } diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 9c95ffca19bc0..7025022a2cdf4 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -2,6 +2,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_index::bit_set::BitSet; +use rustc_infer::infer::DefiningAnchor; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::visit::NonUseContext::VarDebugInfo; @@ -12,12 +13,13 @@ use rustc_middle::mir::{ ProjectionElem, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind, Terminator, TerminatorKind, UnOp, START_BLOCK, }; -use rustc_middle::ty::fold::BottomUpFolder; -use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeFoldable, TypeVisitable}; +use rustc_middle::traits::ObligationCause; +use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitable}; use rustc_mir_dataflow::impls::MaybeStorageLive; use rustc_mir_dataflow::storage::always_storage_live_locals; use rustc_mir_dataflow::{Analysis, ResultsCursor}; use rustc_target::abi::{Size, VariantIdx}; +use rustc_trait_selection::traits::ObligationCtxt; #[derive(Copy, Clone, Debug)] enum EdgeKind { @@ -87,25 +89,36 @@ pub fn equal_up_to_regions<'tcx>( return true; } - // Normalize lifetimes away on both sides, then compare. - let normalize = |ty: Ty<'tcx>| { - tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty).fold_with( - &mut BottomUpFolder { - tcx, - // FIXME: We erase all late-bound lifetimes, but this is not fully correct. - // If you have a type like ` fn(&'a u32) as SomeTrait>::Assoc`, - // this is not necessarily equivalent to `::Assoc`, - // since one may have an `impl SomeTrait for fn(&32)` and - // `impl SomeTrait for fn(&'static u32)` at the same time which - // specify distinct values for Assoc. (See also #56105) - lt_op: |_| tcx.lifetimes.re_erased, - // Leave consts and types unchanged. - ct_op: |ct| ct, - ty_op: |ty| ty, - }, - ) - }; - tcx.infer_ctxt().enter(|infcx| infcx.can_eq(param_env, normalize(src), normalize(dest)).is_ok()) + may_subtype_ignoring_regions(tcx, param_env, src, dest) + || may_subtype_ignoring_regions(tcx, param_env, dest, src) +} + +fn may_subtype_ignoring_regions<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + src: Ty<'tcx>, + dest: Ty<'tcx>, +) -> bool { + let mut builder = + tcx.infer_ctxt().ignoring_regions().with_opaque_type_inference(DefiningAnchor::Bubble); + builder.enter(|infcx| { + let ocx = ObligationCtxt::new(&infcx); + let cause = ObligationCause::dummy(); + let src = ocx.normalize(cause.clone(), param_env, src); + let dest = ocx.normalize(cause.clone(), param_env, dest); + let Ok(infer_ok) = infcx.at(&cause, param_env).eq(src, dest) else { + return false; + }; + let () = ocx.register_infer_ok_obligations(infer_ok); + let errors = ocx.select_all_or_error(); + // With `Reveal::All`, opaque types get normalized away, with `Reveal::UserFacing` + // we would get unification errors because we're unable to look into opaque types, + // even if they're constrained in our current function. + // + // It seems very unlikely that this hides any bugs. + let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); + errors.is_empty() + }) } struct TypeChecker<'a, 'tcx> { @@ -188,16 +201,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // all normal lifetimes are erased, higher-ranked types with their // late-bound lifetimes are still around and can lead to type // differences. So we compare ignoring lifetimes. - - // First, try with reveal_all. This might not work in some cases, as the predicates - // can be cleared in reveal_all mode. We try the reveal first anyways as it is used - // by some other passes like inlining as well. - let param_env = self.param_env.with_reveal_all_normalized(self.tcx); - if equal_up_to_regions(self.tcx, param_env, src, dest) { - return true; - } - - // If this fails, we can try it without the reveal. equal_up_to_regions(self.tcx, self.param_env, src, dest) } } @@ -284,7 +287,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { this.fail( location, format!( - "Field projection `{:?}.{:?}` specified type `{:?}`, but actual type is {:?}", + "Field projection `{:?}.{:?}` specified type `{:?}`, but actual type is `{:?}`", parent, f, ty, f_ty ) ) diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 99de5b6598126..e7f07f21cf920 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -3309,4 +3309,13 @@ impl<'tcx> InferCtxt<'_, 'tcx> { _ => false, } } + + pub fn concrete_ctfe_failure_error(&self, span: Span) -> ErrorGuaranteed { + self.tcx + .sess + .struct_span_err(span, "unable to use constant with a hidden value in the type system") + .note("this most often happens when trying to look into an opaque type") + .note("the type system cannot access the hidden type of opaque types") + .emit() + } } diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index 734c31192c7c3..91cb52f5817a9 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -20,7 +20,9 @@ impl<'tcx> TyCtxt<'tcx> { let substs = InternalSubsts::identity_for_item(self, def_id); let instance = ty::Instance::new(def_id, substs); let cid = GlobalId { instance, promoted: None }; - let param_env = self.param_env(def_id).with_reveal_all_normalized(self); + // This function isn't used in the type system, so we're free to use + // `param_env_reveal_all_normalized` here. + let param_env = self.param_env_reveal_all_normalized(def_id); self.const_eval_global_id(param_env, cid, None) } /// Resolves and evaluates a constant. @@ -188,8 +190,9 @@ impl<'tcx> TyCtxtEnsure<'tcx> { let substs = InternalSubsts::identity_for_item(self.tcx, def_id); let instance = ty::Instance::new(def_id, substs); let cid = GlobalId { instance, promoted: None }; - let param_env = - self.tcx.param_env(def_id).with_reveal_all_normalized(self.tcx).with_const(); + // This function isn't used in the type system, so we're free to use + // `param_env_reveal_all_normalized` here. + let param_env = self.tcx.param_env_reveal_all_normalized(def_id).with_const(); // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should // improve caching of queries. let inputs = self.tcx.erase_regions(param_env.and(cid)); diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index ac5fddb7ad1eb..a9e0a28013eed 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -84,7 +84,7 @@ impl<'tcx> ConstValue<'tcx> { param_env: ParamEnv<'tcx>, ty: Ty<'tcx>, ) -> Option { - let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size; + let size = tcx.layout_of(param_env.and(ty)).ok()?.size; self.try_to_bits(size) } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 78a1678881583..a8974b90de87f 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2175,17 +2175,13 @@ impl<'tcx> ConstantKind<'tcx> { Self::Ty(ct) => ct.try_eval_bits(tcx, param_env, ty), Self::Val(val, t) => { assert_eq!(*t, ty); - let size = - tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size; + let size = tcx.layout_of(param_env.and(ty)).ok()?.size; val.try_to_bits(size) } Self::Unevaluated(uneval, ty) => { match tcx.const_eval_resolve(param_env, *uneval, None) { Ok(val) => { - let size = tcx - .layout_of(param_env.with_reveal_all_normalized(tcx).and(*ty)) - .ok()? - .size; + let size = tcx.layout_of(param_env.and(*ty)).ok()?.size; val.try_to_bits(size) } Err(_) => None, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index cf5b365b27c99..8fb5fb067eda2 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1246,8 +1246,6 @@ rustc_queries! { } /// Like `param_env`, but returns the `ParamEnv` in `Reveal::All` mode. - /// Prefer this over `tcx.param_env(def_id).with_reveal_all_normalized(tcx)`, - /// as this method is more efficient. query param_env_reveal_all_normalized(def_id: DefId) -> ty::ParamEnv<'tcx> { desc { |tcx| "computing revealed normalized predicates of `{}`", tcx.def_path_str(def_id) } } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 68a7af0b8c8d7..73e00c355b077 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -71,13 +71,17 @@ pub enum Reveal { /// Also, `impl Trait` is normalized to the concrete type, /// which has to be already collected by type-checking. /// - /// NOTE: as `impl Trait`'s concrete type should *never* - /// be observable directly by the user, `Reveal::All` - /// should not be used by checks which may expose - /// type equality or type contents to the user. - /// There are some exceptions, e.g., around auto traits and - /// transmute-checking, which expose some details, but - /// not the whole concrete type of the `impl Trait`. + /// **This should not be used at any point before borrowck** + /// + /// The concrete type of an opaque type should *never* + /// be observable directly by the user and doing so can cause + /// cycles if done before borrowck. Therefore, `Reveal::All` + /// should not be used by checks which may expose type equality + /// or type contents to the user. + /// + /// There are some places where we do observe some details about + /// the concrete type of opaque types, e.g., around auto traits and + /// transmute-checking, but these shouldn't rely on `Reveal::All`. All, } diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 315e3794f15e9..ff3d199355c90 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -206,7 +206,7 @@ impl<'tcx> Const<'tcx> { ty: Ty<'tcx>, ) -> Option { assert_eq!(self.ty(), ty); - let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size; + let size = tcx.layout_of(param_env.and(ty)).ok()?.size; // if `ty` does not depend on generic parameters, use an empty param_env self.kind().eval(tcx, param_env).try_to_bits(size) } diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index c444ec23563ce..42edbac1fc981 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -179,16 +179,7 @@ impl<'tcx> ConstKind<'tcx> { if let ConstKind::Unevaluated(unevaluated) = self { use crate::mir::interpret::ErrorHandled; - // HACK(eddyb) this erases lifetimes even though `const_eval_resolve` - // also does later, but we want to do it before checking for - // inference variables. - // Note that we erase regions *before* calling `with_reveal_all_normalized`, - // so that we don't try to invoke this query with - // any region variables. - let param_env_and = tcx - .erase_regions(param_env) - .with_reveal_all_normalized(tcx) - .and(tcx.erase_regions(unevaluated)); + let param_env_and = tcx.erase_regions(param_env).and(tcx.erase_regions(unevaluated)); // HACK(eddyb) when the query key would contain inference variables, // attempt using identity substs and `ParamEnv` instead, that will succeed diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 4fb4c9b11e7ea..df98d1021171f 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -246,6 +246,8 @@ impl<'tcx> SizeSkeleton<'tcx> { ) -> Result, LayoutError<'tcx>> { debug_assert!(!ty.has_infer_types_or_consts()); + let (param_env, ty) = tcx.reveal_opaque_types_in_value(param_env, ty); + // First try computing a static layout. let err = match tcx.layout_of(param_env.and(ty)) { Ok(layout) => { @@ -337,7 +339,7 @@ impl<'tcx> SizeSkeleton<'tcx> { } } - ty::Projection(_) | ty::Opaque(..) => { + ty::Projection(_) => { let normalized = tcx.normalize_erasing_regions(param_env, ty); if ty == normalized { Err(err) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 753d7bffe84c2..a520a2c034c00 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1622,27 +1622,6 @@ impl<'tcx> ParamEnv<'tcx> { *self = self.with_constness(constness.and(self.constness())) } - /// Returns a new parameter environment with the same clauses, but - /// which "reveals" the true results of projections in all cases - /// (even for associated types that are specializable). This is - /// the desired behavior during codegen and certain other special - /// contexts; normally though we want to use `Reveal::UserFacing`, - /// which is the default. - /// All opaque types in the caller_bounds of the `ParamEnv` - /// will be normalized to their underlying types. - /// See PR #65989 and issue #65918 for more details - pub fn with_reveal_all_normalized(self, tcx: TyCtxt<'tcx>) -> Self { - if self.packed.tag().reveal == traits::Reveal::All { - return self; - } - - ParamEnv::new( - tcx.normalize_opaque_types(self.caller_bounds()), - Reveal::All, - self.constness(), - ) - } - /// Returns this same environment but with no caller bounds. #[inline] pub fn without_caller_bounds(self) -> Self { diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 713f9067a85e2..9716e5d7786c0 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1,6 +1,7 @@ //! Miscellaneous type-system utilities that are too small to deserve their own modules. use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use crate::mir; use crate::ty::layout::IntegerExt; use crate::ty::query::TyCtxtAt; use crate::ty::{ @@ -12,6 +13,7 @@ use rustc_apfloat::Float as _; use rustc_ast as ast; use rustc_attr::{self as attr, SignedInt, UnsignedInt}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::sso::SsoHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; @@ -647,6 +649,79 @@ impl<'tcx> TyCtxt<'tcx> { if visitor.found_recursion { Err(expanded_type) } else { Ok(expanded_type) } } + /// Only reveals the opaque types in `value` while keeping other opaque types + /// in the `param_env` opaque. + /// + /// This is used to allow the use of opaque types in const evaluation and layout + /// computation without causing cycles by revealing unrelated opaque types in + /// the environment. + pub fn reveal_opaque_types_in_value>( + self, + param_env: ty::ParamEnv<'tcx>, + value: T, + ) -> (ty::ParamEnv<'tcx>, T) { + if !value.has_opaque_types() { + return (param_env, value); + } + + struct GatherAndReveal<'tcx> { + tcx: TyCtxt<'tcx>, + should_gather: bool, + to_reveal: SmallVec<[DefId; 1]>, + cache: SsoHashMap, Ty<'tcx>>, + } + impl<'tcx> TypeFolder<'tcx> for GatherAndReveal<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + if t.has_opaque_types() { + if let Some(&value) = self.cache.get(&t) { + return value; + } + + let result = match t.kind() { + &ty::Opaque(def_id, substs) if self.should_gather => { + if !self.to_reveal.contains(&def_id) { + self.to_reveal.push(def_id); + } + self.tcx.bound_type_of(def_id).subst(self.tcx, substs.fold_with(self)) + } + &ty::Opaque(def_id, substs) if self.to_reveal.contains(&def_id) => { + self.tcx.bound_type_of(def_id).subst(self.tcx, substs.fold_with(self)) + } + _ => t.super_fold_with(self), + }; + self.cache.insert(t, result); + result + } else { + t + } + } + + fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + if p.has_opaque_types() { p.super_fold_with(self) } else { p } + } + + fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> { + c.super_fold_with(self) + } + } + + let mut folder = GatherAndReveal { + tcx: self, + should_gather: true, + to_reveal: Default::default(), + cache: Default::default(), + }; + + let value = value.fold_with(&mut folder); + folder.should_gather = false; + let param_env = param_env.fold_with(&mut folder); + (param_env, value) + } + pub fn bound_type_of(self, def_id: DefId) -> ty::EarlyBinder> { ty::EarlyBinder(self.type_of(def_id)) } diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 895af80bd7f33..364db51ff10a8 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -480,11 +480,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { _ => return pat_from_kind(self.lower_variant_or_leaf(res, id, span, ty, vec![])), }; - // Use `Reveal::All` here because patterns are always monomorphic even if their function - // isn't. - let param_env_reveal_all = self.param_env.with_reveal_all_normalized(self.tcx); let substs = self.typeck_results.node_substs(id); - let instance = match ty::Instance::resolve(self.tcx, param_env_reveal_all, def_id, substs) { + let instance = match ty::Instance::resolve(self.tcx, self.param_env, def_id, substs) { Ok(Some(i)) => i, Ok(None) => { // It should be assoc consts if there's no error but we cannot resolve it. @@ -507,7 +504,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let mir_structural_match_violation = self.tcx.mir_const_qualif(instance.def_id()).custom_eq; debug!("mir_structural_match_violation({:?}) -> {}", qpath, mir_structural_match_violation); - match self.tcx.const_eval_instance(param_env_reveal_all, instance, Some(span)) { + match self.tcx.const_eval_instance(self.param_env, instance, Some(span)) { Ok(literal) => { let const_ = mir::ConstantKind::Val(literal, ty); let pattern = self.const_to_pat(const_, id, span, mir_structural_match_violation); diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index 702ca2eaf5c4d..a636187e8c014 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -3,7 +3,6 @@ use rustc_hir::lang_items::LangItem; use rustc_index::vec::Idx; use rustc_middle::mir::patch::MirPatch; use rustc_middle::mir::*; -use rustc_middle::traits::Reveal; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -273,7 +272,6 @@ where let subpath = self.elaborator.field_subpath(variant_path, field); let tcx = self.tcx(); - assert_eq!(self.elaborator.param_env().reveal(), Reveal::All); let field_ty = tcx.normalize_erasing_regions(self.elaborator.param_env(), f.ty(tcx, substs)); (tcx.mk_place_field(base_place, field, field_ty), subpath) diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index 65f4956d23acd..4ddce50ef6d82 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -25,7 +25,7 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops { debug!("elaborate_drops({:?} @ {:?})", body.source, body.span); let def_id = body.source.def_id(); - let param_env = tcx.param_env_reveal_all_normalized(def_id); + let param_env = tcx.param_env(def_id); let (side_table, move_data) = match MoveData::gather_moves(body, tcx, param_env) { Ok(move_data) => move_data, Err((move_data, _)) => { diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index 46c4a702fde95..a37b8b64d5e9a 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -25,7 +25,7 @@ pub fn test_layout(tcx: TyCtxt<'_>) { fn dump_layout_of<'tcx>(tcx: TyCtxt<'tcx>, item_def_id: LocalDefId, attr: &Attribute) { let tcx = tcx; - let param_env = tcx.param_env(item_def_id); + let param_env = tcx.param_env_reveal_all_normalized(item_def_id); let ty = tcx.type_of(item_def_id); match tcx.layout_of(param_env.and(ty)) { Ok(ty_layout) => { @@ -66,10 +66,7 @@ fn dump_layout_of<'tcx>(tcx: TyCtxt<'tcx>, item_def_id: LocalDefId, attr: &Attri } sym::debug => { - let normalized_ty = tcx.normalize_erasing_regions( - param_env.with_reveal_all_normalized(tcx), - ty, - ); + let normalized_ty = tcx.normalize_erasing_regions(param_env, ty); tcx.sess.span_err( tcx.def_span(item_def_id.to_def_id()), &format!("layout_of({:?}) = {:#?}", normalized_ty, *ty_layout), diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 3f98db6b2a924..c53c0ba17d5dd 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -186,10 +186,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>( let concrete = infcx.const_eval_resolve(param_env, uv, Some(span)); match concrete { Err(ErrorHandled::TooGeneric) => { - Err(NotConstEvaluatable::Error(infcx.tcx.sess.delay_span_bug( - span, - format!("Missing value for constant, but no error reported?"), - ))) + Err(NotConstEvaluatable::Error(infcx.concrete_ctfe_failure_error(span))) } Err(ErrorHandled::Linted) => { let reported = infcx @@ -241,8 +238,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>( } else if uv.has_param_types_or_consts() { NotConstEvaluatable::MentionsParam } else { - let guar = infcx.tcx.sess.delay_span_bug(span, format!("Missing value for constant, but no error reported?")); - NotConstEvaluatable::Error(guar) + NotConstEvaluatable::Error(infcx.concrete_ctfe_failure_error(span)) }; Err(err) diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index fa1dc90e4a24b..eb27a4d09dfa5 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -136,7 +136,6 @@ fn resolve_associated_item<'tcx>( }); let substs = tcx.infer_ctxt().enter(|infcx| { - let param_env = param_env.with_reveal_all_normalized(tcx); let substs = rcvr_substs.rebase_onto(tcx, trait_def_id, impl_data.substs); let substs = translate_substs( &infcx, @@ -173,7 +172,11 @@ fn resolve_associated_item<'tcx>( // If the item does not have a value, then we cannot return an instance. if !leaf_def.item.defaultness(tcx).has_value() { - return Ok(None); + let guard = tcx.sess.delay_span_bug( + tcx.def_span(leaf_def.item.def_id), + "missing value for assoc item in impl", + ); + return Err(guard); } let substs = tcx.erase_regions(substs); diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 9e4dc26bfd4d2..3157cbebb77b8 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -35,7 +35,6 @@ fn layout_of<'tcx>( let (param_env, ty) = query.into_parts(); debug!(?ty); - let param_env = param_env.with_reveal_all_normalized(tcx); let unnormalized_ty = ty; // FIXME: We might want to have two different versions of `layout_of`: @@ -49,6 +48,8 @@ fn layout_of<'tcx>( } }; + let (param_env, ty) = tcx.reveal_opaque_types_in_value(param_env, ty); + if ty != unnormalized_ty { // Ensure this layout is also cached for the normalized type. return tcx.layout_of(param_env.and(ty)); @@ -1335,13 +1336,13 @@ fn layout_of_uncached<'tcx>( } // Types with no meaningful known layout. - ty::Projection(_) | ty::Opaque(..) => { + ty::Projection(_) => { // NOTE(eddyb) `layout_of` query should've normalized these away, // if that was possible, so there's no reason to try again here. return Err(LayoutError::Unknown(ty)); } - ty::Placeholder(..) | ty::GeneratorWitness(..) | ty::Infer(_) => { + ty::Placeholder(..) | ty::GeneratorWitness(..) | ty::Infer(_) | ty::Opaque(..) => { bug!("Layout::compute: unexpected type `{}`", ty) } diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index f7db39dfec3b8..96c60f49f2f06 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -334,7 +334,12 @@ fn well_formed_types_in_env<'tcx>( } fn param_env_reveal_all_normalized(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { - tcx.param_env(def_id).with_reveal_all_normalized(tcx) + let param_env = tcx.param_env(def_id); + ty::ParamEnv::new( + tcx.normalize_opaque_types(param_env.caller_bounds()), + traits::Reveal::All, + param_env.constness(), + ) } fn instance_def_size_estimate<'tcx>( diff --git a/src/test/mir-opt/inline/inline_generator.main.Inline.diff b/src/test/mir-opt/inline/inline_generator.main.Inline.diff index 3fd8aad723880..08668887bbeba 100644 --- a/src/test/mir-opt/inline/inline_generator.main.Inline.diff +++ b/src/test/mir-opt/inline/inline_generator.main.Inline.diff @@ -50,7 +50,7 @@ + Deinit(_4); // scope 2 at $DIR/inline-generator.rs:15:5: 15:41 + discriminant(_4) = 0; // scope 2 at $DIR/inline-generator.rs:15:5: 15:41 _3 = &mut _4; // scope 0 at $DIR/inline-generator.rs:+1:23: +1:31 -- _2 = Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:8]>::new(move _3) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-generator.rs:+1:14: +1:32 +- _2 = Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:8]>::new(move _3) -> [return: bb2, unwind: bb7]; // scope 0 at $DIR/inline-generator.rs:+1:14: +1:32 - // mir::Constant - // + span: $DIR/inline-generator.rs:9:14: 9:22 - // + user_ty: UserType(0) @@ -67,7 +67,7 @@ + StorageDead(_6); // scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL + StorageDead(_5); // scope 4 at $SRC_DIR/core/src/pin.rs:LL:COL StorageDead(_3); // scope 0 at $DIR/inline-generator.rs:+1:31: +1:32 -- _1 = <[generator@$DIR/inline-generator.rs:15:5: 15:8] as Generator>::resume(move _2, const false) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/inline-generator.rs:+1:14: +1:46 +- _1 = <[generator@$DIR/inline-generator.rs:15:5: 15:8] as Generator>::resume(move _2, const false) -> [return: bb3, unwind: bb7]; // scope 0 at $DIR/inline-generator.rs:+1:14: +1:46 - // mir::Constant - // + span: $DIR/inline-generator.rs:9:33: 9:39 - // + literal: Const { ty: for<'a> fn(Pin<&'a mut [generator@$DIR/inline-generator.rs:15:5: 15:8]>, bool) -> GeneratorState<<[generator@$DIR/inline-generator.rs:15:5: 15:8] as Generator>::Yield, <[generator@$DIR/inline-generator.rs:15:5: 15:8] as Generator>::Return> {<[generator@$DIR/inline-generator.rs:15:5: 15:8] as Generator>::resume}, val: Value() } @@ -77,7 +77,7 @@ + StorageLive(_11); // scope 0 at $DIR/inline-generator.rs:+1:14: +1:46 + _13 = deref_copy (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline-generator.rs:15:5: 15:41 + _12 = discriminant((*_13)); // scope 6 at $DIR/inline-generator.rs:15:5: 15:41 -+ switchInt(move _12) -> [0_u32: bb3, 1_u32: bb8, 3_u32: bb7, otherwise: bb9]; // scope 6 at $DIR/inline-generator.rs:15:5: 15:41 ++ switchInt(move _12) -> [0_u32: bb7, 1_u32: bb12, 3_u32: bb11, otherwise: bb13]; // scope 6 at $DIR/inline-generator.rs:15:5: 15:41 } - bb3: { @@ -86,36 +86,60 @@ + StorageDead(_10); // scope 0 at $DIR/inline-generator.rs:+1:14: +1:46 + StorageDead(_7); // scope 0 at $DIR/inline-generator.rs:+1:14: +1:46 StorageDead(_2); // scope 0 at $DIR/inline-generator.rs:+1:45: +1:46 +- drop(_4) -> [return: bb4, unwind: bb6]; // scope 0 at $DIR/inline-generator.rs:+1:46: +1:47 ++ drop(_4) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-generator.rs:+1:46: +1:47 + } + +- bb4: { ++ bb2: { StorageDead(_4); // scope 0 at $DIR/inline-generator.rs:+1:46: +1:47 _0 = const (); // scope 0 at $DIR/inline-generator.rs:+0:11: +2:2 +- drop(_1) -> [return: bb5, unwind: bb8]; // scope 0 at $DIR/inline-generator.rs:+2:1: +2:2 ++ drop(_1) -> [return: bb3, unwind: bb6]; // scope 0 at $DIR/inline-generator.rs:+2:1: +2:2 + } + +- bb5: { ++ bb3: { StorageDead(_1); // scope 0 at $DIR/inline-generator.rs:+2:1: +2:2 return; // scope 0 at $DIR/inline-generator.rs:+2:2: +2:2 } -- bb4 (cleanup): { -+ bb2 (cleanup): { +- bb6 (cleanup): { +- drop(_1) -> bb8; // scope 0 at $DIR/inline-generator.rs:+2:1: +2:2 ++ bb4 (cleanup): { ++ drop(_1) -> bb6; // scope 0 at $DIR/inline-generator.rs:+2:1: +2:2 + } + +- bb7 (cleanup): { +- drop(_4) -> bb8; // scope 0 at $DIR/inline-generator.rs:+1:46: +1:47 ++ bb5 (cleanup): { ++ drop(_4) -> bb6; // scope 0 at $DIR/inline-generator.rs:+1:46: +1:47 + } + +- bb8 (cleanup): { ++ bb6 (cleanup): { resume; // scope 0 at $DIR/inline-generator.rs:+0:1: +2:2 + } + -+ bb3: { ++ bb7: { + _11 = move _7; // scope 6 at $DIR/inline-generator.rs:15:5: 15:41 + StorageLive(_8); // scope 6 at $DIR/inline-generator.rs:15:17: 15:39 + StorageLive(_9); // scope 6 at $DIR/inline-generator.rs:15:20: 15:21 + _9 = _11; // scope 6 at $DIR/inline-generator.rs:15:20: 15:21 -+ switchInt(move _9) -> [false: bb5, otherwise: bb4]; // scope 6 at $DIR/inline-generator.rs:15:20: 15:21 ++ switchInt(move _9) -> [false: bb9, otherwise: bb8]; // scope 6 at $DIR/inline-generator.rs:15:20: 15:21 + } + -+ bb4: { ++ bb8: { + _8 = const 7_i32; // scope 6 at $DIR/inline-generator.rs:15:24: 15:25 -+ goto -> bb6; // scope 6 at $DIR/inline-generator.rs:15:17: 15:39 ++ goto -> bb10; // scope 6 at $DIR/inline-generator.rs:15:17: 15:39 + } + -+ bb5: { ++ bb9: { + _8 = const 13_i32; // scope 6 at $DIR/inline-generator.rs:15:35: 15:37 -+ goto -> bb6; // scope 6 at $DIR/inline-generator.rs:15:17: 15:39 ++ goto -> bb10; // scope 6 at $DIR/inline-generator.rs:15:17: 15:39 + } + -+ bb6: { ++ bb10: { + StorageDead(_9); // scope 6 at $DIR/inline-generator.rs:15:38: 15:39 + Deinit(_1); // scope 6 at $DIR/inline-generator.rs:15:11: 15:39 + ((_1 as Yielded).0: i32) = move _8; // scope 6 at $DIR/inline-generator.rs:15:11: 15:39 @@ -125,7 +149,7 @@ + goto -> bb1; // scope 0 at $DIR/inline-generator.rs:15:11: 15:39 + } + -+ bb7: { ++ bb11: { + StorageLive(_8); // scope 6 at $DIR/inline-generator.rs:15:5: 15:41 + _10 = move _7; // scope 6 at $DIR/inline-generator.rs:15:5: 15:41 + StorageDead(_8); // scope 6 at $DIR/inline-generator.rs:15:38: 15:39 @@ -137,11 +161,11 @@ + goto -> bb1; // scope 0 at $DIR/inline-generator.rs:15:41: 15:41 + } + -+ bb8: { -+ assert(const false, "generator resumed after completion") -> [success: bb8, unwind: bb2]; // scope 6 at $DIR/inline-generator.rs:15:5: 15:41 ++ bb12: { ++ assert(const false, "generator resumed after completion") -> [success: bb12, unwind: bb5]; // scope 6 at $DIR/inline-generator.rs:15:5: 15:41 + } + -+ bb9: { ++ bb13: { + unreachable; // scope 6 at $DIR/inline-generator.rs:15:5: 15:41 } } diff --git a/src/test/mir-opt/inline/issue_78442.bar.Inline.diff b/src/test/mir-opt/inline/issue_78442.bar.Inline.diff index 4186650dfabe0..7714b02dbe555 100644 --- a/src/test/mir-opt/inline/issue_78442.bar.Inline.diff +++ b/src/test/mir-opt/inline/issue_78442.bar.Inline.diff @@ -15,8 +15,8 @@ StorageLive(_2); // scope 0 at $DIR/issue-78442.rs:+4:5: +4:17 StorageLive(_3); // scope 0 at $DIR/issue-78442.rs:+4:5: +4:15 StorageLive(_4); // scope 0 at $DIR/issue-78442.rs:+4:5: +4:15 -- _4 = hide_foo() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:+4:5: +4:15 -+ _4 = hide_foo() -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-78442.rs:+4:5: +4:15 +- _4 = hide_foo() -> [return: bb1, unwind: bb6]; // scope 0 at $DIR/issue-78442.rs:+4:5: +4:15 ++ _4 = hide_foo() -> [return: bb1, unwind: bb5]; // scope 0 at $DIR/issue-78442.rs:+4:5: +4:15 // mir::Constant // + span: $DIR/issue-78442.rs:11:5: 11:13 // + literal: Const { ty: fn() -> impl Fn() {hide_foo}, val: Value() } @@ -26,43 +26,52 @@ _3 = &_4; // scope 0 at $DIR/issue-78442.rs:+4:5: +4:15 StorageLive(_5); // scope 0 at $DIR/issue-78442.rs:+4:5: +4:17 Deinit(_5); // scope 0 at $DIR/issue-78442.rs:+4:5: +4:17 -- _2 = >::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:+4:5: +4:17 +- _2 = >::call(move _3, move _5) -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/issue-78442.rs:+4:5: +4:17 - // mir::Constant - // + span: $DIR/issue-78442.rs:11:5: 11:15 - // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() {foo}, ()) -> >::Output {>::call}, val: Value() } -+ _2 = move (*_3)() -> [return: bb5, unwind: bb3]; // scope 1 at $SRC_DIR/core/src/ops/function.rs:LL:COL ++ _2 = move (*_3)() -> [return: bb7, unwind: bb4]; // scope 1 at $SRC_DIR/core/src/ops/function.rs:LL:COL } bb2: { - StorageDead(_5); // scope 0 at $DIR/issue-78442.rs:+4:16: +4:17 - StorageDead(_3); // scope 0 at $DIR/issue-78442.rs:+4:16: +4:17 -- StorageDead(_4); // scope 0 at $DIR/issue-78442.rs:+4:17: +4:18 -- StorageDead(_2); // scope 0 at $DIR/issue-78442.rs:+4:17: +4:18 -- _0 = const (); // scope 0 at $DIR/issue-78442.rs:+3:3: +5:2 -- drop(_1) -> [return: bb3, unwind: bb5]; // scope 0 at $DIR/issue-78442.rs:+5:1: +5:2 -+ return; // scope 0 at $DIR/issue-78442.rs:+5:2: +5:2 +- drop(_4) -> [return: bb3, unwind: bb6]; // scope 0 at $DIR/issue-78442.rs:+4:17: +4:18 +- } +- +- bb3: { + StorageDead(_4); // scope 0 at $DIR/issue-78442.rs:+4:17: +4:18 + StorageDead(_2); // scope 0 at $DIR/issue-78442.rs:+4:17: +4:18 + _0 = const (); // scope 0 at $DIR/issue-78442.rs:+3:3: +5:2 +- drop(_1) -> [return: bb4, unwind: bb7]; // scope 0 at $DIR/issue-78442.rs:+5:1: +5:2 ++ drop(_1) -> [return: bb3, unwind: bb6]; // scope 0 at $DIR/issue-78442.rs:+5:1: +5:2 } -- bb3: { -- return; // scope 0 at $DIR/issue-78442.rs:+5:2: +5:2 -+ bb3 (cleanup): { -+ drop(_1) -> bb4; // scope 0 at $DIR/issue-78442.rs:+5:1: +5:2 +- bb4: { ++ bb3: { + return; // scope 0 at $DIR/issue-78442.rs:+5:2: +5:2 + } + ++ bb4 (cleanup): { ++ drop(_4) -> bb5; // scope 0 at $DIR/issue-78442.rs:+4:17: +4:18 ++ } ++ + bb5 (cleanup): { +- drop(_4) -> bb6; // scope 0 at $DIR/issue-78442.rs:+4:17: +4:18 ++ drop(_1) -> bb6; // scope 0 at $DIR/issue-78442.rs:+5:1: +5:2 } - bb4 (cleanup): { -- drop(_1) -> bb5; // scope 0 at $DIR/issue-78442.rs:+5:1: +5:2 + bb6 (cleanup): { +- drop(_1) -> bb7; // scope 0 at $DIR/issue-78442.rs:+5:1: +5:2 + resume; // scope 0 at $DIR/issue-78442.rs:+0:1: +5:2 } -- bb5 (cleanup): { +- bb7 (cleanup): { - resume; // scope 0 at $DIR/issue-78442.rs:+0:1: +5:2 -+ bb5: { ++ bb7: { + StorageDead(_5); // scope 0 at $DIR/issue-78442.rs:+4:16: +4:17 + StorageDead(_3); // scope 0 at $DIR/issue-78442.rs:+4:16: +4:17 -+ StorageDead(_4); // scope 0 at $DIR/issue-78442.rs:+4:17: +4:18 -+ StorageDead(_2); // scope 0 at $DIR/issue-78442.rs:+4:17: +4:18 -+ _0 = const (); // scope 0 at $DIR/issue-78442.rs:+3:3: +5:2 -+ drop(_1) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:+5:1: +5:2 ++ drop(_4) -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/issue-78442.rs:+4:17: +4:18 } } diff --git a/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff b/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff index 24e9a3df15acd..04704118e29b1 100644 --- a/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff +++ b/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff @@ -15,7 +15,7 @@ StorageLive(_2); // scope 0 at $DIR/issue-78442.rs:+4:5: +4:17 StorageLive(_3); // scope 0 at $DIR/issue-78442.rs:+4:5: +4:15 StorageLive(_4); // scope 0 at $DIR/issue-78442.rs:+4:5: +4:15 - _4 = hide_foo() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:+4:5: +4:15 + _4 = hide_foo() -> [return: bb1, unwind: bb6]; // scope 0 at $DIR/issue-78442.rs:+4:5: +4:15 // mir::Constant // + span: $DIR/issue-78442.rs:11:5: 11:13 // + literal: Const { ty: fn() -> impl Fn() {hide_foo}, val: Value() } @@ -25,8 +25,8 @@ _3 = &_4; // scope 0 at $DIR/issue-78442.rs:+4:5: +4:15 StorageLive(_5); // scope 0 at $DIR/issue-78442.rs:+4:5: +4:17 Deinit(_5); // scope 0 at $DIR/issue-78442.rs:+4:5: +4:17 -- _2 = >::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:+4:5: +4:17 -+ _2 = >::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:+4:5: +4:17 +- _2 = >::call(move _3, move _5) -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/issue-78442.rs:+4:5: +4:17 ++ _2 = >::call(move _3, move _5) -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/issue-78442.rs:+4:5: +4:17 // mir::Constant // + span: $DIR/issue-78442.rs:11:5: 11:15 - // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a impl Fn(), ()) -> >::Output {>::call}, val: Value() } @@ -36,21 +36,29 @@ bb2: { StorageDead(_5); // scope 0 at $DIR/issue-78442.rs:+4:16: +4:17 StorageDead(_3); // scope 0 at $DIR/issue-78442.rs:+4:16: +4:17 + drop(_4) -> [return: bb3, unwind: bb6]; // scope 0 at $DIR/issue-78442.rs:+4:17: +4:18 + } + + bb3: { StorageDead(_4); // scope 0 at $DIR/issue-78442.rs:+4:17: +4:18 StorageDead(_2); // scope 0 at $DIR/issue-78442.rs:+4:17: +4:18 _0 = const (); // scope 0 at $DIR/issue-78442.rs:+3:3: +5:2 - drop(_1) -> [return: bb3, unwind: bb5]; // scope 0 at $DIR/issue-78442.rs:+5:1: +5:2 + drop(_1) -> [return: bb4, unwind: bb7]; // scope 0 at $DIR/issue-78442.rs:+5:1: +5:2 } - bb3: { + bb4: { return; // scope 0 at $DIR/issue-78442.rs:+5:2: +5:2 } - bb4 (cleanup): { - drop(_1) -> bb5; // scope 0 at $DIR/issue-78442.rs:+5:1: +5:2 + bb5 (cleanup): { + drop(_4) -> bb6; // scope 0 at $DIR/issue-78442.rs:+4:17: +4:18 } - bb5 (cleanup): { + bb6 (cleanup): { + drop(_1) -> bb7; // scope 0 at $DIR/issue-78442.rs:+5:1: +5:2 + } + + bb7 (cleanup): { resume; // scope 0 at $DIR/issue-78442.rs:+0:1: +5:2 } } diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-76595.rs b/src/test/ui/const-generics/generic_const_exprs/issue-76595.rs index faa8b3d10de4f..a30740466d3aa 100644 --- a/src/test/ui/const-generics/generic_const_exprs/issue-76595.rs +++ b/src/test/ui/const-generics/generic_const_exprs/issue-76595.rs @@ -14,4 +14,5 @@ fn test() where Bool<{core::mem::size_of::() > 4}>: True { fn main() { test::<2>(); //~^ ERROR this function takes 2 generic arguments + //~| ERROR unable to use constant with a hidden value in the type system } diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-76595.stderr b/src/test/ui/const-generics/generic_const_exprs/issue-76595.stderr index c587a7e153fe3..35269a2445a32 100644 --- a/src/test/ui/const-generics/generic_const_exprs/issue-76595.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/issue-76595.stderr @@ -16,6 +16,15 @@ help: add missing generic argument LL | test::<2, P>(); | +++ -error: aborting due to previous error +error: unable to use constant with a hidden value in the type system + --> $DIR/issue-76595.rs:15:5 + | +LL | test::<2>(); + | ^^^^^^^^^ + | + = note: this most often happens when trying to look into an opaque type + = note: the type system cannot access the hidden type of opaque types + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0107`. diff --git a/src/test/ui/const-generics/issues/issue-83765.stderr b/src/test/ui/const-generics/issues/issue-83765.stderr index 4becf3a364cf1..efaad74fca125 100644 --- a/src/test/ui/const-generics/issues/issue-83765.stderr +++ b/src/test/ui/const-generics/issues/issue-83765.stderr @@ -10,11 +10,11 @@ note: ...which requires computing candidate for ` as TensorDimension>::DIM`, completing the cycle -note: cycle used when computing candidate for ` as TensorDimension>` - --> $DIR/issue-83765.rs:4:1 +note: cycle used when const-evaluating + checking `TensorSize::size::{constant#0}` + --> $DIR/issue-83765.rs:16:31 | -LL | trait TensorDimension { - | ^^^^^^^^^^^^^^^^^^^^^ +LL | fn size(&self) -> [usize; Self::DIM]; + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-86530.rs b/src/test/ui/const-generics/issues/issue-86530.rs index b024decd4e11c..50d49dfe21e85 100644 --- a/src/test/ui/const-generics/issues/issue-86530.rs +++ b/src/test/ui/const-generics/issues/issue-86530.rs @@ -15,6 +15,7 @@ where fn unit_literals() { z(" "); //~^ ERROR: the trait bound `&str: X` is not satisfied + //~| ERROR: unable to use constant with a hidden value in the type system } fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-86530.stderr b/src/test/ui/const-generics/issues/issue-86530.stderr index c63857b2314e9..be6e664facd23 100644 --- a/src/test/ui/const-generics/issues/issue-86530.stderr +++ b/src/test/ui/const-generics/issues/issue-86530.stderr @@ -1,3 +1,12 @@ +error: unable to use constant with a hidden value in the type system + --> $DIR/issue-86530.rs:16:5 + | +LL | z(" "); + | ^ + | + = note: this most often happens when trying to look into an opaque type + = note: the type system cannot access the hidden type of opaque types + error[E0277]: the trait bound `&str: X` is not satisfied --> $DIR/issue-86530.rs:16:7 | @@ -15,6 +24,6 @@ LL | where LL | T: X, | ^ required by this bound in `z` -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/consts/const-size_of-cycle.stderr b/src/test/ui/consts/const-size_of-cycle.stderr index 46f02ce8a4533..c34f472490245 100644 --- a/src/test/ui/consts/const-size_of-cycle.stderr +++ b/src/test/ui/consts/const-size_of-cycle.stderr @@ -7,11 +7,6 @@ LL | bytes: [u8; std::mem::size_of::()] note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`... --> $DIR/const-size_of-cycle.rs:4:17 | -LL | bytes: [u8; std::mem::size_of::()] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`... - --> $DIR/const-size_of-cycle.rs:4:17 - | LL | bytes: [u8; std::mem::size_of::()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires computing layout of `Foo`... diff --git a/src/test/ui/consts/issue-44415.stderr b/src/test/ui/consts/issue-44415.stderr index 57f94f8c6ab52..2ee2741042507 100644 --- a/src/test/ui/consts/issue-44415.stderr +++ b/src/test/ui/consts/issue-44415.stderr @@ -7,11 +7,6 @@ LL | bytes: [u8; unsafe { intrinsics::size_of::() }], note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`... --> $DIR/issue-44415.rs:6:17 | -LL | bytes: [u8; unsafe { intrinsics::size_of::() }], - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`... - --> $DIR/issue-44415.rs:6:17 - | LL | bytes: [u8; unsafe { intrinsics::size_of::() }], | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires computing layout of `Foo`... diff --git a/src/test/ui/impl-trait/in-ctfe/array-len-size-of.rs b/src/test/ui/impl-trait/in-ctfe/array-len-size-of.rs new file mode 100644 index 0000000000000..50090ee5c9d31 --- /dev/null +++ b/src/test/ui/impl-trait/in-ctfe/array-len-size-of.rs @@ -0,0 +1,27 @@ +// This pattern is used in https://github.com/GoldsteinE/name-it and requires us +// to reveal opaque types during ctfe, even with `Reveal::UserFacing`. +// +// check-pass +use std::mem; +fn returns_opaque() -> impl Sized { + 0u8 +} + +struct Wrapper(T); +fn returns_wrapped() -> impl Sized { + Wrapper(returns_opaque()) +} + +struct NamedOpaqueType { + data: [mem::MaybeUninit; size_of_fut(returns_opaque)] +} + +struct NamedOpaqueTypeWrapper { + data: [mem::MaybeUninit; size_of_fut(returns_wrapped)] +} + +const fn size_of_fut(x: fn() -> FUT) -> usize { + mem::size_of::() +} + +fn main() {} diff --git a/src/test/ui/impl-trait/in-ctfe/array-len.rs b/src/test/ui/impl-trait/in-ctfe/array-len.rs new file mode 100644 index 0000000000000..aebc8e603cd06 --- /dev/null +++ b/src/test/ui/impl-trait/in-ctfe/array-len.rs @@ -0,0 +1,32 @@ +// For this to compile we have to reveal opaque types during ctfe without relying +// on `Reveal::All` as that would cause cycles. +// +// check-pass +#![feature(type_alias_impl_trait)] +#![crate_type = "lib"] +trait MyTrait: Copy { + const ASSOC: usize; +} + +impl MyTrait for u8 { + const ASSOC: usize = 32; +} + +const fn yeet() -> impl MyTrait { + 0u8 +} + +const fn output(_: T) -> usize { + ::ASSOC +} + +type Cycle = impl Sized; +fn define() -> Cycle {} + +fn with_opaque_in_env() +where + Cycle: Sized, +{ + let x = [0u8; output(yeet())]; + println!("{:?}", x); +} diff --git a/src/test/ui/impl-trait/in-ctfe/as-field.rs b/src/test/ui/impl-trait/in-ctfe/as-field.rs new file mode 100644 index 0000000000000..6d254dbf4175f --- /dev/null +++ b/src/test/ui/impl-trait/in-ctfe/as-field.rs @@ -0,0 +1,46 @@ +// For this to compile we have to reveal opaque types during ctfe without relying +// on `Reveal::All` as that would cause cycles. +// +// check-pass +#![feature(type_alias_impl_trait)] +#![crate_type = "lib"] + +mod scope { + pub type Opaque = impl Copy; + + pub const fn from_usize(x: usize) -> Opaque { + x + } + + pub const fn to_usize(x: Opaque) -> usize { + x + } +} + +#[derive(Copy, Clone)] +struct Foo { + field: scope::Opaque, +} + +impl Foo { + const fn new(field: usize) -> Self { + Foo { + field: scope::from_usize(field), + } + } + + const fn value(self) -> usize { + scope::to_usize(self.field) + } +} + +type Cycle = impl Sized; +fn define() -> Cycle {} + +fn with_opaque_in_env() +where + Cycle: Sized, +{ + let x = [0u8; Foo::new(3).value()]; + println!("{:?}", x); +} diff --git a/src/test/ui/impl-trait/in-ctfe/enum-discr.rs b/src/test/ui/impl-trait/in-ctfe/enum-discr.rs new file mode 100644 index 0000000000000..fee291f38dfe7 --- /dev/null +++ b/src/test/ui/impl-trait/in-ctfe/enum-discr.rs @@ -0,0 +1,35 @@ +// For this to compile we have to reveal opaque types during ctfe without relying +// on `Reveal::All` as that would cause cycles. +// +// check-pass +#![feature(type_alias_impl_trait)] +trait MyTrait: Copy { + const ASSOC: usize; +} + +impl MyTrait for u8 { + const ASSOC: usize = 32; +} + +const fn yeet() -> impl MyTrait { + 0u8 +} + +const fn output(_: T) -> usize { + ::ASSOC +} + +type Cycle = impl Sized; +fn define() -> Cycle {} + +#[repr(usize)] +enum Foo +where + Cycle: Sized, +{ + Bar = output(yeet()), +} + +fn main() { + println!("{}", Foo::Bar as usize); +} diff --git a/src/test/ui/impl-trait/in-ctfe/match-arm-exhaustive.rs b/src/test/ui/impl-trait/in-ctfe/match-arm-exhaustive.rs new file mode 100644 index 0000000000000..9728bbeed5495 --- /dev/null +++ b/src/test/ui/impl-trait/in-ctfe/match-arm-exhaustive.rs @@ -0,0 +1,25 @@ +// Checks that opaque types can be used during ctfe. +// +// check-pass +trait MyTrait: Copy { + const ASSOC: u8; +} + +impl MyTrait for () { + const ASSOC: u8 = 0; +} + +const fn yeet() -> impl MyTrait {} + +const fn output(_: T) -> u8 { + ::ASSOC +} + +const CT: u8 = output(yeet()); + +fn main() { + match 0 { + CT => (), + 1.. => (), + } +} diff --git a/src/test/ui/impl-trait/issues/issue-78722.rs b/src/test/ui/impl-trait/issues/issue-78722.rs index 9ee1ba3d3b486..f05a80d347add 100644 --- a/src/test/ui/impl-trait/issues/issue-78722.rs +++ b/src/test/ui/impl-trait/issues/issue-78722.rs @@ -7,7 +7,6 @@ type F = impl core::future::Future; struct Bug { V1: [(); { fn concrete_use() -> F { - //~^ ERROR expected `impl Future` to be a future that resolves to `u8`, but it resolves to `()` async {} } let f: F = async { 1 }; diff --git a/src/test/ui/impl-trait/issues/issue-78722.stderr b/src/test/ui/impl-trait/issues/issue-78722.stderr index a96994f5a7fb8..ea789ca54a532 100644 --- a/src/test/ui/impl-trait/issues/issue-78722.stderr +++ b/src/test/ui/impl-trait/issues/issue-78722.stderr @@ -1,5 +1,5 @@ error[E0658]: `async` blocks are not allowed in constants - --> $DIR/issue-78722.rs:13:20 + --> $DIR/issue-78722.rs:12:20 | LL | let f: F = async { 1 }; | ^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | let f: F = async { 1 }; = help: add `#![feature(const_async_blocks)]` to the crate attributes to enable error[E0493]: destructor of `F` cannot be evaluated at compile-time - --> $DIR/issue-78722.rs:13:13 + --> $DIR/issue-78722.rs:12:13 | LL | let f: F = async { 1 }; | ^ the destructor for this type cannot be evaluated in constants @@ -16,13 +16,7 @@ LL | let f: F = async { 1 }; LL | }], | - value is dropped here -error[E0271]: expected `impl Future` to be a future that resolves to `u8`, but it resolves to `()` - --> $DIR/issue-78722.rs:9:30 - | -LL | fn concrete_use() -> F { - | ^ expected `()`, found `u8` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0271, E0493, E0658. -For more information about an error, try `rustc --explain E0271`. +Some errors have detailed explanations: E0493, E0658. +For more information about an error, try `rustc --explain E0493`. diff --git a/src/test/ui/impl-trait/transmute/in-defining-scope.rs b/src/test/ui/impl-trait/transmute/in-defining-scope.rs new file mode 100644 index 0000000000000..e6eb9014f0d06 --- /dev/null +++ b/src/test/ui/impl-trait/transmute/in-defining-scope.rs @@ -0,0 +1,12 @@ +// This causes query cycles when trying to reveal the hidden type of `foo`. +use std::mem::transmute; +fn foo() -> impl Sized { + //~^ ERROR cycle detected when computing type + unsafe { + transmute::<_, u8>(foo()); + //~^ ERROR cannot transmute between types of different sizes, or dependently-sized types + } + 0u8 +} + +fn main() {} diff --git a/src/test/ui/impl-trait/transmute/in-defining-scope.stderr b/src/test/ui/impl-trait/transmute/in-defining-scope.stderr new file mode 100644 index 0000000000000..8244334e419d2 --- /dev/null +++ b/src/test/ui/impl-trait/transmute/in-defining-scope.stderr @@ -0,0 +1,67 @@ +error[E0391]: cycle detected when computing type of `foo::{opaque#0}` + --> $DIR/in-defining-scope.rs:3:13 + | +LL | fn foo() -> impl Sized { + | ^^^^^^^^^^ + | +note: ...which requires borrow-checking `foo`... + --> $DIR/in-defining-scope.rs:3:1 + | +LL | fn foo() -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires processing `foo`... + --> $DIR/in-defining-scope.rs:3:1 + | +LL | fn foo() -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires processing MIR for `foo`... + --> $DIR/in-defining-scope.rs:3:1 + | +LL | fn foo() -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires unsafety-checking `foo`... + --> $DIR/in-defining-scope.rs:3:1 + | +LL | fn foo() -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building MIR for `foo`... + --> $DIR/in-defining-scope.rs:3:1 + | +LL | fn foo() -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building THIR for `foo`... + --> $DIR/in-defining-scope.rs:3:1 + | +LL | fn foo() -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `foo`... + --> $DIR/in-defining-scope.rs:3:1 + | +LL | fn foo() -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which again requires computing type of `foo::{opaque#0}`, completing the cycle +note: cycle used when checking item types in top-level module + --> $DIR/in-defining-scope.rs:2:1 + | +LL | / use std::mem::transmute; +LL | | fn foo() -> impl Sized { +LL | | +LL | | unsafe { +... | +LL | | +LL | | fn main() {} + | |____________^ + +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> $DIR/in-defining-scope.rs:6:9 + | +LL | transmute::<_, u8>(foo()); + | ^^^^^^^^^^^^^^^^^^ + | + = note: source type: `impl Sized` (size can vary because of [type error]) + = note: target type: `u8` (8 bits) + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0391, E0512. +For more information about an error, try `rustc --explain E0391`. diff --git a/src/test/ui/impl-trait/transmute/outside-of-defining-scope.rs b/src/test/ui/impl-trait/transmute/outside-of-defining-scope.rs new file mode 100644 index 0000000000000..955db70335add --- /dev/null +++ b/src/test/ui/impl-trait/transmute/outside-of-defining-scope.rs @@ -0,0 +1,20 @@ +// For this to compile we have to reveal opaque types during typeck +// without using `Reveal::All` as that would cause a cycle when revealing `Cycle`. +// +// check-pass +#![feature(type_alias_impl_trait)] +#![crate_type = "lib"] +use std::mem::transmute; +fn foo() -> impl Sized { + 0u8 +} + +type Cycle = impl Sized; +fn define() -> Cycle {} + +unsafe fn with_opaque_in_env() -> u8 +where + Cycle: Sized, +{ + transmute::<_, u8>(foo()) +} diff --git a/src/test/ui/issues/issue-77919.rs b/src/test/ui/issues/issue-77919.rs index 966d76d148af3..a63b246f9a519 100644 --- a/src/test/ui/issues/issue-77919.rs +++ b/src/test/ui/issues/issue-77919.rs @@ -1,5 +1,6 @@ fn main() { [1; >::VAL]; + //~^ ERROR unable to use constant with a hidden value in the type system } trait TypeVal { const VAL: T; diff --git a/src/test/ui/issues/issue-77919.stderr b/src/test/ui/issues/issue-77919.stderr index ca256847b1f3b..9bb26f1671192 100644 --- a/src/test/ui/issues/issue-77919.stderr +++ b/src/test/ui/issues/issue-77919.stderr @@ -1,5 +1,5 @@ error[E0412]: cannot find type `PhantomData` in this scope - --> $DIR/issue-77919.rs:9:9 + --> $DIR/issue-77919.rs:10:9 | LL | _n: PhantomData, | ^^^^^^^^^^^ not found in this scope @@ -10,7 +10,7 @@ LL | use std::marker::PhantomData; | error[E0412]: cannot find type `VAL` in this scope - --> $DIR/issue-77919.rs:11:63 + --> $DIR/issue-77919.rs:12:63 | LL | impl TypeVal for Multiply where N: TypeVal {} | - ^^^ not found in this scope @@ -18,7 +18,7 @@ LL | impl TypeVal for Multiply where N: TypeVal {} | help: you might be missing a type parameter: `, VAL` error[E0046]: not all trait items implemented, missing: `VAL` - --> $DIR/issue-77919.rs:11:1 + --> $DIR/issue-77919.rs:12:1 | LL | const VAL: T; | ------------ `VAL` from trait @@ -26,7 +26,16 @@ LL | const VAL: T; LL | impl TypeVal for Multiply where N: TypeVal {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation -error: aborting due to 3 previous errors +error: unable to use constant with a hidden value in the type system + --> $DIR/issue-77919.rs:2:9 + | +LL | [1; >::VAL]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this most often happens when trying to look into an opaque type + = note: the type system cannot access the hidden type of opaque types + +error: aborting due to 4 previous errors Some errors have detailed explanations: E0046, E0412. For more information about an error, try `rustc --explain E0046`. diff --git a/src/test/ui/pattern/non-structural-match-types.rs b/src/test/ui/pattern/non-structural-match-types.rs index 5c33154736650..bd328407e16cc 100644 --- a/src/test/ui/pattern/non-structural-match-types.rs +++ b/src/test/ui/pattern/non-structural-match-types.rs @@ -9,6 +9,7 @@ fn main() { const { || {} } => {}, //~ ERROR cannot be used in patterns } match loop {} { - const { async {} } => {}, //~ ERROR cannot be used in patterns + const { async {} } => {}, + //~^ ERROR `impl Future` cannot be used in patterns } } diff --git a/src/test/ui/recursion/issue-26548-recursion-via-normalize.rs b/src/test/ui/recursion/issue-26548-recursion-via-normalize.rs index 91958dffcf4df..6266ee105c95b 100644 --- a/src/test/ui/recursion/issue-26548-recursion-via-normalize.rs +++ b/src/test/ui/recursion/issue-26548-recursion-via-normalize.rs @@ -1,10 +1,10 @@ -//~ ERROR cycle detected when computing layout of `core::option::Option` +//~ ERROR cycle detected when computing layout of `core::option::Option<::It>` +//~| NOTE ...which requires computing layout of `core::option::Option`... //~| NOTE ...which requires computing layout of `S`... -//~| NOTE ...which requires computing layout of `core::option::Option<::It>`... -//~| NOTE ...which again requires computing layout of `core::option::Option`, completing the cycle -//~| NOTE cycle used when computing layout of `core::option::Option<::It>` +//~| NOTE ...which again requires computing layout of `core::option::Option<::It>`, completing the cycle trait Mirror { + //~^ NOTE cycle used when checking deathness of variables in top-level module type It: ?Sized; } impl Mirror for T { diff --git a/src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr b/src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr index a75097cdbfbda..d5ad0d640186c 100644 --- a/src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr +++ b/src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr @@ -1,9 +1,19 @@ -error[E0391]: cycle detected when computing layout of `core::option::Option` +error[E0391]: cycle detected when computing layout of `core::option::Option<::It>` | + = note: ...which requires computing layout of `core::option::Option`... = note: ...which requires computing layout of `S`... - = note: ...which requires computing layout of `core::option::Option<::It>`... - = note: ...which again requires computing layout of `core::option::Option`, completing the cycle - = note: cycle used when computing layout of `core::option::Option<::It>` + = note: ...which again requires computing layout of `core::option::Option<::It>`, completing the cycle +note: cycle used when checking deathness of variables in top-level module + --> $DIR/issue-26548-recursion-via-normalize.rs:6:1 + | +LL | / trait Mirror { +LL | | +LL | | type It: ?Sized; +LL | | } +... | +LL | | let _s = S(None); +LL | | } + | |_^ error: aborting due to previous error diff --git a/src/test/ui/specialization/ctfe/default-assoc-const.rs b/src/test/ui/specialization/ctfe/default-assoc-const.rs new file mode 100644 index 0000000000000..7b1e03fbc5254 --- /dev/null +++ b/src/test/ui/specialization/ctfe/default-assoc-const.rs @@ -0,0 +1,22 @@ +// ICE fixed by #102657. +// +// See that PR for more details. +#![feature(specialization)] +//~^ WARNING the feature `specialization` is incomplete and may not be safe to use + +trait Foo { + const ASSOC: usize; +} + + +impl Foo for u32 { + default const ASSOC: usize = 0; +} + +fn foo() -> [u8; 0] { + [0; ::ASSOC] + //~^ ERROR unable to use constant with a hidden value in the type system + //~| ERROR mismatched types +} + +fn main() {} diff --git a/src/test/ui/specialization/ctfe/default-assoc-const.stderr b/src/test/ui/specialization/ctfe/default-assoc-const.stderr new file mode 100644 index 0000000000000..d7ceae8e619bc --- /dev/null +++ b/src/test/ui/specialization/ctfe/default-assoc-const.stderr @@ -0,0 +1,33 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/default-assoc-const.rs:4:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #31844 for more information + = help: consider using `min_specialization` instead, which is more stable and complete + = note: `#[warn(incomplete_features)]` on by default + +error[E0308]: mismatched types + --> $DIR/default-assoc-const.rs:17:5 + | +LL | fn foo() -> [u8; 0] { + | ------- expected `[u8; 0]` because of return type +LL | [0; ::ASSOC] + | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `0`, found `::ASSOC` + | + = note: expected array `[u8; 0]` + found array `[u8; _]` + +error: unable to use constant with a hidden value in the type system + --> $DIR/default-assoc-const.rs:17:9 + | +LL | [0; ::ASSOC] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: this most often happens when trying to look into an opaque type + = note: the type system cannot access the hidden type of opaque types + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/specialization/ctfe/default-assoc-type.rs b/src/test/ui/specialization/ctfe/default-assoc-type.rs new file mode 100644 index 0000000000000..03b0d95e74c88 --- /dev/null +++ b/src/test/ui/specialization/ctfe/default-assoc-type.rs @@ -0,0 +1,29 @@ +// ICE fixed by #102657. +// +// See that PR for more details. +#![feature(specialization)] +//~^ WARNING the feature `specialization` is incomplete and may not be safe to use + +trait Foo { + type Assoc: Trait; +} + +impl Foo for Vec { + default type Assoc = u32; +} + +trait Trait { + const ASSOC: usize; +} + +impl Trait for u32 { + const ASSOC: usize = 0; +} + +fn foo() -> [u8; 0] { + [0; < as Foo>::Assoc as Trait>::ASSOC] + //~^ ERROR unable to use constant with a hidden value in the type system + //~| ERROR mismatched types +} + +fn main() {} diff --git a/src/test/ui/specialization/ctfe/default-assoc-type.stderr b/src/test/ui/specialization/ctfe/default-assoc-type.stderr new file mode 100644 index 0000000000000..e73fad348b3db --- /dev/null +++ b/src/test/ui/specialization/ctfe/default-assoc-type.stderr @@ -0,0 +1,33 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/default-assoc-type.rs:4:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #31844 for more information + = help: consider using `min_specialization` instead, which is more stable and complete + = note: `#[warn(incomplete_features)]` on by default + +error[E0308]: mismatched types + --> $DIR/default-assoc-type.rs:24:5 + | +LL | fn foo() -> [u8; 0] { + | ------- expected `[u8; 0]` because of return type +LL | [0; < as Foo>::Assoc as Trait>::ASSOC] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `0`, found `< as Foo>::Assoc as Trait>::ASSOC` + | + = note: expected array `[u8; 0]` + found array `[u8; _]` + +error: unable to use constant with a hidden value in the type system + --> $DIR/default-assoc-type.rs:24:9 + | +LL | [0; < as Foo>::Assoc as Trait>::ASSOC] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this most often happens when trying to look into an opaque type + = note: the type system cannot access the hidden type of opaque types + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/specialization/transmute-specialization.rs b/src/test/ui/specialization/transmute-specialization.rs index 499334d983b1f..3c4a0b869cb83 100644 --- a/src/test/ui/specialization/transmute-specialization.rs +++ b/src/test/ui/specialization/transmute-specialization.rs @@ -1,5 +1,3 @@ -// run-pass - #![feature(specialization)] //~ WARN the feature `specialization` is incomplete trait Specializable { type Output; } @@ -11,5 +9,6 @@ impl Specializable for T { fn main() { unsafe { std::mem::transmute::::Output>(0); + //~^ ERROR cannot transmute between types of different sizes } } diff --git a/src/test/ui/specialization/transmute-specialization.stderr b/src/test/ui/specialization/transmute-specialization.stderr index b1c26d7dacc62..86f8bc6fbb6c9 100644 --- a/src/test/ui/specialization/transmute-specialization.stderr +++ b/src/test/ui/specialization/transmute-specialization.stderr @@ -1,5 +1,5 @@ warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/transmute-specialization.rs:3:12 + --> $DIR/transmute-specialization.rs:1:12 | LL | #![feature(specialization)] | ^^^^^^^^^^^^^^ @@ -8,5 +8,15 @@ LL | #![feature(specialization)] = help: consider using `min_specialization` instead, which is more stable and complete = note: `#[warn(incomplete_features)]` on by default -warning: 1 warning emitted +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> $DIR/transmute-specialization.rs:11:9 + | +LL | std::mem::transmute::::Output>(0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `u16` (16 bits) + = note: target type: `<() as Specializable>::Output` (this type does not have a fixed size) + +error: aborting due to previous error; 1 warning emitted +For more information about this error, try `rustc --explain E0512`. diff --git a/src/test/ui/type-alias-impl-trait/in-where-clause.rs b/src/test/ui/type-alias-impl-trait/in-where-clause.rs new file mode 100644 index 0000000000000..ea7e132a02638 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/in-where-clause.rs @@ -0,0 +1,15 @@ +// check-pass +// This previously caused a query cycle as we evaluated +// `1 + 2` with `Reveal::All` during typeck, causing us to +// to get the concrete type of `Bar` while computing it. +#![feature(type_alias_impl_trait)] +type Bar = impl Sized; + +fn foo() -> Bar +where + Bar: Send, +{ + [0; 1 + 2] +} + +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/issue-53092-2.stderr b/src/test/ui/type-alias-impl-trait/issue-53092-2.stderr index 1b89d55711dbd..19352767a224b 100644 --- a/src/test/ui/type-alias-impl-trait/issue-53092-2.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-53092-2.stderr @@ -9,8 +9,6 @@ note: ...which requires type-checking `CONST_BUG`... | LL | const CONST_BUG: Bug = unsafe { std::mem::transmute(|_: u8| ()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which requires computing layout of `Bug`... - = note: ...which requires normalizing `Bug`... = note: ...which again requires computing type of `Bug::{opaque#0}`, completing the cycle note: cycle used when checking item types in top-level module --> $DIR/issue-53092-2.rs:1:1 diff --git a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs index c2ab6a9d10aa6..3edfedd896eb4 100644 --- a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs +++ b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs @@ -12,7 +12,7 @@ const LEAK_FREE: Bar = leak_free(); fn leak_free_test() { match LEAK_FREE { LEAK_FREE => (), - //~^ `Bar` cannot be used in patterns + //~^ ERROR `Bar` cannot be used in patterns _ => (), } } diff --git a/src/test/ui/type-alias-impl-trait/structural-match.rs b/src/test/ui/type-alias-impl-trait/structural-match.rs index 7cc9ccaabdca4..1c132f6f58373 100644 --- a/src/test/ui/type-alias-impl-trait/structural-match.rs +++ b/src/test/ui/type-alias-impl-trait/structural-match.rs @@ -13,7 +13,7 @@ const VALUE: Foo = value(); fn test() { match VALUE { VALUE => (), - //~^ `Foo` cannot be used in patterns + //~^ ERROR `Foo` cannot be used in patterns _ => (), } }