Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 11ac57a

Browse files
Rollup merge of rust-lang#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

Lines changed: 87 additions & 2 deletions
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

Lines changed: 33 additions & 3 deletions
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

Lines changed: 1 addition & 0 deletions
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

Lines changed: 1 addition & 0 deletions
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

Lines changed: 1 addition & 0 deletions
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

Lines changed: 1 addition & 0 deletions
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

Lines changed: 2 additions & 0 deletions
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

Lines changed: 1 addition & 0 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 7 additions & 9 deletions
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
}

0 commit comments

Comments
 (0)