Skip to content

Commit 69b71de

Browse files
committed
Proper const stability check, default to unstable
Rather than deferring to const eval for checking if a trait is const, we now check up-front. This allows the error to be emitted earlier, notably at the same time as other stability checks. Also included in this commit is a change of the default const stability level to UNstable. Previously, an item that was `const` but did not explicitly state it was unstable was implicitly stable.
1 parent 9a52401 commit 69b71de

File tree

16 files changed

+196
-93
lines changed

16 files changed

+196
-93
lines changed

compiler/rustc_const_eval/src/transform/check_consts/check.rs

-12
Original file line numberDiff line numberDiff line change
@@ -218,18 +218,6 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
218218

219219
// The local type and predicate checks are not free and only relevant for `const fn`s.
220220
if self.const_kind() == hir::ConstContext::ConstFn {
221-
// Prevent const trait methods from being annotated as `stable`.
222-
// FIXME: Do this as part of stability checking.
223-
if self.is_const_stable_const_fn() {
224-
if crate::const_eval::is_parent_const_impl_raw(tcx, def_id) {
225-
self.ccx
226-
.tcx
227-
.sess
228-
.struct_span_err(self.span, "trait methods cannot be stable const fn")
229-
.emit();
230-
}
231-
}
232-
233221
for (idx, local) in body.local_decls.iter_enumerated() {
234222
// Handle the return place below.
235223
if idx == RETURN_PLACE || local.internal {

compiler/rustc_const_eval/src/transform/check_consts/mod.rs

+35-7
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,6 @@ pub fn rustc_allow_const_fn_unstable(tcx: TyCtxt<'_>, def_id: DefId, feature_gat
8686
// functions are subject to more stringent restrictions than "const-unstable" functions: They
8787
// cannot use unstable features and can only call other "const-stable" functions.
8888
pub fn is_const_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
89-
use attr::{ConstStability, StabilityLevel};
90-
9189
// A default body marked const is not const-stable because const
9290
// trait fns currently cannot be const-stable. We shouldn't
9391
// restrict default bodies to only call const-stable functions.
@@ -98,9 +96,39 @@ pub fn is_const_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
9896
// Const-stability is only relevant for `const fn`.
9997
assert!(tcx.is_const_fn_raw(def_id));
10098

101-
// A function is only const-stable if it has `#[rustc_const_stable]`.
102-
matches!(
103-
tcx.lookup_const_stability(def_id),
104-
Some(ConstStability { level: StabilityLevel::Stable { .. }, .. })
105-
)
99+
// A function is only const-stable if it has `#[rustc_const_stable]` or it the trait it belongs
100+
// to is const-stable.
101+
match tcx.lookup_const_stability(def_id) {
102+
Some(stab) => stab.is_const_stable(),
103+
None if is_parent_const_stable_trait(tcx, def_id) => {
104+
// Remove this when `#![feature(const_trait_impl)]` is stabilized,
105+
// returning `true` unconditionally.
106+
tcx.sess.delay_span_bug(
107+
tcx.def_span(def_id),
108+
"trait implementations cannot be const stable yet",
109+
);
110+
true
111+
}
112+
None => false, // By default, items are not const stable.
113+
}
114+
}
115+
116+
fn is_parent_const_stable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
117+
let local_def_id = def_id.expect_local();
118+
let hir_id = tcx.local_def_id_to_hir_id(local_def_id);
119+
120+
let Some(parent) = tcx.hir().find_parent_node(hir_id) else { return false };
121+
let parent_def = tcx.hir().get(parent);
122+
123+
if !matches!(
124+
parent_def,
125+
hir::Node::Item(hir::Item {
126+
kind: hir::ItemKind::Impl(hir::Impl { constness: hir::Constness::Const, .. }),
127+
..
128+
})
129+
) {
130+
return false;
131+
}
132+
133+
tcx.lookup_const_stability(parent.owner).map_or(false, |stab| stab.is_const_stable())
106134
}

compiler/rustc_interface/src/passes.rs

+4
Original file line numberDiff line numberDiff line change
@@ -982,6 +982,10 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
982982

983983
sess.time("layout_testing", || layout_test::test_layout(tcx));
984984

985+
sess.time("stable_impl_const_trait_checking", || {
986+
rustc_passes::stability::check_const_impl_trait(tcx)
987+
});
988+
985989
// Avoid overwhelming user with errors if borrow checking failed.
986990
// I'm not sure how helpful this is, to be honest, but it avoids a
987991
// lot of annoying errors in the ui tests (basically,

compiler/rustc_middle/src/ty/context.rs

+15
Original file line numberDiff line numberDiff line change
@@ -2802,6 +2802,21 @@ impl<'tcx> TyCtxt<'tcx> {
28022802
false
28032803
}
28042804
}
2805+
2806+
/// Whether the trait impl is marked const. This does not consider stability or feature gates.
2807+
pub fn is_const_trait_impl_raw(self, def_id: DefId) -> bool {
2808+
let Some(local_def_id) = def_id.as_local() else { return false };
2809+
let hir_id = self.local_def_id_to_hir_id(local_def_id);
2810+
let node = self.hir().get(hir_id);
2811+
2812+
matches!(
2813+
node,
2814+
hir::Node::Item(hir::Item {
2815+
kind: hir::ItemKind::Impl(hir::Impl { constness: hir::Constness::Const, .. }),
2816+
..
2817+
})
2818+
)
2819+
}
28052820
}
28062821

28072822
impl<'tcx> TyCtxtAt<'tcx> {

compiler/rustc_passes/src/stability.rs

+52-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use rustc_hir::def::{DefKind, Res};
99
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX};
1010
use rustc_hir::hir_id::CRATE_HIR_ID;
1111
use rustc_hir::intravisit::{self, Visitor};
12+
use rustc_hir::itemlikevisit::ItemLikeVisitor;
1213
use rustc_hir::{FieldDef, Generics, HirId, Item, TraitRef, Ty, TyKind, Variant};
1314
use rustc_middle::hir::nested_filter;
1415
use rustc_middle::middle::privacy::AccessLevels;
@@ -530,7 +531,8 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> {
530531
return;
531532
}
532533

533-
let is_const = self.tcx.is_const_fn(def_id.to_def_id());
534+
let is_const = self.tcx.is_const_fn(def_id.to_def_id())
535+
|| self.tcx.is_const_trait_impl_raw(def_id.to_def_id());
534536
let is_stable = self
535537
.tcx
536538
.lookup_stability(def_id)
@@ -604,6 +606,44 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
604606
// stable (assuming they have not inherited instability from their parent).
605607
}
606608

609+
struct CheckStableConstImplTrait<'tcx> {
610+
tcx: TyCtxt<'tcx>,
611+
}
612+
613+
impl<'tcx> ItemLikeVisitor<'tcx> for CheckStableConstImplTrait<'tcx> {
614+
fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
615+
if !matches!(
616+
item.kind,
617+
hir::ItemKind::Impl(hir::Impl {
618+
of_trait: Some(_),
619+
constness: hir::Constness::Const,
620+
..
621+
})
622+
) {
623+
return;
624+
}
625+
626+
if self.tcx.lookup_const_stability(item.def_id).map_or(false, |stab| stab.is_const_stable())
627+
{
628+
self.tcx
629+
.sess
630+
.struct_span_err(item.span, "trait implementations cannot be const stable yet")
631+
.note("see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information")
632+
.emit();
633+
}
634+
}
635+
636+
fn visit_trait_item(&mut self, _trait_item: &'tcx hir::TraitItem<'tcx>) {
637+
// Nothing to do here.
638+
}
639+
fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem<'tcx>) {
640+
// Nothing to do here.
641+
}
642+
fn visit_foreign_item(&mut self, _foreign_item: &'tcx hir::ForeignItem<'tcx>) {
643+
// Nothing to do here.
644+
}
645+
}
646+
607647
fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
608648
let mut index = Index {
609649
stab_map: Default::default(),
@@ -824,6 +864,17 @@ impl<'tcx> Visitor<'tcx> for CheckTraitImplStable<'tcx> {
824864
}
825865
}
826866

867+
pub fn check_const_impl_trait(tcx: TyCtxt<'_>) {
868+
let features = tcx.features(); // FIXME How cheap is this call?
869+
// Both feature gates have to be enabled for this check to have any effect.
870+
if !features.staged_api || !features.const_trait_impl {
871+
return;
872+
}
873+
874+
let mut visitor = CheckStableConstImplTrait { tcx };
875+
tcx.hir().visit_all_item_likes(&mut visitor);
876+
}
877+
827878
/// Given the list of enabled features that were not language features (i.e., that
828879
/// were expected to be library features), and the list of features used from
829880
/// libraries, identify activated features that don't exist and error about them.

src/test/ui/consts/rustc-impl-const-stability.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
1-
// build-pass
1+
// check-pass
22

33
#![crate_type = "lib"]
44
#![feature(staged_api)]
55
#![feature(const_trait_impl)]
66
#![stable(feature = "foo", since = "1.0.0")]
77

8-
98
#[stable(feature = "potato", since = "1.27.0")]
109
pub struct Data {
11-
_data: u128
10+
_data: u128,
1211
}
1312

1413
#[stable(feature = "potato", since = "1.27.0")]
14+
#[rustc_const_unstable(feature = "data_foo", issue = "none")]
1515
impl const Default for Data {
16-
#[rustc_const_unstable(feature = "data_foo", issue = "none")]
1716
fn default() -> Data {
1817
Data { _data: 42 }
1918
}

src/test/ui/rfc-2632-const-trait-impl/auxiliary/staged-api.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#![feature(const_trait_impl)]
2-
32
#![feature(staged_api)]
43
#![stable(feature = "rust1", since = "1.0.0")]
54

@@ -13,9 +12,7 @@ pub trait MyTrait {
1312
pub struct Unstable;
1413

1514
#[stable(feature = "rust1", since = "1.0.0")]
16-
#[rustc_const_unstable(feature = "staged", issue = "none")]
15+
#[rustc_const_unstable(feature = "unstable", issue = "none")]
1716
impl const MyTrait for Unstable {
18-
fn func() {
19-
20-
}
17+
fn func() {}
2118
}

src/test/ui/rfc-2632-const-trait-impl/stability.rs

+7-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#![feature(allow_internal_unstable)]
2-
#![feature(const_add)]
31
#![feature(const_trait_impl)]
42
#![feature(staged_api)]
53
#![stable(feature = "rust1", since = "1.0.0")]
@@ -10,10 +8,10 @@ pub struct Int(i32);
108
#[stable(feature = "rust1", since = "1.0.0")]
119
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
1210
impl const std::ops::Sub for Int {
11+
//~^ ERROR trait implementations cannot be const stable yet
1312
type Output = Self;
1413

1514
fn sub(self, rhs: Self) -> Self {
16-
//~^ ERROR trait methods cannot be stable const fn
1715
Int(self.0 - rhs.0)
1816
}
1917
}
@@ -30,16 +28,16 @@ impl const std::ops::Add for Int {
3028

3129
#[stable(feature = "rust1", since = "1.0.0")]
3230
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
33-
pub const fn foo() -> Int {
34-
Int(1i32) + Int(2i32)
31+
pub const fn const_err() {
32+
Int(0) + Int(0);
3533
//~^ ERROR not yet stable as a const fn
34+
Int(0) - Int(0);
3635
}
3736

38-
// ok
3937
#[stable(feature = "rust1", since = "1.0.0")]
40-
#[rustc_const_unstable(feature = "bar", issue = "none")]
41-
pub const fn bar() -> Int {
42-
Int(1i32) + Int(2i32)
38+
pub fn non_const_success() {
39+
Int(0) + Int(0);
40+
Int(0) - Int(0);
4341
}
4442

4543
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,24 @@
1-
error: trait methods cannot be stable const fn
2-
--> $DIR/stability.rs:15:5
3-
|
4-
LL | / fn sub(self, rhs: Self) -> Self {
5-
LL | |
6-
LL | | Int(self.0 - rhs.0)
7-
LL | | }
8-
| |_____^
9-
101
error: `<Int as Add>::add` is not yet stable as a const fn
11-
--> $DIR/stability.rs:34:5
2+
--> $DIR/stability.rs:32:5
123
|
13-
LL | Int(1i32) + Int(2i32)
14-
| ^^^^^^^^^^^^^^^^^^^^^
4+
LL | Int(0) + Int(0);
5+
| ^^^^^^^^^^^^^^^
156
|
167
= help: const-stable functions can only call other const-stable functions
178

9+
error: trait implementations cannot be const stable yet
10+
--> $DIR/stability.rs:10:1
11+
|
12+
LL | / impl const std::ops::Sub for Int {
13+
LL | |
14+
LL | | type Output = Self;
15+
LL | |
16+
... |
17+
LL | | }
18+
LL | | }
19+
| |_^
20+
|
21+
= note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
22+
1823
error: aborting due to 2 previous errors
1924

src/test/ui/rfc-2632-const-trait-impl/staged-api.rs

+7-10
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
// revisions: stock staged
2-
#![cfg_attr(staged, feature(staged))]
1+
// revisions: stable unstable
32

3+
#![cfg_attr(unstable, feature(unstable))] // The feature from the ./auxiliary/staged-api.rs file.
44
#![feature(const_trait_impl)]
5-
#![allow(incomplete_features)]
6-
75
#![feature(staged_api)]
86
#![stable(feature = "rust1", since = "1.0.0")]
97

@@ -16,12 +14,11 @@ use staged_api::*;
1614
pub struct Stable;
1715

1816
#[stable(feature = "rust1", since = "1.0.0")]
19-
#[cfg_attr(staged, rustc_const_stable(feature = "rust1", since = "1.0.0"))]
20-
// ^ should trigger error with or without the attribute
17+
#[cfg_attr(stable, rustc_const_stable(feature = "rust1", since = "1.0.0"))]
2118
impl const MyTrait for Stable {
22-
fn func() { //~ ERROR trait methods cannot be stable const fn
23-
24-
}
19+
//[stable]~^ ERROR trait implementations cannot be const stable yet
20+
//[unstable]~^^ ERROR implementation has missing const stability attribute
21+
fn func() {}
2522
}
2623

2724
fn non_const_context() {
@@ -32,7 +29,7 @@ fn non_const_context() {
3229
#[unstable(feature = "none", issue = "none")]
3330
const fn const_context() {
3431
Unstable::func();
35-
//[stock]~^ ERROR `<staged_api::Unstable as staged_api::MyTrait>::func` is not yet stable as a const fn
32+
//[stable]~^ ERROR `<staged_api::Unstable as staged_api::MyTrait>::func` is not yet stable as a const fn
3633
Stable::func();
3734
}
3835

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error: `<staged_api::Unstable as staged_api::MyTrait>::func` is not yet stable as a const fn
2+
--> $DIR/staged-api.rs:31:5
3+
|
4+
LL | Unstable::func();
5+
| ^^^^^^^^^^^^^^^^
6+
|
7+
= help: add `#![feature(unstable)]` to the crate attributes to enable
8+
9+
error: trait implementations cannot be const stable yet
10+
--> $DIR/staged-api.rs:18:1
11+
|
12+
LL | / impl const MyTrait for Stable {
13+
LL | |
14+
LL | |
15+
LL | | fn func() {}
16+
LL | | }
17+
| |_^
18+
|
19+
= note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
20+
21+
error: aborting due to 2 previous errors
22+

src/test/ui/rfc-2632-const-trait-impl/staged-api.staged.stderr

-10
This file was deleted.

src/test/ui/rfc-2632-const-trait-impl/staged-api.stock.stderr

-18
This file was deleted.

0 commit comments

Comments
 (0)