about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-09-21 21:24:19 +0200
committerGitHub <noreply@github.com>2019-09-21 21:24:19 +0200
commit25bdd76a545d8a6a62d20d8dad2690abb13ab10f (patch)
tree023d9692d5c1574a1eea33eb787c9655f313cdd7
parent05d7ae25bf0efe7a42df6994eeceee5bff19cf3e (diff)
parent9d4053f6921f3259076e2d88f983f9666a78ef4b (diff)
downloadrust-25bdd76a545d8a6a62d20d8dad2690abb13ab10f.tar.gz
rust-25bdd76a545d8a6a62d20d8dad2690abb13ab10f.zip
Rollup merge of #64635 - gnzlbg:const_fn_ptr, r=oli-obk
Allow using fn pointers in const fn with unleash miri

This allows using function pointers in const fns  when `-Zunleash-the-miri-within-you` is enabled.

If the call to the `const fn` happens in a `const`-context, the function pointer is required to point to a `const fn`:

```rust
fn non_const_fn() -> i32 { 42 }
const fn const_fn() -> i32 { 42 }
const fn foo(x: fn() -> i32) -> i32 { x() }

let x: i32 = foo(non_const_fn_ptr); // OK
let y: i32 = foo(const_fn_ptr); // OK
const X: i32 = foo(non_const_fn_ptr); // ERROR: `non_const_fn` is not `const fn`
const Y: i32 = foo(const_fn_ptr); // OK
```

r? @oli-obk
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs11
-rw-r--r--src/test/ui/consts/const-eval/const_fn_ptr.rs37
-rw-r--r--src/test/ui/consts/const-eval/const_fn_ptr.stderr152
-rw-r--r--src/test/ui/consts/const-eval/const_fn_ptr_fail.rs13
-rw-r--r--src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs26
-rw-r--r--src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr71
6 files changed, 308 insertions, 2 deletions
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 7cc1e634cf8..795721f3b3f 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -1407,10 +1407,17 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
                     }
                 }
                 ty::FnPtr(_) => {
-                    if self.mode.requires_const_checking() {
+                    let unleash_miri = self
+                        .tcx
+                        .sess
+                        .opts
+                        .debugging_opts
+                        .unleash_the_miri_inside_of_you;
+                    if self.mode.requires_const_checking() && !unleash_miri {
                         let mut err = self.tcx.sess.struct_span_err(
                             self.span,
-                            &format!("function pointers are not allowed in const fn"));
+                            "function pointers are not allowed in const fn"
+                        );
                         err.emit();
                     }
                 }
diff --git a/src/test/ui/consts/const-eval/const_fn_ptr.rs b/src/test/ui/consts/const-eval/const_fn_ptr.rs
new file mode 100644
index 00000000000..498f801db81
--- /dev/null
+++ b/src/test/ui/consts/const-eval/const_fn_ptr.rs
@@ -0,0 +1,37 @@
+// run-pass
+// compile-flags: -Zunleash-the-miri-inside-of-you
+#![feature(const_fn)]
+
+fn double(x: usize) -> usize { x * 2 }
+const fn double_const(x: usize) -> usize { x * 2 }
+
+const X: fn(usize) -> usize = double;
+const X_const: fn(usize) -> usize = double_const;
+
+const fn bar(x: usize) -> usize {
+    X(x)
+}
+
+const fn bar_const(x: usize) -> usize {
+    X_const(x)
+}
+
+const fn foo(x: fn(usize) -> usize, y: usize)  -> usize {
+    x(y)
+}
+
+fn main() {
+    const Y: usize = bar_const(2);
+    assert_eq!(Y, 4);
+    let y = bar_const(2);
+    assert_eq!(y, 4);
+    let y = bar(2);
+    assert_eq!(y, 4);
+
+    const Z: usize = foo(double_const, 2);
+    assert_eq!(Z, 4);
+    let z = foo(double_const, 2);
+    assert_eq!(z, 4);
+    let z = foo(double, 2);
+    assert_eq!(z, 4);
+}
diff --git a/src/test/ui/consts/const-eval/const_fn_ptr.stderr b/src/test/ui/consts/const-eval/const_fn_ptr.stderr
new file mode 100644
index 00000000000..41452ee59eb
--- /dev/null
+++ b/src/test/ui/consts/const-eval/const_fn_ptr.stderr
@@ -0,0 +1,152 @@
+warning: skipping const checks
+  --> $DIR/const_fn_ptr.rs:25:5
+   |
+LL |     assert_eq!(Y, 4);
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+warning: skipping const checks
+  --> $DIR/const_fn_ptr.rs:25:5
+   |
+LL |     assert_eq!(Y, 4);
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+warning: skipping const checks
+  --> $DIR/const_fn_ptr.rs:25:5
+   |
+LL |     assert_eq!(Y, 4);
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+warning: skipping const checks
+  --> $DIR/const_fn_ptr.rs:27:5
+   |
+LL |     assert_eq!(y, 4);
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+warning: skipping const checks
+  --> $DIR/const_fn_ptr.rs:27:5
+   |
+LL |     assert_eq!(y, 4);
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+warning: skipping const checks
+  --> $DIR/const_fn_ptr.rs:27:5
+   |
+LL |     assert_eq!(y, 4);
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+warning: skipping const checks
+  --> $DIR/const_fn_ptr.rs:29:5
+   |
+LL |     assert_eq!(y, 4);
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+warning: skipping const checks
+  --> $DIR/const_fn_ptr.rs:29:5
+   |
+LL |     assert_eq!(y, 4);
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+warning: skipping const checks
+  --> $DIR/const_fn_ptr.rs:29:5
+   |
+LL |     assert_eq!(y, 4);
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+warning: skipping const checks
+  --> $DIR/const_fn_ptr.rs:32:5
+   |
+LL |     assert_eq!(Z, 4);
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+warning: skipping const checks
+  --> $DIR/const_fn_ptr.rs:32:5
+   |
+LL |     assert_eq!(Z, 4);
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+warning: skipping const checks
+  --> $DIR/const_fn_ptr.rs:32:5
+   |
+LL |     assert_eq!(Z, 4);
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+warning: skipping const checks
+  --> $DIR/const_fn_ptr.rs:34:5
+   |
+LL |     assert_eq!(z, 4);
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+warning: skipping const checks
+  --> $DIR/const_fn_ptr.rs:34:5
+   |
+LL |     assert_eq!(z, 4);
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+warning: skipping const checks
+  --> $DIR/const_fn_ptr.rs:34:5
+   |
+LL |     assert_eq!(z, 4);
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+warning: skipping const checks
+  --> $DIR/const_fn_ptr.rs:36:5
+   |
+LL |     assert_eq!(z, 4);
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+warning: skipping const checks
+  --> $DIR/const_fn_ptr.rs:36:5
+   |
+LL |     assert_eq!(z, 4);
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+warning: skipping const checks
+  --> $DIR/const_fn_ptr.rs:36:5
+   |
+LL |     assert_eq!(z, 4);
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+warning: constant `X_const` should have an upper case name
+  --> $DIR/const_fn_ptr.rs:9:7
+   |
+LL | const X_const: fn(usize) -> usize = double_const;
+   |       ^^^^^^^ help: convert the identifier to upper case: `X_CONST`
+   |
+   = note: `#[warn(non_upper_case_globals)]` on by default
+
diff --git a/src/test/ui/consts/const-eval/const_fn_ptr_fail.rs b/src/test/ui/consts/const-eval/const_fn_ptr_fail.rs
new file mode 100644
index 00000000000..14bd6558e7f
--- /dev/null
+++ b/src/test/ui/consts/const-eval/const_fn_ptr_fail.rs
@@ -0,0 +1,13 @@
+// run-pass
+// compile-flags: -Zunleash-the-miri-inside-of-you
+#![feature(const_fn)]
+#![allow(unused)]
+
+fn double(x: usize) -> usize { x * 2 }
+const X: fn(usize) -> usize = double;
+
+const fn bar(x: usize) -> usize {
+    X(x) // FIXME: this should error someday
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs
new file mode 100644
index 00000000000..74c60f9a2a5
--- /dev/null
+++ b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs
@@ -0,0 +1,26 @@
+// compile-flags: -Zunleash-the-miri-inside-of-you
+#![feature(const_fn)]
+#![allow(const_err)]
+
+fn double(x: usize) -> usize { x * 2 }
+const X: fn(usize) -> usize = double;
+
+const fn bar(x: fn(usize) -> usize, y: usize) -> usize {
+    x(y)
+}
+
+const Y: usize = bar(X, 2); // FIXME: should fail to typeck someday
+const Z: usize = bar(double, 2); // FIXME: should fail to typeck someday
+
+fn main() {
+    assert_eq!(Y, 4);
+    //~^ ERROR evaluation of constant expression failed
+    //~^^ WARN skipping const checks
+    //~^^^ WARN skipping const checks
+    //~^^^^ WARN skipping const checks
+    assert_eq!(Z, 4);
+    //~^ ERROR evaluation of constant expression failed
+    //~^^ WARN skipping const checks
+    //~^^^ WARN skipping const checks
+    //~^^^^ WARN skipping const checks
+}
diff --git a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr
new file mode 100644
index 00000000000..611cc5313c0
--- /dev/null
+++ b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr
@@ -0,0 +1,71 @@
+warning: skipping const checks
+  --> $DIR/const_fn_ptr_fail2.rs:16:5
+   |
+LL |     assert_eq!(Y, 4);
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+warning: skipping const checks
+  --> $DIR/const_fn_ptr_fail2.rs:16:5
+   |
+LL |     assert_eq!(Y, 4);
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+warning: skipping const checks
+  --> $DIR/const_fn_ptr_fail2.rs:16:5
+   |
+LL |     assert_eq!(Y, 4);
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+warning: skipping const checks
+  --> $DIR/const_fn_ptr_fail2.rs:21:5
+   |
+LL |     assert_eq!(Z, 4);
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+warning: skipping const checks
+  --> $DIR/const_fn_ptr_fail2.rs:21:5
+   |
+LL |     assert_eq!(Z, 4);
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+warning: skipping const checks
+  --> $DIR/const_fn_ptr_fail2.rs:21:5
+   |
+LL |     assert_eq!(Z, 4);
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error[E0080]: evaluation of constant expression failed
+  --> $DIR/const_fn_ptr_fail2.rs:16:5
+   |
+LL |     assert_eq!(Y, 4);
+   |     ^^^^^^^^^^^-^^^^^
+   |                |
+   |                referenced constant has errors
+   |
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error[E0080]: evaluation of constant expression failed
+  --> $DIR/const_fn_ptr_fail2.rs:21:5
+   |
+LL |     assert_eq!(Z, 4);
+   |     ^^^^^^^^^^^-^^^^^
+   |                |
+   |                referenced constant has errors
+   |
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0080`.