about summary refs log tree commit diff
diff options
context:
space:
mode:
authorkennytm <kennytm@gmail.com>2018-02-10 14:24:04 +0800
committerGitHub <noreply@github.com>2018-02-10 14:24:04 +0800
commit1e10ca0b030c4c68336be44260da1625fc98cb9d (patch)
treeecc388e742458fac6a193db44aa0a2373a03888f
parentd6394e51a01c9617c9d33a78d66db2236d8994dc (diff)
parent7a20fc14ef255df1ce2c417943605015aba2b1ff (diff)
downloadrust-1e10ca0b030c4c68336be44260da1625fc98cb9d.tar.gz
rust-1e10ca0b030c4c68336be44260da1625fc98cb9d.zip
Rollup merge of #48078 - alexcrichton:fix-required-const-and-proc-macro, r=eddyb
Disallow function pointers to #[rustc_args_required_const]

This commit disallows acquiring a function pointer to functions tagged as
`#[rustc_args_required_const]`. This is intended to be used as future-proofing
for the stdsimd crate to avoid taking a function pointer to any intrinsic which
has a hard requirement that one of the arguments is a constant value.

Note that the first commit here isn't related specifically to this feature, but was necessary to get this working in stdsimd!
-rw-r--r--src/librustc_mir/interpret/eval_context.rs4
-rw-r--r--src/librustc_trans/mir/constant.rs4
-rw-r--r--src/librustc_trans/mir/rvalue.rs4
-rw-r--r--src/librustc_typeck/check/mod.rs32
-rw-r--r--src/libsyntax/feature_gate.rs5
-rw-r--r--src/test/compile-fail/rustc-args-required-const2.rs20
6 files changed, 69 insertions, 0 deletions
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index 02fcb69fef5..52b87282180 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -716,6 +716,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
                     ReifyFnPointer => {
                         match self.eval_operand(operand)?.ty.sty {
                             ty::TyFnDef(def_id, substs) => {
+                                if self.tcx.has_attr(def_id, "rustc_args_required_const") {
+                                    bug!("reifying a fn ptr that requires \
+                                          const arguments");
+                                }
                                 let instance = self.resolve(def_id, substs)?;
                                 let fn_ptr = self.memory.create_fn_alloc(instance);
                                 let valty = ValTy {
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index 49b4ef0d385..d470f92b752 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -714,6 +714,10 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                     mir::CastKind::ReifyFnPointer => {
                         match operand.ty.sty {
                             ty::TyFnDef(def_id, substs) => {
+                                if tcx.has_attr(def_id, "rustc_args_required_const") {
+                                    bug!("reifying a fn ptr that requires \
+                                          const arguments");
+                                }
                                 callee::resolve_and_get_fn(self.cx, def_id, substs)
                             }
                             _ => {
diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs
index d1bc4fe9001..2e876ec118d 100644
--- a/src/librustc_trans/mir/rvalue.rs
+++ b/src/librustc_trans/mir/rvalue.rs
@@ -195,6 +195,10 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
                     mir::CastKind::ReifyFnPointer => {
                         match operand.layout.ty.sty {
                             ty::TyFnDef(def_id, substs) => {
+                                if bx.cx.tcx.has_attr(def_id, "rustc_args_required_const") {
+                                    bug!("reifying a fn ptr that requires \
+                                          const arguments");
+                                }
                                 OperandValue::Immediate(
                                     callee::resolve_and_get_fn(bx.cx, def_id, substs))
                             }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 5fd4e0cb109..165b499cc62 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -4897,6 +4897,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
         }
 
+        self.check_rustc_args_require_const(def.def_id(), node_id, span);
+
         debug!("instantiate_value_path: type of {:?} is {:?}",
                node_id,
                ty_substituted);
@@ -4904,6 +4906,36 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         ty_substituted
     }
 
+    fn check_rustc_args_require_const(&self,
+                                      def_id: DefId,
+                                      node_id: ast::NodeId,
+                                      span: Span) {
+        // We're only interested in functions tagged with
+        // #[rustc_args_required_const], so ignore anything that's not.
+        if !self.tcx.has_attr(def_id, "rustc_args_required_const") {
+            return
+        }
+
+        // If our calling expression is indeed the function itself, we're good!
+        // If not, generate an error that this can only be called directly.
+        match self.tcx.hir.get(self.tcx.hir.get_parent_node(node_id)) {
+            Node::NodeExpr(expr) => {
+                match expr.node {
+                    hir::ExprCall(ref callee, ..) => {
+                        if callee.id == node_id {
+                            return
+                        }
+                    }
+                    _ => {}
+                }
+            }
+            _ => {}
+        }
+
+        self.tcx.sess.span_err(span, "this function can only be invoked \
+                                      directly, not through a function pointer");
+    }
+
     /// Report errors if the provided parameters are too few or too many.
     fn check_path_parameter_count(&self,
                                   span: Span,
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 9c6520cd874..ae0556320b0 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -984,6 +984,11 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
                                  "wasm_import_memory attribute is currently unstable",
                                  cfg_fn!(wasm_import_memory))),
 
+    ("rustc_args_required_const", Whitelisted, Gated(Stability::Unstable,
+                                 "rustc_attrs",
+                                 "never will be stable",
+                                 cfg_fn!(rustc_attrs))),
+
     // Crate level attributes
     ("crate_name", CrateLevel, Ungated),
     ("crate_type", CrateLevel, Ungated),
diff --git a/src/test/compile-fail/rustc-args-required-const2.rs b/src/test/compile-fail/rustc-args-required-const2.rs
new file mode 100644
index 00000000000..aa63019307b
--- /dev/null
+++ b/src/test/compile-fail/rustc-args-required-const2.rs
@@ -0,0 +1,20 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(attr_literals, rustc_attrs, const_fn)]
+
+#[rustc_args_required_const(0)]
+fn foo(_a: i32) {
+}
+
+fn main() {
+    let a = foo; //~ ERROR: this function can only be invoked directly
+    a(2);
+}