about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2018-02-08 13:11:13 -0800
committerAlex Crichton <alex@alexcrichton.com>2018-02-08 14:46:27 -0800
commit7a20fc14ef255df1ce2c417943605015aba2b1ff (patch)
treef0163032b60fc571fb380761379eb7534bb43401
parent35dca7edd3e5181459c8e410a59a1b6e3e97a360 (diff)
downloadrust-7a20fc14ef255df1ce2c417943605015aba2b1ff.tar.gz
rust-7a20fc14ef255df1ce2c417943605015aba2b1ff.zip
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.
-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/test/compile-fail/rustc-args-required-const2.rs20
5 files changed, 64 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 cd1975488a2..ff9ea40073f 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 f044b2c711e..8bb38332d0e 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -4877,6 +4877,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);
@@ -4884,6 +4886,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/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);
+}