diff options
| author | Ralf Jung <post@ralfj.de> | 2021-05-09 14:04:34 +0200 |
|---|---|---|
| committer | Ralf Jung <post@ralfj.de> | 2021-05-12 16:14:57 +0200 |
| commit | 22e1778ec0e7fc77ae465bd0f69ead91447be742 (patch) | |
| tree | 5d17af00eb587cf1c4d8ab31ab2807f0034c9342 | |
| parent | e1ff91f439bc09f566da211c6449821b4e949279 (diff) | |
| download | rust-22e1778ec0e7fc77ae465bd0f69ead91447be742.tar.gz rust-22e1778ec0e7fc77ae465bd0f69ead91447be742.zip | |
rustc_args_required_const is no longer a promotion site
| -rw-r--r-- | compiler/rustc_mir/src/transform/promote_consts.rs | 189 | ||||
| -rw-r--r-- | src/test/ui/consts/const_arg_local.rs | 11 | ||||
| -rw-r--r-- | src/test/ui/consts/const_arg_local.stderr | 8 | ||||
| -rw-r--r-- | src/test/ui/consts/const_arg_promotable.rs | 10 | ||||
| -rw-r--r-- | src/test/ui/consts/const_arg_promotable.stderr | 8 | ||||
| -rw-r--r-- | src/test/ui/consts/const_arg_promotable2.rs | 18 | ||||
| -rw-r--r-- | src/test/ui/consts/const_arg_promotable2.stderr | 8 | ||||
| -rw-r--r-- | src/test/ui/consts/const_arg_wrapper.rs | 10 | ||||
| -rw-r--r-- | src/test/ui/consts/const_arg_wrapper.stderr | 8 | ||||
| -rw-r--r-- | src/test/ui/consts/rustc-args-required-const.rs | 27 | ||||
| -rw-r--r-- | src/test/ui/consts/rustc-args-required-const.stderr | 14 |
11 files changed, 28 insertions, 283 deletions
diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs index 1bbaf833c4f..f786f327ba2 100644 --- a/compiler/rustc_mir/src/transform/promote_consts.rs +++ b/compiler/rustc_mir/src/transform/promote_consts.rs @@ -12,20 +12,16 @@ //! initialization and can otherwise silence errors, if //! move analysis runs after promotion on broken MIR. -use rustc_ast::LitKind; use rustc_hir as hir; -use rustc_hir::def_id::DefId; use rustc_middle::mir::traversal::ReversePostorder; use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::{self, List, TyCtxt, TypeFoldable}; -use rustc_span::symbol::sym; use rustc_span::Span; use rustc_index::vec::{Idx, IndexVec}; -use rustc_target::spec::abi::Abi; use std::cell::Cell; use std::{cmp, iter, mem}; @@ -101,47 +97,16 @@ impl TempState { pub enum Candidate { /// Borrow of a constant temporary, candidate for lifetime extension. Ref(Location), - - /// Currently applied to function calls where the callee has the unstable - /// `#[rustc_args_required_const]` attribute as well as the SIMD shuffle - /// intrinsic. The intrinsic requires the arguments are indeed constant and - /// the attribute currently provides the semantic requirement that arguments - /// must be constant. - Argument { bb: BasicBlock, index: usize }, } impl Candidate { - /// Returns `true` if we should use the "explicit" rules for promotability for this `Candidate`. - fn forces_explicit_promotion(&self) -> bool { - match self { - Candidate::Ref(_) => false, - Candidate::Argument { .. } => true, - } - } - fn source_info(&self, body: &Body<'_>) -> SourceInfo { match self { Candidate::Ref(location) => *body.source_info(*location), - Candidate::Argument { bb, .. } => *body.source_info(body.terminator_loc(*bb)), } } } -fn args_required_const(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Vec<usize>> { - let attrs = tcx.get_attrs(def_id); - let attr = attrs.iter().find(|a| tcx.sess.check_name(a, sym::rustc_args_required_const))?; - let mut ret = vec![]; - for meta in attr.meta_item_list()? { - match meta.literal()?.kind { - LitKind::Int(a, _) => { - ret.push(a as usize); - } - _ => bug!("invalid arg index"), - } - } - Some(ret) -} - struct Collector<'a, 'tcx> { ccx: &'a ConstCx<'a, 'tcx>, temps: IndexVec<Local, TempState>, @@ -208,31 +173,6 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> { _ => {} } } - - fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { - self.super_terminator(terminator, location); - - if let TerminatorKind::Call { ref func, .. } = terminator.kind { - if let ty::FnDef(def_id, _) = *func.ty(self.ccx.body, self.ccx.tcx).kind() { - let fn_sig = self.ccx.tcx.fn_sig(def_id); - if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = fn_sig.abi() { - let name = self.ccx.tcx.item_name(def_id); - // FIXME(eddyb) use `#[rustc_args_required_const(2)]` for shuffles. - if name.as_str().starts_with("simd_shuffle") { - self.candidates.push(Candidate::Argument { bb: location.block, index: 2 }); - - return; // Don't double count `simd_shuffle` candidates - } - } - - if let Some(constant_args) = args_required_const(self.ccx.tcx, def_id) { - for index in constant_args { - self.candidates.push(Candidate::Argument { bb: location.block, index }); - } - } - } - } - } } pub fn collect_temps_and_candidates( @@ -256,14 +196,6 @@ pub fn collect_temps_and_candidates( struct Validator<'a, 'tcx> { ccx: &'a ConstCx<'a, 'tcx>, temps: &'a IndexVec<Local, TempState>, - - /// Explicit promotion happens e.g. for constant arguments declared via - /// `rustc_args_required_const`. - /// Implicit promotion has almost the same rules, except that disallows `const fn` - /// except for those marked `#[rustc_promotable]`. This is to avoid changing - /// a legitimate run-time operation into a failing compile-time operation - /// e.g. due to addresses being compared inside the function. - explicit: bool, } impl std::ops::Deref for Validator<'a, 'tcx> { @@ -280,8 +212,6 @@ impl<'tcx> Validator<'_, 'tcx> { fn validate_candidate(&self, candidate: Candidate) -> Result<(), Unpromotable> { match candidate { Candidate::Ref(loc) => { - assert!(!self.explicit); - let statement = &self.body[loc.block].statements[loc.statement_index]; match &statement.kind { StatementKind::Assign(box (_, Rvalue::Ref(_, kind, place))) => { @@ -310,15 +240,6 @@ impl<'tcx> Validator<'_, 'tcx> { _ => bug!(), } } - Candidate::Argument { bb, index } => { - assert!(self.explicit); - - let terminator = self.body[bb].terminator(); - match &terminator.kind { - TerminatorKind::Call { args, .. } => self.validate_operand(&args[index]), - _ => bug!(), - } - } } } @@ -448,12 +369,10 @@ impl<'tcx> Validator<'_, 'tcx> { ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {} ProjectionElem::Index(local) => { - if !self.explicit { - let mut promotable = false; - // Only accept if we can predict the index and are indexing an array. - let val = if let TempState::Defined { location: loc, .. } = - self.temps[local] - { + let mut promotable = false; + // Only accept if we can predict the index and are indexing an array. + let val = + if let TempState::Defined { location: loc, .. } = self.temps[local] { let block = &self.body[loc.block]; if loc.statement_index < block.statements.len() { let statement = &block.statements[loc.statement_index]; @@ -470,28 +389,27 @@ impl<'tcx> Validator<'_, 'tcx> { } else { None }; - if let Some(idx) = val { - // Determine the type of the thing we are indexing. - let ty = place_base.ty(self.body, self.tcx).ty; - match ty.kind() { - ty::Array(_, len) => { - // It's an array; determine its length. - if let Some(len) = - len.try_eval_usize(self.tcx, self.param_env) - { - // If the index is in-bounds, go ahead. - if idx < len { - promotable = true; - } + if let Some(idx) = val { + // Determine the type of the thing we are indexing. + let ty = place_base.ty(self.body, self.tcx).ty; + match ty.kind() { + ty::Array(_, len) => { + // It's an array; determine its length. + if let Some(len) = len.try_eval_usize(self.tcx, self.param_env) + { + // If the index is in-bounds, go ahead. + if idx < len { + promotable = true; } } - _ => {} } + _ => {} } - if !promotable { - return Err(Unpromotable); - } } + if !promotable { + return Err(Unpromotable); + } + self.validate_local(local)?; } @@ -636,7 +554,7 @@ impl<'tcx> Validator<'_, 'tcx> { match op { BinOp::Div | BinOp::Rem => { - if !self.explicit && lhs_ty.is_integral() { + if lhs_ty.is_integral() { // Integer division: the RHS must be a non-zero const. let const_val = match rhs { Operand::Constant(c) => { @@ -721,13 +639,12 @@ impl<'tcx> Validator<'_, 'tcx> { ) -> Result<(), Unpromotable> { let fn_ty = callee.ty(self.body, self.tcx); - // When doing explicit promotion and inside const/static items, we promote all (eligible) function calls. + // Inside const/static items, we promote all (eligible) function calls. // Everywhere else, we require `#[rustc_promotable]` on the callee. - let promote_all_const_fn = self.explicit - || matches!( - self.const_kind, - Some(hir::ConstContext::Static(_) | hir::ConstContext::Const) - ); + let promote_all_const_fn = matches!( + self.const_kind, + Some(hir::ConstContext::Static(_) | hir::ConstContext::Const) + ); if !promote_all_const_fn { if let ty::FnDef(def_id, _) = *fn_ty.kind() { // Never promote runtime `const fn` calls of @@ -765,41 +682,12 @@ pub fn validate_candidates( temps: &IndexVec<Local, TempState>, candidates: &[Candidate], ) -> Vec<Candidate> { - let mut validator = Validator { ccx, temps, explicit: false }; + let validator = Validator { ccx, temps }; candidates .iter() .copied() - .filter(|&candidate| { - validator.explicit = candidate.forces_explicit_promotion(); - - // FIXME(eddyb) also emit the errors for shuffle indices - // and `#[rustc_args_required_const]` arguments here. - - let is_promotable = validator.validate_candidate(candidate).is_ok(); - - // If we use explicit validation, we carry the risk of turning a legitimate run-time - // operation into a failing compile-time operation. Make sure that does not happen - // by asserting that there is no possible run-time behavior here in case promotion - // fails. - if validator.explicit && !is_promotable { - ccx.tcx.sess.delay_span_bug( - ccx.body.span, - "Explicit promotion requested, but failed to promote", - ); - } - - match candidate { - Candidate::Argument { bb, index } if !is_promotable => { - let span = ccx.body[bb].terminator().source_info.span; - let msg = format!("argument {} is required to be a constant", index + 1); - ccx.tcx.sess.span_err(span, &msg); - } - _ => (), - } - - is_promotable - }) + .filter(|&candidate| validator.validate_candidate(candidate).is_ok()) .collect() } @@ -1039,26 +927,6 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { _ => bug!(), } } - Candidate::Argument { bb, index } => { - let terminator = blocks[bb].terminator_mut(); - match terminator.kind { - TerminatorKind::Call { ref mut args, .. } => { - let ty = args[index].ty(local_decls, self.tcx); - let span = terminator.source_info.span; - - Rvalue::Use(mem::replace(&mut args[index], promoted_operand(ty, span))) - } - // 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 None, - _ => bug!(), - } - } } }; @@ -1113,7 +981,6 @@ pub fn promote_candidates<'tcx>( } } } - Candidate::Argument { .. } => {} } // Declare return place local so that `mir::Body::new` doesn't complain. diff --git a/src/test/ui/consts/const_arg_local.rs b/src/test/ui/consts/const_arg_local.rs deleted file mode 100644 index 9add1f8d5a3..00000000000 --- a/src/test/ui/consts/const_arg_local.rs +++ /dev/null @@ -1,11 +0,0 @@ -#![feature(rustc_attrs)] - -#[rustc_args_required_const(0)] -fn foo(_imm8: i32) {} - -fn bar() { - let imm8 = 3; - foo(imm8) //~ ERROR argument 1 is required to be a constant -} - -fn main() {} diff --git a/src/test/ui/consts/const_arg_local.stderr b/src/test/ui/consts/const_arg_local.stderr deleted file mode 100644 index bad85471a6b..00000000000 --- a/src/test/ui/consts/const_arg_local.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: argument 1 is required to be a constant - --> $DIR/const_arg_local.rs:8:5 - | -LL | foo(imm8) - | ^^^^^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/consts/const_arg_promotable.rs b/src/test/ui/consts/const_arg_promotable.rs deleted file mode 100644 index cea3817550e..00000000000 --- a/src/test/ui/consts/const_arg_promotable.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![feature(rustc_attrs)] - -#[rustc_args_required_const(0)] -fn foo(_imm8: i32) {} - -fn bar() { - foo(*&mut 42) //~ ERROR argument 1 is required to be a constant -} - -fn main() {} diff --git a/src/test/ui/consts/const_arg_promotable.stderr b/src/test/ui/consts/const_arg_promotable.stderr deleted file mode 100644 index b24b245b3ce..00000000000 --- a/src/test/ui/consts/const_arg_promotable.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: argument 1 is required to be a constant - --> $DIR/const_arg_promotable.rs:7:5 - | -LL | foo(*&mut 42) - | ^^^^^^^^^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/consts/const_arg_promotable2.rs b/src/test/ui/consts/const_arg_promotable2.rs deleted file mode 100644 index 3399e51ed4e..00000000000 --- a/src/test/ui/consts/const_arg_promotable2.rs +++ /dev/null @@ -1,18 +0,0 @@ -// This test is a regression test for a bug where we only checked function calls in no-const -// functions for `rustc_args_required_const` arguments. This meant that even though `bar` needs its -// argument to be const, inside a const fn (callable at runtime), the value for it may come from a -// non-constant (namely an argument to the const fn). - -#![feature(rustc_attrs)] -const fn foo(a: i32) { - bar(a); //~ ERROR argument 1 is required to be a constant -} - -#[rustc_args_required_const(0)] -const fn bar(_: i32) {} - -fn main() { - // this function call will pass a runtime-value (number of program arguments) to `foo`, which - // will in turn forward it to `bar`, which expects a compile-time argument - foo(std::env::args().count() as i32); -} diff --git a/src/test/ui/consts/const_arg_promotable2.stderr b/src/test/ui/consts/const_arg_promotable2.stderr deleted file mode 100644 index 149d1ce8940..00000000000 --- a/src/test/ui/consts/const_arg_promotable2.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: argument 1 is required to be a constant - --> $DIR/const_arg_promotable2.rs:8:5 - | -LL | bar(a); - | ^^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/consts/const_arg_wrapper.rs b/src/test/ui/consts/const_arg_wrapper.rs deleted file mode 100644 index 3dd3a2ffaf3..00000000000 --- a/src/test/ui/consts/const_arg_wrapper.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![feature(rustc_attrs)] - -#[rustc_args_required_const(0)] -fn foo(_imm8: i32) {} - -fn bar(imm8: i32) { - foo(imm8) //~ ERROR argument 1 is required to be a constant -} - -fn main() {} diff --git a/src/test/ui/consts/const_arg_wrapper.stderr b/src/test/ui/consts/const_arg_wrapper.stderr deleted file mode 100644 index 9cd95a2020f..00000000000 --- a/src/test/ui/consts/const_arg_wrapper.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: argument 1 is required to be a constant - --> $DIR/const_arg_wrapper.rs:7:5 - | -LL | foo(imm8) - | ^^^^^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/consts/rustc-args-required-const.rs b/src/test/ui/consts/rustc-args-required-const.rs deleted file mode 100644 index 0723b66879c..00000000000 --- a/src/test/ui/consts/rustc-args-required-const.rs +++ /dev/null @@ -1,27 +0,0 @@ -#![feature(rustc_attrs)] - -#[rustc_args_required_const(0)] -fn foo(_a: i32) { -} - -#[rustc_args_required_const(1)] -fn bar(_a: i32, _b: i32) { -} - -const A: i32 = 3; - -const fn baz() -> i32 { - 3 -} - -fn main() { - foo(2); - foo(2 + 3); - const BAZ: i32 = baz(); - foo(BAZ); - let a = 4; - foo(A); - foo(a); //~ ERROR: argument 1 is required to be a constant - bar(a, 3); - bar(a, a); //~ ERROR: argument 2 is required to be a constant -} diff --git a/src/test/ui/consts/rustc-args-required-const.stderr b/src/test/ui/consts/rustc-args-required-const.stderr deleted file mode 100644 index 8b302692053..00000000000 --- a/src/test/ui/consts/rustc-args-required-const.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: argument 1 is required to be a constant - --> $DIR/rustc-args-required-const.rs:24:5 - | -LL | foo(a); - | ^^^^^^ - -error: argument 2 is required to be a constant - --> $DIR/rustc-args-required-const.rs:26:5 - | -LL | bar(a, a); - | ^^^^^^^^^ - -error: aborting due to 2 previous errors - |
