Auto merge of #97177 - oli-obk:const-stability, r=davidtwco
Implement proper stability check for const impl Trait, fall back to unstable const when undeclared Continuation of #93960 `@jhpratt` it looks to me like the test was simply not testing for the failure you were looking for? Your checks actually do the right thing for const traits?
This commit is contained in:
commit
acfd327fd4
22 changed files with 259 additions and 168 deletions
|
@ -101,6 +101,16 @@ pub struct Stability {
|
|||
pub feature: Symbol,
|
||||
}
|
||||
|
||||
impl Stability {
|
||||
pub fn is_unstable(&self) -> bool {
|
||||
self.level.is_unstable()
|
||||
}
|
||||
|
||||
pub fn is_stable(&self) -> bool {
|
||||
self.level.is_stable()
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the `#[rustc_const_unstable]` and `#[rustc_const_stable]` attributes.
|
||||
#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[derive(HashStable_Generic)]
|
||||
|
@ -111,6 +121,16 @@ pub struct ConstStability {
|
|||
pub promotable: bool,
|
||||
}
|
||||
|
||||
impl ConstStability {
|
||||
pub fn is_const_unstable(&self) -> bool {
|
||||
self.level.is_unstable()
|
||||
}
|
||||
|
||||
pub fn is_const_stable(&self) -> bool {
|
||||
self.level.is_stable()
|
||||
}
|
||||
}
|
||||
|
||||
/// The available stability levels.
|
||||
#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
|
||||
#[derive(HashStable_Generic)]
|
||||
|
|
|
@ -9,7 +9,7 @@ use rustc_span::symbol::Symbol;
|
|||
pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Symbol> {
|
||||
if tcx.is_const_fn_raw(def_id) {
|
||||
let const_stab = tcx.lookup_const_stability(def_id)?;
|
||||
if const_stab.level.is_unstable() { Some(const_stab.feature) } else { None }
|
||||
if const_stab.is_const_unstable() { Some(const_stab.feature) } else { None }
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
|
@ -229,18 +229,6 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
|
|||
|
||||
// The local type and predicate checks are not free and only relevant for `const fn`s.
|
||||
if self.const_kind() == hir::ConstContext::ConstFn {
|
||||
// Prevent const trait methods from being annotated as `stable`.
|
||||
// FIXME: Do this as part of stability checking.
|
||||
if self.is_const_stable_const_fn() {
|
||||
if crate::const_eval::is_parent_const_impl_raw(tcx, def_id) {
|
||||
self.ccx
|
||||
.tcx
|
||||
.sess
|
||||
.struct_span_err(self.span, "trait methods cannot be stable const fn")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
for (idx, local) in body.local_decls.iter_enumerated() {
|
||||
// Handle the return place below.
|
||||
if idx == RETURN_PLACE || local.internal {
|
||||
|
@ -944,7 +932,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
// have no `rustc_const_stable` attributes to be const-unstable as well. This
|
||||
// should be fixed later.
|
||||
let callee_is_unstable_unmarked = tcx.lookup_const_stability(callee).is_none()
|
||||
&& tcx.lookup_stability(callee).map_or(false, |s| s.level.is_unstable());
|
||||
&& tcx.lookup_stability(callee).map_or(false, |s| s.is_unstable());
|
||||
if callee_is_unstable_unmarked {
|
||||
trace!("callee_is_unstable_unmarked");
|
||||
// We do not use `const` modifiers for intrinsic "functions", as intrinsics are
|
||||
|
|
|
@ -84,8 +84,6 @@ pub fn rustc_allow_const_fn_unstable(
|
|||
// functions are subject to more stringent restrictions than "const-unstable" functions: They
|
||||
// cannot use unstable features and can only call other "const-stable" functions.
|
||||
pub fn is_const_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||
use attr::{ConstStability, Stability, StabilityLevel};
|
||||
|
||||
// A default body marked const is not const-stable because const
|
||||
// trait fns currently cannot be const-stable. We shouldn't
|
||||
// restrict default bodies to only call const-stable functions.
|
||||
|
@ -96,22 +94,39 @@ pub fn is_const_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
|||
// Const-stability is only relevant for `const fn`.
|
||||
assert!(tcx.is_const_fn_raw(def_id));
|
||||
|
||||
// Functions with `#[rustc_const_unstable]` are const-unstable.
|
||||
// A function is only const-stable if it has `#[rustc_const_stable]` or it the trait it belongs
|
||||
// to is const-stable.
|
||||
match tcx.lookup_const_stability(def_id) {
|
||||
Some(ConstStability { level: StabilityLevel::Unstable { .. }, .. }) => return false,
|
||||
Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => return true,
|
||||
None => {}
|
||||
Some(stab) => stab.is_const_stable(),
|
||||
None if is_parent_const_stable_trait(tcx, def_id) => {
|
||||
// Remove this when `#![feature(const_trait_impl)]` is stabilized,
|
||||
// returning `true` unconditionally.
|
||||
tcx.sess.delay_span_bug(
|
||||
tcx.def_span(def_id),
|
||||
"trait implementations cannot be const stable yet",
|
||||
);
|
||||
true
|
||||
}
|
||||
None => false, // By default, items are not const stable.
|
||||
}
|
||||
}
|
||||
|
||||
// Functions with `#[unstable]` are const-unstable.
|
||||
//
|
||||
// FIXME(ecstaticmorse): We should keep const-stability attributes wholly separate from normal stability
|
||||
// attributes. `#[unstable]` should be irrelevant.
|
||||
if let Some(Stability { level: StabilityLevel::Unstable { .. }, .. }) =
|
||||
tcx.lookup_stability(def_id)
|
||||
{
|
||||
fn is_parent_const_stable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||
let local_def_id = def_id.expect_local();
|
||||
let hir_id = tcx.local_def_id_to_hir_id(local_def_id);
|
||||
|
||||
let Some(parent) = tcx.hir().find_parent_node(hir_id) else { return false };
|
||||
let parent_def = tcx.hir().get(parent);
|
||||
|
||||
if !matches!(
|
||||
parent_def,
|
||||
hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Impl(hir::Impl { constness: hir::Constness::Const, .. }),
|
||||
..
|
||||
})
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
tcx.lookup_const_stability(parent.owner).map_or(false, |stab| stab.is_const_stable())
|
||||
}
|
||||
|
|
|
@ -2791,7 +2791,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
pub fn is_const_fn(self, def_id: DefId) -> bool {
|
||||
if self.is_const_fn_raw(def_id) {
|
||||
match self.lookup_const_stability(def_id) {
|
||||
Some(stability) if stability.level.is_unstable() => {
|
||||
Some(stability) if stability.is_const_unstable() => {
|
||||
// has a `rustc_const_unstable` attribute, check whether the user enabled the
|
||||
// corresponding feature gate.
|
||||
self.features()
|
||||
|
@ -2808,6 +2808,21 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether the trait impl is marked const. This does not consider stability or feature gates.
|
||||
pub fn is_const_trait_impl_raw(self, def_id: DefId) -> bool {
|
||||
let Some(local_def_id) = def_id.as_local() else { return false };
|
||||
let hir_id = self.local_def_id_to_hir_id(local_def_id);
|
||||
let node = self.hir().get(hir_id);
|
||||
|
||||
matches!(
|
||||
node,
|
||||
hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Impl(hir::Impl { constness: hir::Constness::Const, .. }),
|
||||
..
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TyCtxtAt<'tcx> {
|
||||
|
|
|
@ -147,7 +147,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
|
|||
// Propagate unstability. This can happen even for non-staged-api crates in case
|
||||
// -Zforce-unstable-if-unmarked is set.
|
||||
if let Some(stab) = self.parent_stab {
|
||||
if inherit_deprecation.yes() && stab.level.is_unstable() {
|
||||
if inherit_deprecation.yes() && stab.is_unstable() {
|
||||
self.index.stab_map.insert(def_id, stab);
|
||||
}
|
||||
}
|
||||
|
@ -190,7 +190,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
|
|||
if const_stab.is_none() {
|
||||
debug!("annotate: const_stab not found, parent = {:?}", self.parent_const_stab);
|
||||
if let Some(parent) = self.parent_const_stab {
|
||||
if parent.level.is_unstable() {
|
||||
if parent.is_const_unstable() {
|
||||
self.index.const_stab_map.insert(def_id, parent);
|
||||
}
|
||||
}
|
||||
|
@ -272,9 +272,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
|
|||
if stab.is_none() {
|
||||
debug!("annotate: stab not found, parent = {:?}", self.parent_stab);
|
||||
if let Some(stab) = self.parent_stab {
|
||||
if inherit_deprecation.yes() && stab.level.is_unstable()
|
||||
|| inherit_from_parent.yes()
|
||||
{
|
||||
if inherit_deprecation.yes() && stab.is_unstable() || inherit_from_parent.yes() {
|
||||
self.index.stab_map.insert(def_id, stab);
|
||||
}
|
||||
}
|
||||
|
@ -532,7 +530,8 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> {
|
|||
return;
|
||||
}
|
||||
|
||||
let is_const = self.tcx.is_const_fn(def_id.to_def_id());
|
||||
let is_const = self.tcx.is_const_fn(def_id.to_def_id())
|
||||
|| self.tcx.is_const_trait_impl_raw(def_id.to_def_id());
|
||||
let is_stable = self
|
||||
.tcx
|
||||
.lookup_stability(def_id)
|
||||
|
@ -710,16 +709,23 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
|
|||
// For implementations of traits, check the stability of each item
|
||||
// individually as it's possible to have a stable trait with unstable
|
||||
// items.
|
||||
hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref t), self_ty, items, .. }) => {
|
||||
if self.tcx.features().staged_api {
|
||||
hir::ItemKind::Impl(hir::Impl {
|
||||
of_trait: Some(ref t),
|
||||
self_ty,
|
||||
items,
|
||||
constness,
|
||||
..
|
||||
}) => {
|
||||
let features = self.tcx.features();
|
||||
if features.staged_api {
|
||||
let attrs = self.tcx.hir().attrs(item.hir_id());
|
||||
let (stab, const_stab) = attr::find_stability(&self.tcx.sess, attrs, item.span);
|
||||
|
||||
// If this impl block has an #[unstable] attribute, give an
|
||||
// error if all involved types and traits are stable, because
|
||||
// it will have no effect.
|
||||
// See: https://github.com/rust-lang/rust/issues/55436
|
||||
let attrs = self.tcx.hir().attrs(item.hir_id());
|
||||
if let (Some((Stability { level: attr::Unstable { .. }, .. }, span)), _) =
|
||||
attr::find_stability(&self.tcx.sess, attrs, item.span)
|
||||
{
|
||||
if let Some((Stability { level: attr::Unstable { .. }, .. }, span)) = stab {
|
||||
let mut c = CheckTraitImplStable { tcx: self.tcx, fully_stable: true };
|
||||
c.visit_ty(self_ty);
|
||||
c.visit_trait_ref(t);
|
||||
|
@ -735,6 +741,19 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
// `#![feature(const_trait_impl)]` is unstable, so any impl declared stable
|
||||
// needs to have an error emitted.
|
||||
if features.const_trait_impl
|
||||
&& *constness == hir::Constness::Const
|
||||
&& const_stab.map_or(false, |(stab, _)| stab.is_const_stable())
|
||||
{
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(item.span, "trait implementations cannot be const stable yet")
|
||||
.note("see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
for impl_item_ref in *items {
|
||||
|
|
|
@ -344,7 +344,7 @@ pub(crate) fn build_impl(
|
|||
}
|
||||
|
||||
if let Some(stab) = tcx.lookup_stability(did) {
|
||||
if stab.level.is_unstable() && stab.feature == sym::rustc_private {
|
||||
if stab.is_unstable() && stab.feature == sym::rustc_private {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -373,7 +373,7 @@ pub(crate) fn build_impl(
|
|||
}
|
||||
|
||||
if let Some(stab) = tcx.lookup_stability(did) {
|
||||
if stab.level.is_unstable() && stab.feature == sym::rustc_private {
|
||||
if stab.is_unstable() && stab.feature == sym::rustc_private {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -632,7 +632,7 @@ impl Item {
|
|||
self.stability(tcx).as_ref().and_then(|s| {
|
||||
let mut classes = Vec::with_capacity(2);
|
||||
|
||||
if s.level.is_unstable() {
|
||||
if s.is_unstable() {
|
||||
classes.push("unstable");
|
||||
}
|
||||
|
||||
|
|
|
@ -445,10 +445,7 @@ fn extra_info_tags(item: &clean::Item, parent: &clean::Item, tcx: TyCtxt<'_>) ->
|
|||
|
||||
// The "rustc_private" crates are permanently unstable so it makes no sense
|
||||
// to render "unstable" everywhere.
|
||||
if item
|
||||
.stability(tcx)
|
||||
.as_ref()
|
||||
.map(|s| s.level.is_unstable() && s.feature != sym::rustc_private)
|
||||
if item.stability(tcx).as_ref().map(|s| s.is_unstable() && s.feature != sym::rustc_private)
|
||||
== Some(true)
|
||||
{
|
||||
tags += &tag_html("unstable", "", "Experimental");
|
||||
|
|
|
@ -1,19 +1,18 @@
|
|||
// build-pass
|
||||
// check-pass
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![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
|
||||
_data: u128,
|
||||
}
|
||||
|
||||
#[stable(feature = "potato", since = "1.27.0")]
|
||||
#[rustc_const_unstable(feature = "data_foo", issue = "none")]
|
||||
impl const Default for Data {
|
||||
#[rustc_const_unstable(feature = "data_foo", issue = "none")]
|
||||
fn default() -> Data {
|
||||
Data { _data: 42 }
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#![feature(const_trait_impl)]
|
||||
|
||||
#![feature(staged_api)]
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
|
@ -13,9 +12,7 @@ pub trait MyTrait {
|
|||
pub struct Unstable;
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_const_unstable(feature = "staged", issue = "none")]
|
||||
#[rustc_const_unstable(feature = "unstable", issue = "none")]
|
||||
impl const MyTrait for Unstable {
|
||||
fn func() {
|
||||
|
||||
}
|
||||
fn func() {}
|
||||
}
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
#![feature(allow_internal_unstable)]
|
||||
#![feature(const_add)]
|
||||
#![feature(const_trait_impl)]
|
||||
#![feature(staged_api)]
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct Int(i32);
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
|
||||
impl const std::ops::Sub for Int {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self {
|
||||
//~^ ERROR trait methods cannot be stable const fn
|
||||
Int(self.0 - rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_const_unstable(feature = "const_add", issue = "none")]
|
||||
impl const std::ops::Add for Int {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: Self) -> Self {
|
||||
Int(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
|
||||
pub const fn foo() -> Int {
|
||||
Int(1i32) + Int(2i32)
|
||||
//~^ ERROR not yet stable as a const fn
|
||||
}
|
||||
|
||||
// ok
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_const_unstable(feature = "bar", issue = "none")]
|
||||
pub const fn bar() -> Int {
|
||||
Int(1i32) + Int(2i32)
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -1,19 +0,0 @@
|
|||
error: trait methods cannot be stable const fn
|
||||
--> $DIR/stability.rs:15:5
|
||||
|
|
||||
LL | / fn sub(self, rhs: Self) -> Self {
|
||||
LL | |
|
||||
LL | | Int(self.0 - rhs.0)
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
||||
error: `<Int as Add>::add` is not yet stable as a const fn
|
||||
--> $DIR/stability.rs:34:5
|
||||
|
|
||||
LL | Int(1i32) + Int(2i32)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: const-stable functions can only call other const-stable functions
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// aux-build: staged-api.rs
|
||||
extern crate staged_api;
|
||||
|
||||
use staged_api::*;
|
||||
|
||||
// Const stability has no impact on usage in non-const contexts.
|
||||
fn non_const_context() {
|
||||
Unstable::func();
|
||||
}
|
||||
|
||||
const fn stable_const_context() {
|
||||
Unstable::func();
|
||||
//~^ ERROR cannot call non-const fn `<staged_api::Unstable as staged_api::MyTrait>::func` in constant functions
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,11 @@
|
|||
error[E0015]: cannot call non-const fn `<staged_api::Unstable as staged_api::MyTrait>::func` in constant functions
|
||||
--> $DIR/staged-api-user-crate.rs:12:5
|
||||
|
|
||||
LL | Unstable::func();
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0015`.
|
|
@ -1,9 +1,7 @@
|
|||
// revisions: stock staged
|
||||
#![cfg_attr(staged, feature(staged))]
|
||||
// revisions: stable unstable
|
||||
|
||||
#![cfg_attr(unstable, feature(unstable))] // The feature from the ./auxiliary/staged-api.rs file.
|
||||
#![feature(const_trait_impl)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
#![feature(staged_api)]
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
|
@ -13,27 +11,53 @@ extern crate staged_api;
|
|||
use staged_api::*;
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct Stable;
|
||||
pub struct Foo;
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg_attr(staged, rustc_const_stable(feature = "rust1", since = "1.0.0"))]
|
||||
// ^ should trigger error with or without the attribute
|
||||
impl const MyTrait for Stable {
|
||||
fn func() { //~ ERROR trait methods cannot be stable const fn
|
||||
|
||||
}
|
||||
#[cfg_attr(unstable, rustc_const_unstable(feature = "foo", issue = "none"))]
|
||||
#[cfg_attr(stable, rustc_const_stable(feature = "foo", since = "1.0.0"))]
|
||||
impl const MyTrait for Foo {
|
||||
//[stable]~^ ERROR trait implementations cannot be const stable yet
|
||||
fn func() {}
|
||||
}
|
||||
|
||||
// Const stability has no impact on usage in non-const contexts.
|
||||
fn non_const_context() {
|
||||
Unstable::func();
|
||||
Stable::func();
|
||||
Foo::func();
|
||||
}
|
||||
|
||||
#[unstable(feature = "none", issue = "none")]
|
||||
const fn const_context() {
|
||||
Unstable::func();
|
||||
//[stock]~^ ERROR `<staged_api::Unstable as staged_api::MyTrait>::func` is not yet stable as a const fn
|
||||
Stable::func();
|
||||
// ^ This is okay regardless of whether the `unstable` feature is enabled, as this function is
|
||||
// not const-stable.
|
||||
Foo::func();
|
||||
//[unstable]~^ ERROR not yet stable as a const fn
|
||||
// ^ fails, because the `foo` feature is not active
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg_attr(unstable, rustc_const_unstable(feature = "foo", issue = "none"))]
|
||||
pub const fn const_context_not_const_stable() {
|
||||
//[stable]~^ ERROR function has missing const stability attribute
|
||||
Unstable::func();
|
||||
// ^ This is okay regardless of whether the `unstable` feature is enabled, as this function is
|
||||
// not const-stable.
|
||||
Foo::func();
|
||||
//[unstable]~^ ERROR not yet stable as a const fn
|
||||
// ^ fails, because the `foo` feature is not active
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_const_stable(feature = "cheese", since = "1.0.0")]
|
||||
const fn stable_const_context() {
|
||||
Unstable::func();
|
||||
//[unstable]~^ ERROR not yet stable as a const fn
|
||||
Foo::func();
|
||||
//[unstable]~^ ERROR not yet stable as a const fn
|
||||
const_context_not_const_stable()
|
||||
//[unstable]~^ ERROR not yet stable as a const fn
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
error: trait implementations cannot be const stable yet
|
||||
--> $DIR/staged-api.rs:19:1
|
||||
|
|
||||
LL | / impl const MyTrait for Foo {
|
||||
LL | |
|
||||
LL | | fn func() {}
|
||||
LL | | }
|
||||
| |_^
|
||||
|
|
||||
= note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
|
||||
|
||||
error: function has missing const stability attribute
|
||||
--> $DIR/staged-api.rs:42:1
|
||||
|
|
||||
LL | / pub const fn const_context_not_const_stable() {
|
||||
LL | |
|
||||
LL | | Unstable::func();
|
||||
LL | | // ^ This is okay regardless of whether the `unstable` feature is enabled, as this function is
|
||||
... |
|
||||
LL | | // ^ fails, because the `foo` feature is not active
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
error: trait methods cannot be stable const fn
|
||||
--> $DIR/staged-api.rs:22:5
|
||||
|
|
||||
LL | / fn func() {
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
error: trait methods cannot be stable const fn
|
||||
--> $DIR/staged-api.rs:22:5
|
||||
|
|
||||
LL | / fn func() {
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
||||
error: `<staged_api::Unstable as staged_api::MyTrait>::func` is not yet stable as a const fn
|
||||
--> $DIR/staged-api.rs:34:5
|
||||
|
|
||||
LL | Unstable::func();
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: add `#![feature(staged)]` to the crate attributes to enable
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
error: `<Foo as staged_api::MyTrait>::func` is not yet stable as a const fn
|
||||
--> $DIR/staged-api.rs:35:5
|
||||
|
|
||||
LL | Foo::func();
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
= help: add `#![feature(foo)]` to the crate attributes to enable
|
||||
|
||||
error: `<Foo as staged_api::MyTrait>::func` is not yet stable as a const fn
|
||||
--> $DIR/staged-api.rs:47:5
|
||||
|
|
||||
LL | Foo::func();
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
= help: add `#![feature(foo)]` to the crate attributes to enable
|
||||
|
||||
error: `<staged_api::Unstable as staged_api::MyTrait>::func` is not yet stable as a const fn
|
||||
--> $DIR/staged-api.rs:55:5
|
||||
|
|
||||
LL | Unstable::func();
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: const-stable functions can only call other const-stable functions
|
||||
|
||||
error: `<Foo as staged_api::MyTrait>::func` is not yet stable as a const fn
|
||||
--> $DIR/staged-api.rs:57:5
|
||||
|
|
||||
LL | Foo::func();
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
= help: const-stable functions can only call other const-stable functions
|
||||
|
||||
error: `const_context_not_const_stable` is not yet stable as a const fn
|
||||
--> $DIR/staged-api.rs:59:5
|
||||
|
|
||||
LL | const_context_not_const_stable()
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: const-stable functions can only call other const-stable functions
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
|
@ -18,9 +18,15 @@ impl Foo {
|
|||
pub const fn bar() {} // ok because function is unstable
|
||||
}
|
||||
|
||||
// FIXME Once #![feature(const_trait_impl)] is allowed to be stable, add a test
|
||||
// for const trait impls. Right now, a "trait methods cannot be stable const fn"
|
||||
// error is emitted. This occurs prior to the lint being tested here, such that
|
||||
// the lint cannot currently be tested on this use case.
|
||||
#[stable(feature = "stable", since = "1.0.0")]
|
||||
pub trait Bar {
|
||||
#[stable(feature = "stable", since = "1.0.0")]
|
||||
fn fun();
|
||||
}
|
||||
#[stable(feature = "stable", since = "1.0.0")]
|
||||
impl const Bar for Foo {
|
||||
//~^ ERROR implementation has missing const stability attribute
|
||||
fn fun() {}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -10,5 +10,14 @@ error: associated function has missing const stability attribute
|
|||
LL | pub const fn foo() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: implementation has missing const stability attribute
|
||||
--> $DIR/missing-const-stability.rs:27:1
|
||||
|
|
||||
LL | / impl const Bar for Foo {
|
||||
LL | |
|
||||
LL | | fn fun() {}
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue