about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2021-05-09 14:04:34 +0200
committerRalf Jung <post@ralfj.de>2021-05-12 16:14:57 +0200
commit22e1778ec0e7fc77ae465bd0f69ead91447be742 (patch)
tree5d17af00eb587cf1c4d8ab31ab2807f0034c9342
parente1ff91f439bc09f566da211c6449821b4e949279 (diff)
downloadrust-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.rs189
-rw-r--r--src/test/ui/consts/const_arg_local.rs11
-rw-r--r--src/test/ui/consts/const_arg_local.stderr8
-rw-r--r--src/test/ui/consts/const_arg_promotable.rs10
-rw-r--r--src/test/ui/consts/const_arg_promotable.stderr8
-rw-r--r--src/test/ui/consts/const_arg_promotable2.rs18
-rw-r--r--src/test/ui/consts/const_arg_promotable2.stderr8
-rw-r--r--src/test/ui/consts/const_arg_wrapper.rs10
-rw-r--r--src/test/ui/consts/const_arg_wrapper.stderr8
-rw-r--r--src/test/ui/consts/rustc-args-required-const.rs27
-rw-r--r--src/test/ui/consts/rustc-args-required-const.stderr14
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
-