Move check to existing pass
This alters the diagnostics a bit, as the trait method is still stable. The only thing this check does is ensure that compilation fails if a trait implementation is declared const-stable.
This commit is contained in:
parent
f0620c9503
commit
5ff331142e
7 changed files with 61 additions and 157 deletions
|
@ -970,10 +970,6 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
|
||||||
|
|
||||||
sess.time("layout_testing", || layout_test::test_layout(tcx));
|
sess.time("layout_testing", || layout_test::test_layout(tcx));
|
||||||
|
|
||||||
sess.time("stable_impl_const_trait_checking", || {
|
|
||||||
rustc_passes::stability::check_const_impl_trait(tcx)
|
|
||||||
});
|
|
||||||
|
|
||||||
// Avoid overwhelming user with errors if borrow checking failed.
|
// Avoid overwhelming user with errors if borrow checking failed.
|
||||||
// I'm not sure how helpful this is, to be honest, but it avoids a
|
// I'm not sure how helpful this is, to be honest, but it avoids a
|
||||||
// lot of annoying errors in the ui tests (basically,
|
// lot of annoying errors in the ui tests (basically,
|
||||||
|
|
|
@ -9,7 +9,6 @@ use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
|
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
|
||||||
use rustc_hir::hir_id::CRATE_HIR_ID;
|
use rustc_hir::hir_id::CRATE_HIR_ID;
|
||||||
use rustc_hir::intravisit::{self, Visitor};
|
use rustc_hir::intravisit::{self, Visitor};
|
||||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
|
||||||
use rustc_hir::{FieldDef, Generics, HirId, Item, TraitRef, Ty, TyKind, Variant};
|
use rustc_hir::{FieldDef, Generics, HirId, Item, TraitRef, Ty, TyKind, Variant};
|
||||||
use rustc_middle::hir::nested_filter;
|
use rustc_middle::hir::nested_filter;
|
||||||
use rustc_middle::middle::privacy::AccessLevels;
|
use rustc_middle::middle::privacy::AccessLevels;
|
||||||
|
@ -606,44 +605,6 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
|
||||||
// stable (assuming they have not inherited instability from their parent).
|
// stable (assuming they have not inherited instability from their parent).
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CheckStableConstImplTrait<'tcx> {
|
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> ItemLikeVisitor<'tcx> for CheckStableConstImplTrait<'tcx> {
|
|
||||||
fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
|
|
||||||
if !matches!(
|
|
||||||
item.kind,
|
|
||||||
hir::ItemKind::Impl(hir::Impl {
|
|
||||||
of_trait: Some(_),
|
|
||||||
constness: hir::Constness::Const,
|
|
||||||
..
|
|
||||||
})
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.tcx.lookup_const_stability(item.def_id).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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_trait_item(&mut self, _trait_item: &'tcx hir::TraitItem<'tcx>) {
|
|
||||||
// Nothing to do here.
|
|
||||||
}
|
|
||||||
fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem<'tcx>) {
|
|
||||||
// Nothing to do here.
|
|
||||||
}
|
|
||||||
fn visit_foreign_item(&mut self, _foreign_item: &'tcx hir::ForeignItem<'tcx>) {
|
|
||||||
// Nothing to do here.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
|
fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
|
||||||
let mut index = Index {
|
let mut index = Index {
|
||||||
stab_map: Default::default(),
|
stab_map: Default::default(),
|
||||||
|
@ -748,16 +709,23 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
|
||||||
// For implementations of traits, check the stability of each item
|
// For implementations of traits, check the stability of each item
|
||||||
// individually as it's possible to have a stable trait with unstable
|
// individually as it's possible to have a stable trait with unstable
|
||||||
// items.
|
// items.
|
||||||
hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref t), self_ty, items, .. }) => {
|
hir::ItemKind::Impl(hir::Impl {
|
||||||
if self.tcx.features().staged_api {
|
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
|
// If this impl block has an #[unstable] attribute, give an
|
||||||
// error if all involved types and traits are stable, because
|
// error if all involved types and traits are stable, because
|
||||||
// it will have no effect.
|
// it will have no effect.
|
||||||
// See: https://github.com/rust-lang/rust/issues/55436
|
// 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)) = stab {
|
||||||
if let (Some((Stability { level: attr::Unstable { .. }, .. }, span)), _) =
|
|
||||||
attr::find_stability(&self.tcx.sess, attrs, item.span)
|
|
||||||
{
|
|
||||||
let mut c = CheckTraitImplStable { tcx: self.tcx, fully_stable: true };
|
let mut c = CheckTraitImplStable { tcx: self.tcx, fully_stable: true };
|
||||||
c.visit_ty(self_ty);
|
c.visit_ty(self_ty);
|
||||||
c.visit_trait_ref(t);
|
c.visit_trait_ref(t);
|
||||||
|
@ -773,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 {
|
for impl_item_ref in *items {
|
||||||
|
@ -864,17 +845,6 @@ impl<'tcx> Visitor<'tcx> for CheckTraitImplStable<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_const_impl_trait(tcx: TyCtxt<'_>) {
|
|
||||||
let features = tcx.features(); // FIXME How cheap is this call?
|
|
||||||
// Both feature gates have to be enabled for this check to have any effect.
|
|
||||||
if !features.staged_api || !features.const_trait_impl {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut visitor = CheckStableConstImplTrait { tcx };
|
|
||||||
tcx.hir().visit_all_item_likes(&mut visitor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Given the list of enabled features that were not language features (i.e., that
|
/// Given the list of enabled features that were not language features (i.e., that
|
||||||
/// were expected to be library features), and the list of features used from
|
/// were expected to be library features), and the list of features used from
|
||||||
/// libraries, identify activated features that don't exist and error about them.
|
/// libraries, identify activated features that don't exist and error about them.
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
#![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 {
|
|
||||||
//~^ ERROR trait implementations cannot be const stable yet
|
|
||||||
type Output = Self;
|
|
||||||
|
|
||||||
fn sub(self, rhs: Self) -> Self {
|
|
||||||
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 const_err() {
|
|
||||||
Int(0) + Int(0);
|
|
||||||
//~^ ERROR not yet stable as a const fn
|
|
||||||
Int(0) - Int(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
|
||||||
pub fn non_const_success() {
|
|
||||||
Int(0) + Int(0);
|
|
||||||
Int(0) - Int(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {}
|
|
|
@ -1,24 +0,0 @@
|
||||||
error: `<Int as Add>::add` is not yet stable as a const fn
|
|
||||||
--> $DIR/stability.rs:32:5
|
|
||||||
|
|
|
||||||
LL | Int(0) + Int(0);
|
|
||||||
| ^^^^^^^^^^^^^^^
|
|
||||||
|
|
|
||||||
= help: const-stable functions can only call other const-stable functions
|
|
||||||
|
|
||||||
error: trait implementations cannot be const stable yet
|
|
||||||
--> $DIR/stability.rs:10:1
|
|
||||||
|
|
|
||||||
LL | / impl const std::ops::Sub for Int {
|
|
||||||
LL | |
|
|
||||||
LL | | type Output = Self;
|
|
||||||
LL | |
|
|
||||||
... |
|
|
||||||
LL | | }
|
|
||||||
LL | | }
|
|
||||||
| |_^
|
|
||||||
|
|
|
||||||
= note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
|
||||||
|
|
|
@ -11,26 +11,36 @@ extern crate staged_api;
|
||||||
use staged_api::*;
|
use staged_api::*;
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub struct Stable;
|
pub struct Foo;
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[cfg_attr(stable, rustc_const_stable(feature = "rust1", since = "1.0.0"))]
|
#[cfg_attr(unstable, rustc_const_unstable(feature = "foo", issue = "none"))]
|
||||||
impl const MyTrait for Stable {
|
impl const MyTrait for Foo {
|
||||||
//[stable]~^ ERROR trait implementations cannot be const stable yet
|
//[stable]~^ ERROR trait implementations cannot be const stable yet
|
||||||
//[unstable]~^^ ERROR implementation has missing const stability attribute
|
|
||||||
fn func() {}
|
fn func() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Const stability has no impact on usage in non-const contexts.
|
||||||
fn non_const_context() {
|
fn non_const_context() {
|
||||||
Unstable::func();
|
Unstable::func();
|
||||||
Stable::func();
|
Foo::func();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unstable(feature = "none", issue = "none")]
|
#[unstable(feature = "none", issue = "none")]
|
||||||
const fn const_context() {
|
const fn const_context() {
|
||||||
Unstable::func();
|
Unstable::func();
|
||||||
//[stable]~^ ERROR `<staged_api::Unstable as staged_api::MyTrait>::func` is not yet stable as a const fn
|
// ^ This is okay regardless of whether the `unstable` feature is enabled, as this function is
|
||||||
Stable::func();
|
// not const-stable.
|
||||||
|
Foo::func();
|
||||||
|
//[unstable]~^ not yet stable as a const fn
|
||||||
|
}
|
||||||
|
|
||||||
|
#[stable(feature = "rust1", 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
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,22 +1,11 @@
|
||||||
error: `<staged_api::Unstable as staged_api::MyTrait>::func` is not yet stable as a const fn
|
error: implementation has missing const stability attribute
|
||||||
--> $DIR/staged-api.rs:31:5
|
|
||||||
|
|
|
||||||
LL | Unstable::func();
|
|
||||||
| ^^^^^^^^^^^^^^^^
|
|
||||||
|
|
|
||||||
= help: add `#![feature(unstable)]` to the crate attributes to enable
|
|
||||||
|
|
||||||
error: trait implementations cannot be const stable yet
|
|
||||||
--> $DIR/staged-api.rs:18:1
|
--> $DIR/staged-api.rs:18:1
|
||||||
|
|
|
|
||||||
LL | / impl const MyTrait for Stable {
|
LL | / impl const MyTrait for Foo {
|
||||||
LL | |
|
|
||||||
LL | |
|
LL | |
|
||||||
LL | | fn func() {}
|
LL | | fn func() {}
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_^
|
| |_^
|
||||||
|
|
|
||||||
= note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,18 @@
|
||||||
error: implementation has missing const stability attribute
|
error: `<Foo as staged_api::MyTrait>::func` is not yet stable as a const fn
|
||||||
--> $DIR/staged-api.rs:18:1
|
--> $DIR/staged-api.rs:34:5
|
||||||
|
|
|
|
||||||
LL | / impl const MyTrait for Stable {
|
LL | Foo::func();
|
||||||
LL | |
|
| ^^^^^^^^^^^
|
||||||
LL | |
|
|
|
||||||
LL | | fn func() {}
|
= help: add `#![feature(foo)]` to the crate attributes to enable
|
||||||
LL | | }
|
|
||||||
| |_^
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: `<Foo as staged_api::MyTrait>::func` is not yet stable as a const fn
|
||||||
|
--> $DIR/staged-api.rs:42:5
|
||||||
|
|
|
||||||
|
LL | Foo::func();
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: add `#![feature(foo)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue