Change:
: produces cc
Not that this fixes the issue, but and aren't necessarily guaranteed to have the same representation without or on both and .
minified: is this a victim of the backwards algorithm for promotion? Just a hunch, but it might have promoted away the call to and then end up trying to promote the , but it's not in the place where it was expected, because it now lives inside the promoted. So it ends up trying to promote an argument in a basic block that was already promoted away
thanks , I'll update the PR that triggered this - for context
As a workaround until we fix this ICE, you can introduce an intermediate explicit constant for the argument to . Or is this part of a user-exposed API?
This is part of a user-exposed API, but that workaround should allow me to at least get the const tests running.
It won't remove the definition if there's more than one use (unless this is fallout from your changes?)
There's only one use. I don't see how my changes could have caused this, but it seems possible. I'll do a bisection
Oh, I see, is and that's missing a check like:
Fix instructions: Add a which, like the variable, is used to mark blocks whose terminator has been promoted out. skip promoting all such terminators when encountering said block id in a ()
You can use a , although I'm not even sure it's necessary. A promoted call ends up as a , so you could just skip it based on that?

Discussion:
let operand = Operand::Copy(promoted_place(ty, span)); mem::replace(&mut args[index], operand) } <ins> // We expected a `TerminatorKind::Call` for which we'd like to promote an // argument. `qualify_consts` saw a `TerminatorKind::Call` here, but // we are seeing a `Goto`. That means that the `promote_temps` method // already promoted this call away entirely. This case occurs when calling // a function requiring a constant argument and as that constant value // providing a value whose computation contains another call to a function // requiring a constant argument. TerminatorKind::Goto { .. } => return, </ins> _ => bug!() } }

let fn_ty = func.ty(self.mir, self.tcx); let mut callee_def_id = None; <del> let (mut is_shuffle, mut is_const_fn) = (false, false); </del> <ins> let mut is_shuffle = false; let mut is_const_fn = false; let mut is_promotable_const_fn = false; </ins> if let ty::FnDef(def_id, _) = fn_ty.sty { callee_def_id = Some(def_id); match self.tcx.fn_sig(def_id).abi() {

// functions without #[rustc_promotable] if self.tcx.is_promotable_const_fn(def_id) { is_const_fn = true; <ins> is_promotable_const_fn = true; } else if self.tcx.is_const_fn(def_id) { is_const_fn = true; </ins> } } else { // stable const fn or unstable const fns with their feature gate

if !constant_arguments.contains(&i) { return } <del> if this.qualif.is_empty() { </del> <ins> // Since the argument is required to be constant, // we care about constness, not promotability. // If we checked for promotability, we'd miss out on // the results of function calls (which are never promoted // in runtime code) // This is not a problem, because the argument explicitly // requests constness, in contrast to regular promotion // which happens even without the user requesting it. // We can error out with a hard error if the argument is not // constant here. if (this.qualif - Qualif::NOT_PROMOTABLE).is_empty() { </ins> this.promotion_candidates.push(candidate); } else { this.tcx.sess.span_err(this.span,

// Be conservative about the returned value of a const fn. let tcx = self.tcx; let ty = dest.ty(self.mir, tcx).to_ty(tcx); <del> self.qualif = Qualif::empty(); </del> <ins> if is_const_fn && !is_promotable_const_fn && self.mode == Mode::Fn { self.qualif = Qualif::NOT_PROMOTABLE; } else { self.qualif = Qualif::empty(); } </ins> self.add_type(ty); } self.assign(dest, location);

<ins> // compile-pass #![feature(const_fn, rustc_attrs)] #[rustc_args_required_const(0)] pub const fn a(value: u8) -> u8 { value } #[rustc_args_required_const(0)] pub fn b(_: u8) { unimplemented!() } fn main() { let _ = b(a(0)); } </ins>