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(
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(
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.
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
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:
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
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;
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,
}
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() {
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
self.annotate(
ctor_hir_id,
i.span,
+ None,
AnnotationKind::Required,
InheritDeprecation::Yes,
InheritConstStability::No,
)
}
}
+ 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,
}
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,
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,
self.annotate(
var.id,
var.span,
+ None,
AnnotationKind::Required,
InheritDeprecation::Yes,
InheritConstStability::No,
v.annotate(
ctor_hir_id,
var.span,
+ None,
AnnotationKind::Required,
InheritDeprecation::Yes,
InheritConstStability::No,
self.annotate(
s.hir_id,
s.span,
+ None,
AnnotationKind::Required,
InheritDeprecation::Yes,
InheritConstStability::No,
self.annotate(
i.hir_id(),
i.span,
+ None,
AnnotationKind::Required,
InheritDeprecation::Yes,
InheritConstStability::No,
self.annotate(
md.hir_id(),
md.span,
+ None,
AnnotationKind::Required,
InheritDeprecation::Yes,
InheritConstStability::No,
self.annotate(
p.hir_id,
p.span,
+ None,
kind,
InheritDeprecation::No,
InheritConstStability::No,
annotator.annotate(
hir::CRATE_HIR_ID,
krate.item.inner,
+ None,
AnnotationKind::Required,
InheritDeprecation::Yes,
InheritConstStability::No,
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();
+}
--- /dev/null
+#![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() {}
--- /dev/null
+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
+
--- /dev/null
+// 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 }
+ }
+}