Rollup merge of #54816 - oli-obk:double_promotion, r=alexreg
Don't try to promote already promoted out temporaries fixes #53201 r? @eddyb
This commit is contained in:
commit
68d5fddeef
3 changed files with 47 additions and 3 deletions
|
|
@ -333,6 +333,14 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||
let operand = Operand::Copy(promoted_place(ty, span));
|
||||
mem::replace(&mut args[index], operand)
|
||||
}
|
||||
// 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,
|
||||
_ => bug!()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -820,7 +820,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
|||
|
||||
let fn_ty = func.ty(self.mir, self.tcx);
|
||||
let mut callee_def_id = None;
|
||||
let (mut is_shuffle, mut is_const_fn) = (false, false);
|
||||
let mut is_shuffle = false;
|
||||
let mut is_const_fn = false;
|
||||
let mut is_promotable_const_fn = false;
|
||||
if let ty::FnDef(def_id, _) = fn_ty.sty {
|
||||
callee_def_id = Some(def_id);
|
||||
match self.tcx.fn_sig(def_id).abi() {
|
||||
|
|
@ -881,6 +883,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
|||
// functions without #[rustc_promotable]
|
||||
if self.tcx.is_promotable_const_fn(def_id) {
|
||||
is_const_fn = true;
|
||||
is_promotable_const_fn = true;
|
||||
} else if self.tcx.is_const_fn(def_id) {
|
||||
is_const_fn = true;
|
||||
}
|
||||
} else {
|
||||
// stable const fn or unstable const fns with their feature gate
|
||||
|
|
@ -982,7 +987,17 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
|||
if !constant_arguments.contains(&i) {
|
||||
return
|
||||
}
|
||||
if this.qualif.is_empty() {
|
||||
// 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() {
|
||||
this.promotion_candidates.push(candidate);
|
||||
} else {
|
||||
this.tcx.sess.span_err(this.span,
|
||||
|
|
@ -1011,7 +1026,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
|||
// Be conservative about the returned value of a const fn.
|
||||
let tcx = self.tcx;
|
||||
let ty = dest.ty(self.mir, tcx).to_ty(tcx);
|
||||
self.qualif = Qualif::empty();
|
||||
if is_const_fn && !is_promotable_const_fn && self.mode == Mode::Fn {
|
||||
self.qualif = Qualif::NOT_PROMOTABLE;
|
||||
} else {
|
||||
self.qualif = Qualif::empty();
|
||||
}
|
||||
self.add_type(ty);
|
||||
}
|
||||
self.assign(dest, location);
|
||||
|
|
|
|||
17
src/test/ui/consts/const-eval/double_promotion.rs
Normal file
17
src/test/ui/consts/const-eval/double_promotion.rs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
// 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));
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue