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!
This commit is contained in:
commit
d85718ad01
7 changed files with 220 additions and 7 deletions
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
47
src/test/ui/consts/rustc-const-stability-require-const.rs
Normal file
47
src/test/ui/consts/rustc-const-stability-require-const.rs
Normal file
|
@ -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() {}
|
|
@ -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
|
||||
|
21
src/test/ui/consts/rustc-impl-const-stability.rs
Normal file
21
src/test/ui/consts/rustc-impl-const-stability.rs
Normal file
|
@ -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 }
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue