]> git.lizzy.rs Git - rust.git/commitdiff
Fix const_fn ICE with non-const function pointer
authorPhilipp Hansch <dev@phansch.net>
Fri, 30 Nov 2018 07:43:50 +0000 (08:43 +0100)
committerPhilipp Hansch <dev@phansch.net>
Fri, 30 Nov 2018 07:43:50 +0000 (08:43 +0100)
src/librustc_mir/transform/qualify_consts.rs
src/test/ui/consts/issue-56164.rs [new file with mode: 0644]
src/test/ui/consts/issue-56164.stderr [new file with mode: 0644]

index 09fe7b14c7973896c0c274a0d8c0b6398ab6b05f..3ad0c41d795a73cebac1241ad08bf7f68b653b28 100644 (file)
@@ -895,145 +895,160 @@ fn visit_terminator_kind(&mut self,
             let mut is_shuffle = false;
             let mut is_const_fn = false;
             let mut is_promotable_const_fn = false;
-            if let ty::FnDef(def_id, _) = fn_ty.sty {
-                callee_def_id = Some(def_id);
-                match self.tcx.fn_sig(def_id).abi() {
-                    Abi::RustIntrinsic |
-                    Abi::PlatformIntrinsic => {
-                        assert!(!self.tcx.is_const_fn(def_id));
-                        match &self.tcx.item_name(def_id).as_str()[..] {
-                            | "size_of"
-                            | "min_align_of"
-                            | "needs_drop"
-                            | "type_id"
-                            | "bswap"
-                            | "bitreverse"
-                            | "ctpop"
-                            | "cttz"
-                            | "cttz_nonzero"
-                            | "ctlz"
-                            | "ctlz_nonzero"
-                            | "overflowing_add"
-                            | "overflowing_sub"
-                            | "overflowing_mul"
-                            | "unchecked_shl"
-                            | "unchecked_shr"
-                            | "rotate_left"
-                            | "rotate_right"
-                            | "add_with_overflow"
-                            | "sub_with_overflow"
-                            | "mul_with_overflow"
-                            // no need to check feature gates, intrinsics are only callable from the
-                            // libstd or with forever unstable feature gates
-                            => is_const_fn = true,
-                            // special intrinsic that can be called diretly without an intrinsic
-                            // feature gate needs a language feature gate
-                            "transmute" => {
-                                // never promote transmute calls
-                                if self.mode != Mode::Fn {
-                                    is_const_fn = true;
-                                    // const eval transmute calls only with the feature gate
-                                    if !self.tcx.features().const_transmute {
-                                        emit_feature_err(
-                                            &self.tcx.sess.parse_sess, "const_transmute",
-                                            self.span, GateIssue::Language,
-                                            &format!("The use of std::mem::transmute() \
-                                            is gated in {}s", self.mode));
+            match fn_ty.sty {
+                ty::FnDef(def_id, _) => {
+                    callee_def_id = Some(def_id);
+                    match self.tcx.fn_sig(def_id).abi() {
+                        Abi::RustIntrinsic |
+                        Abi::PlatformIntrinsic => {
+                            assert!(!self.tcx.is_const_fn(def_id));
+                            match &self.tcx.item_name(def_id).as_str()[..] {
+                                | "size_of"
+                                | "min_align_of"
+                                | "needs_drop"
+                                | "type_id"
+                                | "bswap"
+                                | "bitreverse"
+                                | "ctpop"
+                                | "cttz"
+                                | "cttz_nonzero"
+                                | "ctlz"
+                                | "ctlz_nonzero"
+                                | "overflowing_add"
+                                | "overflowing_sub"
+                                | "overflowing_mul"
+                                | "unchecked_shl"
+                                | "unchecked_shr"
+                                | "rotate_left"
+                                | "rotate_right"
+                                | "add_with_overflow"
+                                | "sub_with_overflow"
+                                | "mul_with_overflow"
+                                // no need to check feature gates, intrinsics are only callable from the
+                                // libstd or with forever unstable feature gates
+                                => is_const_fn = true,
+                                // special intrinsic that can be called diretly without an intrinsic
+                                // feature gate needs a language feature gate
+                                "transmute" => {
+                                    // never promote transmute calls
+                                    if self.mode != Mode::Fn {
+                                        is_const_fn = true;
+                                        // const eval transmute calls only with the feature gate
+                                        if !self.tcx.features().const_transmute {
+                                            emit_feature_err(
+                                                &self.tcx.sess.parse_sess, "const_transmute",
+                                                self.span, GateIssue::Language,
+                                                &format!("The use of std::mem::transmute() \
+                                                is gated in {}s", self.mode));
+                                        }
                                     }
                                 }
-                            }
 
-                            name if name.starts_with("simd_shuffle") => {
-                                is_shuffle = true;
-                            }
+                                name if name.starts_with("simd_shuffle") => {
+                                    is_shuffle = true;
+                                }
 
-                            _ => {}
-                        }
-                    }
-                    _ => {
-                        // in normal functions we only care about promotion
-                        if self.mode == Mode::Fn {
-                            // never promote const fn calls of
-                            // functions without #[rustc_promotable]
-                            if self.tcx.is_promotable_const_fn(def_id) {
-                                is_const_fn = true;
-                                is_promotable_const_fn = true;
-                            } else if self.tcx.is_const_fn(def_id) {
-                                is_const_fn = true;
+                                _ => {}
                             }
-                        } else {
-                            // stable const fn or unstable const fns with their feature gate
-                            // active
-                            if self.tcx.is_const_fn(def_id) {
-                                is_const_fn = true;
-                            } else if self.is_const_panic_fn(def_id) {
-                                // check the const_panic feature gate
-                                // FIXME: cannot allow this inside `allow_internal_unstable` because
-                                // that would make `panic!` insta stable in constants, since the
-                                // macro is marked with the attr
-                                if self.tcx.features().const_panic {
+                        }
+                        _ => {
+                            // in normal functions we only care about promotion
+                            if self.mode == Mode::Fn {
+                                // never promote const fn calls of
+                                // functions without #[rustc_promotable]
+                                if self.tcx.is_promotable_const_fn(def_id) {
                                     is_const_fn = true;
-                                } else {
-                                    // don't allow panics in constants without the feature gate
-                                    emit_feature_err(
-                                        &self.tcx.sess.parse_sess,
-                                        "const_panic",
-                                        self.span,
-                                        GateIssue::Language,
-                                        &format!("panicking in {}s is unstable", self.mode),
-                                    );
-                                }
-                            } else if let Some(feature) = self.tcx.is_unstable_const_fn(def_id) {
-                                // check `#[unstable]` const fns or `#[rustc_const_unstable]`
-                                // functions without the feature gate active in this crate to report
-                                // a better error message than the one below
-                                if self.span.allows_unstable() {
-                                    // `allow_internal_unstable` can make such calls stable
+                                    is_promotable_const_fn = true;
+                                } else if self.tcx.is_const_fn(def_id) {
                                     is_const_fn = true;
-                                } else {
-                                    let mut err = self.tcx.sess.struct_span_err(self.span,
-                                        &format!("`{}` is not yet stable as a const fn",
-                                                self.tcx.item_path_str(def_id)));
-                                    help!(&mut err,
-                                        "in Nightly builds, add `#![feature({})]` \
-                                        to the crate attributes to enable",
-                                        feature);
-                                    err.emit();
                                 }
                             } else {
-                                // FIXME(#24111) Remove this check when const fn stabilizes
-                                let (msg, note) = if let UnstableFeatures::Disallow =
-                                        self.tcx.sess.opts.unstable_features {
-                                    (format!("calls in {}s are limited to \
-                                            tuple structs and tuple variants",
-                                            self.mode),
-                                    Some("a limited form of compile-time function \
-                                        evaluation is available on a nightly \
-                                        compiler via `const fn`"))
+                                // stable const fn or unstable const fns with their feature gate
+                                // active
+                                if self.tcx.is_const_fn(def_id) {
+                                    is_const_fn = true;
+                                } else if self.is_const_panic_fn(def_id) {
+                                    // check the const_panic feature gate
+                                    // FIXME: cannot allow this inside `allow_internal_unstable` because
+                                    // that would make `panic!` insta stable in constants, since the
+                                    // macro is marked with the attr
+                                    if self.tcx.features().const_panic {
+                                        is_const_fn = true;
+                                    } else {
+                                        // don't allow panics in constants without the feature gate
+                                        emit_feature_err(
+                                            &self.tcx.sess.parse_sess,
+                                            "const_panic",
+                                            self.span,
+                                            GateIssue::Language,
+                                            &format!("panicking in {}s is unstable", self.mode),
+                                        );
+                                    }
+                                } else if let Some(feature) = self.tcx.is_unstable_const_fn(def_id) {
+                                    // check `#[unstable]` const fns or `#[rustc_const_unstable]`
+                                    // functions without the feature gate active in this crate to report
+                                    // a better error message than the one below
+                                    if self.span.allows_unstable() {
+                                        // `allow_internal_unstable` can make such calls stable
+                                        is_const_fn = true;
+                                    } else {
+                                        let mut err = self.tcx.sess.struct_span_err(self.span,
+                                            &format!("`{}` is not yet stable as a const fn",
+                                                    self.tcx.item_path_str(def_id)));
+                                        help!(&mut err,
+                                            "in Nightly builds, add `#![feature({})]` \
+                                            to the crate attributes to enable",
+                                            feature);
+                                        err.emit();
+                                    }
                                 } else {
-                                    (format!("calls in {}s are limited \
-                                            to constant functions, \
-                                            tuple structs and tuple variants",
-                                            self.mode),
-                                    None)
-                                };
-                                let mut err = struct_span_err!(
-                                    self.tcx.sess,
-                                    self.span,
-                                    E0015,
-                                    "{}",
-                                    msg,
-                                );
-                                if let Some(note) = note {
-                                    err.span_note(self.span, note);
+                                    // FIXME(#24111) Remove this check when const fn stabilizes
+                                    let (msg, note) = if let UnstableFeatures::Disallow =
+                                            self.tcx.sess.opts.unstable_features {
+                                        (format!("calls in {}s are limited to \
+                                                tuple structs and tuple variants",
+                                                self.mode),
+                                        Some("a limited form of compile-time function \
+                                            evaluation is available on a nightly \
+                                            compiler via `const fn`"))
+                                    } else {
+                                        (format!("calls in {}s are limited \
+                                                to constant functions, \
+                                                tuple structs and tuple variants",
+                                                self.mode),
+                                        None)
+                                    };
+                                    let mut err = struct_span_err!(
+                                        self.tcx.sess,
+                                        self.span,
+                                        E0015,
+                                        "{}",
+                                        msg,
+                                    );
+                                    if let Some(note) = note {
+                                        err.span_note(self.span, note);
+                                    }
+                                    err.emit();
                                 }
-                                err.emit();
                             }
                         }
                     }
+                },
+                ty::FnPtr(_) => {
+                    if self.mode != Mode::Fn {
+                        let mut err = self.tcx.sess.struct_span_err(
+                            self.span,
+                            &format!("function pointers are not allowed in const fn"));
+                        err.emit();
+                    }
+                },
+                _ => {
+                    self.not_const();
+                    return
                 }
             }
 
+
             let constant_arguments = callee_def_id.and_then(|id| {
                 args_required_const(self.tcx, id)
             });
diff --git a/src/test/ui/consts/issue-56164.rs b/src/test/ui/consts/issue-56164.rs
new file mode 100644 (file)
index 0000000..9d1a8b5
--- /dev/null
@@ -0,0 +1,13 @@
+#![feature(const_fn)]
+
+const fn foo() { (||{})() }
+//~^ ERROR calls in constant functions are limited to constant functions, tuple structs and tuple
+// variants
+
+const fn bad(input: fn()) {
+    input()
+    //~^ ERROR function pointers are not allowed in const fn
+}
+
+fn main() {
+}
diff --git a/src/test/ui/consts/issue-56164.stderr b/src/test/ui/consts/issue-56164.stderr
new file mode 100644 (file)
index 0000000..d3e9ce3
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+  --> $DIR/issue-56164.rs:3:18
+   |
+LL | const fn foo() { (||{})() }
+   |                  ^^^^^^^^
+
+error: function pointers are not allowed in const fn
+  --> $DIR/issue-56164.rs:8:5
+   |
+LL |     input()
+   |     ^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0015`.