Skip to content

Commit acfd327

Browse files
committed
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?
2 parents bb5e6c9 + f9c4f2b commit acfd327

22 files changed

+259
-168
lines changed

compiler/rustc_attr/src/builtin.rs

+20
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,16 @@ pub struct Stability {
101101
pub feature: Symbol,
102102
}
103103

104+
impl Stability {
105+
pub fn is_unstable(&self) -> bool {
106+
self.level.is_unstable()
107+
}
108+
109+
pub fn is_stable(&self) -> bool {
110+
self.level.is_stable()
111+
}
112+
}
113+
104114
/// Represents the `#[rustc_const_unstable]` and `#[rustc_const_stable]` attributes.
105115
#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
106116
#[derive(HashStable_Generic)]
@@ -111,6 +121,16 @@ pub struct ConstStability {
111121
pub promotable: bool,
112122
}
113123

124+
impl ConstStability {
125+
pub fn is_const_unstable(&self) -> bool {
126+
self.level.is_unstable()
127+
}
128+
129+
pub fn is_const_stable(&self) -> bool {
130+
self.level.is_stable()
131+
}
132+
}
133+
114134
/// The available stability levels.
115135
#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
116136
#[derive(HashStable_Generic)]

compiler/rustc_const_eval/src/const_eval/fn_queries.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_span::symbol::Symbol;
99
pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Symbol> {
1010
if tcx.is_const_fn_raw(def_id) {
1111
let const_stab = tcx.lookup_const_stability(def_id)?;
12-
if const_stab.level.is_unstable() { Some(const_stab.feature) } else { None }
12+
if const_stab.is_const_unstable() { Some(const_stab.feature) } else { None }
1313
} else {
1414
None
1515
}

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

+1-13
Original file line numberDiff line numberDiff line change
@@ -229,18 +229,6 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
229229

230230
// The local type and predicate checks are not free and only relevant for `const fn`s.
231231
if self.const_kind() == hir::ConstContext::ConstFn {
232-
// Prevent const trait methods from being annotated as `stable`.
233-
// FIXME: Do this as part of stability checking.
234-
if self.is_const_stable_const_fn() {
235-
if crate::const_eval::is_parent_const_impl_raw(tcx, def_id) {
236-
self.ccx
237-
.tcx
238-
.sess
239-
.struct_span_err(self.span, "trait methods cannot be stable const fn")
240-
.emit();
241-
}
242-
}
243-
244232
for (idx, local) in body.local_decls.iter_enumerated() {
245233
// Handle the return place below.
246234
if idx == RETURN_PLACE || local.internal {
@@ -944,7 +932,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
944932
// have no `rustc_const_stable` attributes to be const-unstable as well. This
945933
// should be fixed later.
946934
let callee_is_unstable_unmarked = tcx.lookup_const_stability(callee).is_none()
947-
&& tcx.lookup_stability(callee).map_or(false, |s| s.level.is_unstable());
935+
&& tcx.lookup_stability(callee).map_or(false, |s| s.is_unstable());
948936
if callee_is_unstable_unmarked {
949937
trace!("callee_is_unstable_unmarked");
950938
// We do not use `const` modifiers for intrinsic "functions", as intrinsics are

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

+29-14
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,6 @@ pub fn rustc_allow_const_fn_unstable(
8484
// functions are subject to more stringent restrictions than "const-unstable" functions: They
8585
// cannot use unstable features and can only call other "const-stable" functions.
8686
pub fn is_const_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
87-
use attr::{ConstStability, Stability, StabilityLevel};
88-
8987
// A default body marked const is not const-stable because const
9088
// trait fns currently cannot be const-stable. We shouldn't
9189
// 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 {
9694
// Const-stability is only relevant for `const fn`.
9795
assert!(tcx.is_const_fn_raw(def_id));
9896

99-
// Functions with `#[rustc_const_unstable]` are const-unstable.
97+
// A function is only const-stable if it has `#[rustc_const_stable]` or it the trait it belongs
98+
// to is const-stable.
10099
match tcx.lookup_const_stability(def_id) {
101-
Some(ConstStability { level: StabilityLevel::Unstable { .. }, .. }) => return false,
102-
Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => return true,
103-
None => {}
100+
Some(stab) => stab.is_const_stable(),
101+
None if is_parent_const_stable_trait(tcx, def_id) => {
102+
// Remove this when `#![feature(const_trait_impl)]` is stabilized,
103+
// returning `true` unconditionally.
104+
tcx.sess.delay_span_bug(
105+
tcx.def_span(def_id),
106+
"trait implementations cannot be const stable yet",
107+
);
108+
true
109+
}
110+
None => false, // By default, items are not const stable.
104111
}
112+
}
113+
114+
fn is_parent_const_stable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
115+
let local_def_id = def_id.expect_local();
116+
let hir_id = tcx.local_def_id_to_hir_id(local_def_id);
117+
118+
let Some(parent) = tcx.hir().find_parent_node(hir_id) else { return false };
119+
let parent_def = tcx.hir().get(parent);
105120

106-
// Functions with `#[unstable]` are const-unstable.
107-
//
108-
// FIXME(ecstaticmorse): We should keep const-stability attributes wholly separate from normal stability
109-
// attributes. `#[unstable]` should be irrelevant.
110-
if let Some(Stability { level: StabilityLevel::Unstable { .. }, .. }) =
111-
tcx.lookup_stability(def_id)
112-
{
121+
if !matches!(
122+
parent_def,
123+
hir::Node::Item(hir::Item {
124+
kind: hir::ItemKind::Impl(hir::Impl { constness: hir::Constness::Const, .. }),
125+
..
126+
})
127+
) {
113128
return false;
114129
}
115130

116-
true
131+
tcx.lookup_const_stability(parent.owner).map_or(false, |stab| stab.is_const_stable())
117132
}

compiler/rustc_middle/src/ty/context.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -2791,7 +2791,7 @@ impl<'tcx> TyCtxt<'tcx> {
27912791
pub fn is_const_fn(self, def_id: DefId) -> bool {
27922792
if self.is_const_fn_raw(def_id) {
27932793
match self.lookup_const_stability(def_id) {
2794-
Some(stability) if stability.level.is_unstable() => {
2794+
Some(stability) if stability.is_const_unstable() => {
27952795
// has a `rustc_const_unstable` attribute, check whether the user enabled the
27962796
// corresponding feature gate.
27972797
self.features()
@@ -2808,6 +2808,21 @@ impl<'tcx> TyCtxt<'tcx> {
28082808
false
28092809
}
28102810
}
2811+
2812+
/// Whether the trait impl is marked const. This does not consider stability or feature gates.
2813+
pub fn is_const_trait_impl_raw(self, def_id: DefId) -> bool {
2814+
let Some(local_def_id) = def_id.as_local() else { return false };
2815+
let hir_id = self.local_def_id_to_hir_id(local_def_id);
2816+
let node = self.hir().get(hir_id);
2817+
2818+
matches!(
2819+
node,
2820+
hir::Node::Item(hir::Item {
2821+
kind: hir::ItemKind::Impl(hir::Impl { constness: hir::Constness::Const, .. }),
2822+
..
2823+
})
2824+
)
2825+
}
28112826
}
28122827

28132828
impl<'tcx> TyCtxtAt<'tcx> {

compiler/rustc_passes/src/stability.rs

+31-12
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
147147
// Propagate unstability. This can happen even for non-staged-api crates in case
148148
// -Zforce-unstable-if-unmarked is set.
149149
if let Some(stab) = self.parent_stab {
150-
if inherit_deprecation.yes() && stab.level.is_unstable() {
150+
if inherit_deprecation.yes() && stab.is_unstable() {
151151
self.index.stab_map.insert(def_id, stab);
152152
}
153153
}
@@ -190,7 +190,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
190190
if const_stab.is_none() {
191191
debug!("annotate: const_stab not found, parent = {:?}", self.parent_const_stab);
192192
if let Some(parent) = self.parent_const_stab {
193-
if parent.level.is_unstable() {
193+
if parent.is_const_unstable() {
194194
self.index.const_stab_map.insert(def_id, parent);
195195
}
196196
}
@@ -272,9 +272,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
272272
if stab.is_none() {
273273
debug!("annotate: stab not found, parent = {:?}", self.parent_stab);
274274
if let Some(stab) = self.parent_stab {
275-
if inherit_deprecation.yes() && stab.level.is_unstable()
276-
|| inherit_from_parent.yes()
277-
{
275+
if inherit_deprecation.yes() && stab.is_unstable() || inherit_from_parent.yes() {
278276
self.index.stab_map.insert(def_id, stab);
279277
}
280278
}
@@ -532,7 +530,8 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> {
532530
return;
533531
}
534532

535-
let is_const = self.tcx.is_const_fn(def_id.to_def_id());
533+
let is_const = self.tcx.is_const_fn(def_id.to_def_id())
534+
|| self.tcx.is_const_trait_impl_raw(def_id.to_def_id());
536535
let is_stable = self
537536
.tcx
538537
.lookup_stability(def_id)
@@ -710,16 +709,23 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
710709
// For implementations of traits, check the stability of each item
711710
// individually as it's possible to have a stable trait with unstable
712711
// items.
713-
hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref t), self_ty, items, .. }) => {
714-
if self.tcx.features().staged_api {
712+
hir::ItemKind::Impl(hir::Impl {
713+
of_trait: Some(ref t),
714+
self_ty,
715+
items,
716+
constness,
717+
..
718+
}) => {
719+
let features = self.tcx.features();
720+
if features.staged_api {
721+
let attrs = self.tcx.hir().attrs(item.hir_id());
722+
let (stab, const_stab) = attr::find_stability(&self.tcx.sess, attrs, item.span);
723+
715724
// If this impl block has an #[unstable] attribute, give an
716725
// error if all involved types and traits are stable, because
717726
// it will have no effect.
718727
// See: https://github.com/rust-lang/rust/issues/55436
719-
let attrs = self.tcx.hir().attrs(item.hir_id());
720-
if let (Some((Stability { level: attr::Unstable { .. }, .. }, span)), _) =
721-
attr::find_stability(&self.tcx.sess, attrs, item.span)
722-
{
728+
if let Some((Stability { level: attr::Unstable { .. }, .. }, span)) = stab {
723729
let mut c = CheckTraitImplStable { tcx: self.tcx, fully_stable: true };
724730
c.visit_ty(self_ty);
725731
c.visit_trait_ref(t);
@@ -735,6 +741,19 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
735741
);
736742
}
737743
}
744+
745+
// `#![feature(const_trait_impl)]` is unstable, so any impl declared stable
746+
// needs to have an error emitted.
747+
if features.const_trait_impl
748+
&& *constness == hir::Constness::Const
749+
&& const_stab.map_or(false, |(stab, _)| stab.is_const_stable())
750+
{
751+
self.tcx
752+
.sess
753+
.struct_span_err(item.span, "trait implementations cannot be const stable yet")
754+
.note("see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information")
755+
.emit();
756+
}
738757
}
739758

740759
for impl_item_ref in *items {

src/librustdoc/clean/inline.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ pub(crate) fn build_impl(
344344
}
345345

346346
if let Some(stab) = tcx.lookup_stability(did) {
347-
if stab.level.is_unstable() && stab.feature == sym::rustc_private {
347+
if stab.is_unstable() && stab.feature == sym::rustc_private {
348348
return;
349349
}
350350
}
@@ -373,7 +373,7 @@ pub(crate) fn build_impl(
373373
}
374374

375375
if let Some(stab) = tcx.lookup_stability(did) {
376-
if stab.level.is_unstable() && stab.feature == sym::rustc_private {
376+
if stab.is_unstable() && stab.feature == sym::rustc_private {
377377
return;
378378
}
379379
}

src/librustdoc/clean/types.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -632,7 +632,7 @@ impl Item {
632632
self.stability(tcx).as_ref().and_then(|s| {
633633
let mut classes = Vec::with_capacity(2);
634634

635-
if s.level.is_unstable() {
635+
if s.is_unstable() {
636636
classes.push("unstable");
637637
}
638638

src/librustdoc/html/render/print_item.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -445,10 +445,7 @@ fn extra_info_tags(item: &clean::Item, parent: &clean::Item, tcx: TyCtxt<'_>) ->
445445

446446
// The "rustc_private" crates are permanently unstable so it makes no sense
447447
// to render "unstable" everywhere.
448-
if item
449-
.stability(tcx)
450-
.as_ref()
451-
.map(|s| s.level.is_unstable() && s.feature != sym::rustc_private)
448+
if item.stability(tcx).as_ref().map(|s| s.is_unstable() && s.feature != sym::rustc_private)
452449
== Some(true)
453450
{
454451
tags += &tag_html("unstable", "", "Experimental");

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

-45
This file was deleted.

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

-19
This file was deleted.

0 commit comments

Comments
 (0)