Skip to content

Commit

Permalink
Rollup merge of rust-lang#136688 - fee1-dead-contrib:push-nppsusmpokq…
Browse files Browse the repository at this point in the history
…o, r=compiler-errors

require trait impls to have matching const stabilities as the traits

This resolves rust-lang/project-const-traits#5 by implementing the suggested solution in the given thread

r? ```@RalfJung```
cc ```@rust-lang/project-const-traits```
  • Loading branch information
matthiaskrgr authored Feb 27, 2025
2 parents 262e07a + ef66cbb commit a462ee2
Show file tree
Hide file tree
Showing 8 changed files with 200 additions and 15 deletions.
5 changes: 5 additions & 0 deletions compiler/rustc_const_eval/src/check_consts/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ pub fn rustc_allow_const_fn_unstable(
/// world into two functions: those that are safe to expose on stable (and hence may not use
/// unstable features, not even recursively), and those that are not.
pub fn is_fn_or_trait_safe_to_expose_on_stable(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
// A default body in a `#[const_trait]` is const-stable when the trait is const-stable.
if tcx.is_const_default_method(def_id) {
return is_fn_or_trait_safe_to_expose_on_stable(tcx, tcx.parent(def_id));
}

match tcx.lookup_const_stability(def_id) {
None => {
// In a `staged_api` crate, we do enforce recursive const stability for all unmarked
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_passes/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,12 @@ passes_target_feature_on_statement =
.warn = {-passes_previously_accepted}
.label = {passes_should_be_applied_to_fn.label}
passes_trait_impl_const_stability_mismatch = const stability on the impl does not match the const stability on the trait
passes_trait_impl_const_stability_mismatch_impl_stable = this impl is (implicitly) stable...
passes_trait_impl_const_stability_mismatch_impl_unstable = this impl is unstable...
passes_trait_impl_const_stability_mismatch_trait_stable = ...but the trait is stable
passes_trait_impl_const_stability_mismatch_trait_unstable = ...but the trait is unstable
passes_trait_impl_const_stable =
trait implementations cannot be const stable yet
.note = see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
Expand Down
39 changes: 39 additions & 0 deletions compiler/rustc_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1552,6 +1552,45 @@ pub(crate) struct TraitImplConstStable {
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(passes_trait_impl_const_stability_mismatch)]
pub(crate) struct TraitImplConstStabilityMismatch {
#[primary_span]
pub span: Span,
#[subdiagnostic]
pub impl_stability: ImplConstStability,
#[subdiagnostic]
pub trait_stability: TraitConstStability,
}

#[derive(Subdiagnostic)]
pub(crate) enum TraitConstStability {
#[note(passes_trait_impl_const_stability_mismatch_trait_stable)]
Stable {
#[primary_span]
span: Span,
},
#[note(passes_trait_impl_const_stability_mismatch_trait_unstable)]
Unstable {
#[primary_span]
span: Span,
},
}

#[derive(Subdiagnostic)]
pub(crate) enum ImplConstStability {
#[note(passes_trait_impl_const_stability_mismatch_impl_stable)]
Stable {
#[primary_span]
span: Span,
},
#[note(passes_trait_impl_const_stability_mismatch_impl_unstable)]
Unstable {
#[primary_span]
span: Span,
},
}

#[derive(Diagnostic)]
#[diag(passes_unknown_feature, code = E0635)]
pub(crate) struct UnknownFeature {
Expand Down
60 changes: 46 additions & 14 deletions compiler/rustc_passes/src/stability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
.map(|(stab, _span)| ConstStability::from_partial(stab, const_stability_indirect));

// If this is a const fn but not annotated with stability markers, see if we can inherit regular stability.
if fn_sig.is_some_and(|s| s.header.is_const()) && const_stab.is_none() &&
if fn_sig.is_some_and(|s| s.header.is_const()) && const_stab.is_none() &&
// We only ever inherit unstable features.
let Some(inherit_regular_stab) =
final_stab.filter(|s| s.is_unstable())
Expand Down Expand Up @@ -826,24 +826,56 @@ 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()
&& self.tcx.is_const_trait_impl(item.owner_id.to_def_id())
&& const_stab.is_some_and(|stab| stab.is_const_stable())
&& let hir::Constness::Const = constness
{
self.tcx.dcx().emit_err(errors::TraitImplConstStable { span: item.span });
let stable_or_implied_stable = match const_stab {
None => true,
Some(stab) if stab.is_const_stable() => {
// `#![feature(const_trait_impl)]` is unstable, so any impl declared stable
// needs to have an error emitted.
// Note: Remove this error once `const_trait_impl` is stabilized
self.tcx
.dcx()
.emit_err(errors::TraitImplConstStable { span: item.span });
true
}
Some(_) => false,
};

if let Some(trait_id) = t.trait_def_id()
&& let Some(const_stab) = self.tcx.lookup_const_stability(trait_id)
{
// the const stability of a trait impl must match the const stability on the trait.
if const_stab.is_const_stable() != stable_or_implied_stable {
let trait_span = self.tcx.def_ident_span(trait_id).unwrap();

let impl_stability = if stable_or_implied_stable {
errors::ImplConstStability::Stable { span: item.span }
} else {
errors::ImplConstStability::Unstable { span: item.span }
};
let trait_stability = if const_stab.is_const_stable() {
errors::TraitConstStability::Stable { span: trait_span }
} else {
errors::TraitConstStability::Unstable { span: trait_span }
};

self.tcx.dcx().emit_err(errors::TraitImplConstStabilityMismatch {
span: item.span,
impl_stability,
trait_stability,
});
}
}
}
}

match constness {
rustc_hir::Constness::Const => {
if let Some(def_id) = t.trait_def_id() {
// FIXME(const_trait_impl): Improve the span here.
self.tcx.check_const_stability(def_id, t.path.span, t.path.span);
}
}
rustc_hir::Constness::NotConst => {}
if let hir::Constness::Const = constness
&& let Some(def_id) = t.trait_def_id()
{
// FIXME(const_trait_impl): Improve the span here.
self.tcx.check_const_stability(def_id, t.path.span, t.path.span);
}

for impl_item_ref in *items {
Expand Down
1 change: 1 addition & 0 deletions library/core/src/ops/arith.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ pub trait Add<Rhs = Self> {
macro_rules! add_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_ops", issue = "90080")]
impl const Add for $t {
type Output = $t;

Expand Down
3 changes: 3 additions & 0 deletions library/core/src/ops/deref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ pub trait Deref {
}

#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_deref", issue = "88955")]
impl<T: ?Sized> const Deref for &T {
type Target = T;

Expand All @@ -163,6 +164,7 @@ impl<T: ?Sized> const Deref for &T {
impl<T: ?Sized> !DerefMut for &T {}

#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_deref", issue = "88955")]
impl<T: ?Sized> const Deref for &mut T {
type Target = T;

Expand Down Expand Up @@ -273,6 +275,7 @@ pub trait DerefMut: ~const Deref {
}

#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_deref", issue = "88955")]
impl<T: ?Sized> const DerefMut for &mut T {
fn deref_mut(&mut self) -> &mut T {
*self
Expand Down
32 changes: 32 additions & 0 deletions tests/ui/traits/const-traits/staged-api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,36 @@ const fn implicitly_stable_const_context() {
//~^ ERROR cannot use `#[feature(const_trait_impl)]`
}

// check that const stability of impls and traits must match
#[const_trait]
#[rustc_const_unstable(feature = "beef", issue = "none")]
trait U {}

#[const_trait]
#[rustc_const_stable(since = "0.0.0", feature = "beef2")]
trait S {}

// implied stable
impl const U for u8 {}
//~^ const stability on the impl does not match the const stability on the trait

#[rustc_const_stable(since = "0.0.0", feature = "beef2")]
impl const U for u16 {}
//~^ const stability on the impl does not match the const stability on the trait
//~| trait implementations cannot be const stable yet

#[rustc_const_unstable(feature = "beef", issue = "none")]
impl const U for u32 {}

// implied stable
impl const S for u8 {}

#[rustc_const_stable(since = "0.0.0", feature = "beef2")]
impl const S for u16 {}
//~^ trait implementations cannot be const stable yet

#[rustc_const_unstable(feature = "beef", issue = "none")]
impl const S for u32 {}
//~^ const stability on the impl does not match the const stability on the trait

fn main() {}
69 changes: 68 additions & 1 deletion tests/ui/traits/const-traits/staged-api.stderr
Original file line number Diff line number Diff line change
@@ -1,3 +1,70 @@
error: const stability on the impl does not match the const stability on the trait
--> $DIR/staged-api.rs:98:1
|
LL | impl const U for u8 {}
| ^^^^^^^^^^^^^^^^^^^^^^
|
note: this impl is (implicitly) stable...
--> $DIR/staged-api.rs:98:1
|
LL | impl const U for u8 {}
| ^^^^^^^^^^^^^^^^^^^^^^
note: ...but the trait is unstable
--> $DIR/staged-api.rs:91:7
|
LL | trait U {}
| ^

error: trait implementations cannot be const stable yet
--> $DIR/staged-api.rs:102:1
|
LL | impl const U for u16 {}
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information

error: const stability on the impl does not match the const stability on the trait
--> $DIR/staged-api.rs:102:1
|
LL | impl const U for u16 {}
| ^^^^^^^^^^^^^^^^^^^^^^^
|
note: this impl is (implicitly) stable...
--> $DIR/staged-api.rs:102:1
|
LL | impl const U for u16 {}
| ^^^^^^^^^^^^^^^^^^^^^^^
note: ...but the trait is unstable
--> $DIR/staged-api.rs:91:7
|
LL | trait U {}
| ^

error: trait implementations cannot be const stable yet
--> $DIR/staged-api.rs:113:1
|
LL | impl const S for u16 {}
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information

error: const stability on the impl does not match the const stability on the trait
--> $DIR/staged-api.rs:117:1
|
LL | impl const S for u32 {}
| ^^^^^^^^^^^^^^^^^^^^^^^
|
note: this impl is unstable...
--> $DIR/staged-api.rs:117:1
|
LL | impl const S for u32 {}
| ^^^^^^^^^^^^^^^^^^^^^^^
note: ...but the trait is stable
--> $DIR/staged-api.rs:95:7
|
LL | trait S {}
| ^

error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]`
--> $DIR/staged-api.rs:38:5
|
Expand Down Expand Up @@ -323,5 +390,5 @@ LL + #[rustc_allow_const_fn_unstable(const_trait_impl)]
LL | const fn implicitly_stable_const_context() {
|

error: aborting due to 19 previous errors
error: aborting due to 24 previous errors

0 comments on commit a462ee2

Please sign in to comment.