Skip to content

Commit 1960de0

Browse files
authored
Rollup merge of rust-lang#54816 - oli-obk:double_promotion, r=alexreg
Don't try to promote already promoted out temporaries fixes rust-lang#53201 r? @eddyb
2 parents 5f7c8e1 + fd77500 commit 1960de0

File tree

3 files changed

+47
-3
lines changed

3 files changed

+47
-3
lines changed

Diff for: src/librustc_mir/transform/promote_consts.rs

+8
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,14 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
333333
let operand = Operand::Copy(promoted_place(ty, span));
334334
mem::replace(&mut args[index], operand)
335335
}
336+
// We expected a `TerminatorKind::Call` for which we'd like to promote an
337+
// argument. `qualify_consts` saw a `TerminatorKind::Call` here, but
338+
// we are seeing a `Goto`. That means that the `promote_temps` method
339+
// already promoted this call away entirely. This case occurs when calling
340+
// a function requiring a constant argument and as that constant value
341+
// providing a value whose computation contains another call to a function
342+
// requiring a constant argument.
343+
TerminatorKind::Goto { .. } => return,
336344
_ => bug!()
337345
}
338346
}

Diff for: src/librustc_mir/transform/qualify_consts.rs

+22-3
Original file line numberDiff line numberDiff line change
@@ -820,7 +820,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
820820

821821
let fn_ty = func.ty(self.mir, self.tcx);
822822
let mut callee_def_id = None;
823-
let (mut is_shuffle, mut is_const_fn) = (false, false);
823+
let mut is_shuffle = false;
824+
let mut is_const_fn = false;
825+
let mut is_promotable_const_fn = false;
824826
if let ty::FnDef(def_id, _) = fn_ty.sty {
825827
callee_def_id = Some(def_id);
826828
match self.tcx.fn_sig(def_id).abi() {
@@ -881,6 +883,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
881883
// functions without #[rustc_promotable]
882884
if self.tcx.is_promotable_const_fn(def_id) {
883885
is_const_fn = true;
886+
is_promotable_const_fn = true;
887+
} else if self.tcx.is_const_fn(def_id) {
888+
is_const_fn = true;
884889
}
885890
} else {
886891
// 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> {
982987
if !constant_arguments.contains(&i) {
983988
return
984989
}
985-
if this.qualif.is_empty() {
990+
// Since the argument is required to be constant,
991+
// we care about constness, not promotability.
992+
// If we checked for promotability, we'd miss out on
993+
// the results of function calls (which are never promoted
994+
// in runtime code)
995+
// This is not a problem, because the argument explicitly
996+
// requests constness, in contrast to regular promotion
997+
// which happens even without the user requesting it.
998+
// We can error out with a hard error if the argument is not
999+
// constant here.
1000+
if (this.qualif - Qualif::NOT_PROMOTABLE).is_empty() {
9861001
this.promotion_candidates.push(candidate);
9871002
} else {
9881003
this.tcx.sess.span_err(this.span,
@@ -1011,7 +1026,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
10111026
// Be conservative about the returned value of a const fn.
10121027
let tcx = self.tcx;
10131028
let ty = dest.ty(self.mir, tcx).to_ty(tcx);
1014-
self.qualif = Qualif::empty();
1029+
if is_const_fn && !is_promotable_const_fn && self.mode == Mode::Fn {
1030+
self.qualif = Qualif::NOT_PROMOTABLE;
1031+
} else {
1032+
self.qualif = Qualif::empty();
1033+
}
10151034
self.add_type(ty);
10161035
}
10171036
self.assign(dest, location);

Diff for: src/test/ui/consts/const-eval/double_promotion.rs

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// compile-pass
2+
3+
#![feature(const_fn, rustc_attrs)]
4+
5+
#[rustc_args_required_const(0)]
6+
pub const fn a(value: u8) -> u8 {
7+
value
8+
}
9+
10+
#[rustc_args_required_const(0)]
11+
pub fn b(_: u8) {
12+
unimplemented!()
13+
}
14+
15+
fn main() {
16+
let _ = b(a(0));
17+
}

0 commit comments

Comments
 (0)