Skip to content

Deny more ~const trait bounds #117817

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion compiler/rustc_ast_passes/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -214,9 +214,12 @@ ast_passes_static_without_body =
.suggestion = provide a definition for the static

ast_passes_tilde_const_disallowed = `~const` is not allowed here
.trait = trait objects cannot have `~const` trait bounds
.closure = closures cannot have `~const` trait bounds
.function = this function is not `const`, so it cannot have `~const` trait bounds
.trait = this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds
.impl = this impl is not `const`, so it cannot have `~const` trait bounds
.object = trait objects cannot have `~const` trait bounds
.item = this item cannot have `~const` trait bounds
Copy link
Member

@fee1-dead fee1-dead Nov 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is quite ambiguous and we'd probably always want to have a reason.. OTOH, we don't want to allow tilde const for these "unknown" cases. Would be nice if this was turned into a span_bug! so that a more specific context is always defined.

No need for this PR to have this though.


ast_passes_trait_fn_const =
functions in traits cannot be declared const
Expand Down
75 changes: 30 additions & 45 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ enum SelfSemantic {
enum DisallowTildeConstContext<'a> {
TraitObject,
Fn(FnKind<'a>),
Trait(Span),
Impl(Span),
Item,
}

struct AstValidator<'a> {
Expand Down Expand Up @@ -110,18 +113,6 @@ impl<'a> AstValidator<'a> {
self.disallow_tilde_const = old;
}

fn with_tilde_const_allowed(&mut self, f: impl FnOnce(&mut Self)) {
self.with_tilde_const(None, f)
}

fn with_banned_tilde_const(
&mut self,
ctx: DisallowTildeConstContext<'a>,
f: impl FnOnce(&mut Self),
) {
self.with_tilde_const(Some(ctx), f)
}

fn check_type_alias_where_clause_location(
&mut self,
ty_alias: &TyAlias,
Expand Down Expand Up @@ -173,7 +164,7 @@ impl<'a> AstValidator<'a> {
self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
}
TyKind::TraitObject(..) => self
.with_banned_tilde_const(DisallowTildeConstContext::TraitObject, |this| {
.with_tilde_const(Some(DisallowTildeConstContext::TraitObject), |this| {
visit::walk_ty(this, t)
}),
TyKind::Path(qself, path) => {
Expand Down Expand Up @@ -822,11 +813,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {

this.visit_vis(&item.vis);
this.visit_ident(item.ident);
if let Const::Yes(_) = constness {
this.with_tilde_const_allowed(|this| this.visit_generics(generics));
} else {
this.visit_generics(generics);
}
let disallowed = matches!(constness, Const::No)
.then(|| DisallowTildeConstContext::Impl(item.span));
this.with_tilde_const(disallowed, |this| this.visit_generics(generics));
this.visit_trait_ref(t);
this.visit_ty(self_ty);

Expand All @@ -840,10 +829,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
polarity,
defaultness,
constness,
generics: _,
generics,
of_trait: None,
self_ty,
items: _,
items,
}) => {
let error =
|annotation_span, annotation, only_trait: bool| errors::InherentImplCannot {
Expand Down Expand Up @@ -875,6 +864,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
if let &Const::Yes(span) = constness {
self.err_handler().emit_err(error(span, "`const`", true));
}

self.visit_vis(&item.vis);
self.visit_ident(item.ident);
self.with_tilde_const(None, |this| this.visit_generics(generics));
Copy link
Member Author

@fmease fmease Nov 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently permitting ~const trait bounds on inherent impls not to regress rfc-2632-const-trait-impl/tilde_const_on_impl_bound.rs. Not sure if the following code should compile at some point:

struct Struct;
#[const_trait] trait Trait {}
impl<T: ~const Trait> Struct {
    const fn f(_: T) {}
}

If I were to straight up deny ~const here, it'd obviously fix #117004. I haven't tested yet if the ~const lowering code can properly lower the code above.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably deny this first. We don't really need this to work and making it work certainly adds to the overhead. Perhaps a followup PR? Or I can do that. Thanks for working on this! :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should deny ~const here. If we want to be able to use Trait in const fn f, I think the user should need to write:

struct Struct;
#[const_trait] trait Trait {}
impl<T: Trait> Struct {
    const fn f(_: T) where T: ~const Trait {}
}

at least in my opinion.

self.visit_ty(self_ty);
walk_list!(self, visit_assoc_item, items, AssocCtxt::Impl);
walk_list!(self, visit_attribute, &item.attrs);
return; // Avoid visiting again.
}
ItemKind::Fn(box Fn { defaultness, sig, generics, body }) => {
self.check_defaultness(item.span, *defaultness);
Expand Down Expand Up @@ -955,8 +952,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
// context for the supertraits.
this.visit_vis(&item.vis);
this.visit_ident(item.ident);
this.visit_generics(generics);
this.with_tilde_const_allowed(|this| {
let disallowed =
(!is_const_trait).then(|| DisallowTildeConstContext::Trait(item.span));
this.with_tilde_const(disallowed, |this| {
this.visit_generics(generics);
walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
});
walk_list!(this, visit_assoc_item, items, AssocCtxt::Trait);
Expand All @@ -976,16 +975,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
}
ItemKind::Struct(vdata, generics) => match vdata {
// Duplicating the `Visitor` logic allows catching all cases
// of `Anonymous(Struct, Union)` outside of a field struct or union.
//
// Inside `visit_ty` the validator catches every `Anonymous(Struct, Union)` it
// encounters, and only on `ItemKind::Struct` and `ItemKind::Union`
// it uses `visit_ty_common`, which doesn't contain that specific check.
VariantData::Struct(fields, ..) => {
self.visit_vis(&item.vis);
self.visit_ident(item.ident);
self.visit_generics(generics);
// Permit `Anon{Struct,Union}` as field type.
walk_list!(self, visit_struct_field_def, fields);
walk_list!(self, visit_attribute, &item.attrs);
return;
Expand All @@ -1001,6 +995,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
self.visit_vis(&item.vis);
self.visit_ident(item.ident);
self.visit_generics(generics);
// Permit `Anon{Struct,Union}` as field type.
walk_list!(self, visit_struct_field_def, fields);
walk_list!(self, visit_attribute, &item.attrs);
return;
Expand Down Expand Up @@ -1189,15 +1184,18 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
if let Some(reason) = &self.disallow_tilde_const =>
{
let reason = match reason {
DisallowTildeConstContext::TraitObject => {
errors::TildeConstReason::TraitObject
}
DisallowTildeConstContext::Fn(FnKind::Closure(..)) => {
errors::TildeConstReason::Closure
}
DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => {
errors::TildeConstReason::Function { ident: ident.span }
}
&DisallowTildeConstContext::Trait(span) => errors::TildeConstReason::Trait { span },
&DisallowTildeConstContext::Impl(span) => errors::TildeConstReason::Impl { span },
DisallowTildeConstContext::TraitObject => {
errors::TildeConstReason::TraitObject
}
DisallowTildeConstContext::Item => errors::TildeConstReason::Item,
};
self.err_handler()
.emit_err(errors::TildeConstDisallowed { span: bound.span(), reason });
Expand Down Expand Up @@ -1305,7 +1303,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|| matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)) if self.in_const_trait_or_impl);

let disallowed = (!tilde_const_allowed).then(|| DisallowTildeConstContext::Fn(fk));

self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk));
}

Expand Down Expand Up @@ -1374,18 +1371,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}

match &item.kind {
AssocItemKind::Type(box TyAlias { generics, bounds, ty, .. })
if ctxt == AssocCtxt::Trait =>
{
self.visit_vis(&item.vis);
self.visit_ident(item.ident);
walk_list!(self, visit_attribute, &item.attrs);
self.with_tilde_const_allowed(|this| {
this.visit_generics(generics);
walk_list!(this, visit_param_bound, bounds, BoundKind::Bound);
});
walk_list!(self, visit_ty, ty);
}
AssocItemKind::Fn(box Fn { sig, generics, body, .. })
if self.in_const_trait_or_impl
|| ctxt == AssocCtxt::Trait
Expand Down Expand Up @@ -1537,7 +1522,7 @@ pub fn check_crate(
in_const_trait_or_impl: false,
has_proc_macro_decls: false,
outer_impl_trait: None,
disallow_tilde_const: None,
disallow_tilde_const: Some(DisallowTildeConstContext::Item),
is_impl_trait_banned: false,
lint_buffer: lints,
};
Expand Down
16 changes: 14 additions & 2 deletions compiler/rustc_ast_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -551,15 +551,27 @@ pub struct TildeConstDisallowed {

#[derive(Subdiagnostic)]
pub enum TildeConstReason {
#[note(ast_passes_trait)]
TraitObject,
#[note(ast_passes_closure)]
Closure,
#[note(ast_passes_function)]
Function {
#[primary_span]
ident: Span,
},
#[note(ast_passes_trait)]
Trait {
#[primary_span]
span: Span,
},
#[note(ast_passes_impl)]
Impl {
#[primary_span]
span: Span,
},
#[note(ast_passes_object)]
TraitObject,
#[note(ast_passes_item)]
Item,
}

#[derive(Diagnostic)]
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/generic-const-items/const-trait-impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
#![allow(incomplete_features)]
#![crate_type = "lib"]

// FIXME(generic_const_items): Interpret `~const` as always-const.
const CREATE<T: ~const Create>: T = T::create();
// FIXME(generic_const_items, effects): Introduce `const` bounds to make this work.
const CREATE<T: Create>: T = T::create();

pub const K0: i32 = CREATE::<i32>;
pub const K1: i32 = CREATE; // arg inferred
Expand Down
6 changes: 3 additions & 3 deletions tests/ui/generic-const-items/const-trait-impl.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error[E0015]: cannot call non-const fn `<T as Create>::create` in constants
--> $DIR/const-trait-impl.rs:11:37
--> $DIR/const-trait-impl.rs:11:30
|
LL | const CREATE<T: ~const Create>: T = T::create();
| ^^^^^^^^^^^
LL | const CREATE<T: Create>: T = T::create();
| ^^^^^^^^^^^
|
= note: calls in constants are limited to constant functions, tuple structs and tuple variants

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
error: `~const` is not allowed here
--> $DIR/assoc-type-const-bound-usage.rs:7:17
|
LL | type Assoc: ~const Foo;
| ^^^^^^^^^^
|
= note: this item cannot have `~const` trait bounds

error[E0308]: mismatched types
--> $DIR/assoc-type-const-bound-usage.rs:12:5
|
Expand All @@ -7,6 +15,6 @@ LL | <T as Foo>::Assoc::foo();
= note: expected constant `host`
found constant `true`

error: aborting due to previous error
error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0308`.
10 changes: 9 additions & 1 deletion tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
error: `~const` is not allowed here
--> $DIR/assoc-type.rs:17:15
|
LL | type Bar: ~const std::ops::Add;
| ^^^^^^^^^^^^^^^^^^^^
|
= note: this item cannot have `~const` trait bounds

error: ~const can only be applied to `#[const_trait]` traits
--> $DIR/assoc-type.rs:17:22
|
LL | type Bar: ~const std::ops::Add;
| ^^^^^^^^^^^^^

error: aborting due to previous error
error: aborting due to 2 previous errors

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![feature(const_trait_impl, effects)]
#![feature(const_trait_impl)]

#[const_trait]
trait MyTrait {
Expand Down
21 changes: 6 additions & 15 deletions tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr
Original file line number Diff line number Diff line change
@@ -1,19 +1,10 @@
error[E0493]: destructor of `T` cannot be evaluated at compile-time
--> $DIR/const-drop.rs:19:32
error: `~const` is not allowed here
--> $DIR/const-drop.rs:67:38
|
LL | const fn a<T: ~const Destruct>(_: T) {}
| ^ - value is dropped here
| |
| the destructor for this type cannot be evaluated in constant functions

error[E0493]: destructor of `S<'_>` cannot be evaluated at compile-time
--> $DIR/const-drop.rs:24:13
LL | pub struct ConstDropWithBound<T: ~const SomeTrait>(pub core::marker::PhantomData<T>);
| ^^^^^^^^^^^^^^^^
|
LL | let _ = S(&mut c);
| ^^^^^^^^^- value is dropped here
| |
| the destructor for this type cannot be evaluated in constant functions
= note: this item cannot have `~const` trait bounds

error: aborting due to 2 previous errors
error: aborting due to previous error

For more information about this error, try `rustc --explain E0493`.
1 change: 1 addition & 0 deletions tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ mod t {
fn foo() {}
}

// FIXME(effects): This should be a `const` bound instead of a `~const` one.
pub struct ConstDropWithBound<T: ~const SomeTrait>(pub core::marker::PhantomData<T>);

impl<T: ~const SomeTrait> const Drop for ConstDropWithBound<T> {
Expand Down
21 changes: 6 additions & 15 deletions tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr
Original file line number Diff line number Diff line change
@@ -1,19 +1,10 @@
error[E0493]: destructor of `T` cannot be evaluated at compile-time
--> $DIR/const-drop.rs:19:32
error: `~const` is not allowed here
--> $DIR/const-drop.rs:67:38
|
LL | const fn a<T: ~const Destruct>(_: T) {}
| ^ - value is dropped here
| |
| the destructor for this type cannot be evaluated in constant functions

error[E0493]: destructor of `S<'_>` cannot be evaluated at compile-time
--> $DIR/const-drop.rs:24:13
LL | pub struct ConstDropWithBound<T: ~const SomeTrait>(pub core::marker::PhantomData<T>);
| ^^^^^^^^^^^^^^^^
|
LL | let _ = S(&mut c);
| ^^^^^^^^^- value is dropped here
| |
| the destructor for this type cannot be evaluated in constant functions
= note: this item cannot have `~const` trait bounds

error: aborting due to 2 previous errors
error: aborting due to previous error

For more information about this error, try `rustc --explain E0493`.
9 changes: 0 additions & 9 deletions tests/ui/rfcs/rfc-2632-const-trait-impl/issue-90052.rs

This file was deleted.

14 changes: 0 additions & 14 deletions tests/ui/rfcs/rfc-2632-const-trait-impl/issue-90052.stderr

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,7 @@ trait Bar {
fn bar();
}

// bgr360: I was only able to exercise the code path that raises the
// "missing ~const qualifier" error by making this base impl non-const, even
// though that doesn't really make sense to do. As seen below, if the base impl
// is made const, rustc fails earlier with an overlapping impl failure.
impl<T> Bar for T
impl<T> const Bar for T
where
T: ~const Foo,
{
Expand Down
Loading