Skip to content

Commit

Permalink
Rollup merge of rust-lang#54816 - oli-obk:double_promotion, r=alexreg
Browse files Browse the repository at this point in the history
Don't try to promote already promoted out temporaries

fixes rust-lang#53201

r? @eddyb
  • Loading branch information
kennytm authored Oct 26, 2018
2 parents 5f7c8e1 + fd77500 commit 1960de0
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 3 deletions.
8 changes: 8 additions & 0 deletions src/librustc_mir/transform/promote_consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!()
}
}
Expand Down
25 changes: 22 additions & 3 deletions src/librustc_mir/transform/qualify_consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down
17 changes: 17 additions & 0 deletions src/test/ui/consts/const-eval/double_promotion.rs
Original file line number Diff line number Diff line change
@@ -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));
}

0 comments on commit 1960de0

Please sign in to comment.