about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume1.gomez@gmail.com>2021-07-08 18:30:34 +0200
committerGitHub <noreply@github.com>2021-07-08 18:30:34 +0200
commitd85718ad01124abcb6a7cd2f958bae2285c933f1 (patch)
treee99e6e50e92ffc5d54e2613037e2e5ada83a2c7b
parentff4bf73a4274623e302fcde1f7914d6cf8da40e7 (diff)
parent07f903e0e0816821c41a19774f029086b557738b (diff)
downloadrust-d85718ad01124abcb6a7cd2f958bae2285c933f1.tar.gz
rust-d85718ad01124abcb6a7cd2f958bae2285c933f1.zip
Rollup merge of #86838 - lambinoo:I-69630-rust_const_unstable_check_const, r=oli-obk
Checking that function is const if marked with rustc_const_unstable

Fixes #69630

This one is still missing tests to check the behavior but I checked by hand and it seemed to work.
I would not mind some direction for writing those unit tests!
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0542.md4
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0545.md4
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0547.md4
-rw-r--r--compiler/rustc_passes/src/stability.rs61
-rw-r--r--src/test/ui/consts/rustc-const-stability-require-const.rs47
-rw-r--r--src/test/ui/consts/rustc-const-stability-require-const.stderr86
-rw-r--r--src/test/ui/consts/rustc-impl-const-stability.rs21
7 files changed, 220 insertions, 7 deletions
diff --git a/compiler/rustc_error_codes/src/error_codes/E0542.md b/compiler/rustc_error_codes/src/error_codes/E0542.md
index 7cb58f9d0cb..7fecfeaa57c 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0542.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0542.md
@@ -10,7 +10,7 @@ Erroneous code example:
 fn _stable_fn() {}
 
 #[rustc_const_stable(feature = "_stable_const_fn")] // invalid
-fn _stable_const_fn() {}
+const fn _stable_const_fn() {}
 
 #[stable(feature = "_deprecated_fn", since = "0.1.0")]
 #[rustc_deprecated(
@@ -29,7 +29,7 @@ To fix this issue, you need to provide the `since` field. Example:
 fn _stable_fn() {}
 
 #[rustc_const_stable(feature = "_stable_const_fn", since = "1.0.0")] // ok!
-fn _stable_const_fn() {}
+const fn _stable_const_fn() {}
 
 #[stable(feature = "_deprecated_fn", since = "0.1.0")]
 #[rustc_deprecated(
diff --git a/compiler/rustc_error_codes/src/error_codes/E0545.md b/compiler/rustc_error_codes/src/error_codes/E0545.md
index 9fb935a3ab1..7aba084f4d3 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0545.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0545.md
@@ -10,7 +10,7 @@ Erroneous code example:
 fn _unstable_fn() {}
 
 #[rustc_const_unstable(feature = "_unstable_const_fn", issue = "0")] // invalid
-fn _unstable_const_fn() {}
+const fn _unstable_const_fn() {}
 ```
 
 To fix this issue, you need to provide a correct value in the `issue` field.
@@ -24,7 +24,7 @@ Example:
 fn _unstable_fn() {}
 
 #[rustc_const_unstable(feature = "_unstable_const_fn", issue = "1")] // ok!
-fn _unstable_const_fn() {}
+const fn _unstable_const_fn() {}
 ```
 
 See the [How Rust is Made and “Nightly Rust”][how-rust-made-nightly] appendix
diff --git a/compiler/rustc_error_codes/src/error_codes/E0547.md b/compiler/rustc_error_codes/src/error_codes/E0547.md
index 1aa4b354248..4950325df64 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0547.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0547.md
@@ -10,7 +10,7 @@ Erroneous code example:
 fn _unstable_fn() {}
 
 #[rustc_const_unstable(feature = "_unstable_const_fn")] // invalid
-fn _unstable_const_fn() {}
+const fn _unstable_const_fn() {}
 ```
 
 To fix this issue, you need to provide the `issue` field. Example:
@@ -26,7 +26,7 @@ fn _unstable_fn() {}
     feature = "_unstable_const_fn",
     issue = "none"
 )] // ok!
-fn _unstable_const_fn() {}
+const fn _unstable_const_fn() {}
 ```
 
 See the [How Rust is Made and “Nightly Rust”][how-rust-made-nightly] appendix
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 5830245e837..cd8dd6984d5 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -20,6 +20,7 @@ use rustc_session::parse::feature_err;
 use rustc_session::Session;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::{Span, DUMMY_SP};
+use rustc_target::spec::abi::Abi;
 
 use std::cmp::Ordering;
 use std::iter;
@@ -95,10 +96,12 @@ struct Annotator<'a, 'tcx> {
 impl<'a, 'tcx> Annotator<'a, 'tcx> {
     // Determine the stability for a node based on its attributes and inherited
     // stability. The stability is recorded in the index and used as the parent.
+    // If the node is a function, `fn_sig` is its signature
     fn annotate<F>(
         &mut self,
         hir_id: HirId,
         item_sp: Span,
+        fn_sig: Option<&'tcx hir::FnSig<'tcx>>,
         kind: AnnotationKind,
         inherit_deprecation: InheritDeprecation,
         inherit_const_stability: InheritConstStability,
@@ -163,13 +166,30 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
         }
 
         let (stab, const_stab) = attr::find_stability(&self.tcx.sess, attrs, item_sp);
+        let mut const_span = None;
 
-        let const_stab = const_stab.map(|(const_stab, _)| {
+        let const_stab = const_stab.map(|(const_stab, const_span_node)| {
             let const_stab = self.tcx.intern_const_stability(const_stab);
             self.index.const_stab_map.insert(hir_id, const_stab);
+            const_span = Some(const_span_node);
             const_stab
         });
 
+        // If the current node is a function, has const stability attributes and if it doesn not have an intrinsic ABI,
+        // check if the function/method is const or the parent impl block is const
+        if let (Some(const_span), Some(fn_sig)) = (const_span, fn_sig) {
+            if fn_sig.header.abi != Abi::RustIntrinsic
+                && fn_sig.header.abi != Abi::PlatformIntrinsic
+                && !fn_sig.header.is_const()
+            {
+                if !self.in_trait_impl
+                    || (self.in_trait_impl && !self.tcx.is_const_fn_raw(hir_id.owner.to_def_id()))
+                {
+                    missing_const_err(&self.tcx.sess, fn_sig.span, const_span);
+                }
+            }
+        }
+
         // `impl const Trait for Type` items forward their const stability to their
         // immediate children.
         if const_stab.is_none() {
@@ -367,6 +387,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
         let orig_in_trait_impl = self.in_trait_impl;
         let mut kind = AnnotationKind::Required;
         let mut const_stab_inherit = InheritConstStability::No;
+        let mut fn_sig = None;
+
         match i.kind {
             // Inherent impls and foreign modules serve only as containers for other items,
             // they don't have their own stability. They still can be annotated as unstable
@@ -387,6 +409,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
                     self.annotate(
                         ctor_hir_id,
                         i.span,
+                        None,
                         AnnotationKind::Required,
                         InheritDeprecation::Yes,
                         InheritConstStability::No,
@@ -395,12 +418,16 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
                     )
                 }
             }
+            hir::ItemKind::Fn(ref item_fn_sig, _, _) => {
+                fn_sig = Some(item_fn_sig);
+            }
             _ => {}
         }
 
         self.annotate(
             i.hir_id(),
             i.span,
+            fn_sig,
             kind,
             InheritDeprecation::Yes,
             const_stab_inherit,
@@ -411,9 +438,15 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
     }
 
     fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
+        let fn_sig = match ti.kind {
+            hir::TraitItemKind::Fn(ref fn_sig, _) => Some(fn_sig),
+            _ => None,
+        };
+
         self.annotate(
             ti.hir_id(),
             ti.span,
+            fn_sig,
             AnnotationKind::Required,
             InheritDeprecation::Yes,
             InheritConstStability::No,
@@ -427,9 +460,16 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
     fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
         let kind =
             if self.in_trait_impl { AnnotationKind::Prohibited } else { AnnotationKind::Required };
+
+        let fn_sig = match ii.kind {
+            hir::ImplItemKind::Fn(ref fn_sig, _) => Some(fn_sig),
+            _ => None,
+        };
+
         self.annotate(
             ii.hir_id(),
             ii.span,
+            fn_sig,
             kind,
             InheritDeprecation::Yes,
             InheritConstStability::No,
@@ -444,6 +484,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
         self.annotate(
             var.id,
             var.span,
+            None,
             AnnotationKind::Required,
             InheritDeprecation::Yes,
             InheritConstStability::No,
@@ -453,6 +494,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
                     v.annotate(
                         ctor_hir_id,
                         var.span,
+                        None,
                         AnnotationKind::Required,
                         InheritDeprecation::Yes,
                         InheritConstStability::No,
@@ -470,6 +512,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
         self.annotate(
             s.hir_id,
             s.span,
+            None,
             AnnotationKind::Required,
             InheritDeprecation::Yes,
             InheritConstStability::No,
@@ -484,6 +527,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
         self.annotate(
             i.hir_id(),
             i.span,
+            None,
             AnnotationKind::Required,
             InheritDeprecation::Yes,
             InheritConstStability::No,
@@ -498,6 +542,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
         self.annotate(
             md.hir_id(),
             md.span,
+            None,
             AnnotationKind::Required,
             InheritDeprecation::Yes,
             InheritConstStability::No,
@@ -517,6 +562,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
         self.annotate(
             p.hir_id,
             p.span,
+            None,
             kind,
             InheritDeprecation::No,
             InheritConstStability::No,
@@ -687,6 +733,7 @@ fn stability_index(tcx: TyCtxt<'tcx>, (): ()) -> Index<'tcx> {
         annotator.annotate(
             hir::CRATE_HIR_ID,
             krate.item.inner,
+            None,
             AnnotationKind::Required,
             InheritDeprecation::Yes,
             InheritConstStability::No,
@@ -969,3 +1016,15 @@ fn duplicate_feature_err(sess: &Session, span: Span, feature: Symbol) {
     struct_span_err!(sess, span, E0636, "the feature `{}` has already been declared", feature)
         .emit();
 }
+
+fn missing_const_err(session: &Session, fn_sig_span: Span, const_span: Span) {
+    const ERROR_MSG: &'static str = "attributes `#[rustc_const_unstable]` \
+         and `#[rustc_const_stable]` require \
+         the function or method to be `const`";
+
+    session
+        .struct_span_err(fn_sig_span, ERROR_MSG)
+        .span_help(fn_sig_span, "make the function or method const")
+        .span_label(const_span, "attribute specified here")
+        .emit();
+}
diff --git a/src/test/ui/consts/rustc-const-stability-require-const.rs b/src/test/ui/consts/rustc-const-stability-require-const.rs
new file mode 100644
index 00000000000..4fb259b335c
--- /dev/null
+++ b/src/test/ui/consts/rustc-const-stability-require-const.rs
@@ -0,0 +1,47 @@
+#![crate_type = "lib"]
+#![feature(staged_api)]
+#![stable(feature = "foo", since = "1.0.0")]
+
+#[stable(feature = "foo", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_foo", issue = "none")]
+pub fn foo() {}
+//~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+
+#[stable(feature = "bar", since = "1.0.0")]
+#[rustc_const_stable(feature = "const_bar", since = "1.0.0")]
+pub fn bar() {}
+//~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+
+#[stable(feature = "potato", since = "1.0.0")]
+pub struct Potato;
+
+impl Potato {
+    #[stable(feature = "salad", since = "1.0.0")]
+    #[rustc_const_unstable(feature = "const_salad", issue = "none")]
+    pub fn salad(&self) -> &'static str { "mmmmmm" }
+    //~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+
+    #[stable(feature = "roasted", since = "1.0.0")]
+    #[rustc_const_unstable(feature = "const_roasted", issue = "none")]
+    pub fn roasted(&self) -> &'static str { "mmmmmmmmmm" }
+    //~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+}
+
+#[stable(feature = "bar", since = "1.0.0")]
+#[rustc_const_stable(feature = "const_bar", since = "1.0.0")]
+pub extern "C" fn bar_c() {}
+//~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+
+#[stable(feature = "foo", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_foo", issue = "none")]
+pub extern "C" fn foo_c() {}
+//~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+
+
+#[stable(feature = "foobar", since = "1.0.0")]
+#[rustc_const_unstable(feature = "foobar_const", issue = "none")]
+pub const fn foobar() {}
+
+#[stable(feature = "barfoo", since = "1.0.0")]
+#[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")]
+pub const fn barfoo() {}
diff --git a/src/test/ui/consts/rustc-const-stability-require-const.stderr b/src/test/ui/consts/rustc-const-stability-require-const.stderr
new file mode 100644
index 00000000000..1027b9311b7
--- /dev/null
+++ b/src/test/ui/consts/rustc-const-stability-require-const.stderr
@@ -0,0 +1,86 @@
+error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+  --> $DIR/rustc-const-stability-require-const.rs:7:1
+   |
+LL | #[rustc_const_unstable(feature = "const_foo", issue = "none")]
+   | -------------------------------------------------------------- attribute specified here
+LL | pub fn foo() {}
+   | ^^^^^^^^^^^^
+   |
+help: make the function or method const
+  --> $DIR/rustc-const-stability-require-const.rs:7:1
+   |
+LL | pub fn foo() {}
+   | ^^^^^^^^^^^^
+
+error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+  --> $DIR/rustc-const-stability-require-const.rs:12:1
+   |
+LL | #[rustc_const_stable(feature = "const_bar", since = "1.0.0")]
+   | ------------------------------------------------------------- attribute specified here
+LL | pub fn bar() {}
+   | ^^^^^^^^^^^^
+   |
+help: make the function or method const
+  --> $DIR/rustc-const-stability-require-const.rs:12:1
+   |
+LL | pub fn bar() {}
+   | ^^^^^^^^^^^^
+
+error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+  --> $DIR/rustc-const-stability-require-const.rs:21:5
+   |
+LL |     #[rustc_const_unstable(feature = "const_salad", issue = "none")]
+   |     ---------------------------------------------------------------- attribute specified here
+LL |     pub fn salad(&self) -> &'static str { "mmmmmm" }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: make the function or method const
+  --> $DIR/rustc-const-stability-require-const.rs:21:5
+   |
+LL |     pub fn salad(&self) -> &'static str { "mmmmmm" }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+  --> $DIR/rustc-const-stability-require-const.rs:26:5
+   |
+LL |     #[rustc_const_unstable(feature = "const_roasted", issue = "none")]
+   |     ------------------------------------------------------------------ attribute specified here
+LL |     pub fn roasted(&self) -> &'static str { "mmmmmmmmmm" }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: make the function or method const
+  --> $DIR/rustc-const-stability-require-const.rs:26:5
+   |
+LL |     pub fn roasted(&self) -> &'static str { "mmmmmmmmmm" }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+  --> $DIR/rustc-const-stability-require-const.rs:32:1
+   |
+LL | #[rustc_const_stable(feature = "const_bar", since = "1.0.0")]
+   | ------------------------------------------------------------- attribute specified here
+LL | pub extern "C" fn bar_c() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: make the function or method const
+  --> $DIR/rustc-const-stability-require-const.rs:32:1
+   |
+LL | pub extern "C" fn bar_c() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+  --> $DIR/rustc-const-stability-require-const.rs:37:1
+   |
+LL | #[rustc_const_unstable(feature = "const_foo", issue = "none")]
+   | -------------------------------------------------------------- attribute specified here
+LL | pub extern "C" fn foo_c() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: make the function or method const
+  --> $DIR/rustc-const-stability-require-const.rs:37:1
+   |
+LL | pub extern "C" fn foo_c() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
+
diff --git a/src/test/ui/consts/rustc-impl-const-stability.rs b/src/test/ui/consts/rustc-impl-const-stability.rs
new file mode 100644
index 00000000000..01daa1c9cb4
--- /dev/null
+++ b/src/test/ui/consts/rustc-impl-const-stability.rs
@@ -0,0 +1,21 @@
+// build-pass
+
+#![crate_type = "lib"]
+#![allow(incomplete_features)]
+#![feature(staged_api)]
+#![feature(const_trait_impl)]
+#![stable(feature = "foo", since = "1.0.0")]
+
+
+#[stable(feature = "potato", since = "1.27.0")]
+pub struct Data {
+    _data: u128
+}
+
+#[stable(feature = "potato", since = "1.27.0")]
+impl const Default for Data {
+    #[rustc_const_unstable(feature = "data_foo", issue = "none")]
+    fn default() -> Data {
+        Data { _data: 42 }
+    }
+}