From 9cf9030e1cc4c6231419f5e9f7a5bd42eb1f55c1 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Fri, 20 Sep 2019 18:39:13 +0200 Subject: [PATCH] Allow using fn pointers in const fn behind const_fn_ptr gate --- src/librustc_mir/transform/qualify_consts.rs | 20 ++++++++++--- src/libsyntax/feature_gate/active.rs | 3 ++ src/libsyntax_pos/symbol.rs | 1 + src/test/ui/consts/const-eval/const_fn_ptr.rs | 21 ++++++++++++++ .../ui/consts/const-eval/const_fn_ptr_fail.rs | 15 ++++++++++ .../const-eval/const_fn_ptr_fail.stderr | 20 +++++++++++++ .../consts/const-eval/const_fn_ptr_fail2.rs | 21 ++++++++++++++ .../const-eval/const_fn_ptr_fail2.stderr | 28 +++++++++++++++++++ .../const-eval/feature-gate-const_fn_ptr.rs | 11 ++++++++ .../feature-gate-const_fn_ptr.stderr | 12 ++++++++ 10 files changed, 148 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/consts/const-eval/const_fn_ptr.rs create mode 100644 src/test/ui/consts/const-eval/const_fn_ptr_fail.rs create mode 100644 src/test/ui/consts/const-eval/const_fn_ptr_fail.stderr create mode 100644 src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs create mode 100644 src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr create mode 100644 src/test/ui/consts/const-eval/feature-gate-const_fn_ptr.rs create mode 100644 src/test/ui/consts/const-eval/feature-gate-const_fn_ptr.stderr diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 7cc1e634cf8..3842942d97f 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -1407,11 +1407,23 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { } } ty::FnPtr(_) => { + let unleash_miri = self + .tcx + .sess + .opts + .debugging_opts + .unleash_the_miri_inside_of_you; + let const_fn_ptr = self.tcx.features().const_fn_ptr; if self.mode.requires_const_checking() { - let mut err = self.tcx.sess.struct_span_err( - self.span, - &format!("function pointers are not allowed in const fn")); - err.emit(); + if !(unleash_miri || const_fn_ptr) { + emit_feature_err( + &self.tcx.sess.parse_sess, + sym::const_fn_ptr, + self.span, + GateIssue::Language, + "function pointers in const fn are unstable", + ); + } } } _ => { diff --git a/src/libsyntax/feature_gate/active.rs b/src/libsyntax/feature_gate/active.rs index dd78777b569..d1a17dc14bd 100644 --- a/src/libsyntax/feature_gate/active.rs +++ b/src/libsyntax/feature_gate/active.rs @@ -405,6 +405,9 @@ declare_features! ( /// Allows macro invocations in `extern {}` blocks. (active, macros_in_extern, "1.27.0", Some(49476), None), + /// Allows calling function pointers inside `const` functions. + (active, const_fn_ptr, "1.27.0", Some(51909), None), + /// Allows accessing fields of unions inside `const` functions. (active, const_fn_union, "1.27.0", Some(51909), None), diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 597ae83572c..e6be8a2cb87 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -198,6 +198,7 @@ symbols! { const_compare_raw_pointers, const_constructor, const_fn, + const_fn_ptr, const_fn_union, const_generics, const_indexing, 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..1acb3d8ad10 --- /dev/null +++ b/src/test/ui/consts/const-eval/const_fn_ptr.rs @@ -0,0 +1,21 @@ +// run-pass +#![feature(const_fn)] +#![feature(const_fn_ptr)] + +const fn double(x: usize) -> usize { x * 2 } +const X: fn(usize) -> usize = double; + +const fn bar(x: usize) -> usize { + X(x) +} + +const fn foo(x: fn(usize) -> usize, y: usize) -> usize { + x(y) +} + +fn main() { + const Y: usize = bar(2); + assert_eq!(Y, 4); + const Z: usize = foo(double, 2); + assert_eq!(Z, 4); +} 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..e8041e56c38 --- /dev/null +++ b/src/test/ui/consts/const-eval/const_fn_ptr_fail.rs @@ -0,0 +1,15 @@ +// run-pass + +// FIXME: this should not pass + +#![feature(const_fn)] +#![feature(const_fn_ptr)] + +fn double(x: usize) -> usize { x * 2 } +const X: fn(usize) -> usize = double; + +const fn bar(x: usize) -> usize { + X(x) +} + +fn main() {} diff --git a/src/test/ui/consts/const-eval/const_fn_ptr_fail.stderr b/src/test/ui/consts/const-eval/const_fn_ptr_fail.stderr new file mode 100644 index 00000000000..b7f3a74cc44 --- /dev/null +++ b/src/test/ui/consts/const-eval/const_fn_ptr_fail.stderr @@ -0,0 +1,20 @@ +warning: function is never used: `double` + --> $DIR/const_fn_ptr_fail.rs:8:1 + | +LL | fn double(x: usize) -> usize { x * 2 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: constant item is never used: `X` + --> $DIR/const_fn_ptr_fail.rs:9:1 + | +LL | const X: fn(usize) -> usize = double; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: function is never used: `bar` + --> $DIR/const_fn_ptr_fail.rs:11:1 + | +LL | const fn bar(x: usize) -> usize { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 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..66e01cae314 --- /dev/null +++ b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs @@ -0,0 +1,21 @@ +#![feature(const_fn)] +#![feature(const_fn_ptr)] + +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); +//~^ ERROR any use of this value will cause an error + +const Z: usize = bar(double, 2); +//~^ ERROR any use of this value will cause an error + + +fn main() { + assert_eq!(Y, 4); + assert_eq!(Z, 4); +} 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..020889c2ca1 --- /dev/null +++ b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr @@ -0,0 +1,28 @@ +error: any use of this value will cause an error + --> $DIR/const_fn_ptr_fail2.rs:8:5 + | +LL | x(y) + | ^^^^ + | | + | calling non-const function `double` + | inside call to `bar` at $DIR/const_fn_ptr_fail2.rs:11:18 +... +LL | const Y: usize = bar(X, 2); + | --------------------------- + | + = note: `#[deny(const_err)]` on by default + +error: any use of this value will cause an error + --> $DIR/const_fn_ptr_fail2.rs:8:5 + | +LL | x(y) + | ^^^^ + | | + | calling non-const function `double` + | inside call to `bar` at $DIR/const_fn_ptr_fail2.rs:14:18 +... +LL | const Z: usize = bar(double, 2); + | -------------------------------- + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/consts/const-eval/feature-gate-const_fn_ptr.rs b/src/test/ui/consts/const-eval/feature-gate-const_fn_ptr.rs new file mode 100644 index 00000000000..ea1ca05c31b --- /dev/null +++ b/src/test/ui/consts/const-eval/feature-gate-const_fn_ptr.rs @@ -0,0 +1,11 @@ +#![feature(const_fn)] + +fn main() {} + +const fn foo() {} +const X: fn() = foo; + +const fn bar() { + X() + //~^ ERROR function pointers in const fn are unstable +} diff --git a/src/test/ui/consts/const-eval/feature-gate-const_fn_ptr.stderr b/src/test/ui/consts/const-eval/feature-gate-const_fn_ptr.stderr new file mode 100644 index 00000000000..fe5956d06f2 --- /dev/null +++ b/src/test/ui/consts/const-eval/feature-gate-const_fn_ptr.stderr @@ -0,0 +1,12 @@ +error[E0658]: function pointers in const fn are unstable + --> $DIR/feature-gate-const_fn_ptr.rs:9:5 + | +LL | X() + | ^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/51909 + = help: add `#![feature(const_fn_ptr)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`.