Skip to content

Commit

Permalink
Implement trait const stability
Browse files Browse the repository at this point in the history
  • Loading branch information
fee1-dead committed Dec 26, 2024
1 parent 78af7da commit ee3f3df
Show file tree
Hide file tree
Showing 29 changed files with 207 additions and 62 deletions.
3 changes: 1 addition & 2 deletions compiler/rustc_const_eval/src/check_consts/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -709,8 +709,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
if trait_is_const {
// Trait calls are always conditionally-const.
self.check_op(ops::ConditionallyConstCall { callee, args: fn_args });
// FIXME(const_trait_impl): do a more fine-grained check whether this
// particular trait can be const-stably called.
self.tcx.enforce_trait_const_stability(trait_did, *fn_span);
} else {
// Not even a const trait.
self.check_op(ops::FnCallNonConst {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1612,6 +1612,7 @@ fn check_impl_constness(

let Some(trait_def_id) = hir_trait_ref.trait_def_id() else { return };
if tcx.is_const_trait(trait_def_id) {
tcx.enforce_trait_const_stability(trait_def_id, hir_trait_ref.path.span);
return;
}

Expand Down
23 changes: 13 additions & 10 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -741,9 +741,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
};

if let hir::BoundConstness::Always(span) | hir::BoundConstness::Maybe(span) = constness
&& !self.tcx().is_const_trait(trait_def_id)
{
let (def_span, suggestion, suggestion_pre) =
if !self.tcx().is_const_trait(trait_def_id) {
let (def_span, suggestion, suggestion_pre) =
match (trait_def_id.is_local(), self.tcx().sess.is_nightly_build()) {
(true, true) => (
None,
Expand All @@ -756,14 +756,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
),
(false, _) | (_, false) => (Some(tcx.def_span(trait_def_id)), None, ""),
};
self.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait {
span,
modifier: constness.as_str(),
def_span,
trait_name: self.tcx().def_path_str(trait_def_id),
suggestion_pre,
suggestion,
});
self.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait {
span,
modifier: constness.as_str(),
def_span,
trait_name: self.tcx().def_path_str(trait_def_id),
suggestion_pre,
suggestion,
});
}

tcx.enforce_trait_const_stability(trait_def_id, span)
}

match predicate_filter {
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_middle/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ middle_type_length_limit = reached the type-length limit while instantiating `{$
middle_unknown_layout =
the type `{$ty}` has an unknown layout
middle_unstable_const_trait = `{$def_path}` is not yet stable as a const trait
middle_values_too_big =
values of the type `{$ty}` are too big for the target architecture
middle_written_to_path = the full type name has been written to '{$path}'
8 changes: 8 additions & 0 deletions compiler/rustc_middle/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,3 +171,11 @@ pub struct TypeLengthLimit {
pub path: PathBuf,
pub type_length: usize,
}

#[derive(Diagnostic)]
#[diag(middle_unstable_const_trait)]
pub struct UnstableConstTrait {
#[primary_span]
pub span: Span,
pub def_path: String,
}
30 changes: 30 additions & 0 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use std::{fmt, iter, mem};

use rustc_abi::{ExternAbi, FieldIdx, Layout, LayoutData, TargetDataLayout, VariantIdx};
use rustc_ast as ast;
use rustc_attr_parsing::{ConstStability, StabilityLevel};
use rustc_data_structures::defer;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxHashMap;
Expand Down Expand Up @@ -3132,6 +3133,35 @@ impl<'tcx> TyCtxt<'tcx> {
&& self.impl_trait_header(def_id).unwrap().constness == hir::Constness::Const
}

pub fn enforce_trait_const_stability(self, trait_def_id: DefId, span: Span) {
match self.lookup_const_stability(trait_def_id) {
Some(ConstStability {
level: StabilityLevel::Unstable { implied_by: implied_feature, .. },
feature,
..
}) => {
if span.allows_unstable(feature)
|| implied_feature.is_some_and(|f| span.allows_unstable(f))
{
return;
}
let feature_enabled = trait_def_id.is_local()
|| self.features().enabled(feature)
|| implied_feature.is_some_and(|f| self.features().enabled(f));

if !feature_enabled {
let mut diag = self.dcx().create_err(crate::error::UnstableConstTrait {
span,
def_path: self.def_path_str(trait_def_id),
});
self.disabled_nightly_features(&mut diag, None, [(String::new(), feature)]);
diag.emit();
}
}
_ => {}
}
}

pub fn intrinsic(self, def_id: impl IntoQueryParam<DefId> + Copy) -> Option<ty::IntrinsicDef> {
match self.def_kind(def_id) {
DefKind::Fn | DefKind::AssocFn => {}
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_passes/src/stability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -593,9 +593,11 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> {
}

fn check_missing_const_stability(&self, def_id: LocalDefId, span: Span) {
let is_const = self.tcx.is_const_fn(def_id.to_def_id());
let is_const = self.tcx.is_const_fn(def_id.to_def_id())
|| (self.tcx.def_kind(def_id.to_def_id()) == DefKind::Trait
&& self.tcx.is_const_trait(def_id.to_def_id()));

// Reachable const fn must have a stability attribute.
// Reachable const fn/trait must have a stability attribute.
if is_const
&& self.effective_visibilities.is_reachable(def_id)
&& self.tcx.lookup_const_stability(def_id).is_none()
Expand Down
1 change: 1 addition & 0 deletions library/core/src/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -960,6 +960,7 @@ marker_impls! {
/// This should be used for `~const` bounds,
/// as non-const bounds will always hold for every type.
#[unstable(feature = "const_destruct", issue = "133214")]
#[rustc_const_unstable(feature = "const_destruct", issue = "133214")]
#[lang = "destruct"]
#[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)]
#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
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 @@ -65,6 +65,7 @@
/// ```
#[lang = "add"]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_ops", issue = "90080")]
#[rustc_on_unimplemented(
on(all(_Self = "{integer}", Rhs = "{float}"), message = "cannot add a float to an integer",),
on(all(_Self = "{float}", Rhs = "{integer}"), message = "cannot add an integer to a float",),
Expand Down
2 changes: 2 additions & 0 deletions library/core/src/ops/deref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "Deref"]
#[cfg_attr(not(bootstrap), const_trait)]
#[rustc_const_unstable(feature = "const_deref", issue = "88955")]
pub trait Deref {
/// The resulting type after dereferencing.
#[stable(feature = "rust1", since = "1.0.0")]
Expand Down Expand Up @@ -287,6 +288,7 @@ impl<T: ?Sized> const Deref for &mut T {
#[doc(alias = "*")]
#[stable(feature = "rust1", since = "1.0.0")]
#[const_trait]
#[rustc_const_unstable(feature = "const_deref", issue = "88955")]
pub trait DerefMut: ~const Deref {
/// Mutably dereferences the value.
#[stable(feature = "rust1", since = "1.0.0")]
Expand Down
1 change: 1 addition & 0 deletions library/core/src/ops/drop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@
#[lang = "drop"]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(bootstrap), const_trait)]
#[rustc_const_unstable(feature = "const_destruct", issue = "133214")]
pub trait Drop {
/// Executes the destructor for this type.
///
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/consts/promoted-const-drop.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![feature(const_trait_impl)]
#![feature(const_trait_impl, const_destruct)]

struct A();

Expand Down
2 changes: 1 addition & 1 deletion tests/ui/consts/promoted_const_call.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//@ known-bug: #103507

#![feature(const_trait_impl)]
#![feature(const_trait_impl, const_destruct)]

struct Panic;
impl const Drop for Panic { fn drop(&mut self) { panic!(); } }
Expand Down
1 change: 1 addition & 0 deletions tests/ui/issues/issue-25901.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ struct B;

static S: &'static B = &A;
//~^ ERROR cannot call conditionally-const method
//~| ERROR `Deref` is not yet stable as a const trait

use std::ops::Deref;

Expand Down
10 changes: 9 additions & 1 deletion tests/ui/issues/issue-25901.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ LL | static S: &'static B = &A;
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error: aborting due to 1 previous error
error: `Deref` is not yet stable as a const trait
--> $DIR/issue-25901.rs:4:24
|
LL | static S: &'static B = &A;
| ^^
|
= help: add `#![feature(const_deref)]` to the crate attributes to enable

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0658`.
1 change: 1 addition & 0 deletions tests/ui/self/arbitrary-self-from-method-substs-ice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ impl Foo {
//~| ERROR destructor of `R` cannot be evaluated at compile-time
self.0
//~^ ERROR cannot call conditionally-const method `<R as Deref>::deref` in constant function
//~| ERROR `Deref` is not yet stable as a const trait
}
}

Expand Down
10 changes: 9 additions & 1 deletion tests/ui/self/arbitrary-self-from-method-substs-ice.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ LL | self.0
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error: `Deref` is not yet stable as a const trait
--> $DIR/arbitrary-self-from-method-substs-ice.rs:13:9
|
LL | self.0
| ^^^^^^
|
= help: add `#![feature(const_deref)]` to the crate attributes to enable

error[E0493]: destructor of `R` cannot be evaluated at compile-time
--> $DIR/arbitrary-self-from-method-substs-ice.rs:10:43
|
Expand All @@ -26,7 +34,7 @@ LL | const fn get<R: Deref<Target = Self>>(self: R) -> u32 {
= note: type of `self` must not be a method generic parameter type
= help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)

error: aborting due to 3 previous errors
error: aborting due to 4 previous errors

Some errors have detailed explanations: E0493, E0658, E0801.
For more information about an error, try `rustc --explain E0493`.
1 change: 1 addition & 0 deletions tests/ui/stability-attribute/missing-const-stability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ impl Foo {
#[stable(feature = "stable", since = "1.0.0")]
#[const_trait]
pub trait Bar {
//~^ ERROR: trait has missing const stability attribute
#[stable(feature = "stable", since = "1.0.0")]
fn fun();
}
Expand Down
14 changes: 12 additions & 2 deletions tests/ui/stability-attribute/missing-const-stability.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,18 @@ error: function has missing const stability attribute
LL | pub const fn foo() {}
| ^^^^^^^^^^^^^^^^^^^^^

error: trait has missing const stability attribute
--> $DIR/missing-const-stability.rs:24:1
|
LL | / pub trait Bar {
LL | |
LL | | #[stable(feature = "stable", since = "1.0.0")]
LL | | fn fun();
LL | | }
| |_^

error: function has missing const stability attribute
--> $DIR/missing-const-stability.rs:36:1
--> $DIR/missing-const-stability.rs:37:1
|
LL | pub const unsafe fn size_of_val<T>(x: *const T) -> usize { 42 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -16,5 +26,5 @@ error: associated function has missing const stability attribute
LL | pub const fn foo() {}
| ^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 3 previous errors
error: aborting due to 4 previous errors

11 changes: 1 addition & 10 deletions tests/ui/traits/const-traits/auxiliary/staged-api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#![stable(feature = "rust1", since = "1.0.0")]

#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "unstable", issue = "none")]
#[const_trait]
pub trait MyTrait {
#[stable(feature = "rust1", since = "1.0.0")]
Expand All @@ -14,16 +15,6 @@ pub trait MyTrait {
pub struct Unstable;

#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "unstable", issue = "none")]
impl const MyTrait for Unstable {
fn func() {}
}

#[stable(feature = "rust1", since = "1.0.0")]
pub struct Unstable2;

#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "unstable2", issue = "none")]
impl const MyTrait for Unstable2 {
fn func() {}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//@ known-bug: #110395

#![feature(const_trait_impl)]
#![feature(const_trait_impl, const_ops)]

struct Int(i32);

Expand Down
2 changes: 1 addition & 1 deletion tests/ui/traits/const-traits/const-and-non-const-impl.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//@ known-bug: #110395

#![feature(const_trait_impl)]
#![feature(const_trait_impl, const_ops)]

pub struct Int(i32);

Expand Down
2 changes: 1 addition & 1 deletion tests/ui/traits/const-traits/generic-bound.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//@ check-pass

#![feature(const_trait_impl)]
#![feature(const_trait_impl, const_ops)]

use std::marker::PhantomData;

Expand Down
25 changes: 24 additions & 1 deletion tests/ui/traits/const-traits/staged-api-user-crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,30 @@ fn non_const_context() {

const fn stable_const_context() {
Unstable::func();
//~^ ERROR cannot call conditionally-const associated function `<staged_api::Unstable as staged_api::MyTrait>::func` in constant functions
//~^ ERROR: cannot call conditionally-const associated function `<staged_api::Unstable as staged_api::MyTrait>::func` in constant functions
//~| ERROR: `staged_api::MyTrait` is not yet stable as a const trait
}

struct S1;
impl MyTrait for S1 {
fn func() {}
}

// const impls are gated
struct S2;
impl const MyTrait for S2 {
//~^ ERROR: `staged_api::MyTrait` is not yet stable as a const trait
//~| ERROR: const trait impls are experimental
fn func() {}
}

fn bound1<T: MyTrait>() {}
const fn bound2<T: ~const MyTrait>() {}
//~^ ERROR: `staged_api::MyTrait` is not yet stable as a const trait
//~| ERROR: `staged_api::MyTrait` is not yet stable as a const trait
//~| ERROR: const trait impls are experimental
fn bound3<T: const MyTrait>() {}
//~^ ERROR: `staged_api::MyTrait` is not yet stable as a const trait
//~| ERROR: const trait impls are experimental

fn main() {}
Loading

0 comments on commit ee3f3df

Please sign in to comment.