Skip to content

Commit 11ac57a

Browse files
Rollup merge of #135423 - compiler-errors:enforce-const-trait-syntactical, r=oli-obk,RalfJung
Enforce syntactical stability of const traits in HIR This PR enforces what I'm calling *syntactical* const stability of traits. In other words, it enforces the ability to name `~const`/`const` traits in trait bounds in various syntax positions in HIR (including in the trait of an impl header). This functionality is analogous to the *regular* item stability checker, which is concerned with making sure that you cannot refer to unstable items by name, and is implemented as an extension of that pass. This is separate from enforcing the *recursive* const stability of const trait methods, which is implemented in MIR and runs on MIR bodies. That will require adding a new `NonConstOp` to the const checker and probably adjusting some logic to deduplicate redundant errors. However, this check is separate and necessary for making sure that users don't add `~const`/`const` bounds to items when the trait is not const-stable in the first place. I chose to separate enforcing recursive const stability out of this PR to make it easier to review. I'll probably open a follow-up following this one, blocked on this PR. r? `@RalfJung` cc `@rust-lang/project-const-traits`
2 parents 7c85da9 + 2743df8 commit 11ac57a

21 files changed

+278
-37
lines changed

compiler/rustc_middle/src/middle/stability.rs

+87-2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ pub enum StabilityLevel {
3030
Stable,
3131
}
3232

33+
#[derive(Copy, Clone)]
34+
pub enum UnstableKind {
35+
/// Enforcing regular stability of an item
36+
Regular,
37+
/// Enforcing const stability of an item
38+
Const(Span),
39+
}
40+
3341
/// An entry in the `depr_map`.
3442
#[derive(Copy, Clone, HashStable, Debug, Encodable, Decodable)]
3543
pub struct DeprecationEntry {
@@ -108,10 +116,16 @@ pub fn report_unstable(
108116
is_soft: bool,
109117
span: Span,
110118
soft_handler: impl FnOnce(&'static Lint, Span, String),
119+
kind: UnstableKind,
111120
) {
121+
let qual = match kind {
122+
UnstableKind::Regular => "",
123+
UnstableKind::Const(_) => " const",
124+
};
125+
112126
let msg = match reason {
113-
Some(r) => format!("use of unstable library feature `{feature}`: {r}"),
114-
None => format!("use of unstable library feature `{feature}`"),
127+
Some(r) => format!("use of unstable{qual} library feature `{feature}`: {r}"),
128+
None => format!("use of unstable{qual} library feature `{feature}`"),
115129
};
116130

117131
if is_soft {
@@ -121,6 +135,9 @@ pub fn report_unstable(
121135
if let Some((inner_types, msg, sugg, applicability)) = suggestion {
122136
err.span_suggestion(inner_types, msg, sugg, applicability);
123137
}
138+
if let UnstableKind::Const(kw) = kind {
139+
err.span_label(kw, "trait is not stable as const yet");
140+
}
124141
err.emit();
125142
}
126143
}
@@ -587,13 +604,81 @@ impl<'tcx> TyCtxt<'tcx> {
587604
is_soft,
588605
span,
589606
soft_handler,
607+
UnstableKind::Regular,
590608
),
591609
EvalResult::Unmarked => unmarked(span, def_id),
592610
}
593611

594612
is_allowed
595613
}
596614

615+
/// This function is analogous to `check_optional_stability` but with the logic in
616+
/// `eval_stability_allow_unstable` inlined, and which operating on const stability
617+
/// instead of regular stability.
618+
///
619+
/// This enforces *syntactical* const stability of const traits. In other words,
620+
/// it enforces the ability to name `~const`/`const` traits in trait bounds in various
621+
/// syntax positions in HIR (including in the trait of an impl header).
622+
pub fn check_const_stability(self, def_id: DefId, span: Span, const_kw_span: Span) {
623+
let is_staged_api = self.lookup_stability(def_id.krate.as_def_id()).is_some();
624+
if !is_staged_api {
625+
return;
626+
}
627+
628+
// Only the cross-crate scenario matters when checking unstable APIs
629+
let cross_crate = !def_id.is_local();
630+
if !cross_crate {
631+
return;
632+
}
633+
634+
let stability = self.lookup_const_stability(def_id);
635+
debug!(
636+
"stability: \
637+
inspecting def_id={:?} span={:?} of stability={:?}",
638+
def_id, span, stability
639+
);
640+
641+
match stability {
642+
Some(ConstStability {
643+
level: attr::StabilityLevel::Unstable { reason, issue, is_soft, implied_by, .. },
644+
feature,
645+
..
646+
}) => {
647+
assert!(!is_soft);
648+
649+
if span.allows_unstable(feature) {
650+
debug!("body stability: skipping span={:?} since it is internal", span);
651+
return;
652+
}
653+
if self.features().enabled(feature) {
654+
return;
655+
}
656+
657+
// If this item was previously part of a now-stabilized feature which is still
658+
// enabled (i.e. the user hasn't removed the attribute for the stabilized feature
659+
// yet) then allow use of this item.
660+
if let Some(implied_by) = implied_by
661+
&& self.features().enabled(implied_by)
662+
{
663+
return;
664+
}
665+
666+
report_unstable(
667+
self.sess,
668+
feature,
669+
reason.to_opt_reason(),
670+
issue,
671+
None,
672+
false,
673+
span,
674+
|_, _, _| {},
675+
UnstableKind::Const(const_kw_span),
676+
);
677+
}
678+
Some(_) | None => {}
679+
}
680+
}
681+
597682
pub fn lookup_deprecation(self, id: DefId) -> Option<Deprecation> {
598683
self.lookup_deprecation_entry(id).map(|depr| depr.attr)
599684
}

compiler/rustc_passes/src/stability.rs

+33-3
Original file line numberDiff line numberDiff line change
@@ -593,9 +593,11 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> {
593593
}
594594

595595
fn check_missing_const_stability(&self, def_id: LocalDefId, span: Span) {
596-
let is_const = self.tcx.is_const_fn(def_id.to_def_id());
596+
let is_const = self.tcx.is_const_fn(def_id.to_def_id())
597+
|| (self.tcx.def_kind(def_id.to_def_id()) == DefKind::Trait
598+
&& self.tcx.is_const_trait(def_id.to_def_id()));
597599

598-
// Reachable const fn must have a stability attribute.
600+
// Reachable const fn/trait must have a stability attribute.
599601
if is_const
600602
&& self.effective_visibilities.is_reachable(def_id)
601603
&& self.tcx.lookup_const_stability(def_id).is_none()
@@ -772,7 +774,13 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
772774
// For implementations of traits, check the stability of each item
773775
// individually as it's possible to have a stable trait with unstable
774776
// items.
775-
hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref t), self_ty, items, .. }) => {
777+
hir::ItemKind::Impl(hir::Impl {
778+
of_trait: Some(ref t),
779+
self_ty,
780+
items,
781+
constness,
782+
..
783+
}) => {
776784
let features = self.tcx.features();
777785
if features.staged_api() {
778786
let attrs = self.tcx.hir().attrs(item.hir_id());
@@ -814,6 +822,16 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
814822
}
815823
}
816824

825+
match constness {
826+
rustc_hir::Constness::Const => {
827+
if let Some(def_id) = t.trait_def_id() {
828+
// FIXME(const_trait_impl): Improve the span here.
829+
self.tcx.check_const_stability(def_id, t.path.span, t.path.span);
830+
}
831+
}
832+
rustc_hir::Constness::NotConst => {}
833+
}
834+
817835
for impl_item_ref in *items {
818836
let impl_item = self.tcx.associated_item(impl_item_ref.id.owner_id);
819837

@@ -829,6 +847,18 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
829847
intravisit::walk_item(self, item);
830848
}
831849

850+
fn visit_poly_trait_ref(&mut self, t: &'tcx hir::PolyTraitRef<'tcx>) {
851+
match t.modifiers.constness {
852+
hir::BoundConstness::Always(span) | hir::BoundConstness::Maybe(span) => {
853+
if let Some(def_id) = t.trait_ref.trait_def_id() {
854+
self.tcx.check_const_stability(def_id, t.trait_ref.path.span, span);
855+
}
856+
}
857+
hir::BoundConstness::Never => {}
858+
}
859+
intravisit::walk_poly_trait_ref(self, t);
860+
}
861+
832862
fn visit_path(&mut self, path: &hir::Path<'tcx>, id: hir::HirId) {
833863
if let Some(def_id) = path.res.opt_def_id() {
834864
let method_span = path.segments.last().map(|s| s.ident.span);

compiler/rustc_resolve/src/macros.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1031,6 +1031,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
10311031
is_soft,
10321032
span,
10331033
soft_handler,
1034+
stability::UnstableKind::Regular,
10341035
);
10351036
}
10361037
}

library/core/src/intrinsics/fallback.rs

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#![allow(missing_docs)]
99

1010
#[const_trait]
11+
#[rustc_const_unstable(feature = "core_intrinsics_fallbacks", issue = "none")]
1112
pub trait CarryingMulAdd: Copy + 'static {
1213
type Unsigned: Copy + 'static;
1314
fn carrying_mul_add(

library/core/src/marker.rs

+1
Original file line numberDiff line numberDiff line change
@@ -952,6 +952,7 @@ marker_impls! {
952952
/// This should be used for `~const` bounds,
953953
/// as non-const bounds will always hold for every type.
954954
#[unstable(feature = "const_destruct", issue = "133214")]
955+
#[rustc_const_unstable(feature = "const_destruct", issue = "133214")]
955956
#[lang = "destruct"]
956957
#[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)]
957958
#[rustc_deny_explicit_impl]

library/core/src/ops/arith.rs

+1
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
/// ```
6666
#[lang = "add"]
6767
#[stable(feature = "rust1", since = "1.0.0")]
68+
#[rustc_const_unstable(feature = "const_ops", issue = "90080")]
6869
#[rustc_on_unimplemented(
6970
on(all(_Self = "{integer}", Rhs = "{float}"), message = "cannot add a float to an integer",),
7071
on(all(_Self = "{float}", Rhs = "{integer}"), message = "cannot add an integer to a float",),

library/core/src/ops/deref.rs

+2
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@
134134
#[stable(feature = "rust1", since = "1.0.0")]
135135
#[rustc_diagnostic_item = "Deref"]
136136
#[const_trait]
137+
#[rustc_const_unstable(feature = "const_deref", issue = "88955")]
137138
pub trait Deref {
138139
/// The resulting type after dereferencing.
139140
#[stable(feature = "rust1", since = "1.0.0")]
@@ -263,6 +264,7 @@ impl<T: ?Sized> const Deref for &mut T {
263264
#[doc(alias = "*")]
264265
#[stable(feature = "rust1", since = "1.0.0")]
265266
#[const_trait]
267+
#[rustc_const_unstable(feature = "const_deref", issue = "88955")]
266268
pub trait DerefMut: ~const Deref {
267269
/// Mutably dereferences the value.
268270
#[stable(feature = "rust1", since = "1.0.0")]

library/core/src/ops/drop.rs

+1
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@
204204
#[lang = "drop"]
205205
#[stable(feature = "rust1", since = "1.0.0")]
206206
#[const_trait]
207+
#[rustc_const_unstable(feature = "const_destruct", issue = "133214")]
207208
pub trait Drop {
208209
/// Executes the destructor for this type.
209210
///

tests/ui/consts/promoted-const-drop.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#![feature(const_trait_impl)]
1+
#![feature(const_trait_impl, const_destruct)]
22

33
struct A();
44

+7-9
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,20 @@
1-
//@ known-bug: #103507
2-
3-
#![feature(const_trait_impl)]
1+
#![feature(const_trait_impl, const_destruct)]
42

53
struct Panic;
64
impl const Drop for Panic { fn drop(&mut self) { panic!(); } }
75

86
pub const fn id<T>(x: T) -> T { x }
97
pub const C: () = {
108
let _: &'static _ = &id(&Panic);
11-
//FIXME ~^ ERROR: temporary value dropped while borrowed
12-
//FIXME ~| ERROR: temporary value dropped while borrowed
9+
//~^ ERROR: temporary value dropped while borrowed
10+
//~| ERROR: temporary value dropped while borrowed
1311
};
1412

1513
fn main() {
1614
let _: &'static _ = &id(&Panic);
17-
//FIXME ~^ ERROR: temporary value dropped while borrowed
18-
//FIXME ~| ERROR: temporary value dropped while borrowed
15+
//~^ ERROR: temporary value dropped while borrowed
16+
//~| ERROR: temporary value dropped while borrowed
1917
let _: &'static _ = &&(Panic, 0).1;
20-
//FIXME~^ ERROR: temporary value dropped while borrowed
21-
//FIXME~| ERROR: temporary value dropped while borrowed
18+
//~^ ERROR: temporary value dropped while borrowed
19+
//~| ERROR: temporary value dropped while borrowed
2220
}
+22-15
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,25 @@
1-
error[E0493]: destructor of `Panic` cannot be evaluated at compile-time
2-
--> $DIR/promoted_const_call.rs:10:30
1+
error[E0716]: temporary value dropped while borrowed
2+
--> $DIR/promoted_const_call.rs:8:26
33
|
44
LL | let _: &'static _ = &id(&Panic);
5-
| ^^^^^ - value is dropped here
6-
| |
7-
| the destructor for this type cannot be evaluated in constants
5+
| ---------- ^^^^^^^^^^ creates a temporary value which is freed while still in use
6+
| |
7+
| type annotation requires that borrow lasts for `'static`
8+
...
9+
LL | };
10+
| - temporary value is freed at the end of this statement
11+
12+
error[E0716]: temporary value dropped while borrowed
13+
--> $DIR/promoted_const_call.rs:8:30
814
|
9-
= note: see issue #133214 <https://github.com/rust-lang/rust/issues/133214> for more information
10-
= help: add `#![feature(const_destruct)]` to the crate attributes to enable
11-
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
15+
LL | let _: &'static _ = &id(&Panic);
16+
| ---------- ^^^^^ - temporary value is freed at the end of this statement
17+
| | |
18+
| | creates a temporary value which is freed while still in use
19+
| type annotation requires that borrow lasts for `'static`
1220

1321
error[E0716]: temporary value dropped while borrowed
14-
--> $DIR/promoted_const_call.rs:16:26
22+
--> $DIR/promoted_const_call.rs:14:26
1523
|
1624
LL | let _: &'static _ = &id(&Panic);
1725
| ---------- ^^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -22,7 +30,7 @@ LL | }
2230
| - temporary value is freed at the end of this statement
2331

2432
error[E0716]: temporary value dropped while borrowed
25-
--> $DIR/promoted_const_call.rs:16:30
33+
--> $DIR/promoted_const_call.rs:14:30
2634
|
2735
LL | let _: &'static _ = &id(&Panic);
2836
| ---------- ^^^^^ - temporary value is freed at the end of this statement
@@ -31,7 +39,7 @@ LL | let _: &'static _ = &id(&Panic);
3139
| type annotation requires that borrow lasts for `'static`
3240

3341
error[E0716]: temporary value dropped while borrowed
34-
--> $DIR/promoted_const_call.rs:19:26
42+
--> $DIR/promoted_const_call.rs:17:26
3543
|
3644
LL | let _: &'static _ = &&(Panic, 0).1;
3745
| ---------- ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -42,7 +50,7 @@ LL | }
4250
| - temporary value is freed at the end of this statement
4351

4452
error[E0716]: temporary value dropped while borrowed
45-
--> $DIR/promoted_const_call.rs:19:27
53+
--> $DIR/promoted_const_call.rs:17:27
4654
|
4755
LL | let _: &'static _ = &&(Panic, 0).1;
4856
| ---------- ^^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -52,7 +60,6 @@ LL | let _: &'static _ = &&(Panic, 0).1;
5260
LL | }
5361
| - temporary value is freed at the end of this statement
5462

55-
error: aborting due to 5 previous errors
63+
error: aborting due to 6 previous errors
5664

57-
Some errors have detailed explanations: E0493, E0716.
58-
For more information about an error, try `rustc --explain E0493`.
65+
For more information about this error, try `rustc --explain E0716`.

tests/ui/stability-attribute/missing-const-stability.rs

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ impl Foo {
2222
#[stable(feature = "stable", since = "1.0.0")]
2323
#[const_trait]
2424
pub trait Bar {
25+
//~^ ERROR trait has missing const stability attribute
2526
#[stable(feature = "stable", since = "1.0.0")]
2627
fn fun();
2728
}

tests/ui/stability-attribute/missing-const-stability.stderr

+12-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,18 @@ error: function has missing const stability attribute
44
LL | pub const fn foo() {}
55
| ^^^^^^^^^^^^^^^^^^^^^
66

7+
error: trait has missing const stability attribute
8+
--> $DIR/missing-const-stability.rs:24:1
9+
|
10+
LL | / pub trait Bar {
11+
LL | |
12+
LL | | #[stable(feature = "stable", since = "1.0.0")]
13+
LL | | fn fun();
14+
LL | | }
15+
| |_^
16+
717
error: function has missing const stability attribute
8-
--> $DIR/missing-const-stability.rs:36:1
18+
--> $DIR/missing-const-stability.rs:37:1
919
|
1020
LL | pub const unsafe fn size_of_val<T>(x: *const T) -> usize { 42 }
1121
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -16,5 +26,5 @@ error: associated function has missing const stability attribute
1626
LL | pub const fn foo() {}
1727
| ^^^^^^^^^^^^^^^^^^^^^
1828

19-
error: aborting due to 3 previous errors
29+
error: aborting due to 4 previous errors
2030

tests/ui/traits/const-traits/auxiliary/staged-api.rs

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#![stable(feature = "rust1", since = "1.0.0")]
55

66
#[stable(feature = "rust1", since = "1.0.0")]
7+
#[rustc_const_unstable(feature = "unstable", issue = "none")]
78
#[const_trait]
89
pub trait MyTrait {
910
#[stable(feature = "rust1", since = "1.0.0")]

0 commit comments

Comments
 (0)