Validate ~const
trait bounds on associated fns.
Previously, any associated function could have `~const` trait bounds on generic parameters, which could lead to ICEs when these bounds were used on associated functions of non-`#[const_trait] trait` or non-`impl const` blocks. Includes changes as per @fee1-dead's comments in #116210.
This commit is contained in:
parent
2f89c414f2
commit
884af362f2
@ -52,7 +52,8 @@ struct AstValidator<'a> {
|
||||
/// Are we inside a trait impl?
|
||||
in_trait_impl: bool,
|
||||
|
||||
in_const_trait_impl: bool,
|
||||
/// Are we inside a const trait defn or impl?
|
||||
in_const_trait_or_impl: bool,
|
||||
|
||||
has_proc_macro_decls: bool,
|
||||
|
||||
@ -78,11 +79,19 @@ fn with_in_trait_impl(
|
||||
f: impl FnOnce(&mut Self),
|
||||
) {
|
||||
let old = mem::replace(&mut self.in_trait_impl, is_in);
|
||||
let old_const =
|
||||
mem::replace(&mut self.in_const_trait_impl, matches!(constness, Some(Const::Yes(_))));
|
||||
let old_const = mem::replace(
|
||||
&mut self.in_const_trait_or_impl,
|
||||
matches!(constness, Some(Const::Yes(_))),
|
||||
);
|
||||
f(self);
|
||||
self.in_trait_impl = old;
|
||||
self.in_const_trait_impl = old_const;
|
||||
self.in_const_trait_or_impl = old_const;
|
||||
}
|
||||
|
||||
fn with_in_trait(&mut self, is_const: bool, f: impl FnOnce(&mut Self)) {
|
||||
let old = mem::replace(&mut self.in_const_trait_or_impl, is_const);
|
||||
f(self);
|
||||
self.in_const_trait_or_impl = old;
|
||||
}
|
||||
|
||||
fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
|
||||
@ -933,23 +942,26 @@ fn visit_item(&mut self, item: &'a Item) {
|
||||
}
|
||||
}
|
||||
ItemKind::Trait(box Trait { is_auto, generics, bounds, items, .. }) => {
|
||||
if *is_auto == IsAuto::Yes {
|
||||
// Auto traits cannot have generics, super traits nor contain items.
|
||||
self.deny_generic_params(generics, item.ident.span);
|
||||
self.deny_super_traits(bounds, item.ident.span);
|
||||
self.deny_where_clause(&generics.where_clause, item.ident.span);
|
||||
self.deny_items(items, item.ident.span);
|
||||
}
|
||||
let is_const_trait = attr::contains_name(&item.attrs, sym::const_trait);
|
||||
self.with_in_trait(is_const_trait, |this| {
|
||||
if *is_auto == IsAuto::Yes {
|
||||
// Auto traits cannot have generics, super traits nor contain items.
|
||||
this.deny_generic_params(generics, item.ident.span);
|
||||
this.deny_super_traits(bounds, item.ident.span);
|
||||
this.deny_where_clause(&generics.where_clause, item.ident.span);
|
||||
this.deny_items(items, item.ident.span);
|
||||
}
|
||||
|
||||
// Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
|
||||
// context for the supertraits.
|
||||
self.visit_vis(&item.vis);
|
||||
self.visit_ident(item.ident);
|
||||
self.visit_generics(generics);
|
||||
self.with_tilde_const_allowed(|this| {
|
||||
walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
|
||||
// Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
|
||||
// context for the supertraits.
|
||||
this.visit_vis(&item.vis);
|
||||
this.visit_ident(item.ident);
|
||||
this.visit_generics(generics);
|
||||
this.with_tilde_const_allowed(|this| {
|
||||
walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
|
||||
});
|
||||
walk_list!(this, visit_assoc_item, items, AssocCtxt::Trait);
|
||||
});
|
||||
walk_list!(self, visit_assoc_item, items, AssocCtxt::Trait);
|
||||
walk_list!(self, visit_attribute, &item.attrs);
|
||||
return; // Avoid visiting again
|
||||
}
|
||||
@ -1278,7 +1290,7 @@ fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
|
||||
|
||||
let tilde_const_allowed =
|
||||
matches!(fk.header(), Some(FnHeader { constness: ast::Const::Yes(_), .. }))
|
||||
|| matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)));
|
||||
|| matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)) if self.in_const_trait_or_impl);
|
||||
|
||||
let disallowed = (!tilde_const_allowed).then(|| DisallowTildeConstContext::Fn(fk));
|
||||
|
||||
@ -1363,7 +1375,7 @@ fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
|
||||
walk_list!(self, visit_ty, ty);
|
||||
}
|
||||
AssocItemKind::Fn(box Fn { sig, generics, body, .. })
|
||||
if self.in_const_trait_impl
|
||||
if self.in_const_trait_or_impl
|
||||
|| ctxt == AssocCtxt::Trait
|
||||
|| matches!(sig.header.constness, Const::Yes(_)) =>
|
||||
{
|
||||
@ -1510,7 +1522,7 @@ pub fn check_crate(
|
||||
features,
|
||||
extern_mod: None,
|
||||
in_trait_impl: false,
|
||||
in_const_trait_impl: false,
|
||||
in_const_trait_or_impl: false,
|
||||
has_proc_macro_decls: false,
|
||||
outer_impl_trait: None,
|
||||
disallow_tilde_const: None,
|
||||
|
@ -0,0 +1,28 @@
|
||||
#![feature(const_trait_impl, effects)]
|
||||
|
||||
#[const_trait]
|
||||
trait MyTrait {
|
||||
fn do_something(&self);
|
||||
}
|
||||
|
||||
trait OtherTrait {
|
||||
fn do_something_else() where Self: ~const MyTrait;
|
||||
//~^ ERROR `~const` is not allowed here
|
||||
}
|
||||
|
||||
struct MyStruct<T>(T);
|
||||
|
||||
impl const MyTrait for u32 {
|
||||
fn do_something(&self) {}
|
||||
}
|
||||
|
||||
impl<T> MyStruct<T> {
|
||||
pub fn foo(&self) where T: ~const MyTrait {
|
||||
//~^ ERROR `~const` is not allowed here
|
||||
self.0.do_something();
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
MyStruct(0u32).foo();
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
error: `~const` is not allowed here
|
||||
--> $DIR/const-bound-on-not-const-associated-fn.rs:9:40
|
||||
|
|
||||
LL | fn do_something_else() where Self: ~const MyTrait;
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
note: this function is not `const`, so it cannot have `~const` trait bounds
|
||||
--> $DIR/const-bound-on-not-const-associated-fn.rs:9:8
|
||||
|
|
||||
LL | fn do_something_else() where Self: ~const MyTrait;
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: `~const` is not allowed here
|
||||
--> $DIR/const-bound-on-not-const-associated-fn.rs:20:32
|
||||
|
|
||||
LL | pub fn foo(&self) where T: ~const MyTrait {
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
note: this function is not `const`, so it cannot have `~const` trait bounds
|
||||
--> $DIR/const-bound-on-not-const-associated-fn.rs:20:12
|
||||
|
|
||||
LL | pub fn foo(&self) where T: ~const MyTrait {
|
||||
| ^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
@ -7,7 +7,8 @@
|
||||
|
||||
impl<const N: usize> Foo<N> {
|
||||
fn add<A: ~const Add42>(self) -> Foo<{ A::add(N) }> {
|
||||
//~^ ERROR mismatched types
|
||||
//~^ ERROR `~const` is not allowed here
|
||||
//~| ERROR mismatched types
|
||||
Foo
|
||||
}
|
||||
}
|
||||
@ -30,7 +31,7 @@ fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let foo = Foo::<0>;
|
||||
let foo = bar::<(), _>(foo);
|
||||
let _foo = bar::<(), _>(foo);
|
||||
let foo = Foo::<0>;
|
||||
let foo = bar::<(), _>(foo);
|
||||
let _foo = bar::<(), _>(foo);
|
||||
}
|
||||
|
@ -1,17 +1,29 @@
|
||||
error: `~const` is not allowed here
|
||||
--> $DIR/tilde-const-and-const-params.rs:26:11
|
||||
--> $DIR/tilde-const-and-const-params.rs:9:15
|
||||
|
|
||||
LL | fn add<A: ~const Add42>(self) -> Foo<{ A::add(N) }> {
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
note: this function is not `const`, so it cannot have `~const` trait bounds
|
||||
--> $DIR/tilde-const-and-const-params.rs:9:8
|
||||
|
|
||||
LL | fn add<A: ~const Add42>(self) -> Foo<{ A::add(N) }> {
|
||||
| ^^^
|
||||
|
||||
error: `~const` is not allowed here
|
||||
--> $DIR/tilde-const-and-const-params.rs:27:11
|
||||
|
|
||||
LL | fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> {
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
note: this function is not `const`, so it cannot have `~const` trait bounds
|
||||
--> $DIR/tilde-const-and-const-params.rs:26:4
|
||||
--> $DIR/tilde-const-and-const-params.rs:27:4
|
||||
|
|
||||
LL | fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> {
|
||||
| ^^^
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/tilde-const-and-const-params.rs:26:61
|
||||
--> $DIR/tilde-const-and-const-params.rs:27:61
|
||||
|
|
||||
LL | fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> {
|
||||
| ^^^^^^^^^ expected `false`, found `true`
|
||||
@ -28,6 +40,6 @@ LL | fn add<A: ~const Add42>(self) -> Foo<{ A::add(N) }> {
|
||||
= note: expected constant `false`
|
||||
found constant `true`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
@ -6,7 +6,9 @@ trait Bar {}
|
||||
trait Foo {
|
||||
fn a();
|
||||
fn b() where Self: ~const Bar;
|
||||
//~^ ERROR `~const` is not allowed here
|
||||
fn c<T: ~const Bar>();
|
||||
//~^ ERROR `~const` is not allowed here
|
||||
}
|
||||
|
||||
fn test1<T: Foo>() {
|
||||
|
@ -1,5 +1,29 @@
|
||||
error: `~const` is not allowed here
|
||||
--> $DIR/trait-where-clause.rs:8:24
|
||||
|
|
||||
LL | fn b() where Self: ~const Bar;
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
note: this function is not `const`, so it cannot have `~const` trait bounds
|
||||
--> $DIR/trait-where-clause.rs:8:8
|
||||
|
|
||||
LL | fn b() where Self: ~const Bar;
|
||||
| ^
|
||||
|
||||
error: `~const` is not allowed here
|
||||
--> $DIR/trait-where-clause.rs:10:13
|
||||
|
|
||||
LL | fn c<T: ~const Bar>();
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
note: this function is not `const`, so it cannot have `~const` trait bounds
|
||||
--> $DIR/trait-where-clause.rs:10:8
|
||||
|
|
||||
LL | fn c<T: ~const Bar>();
|
||||
| ^
|
||||
|
||||
error[E0277]: the trait bound `T: Bar` is not satisfied
|
||||
--> $DIR/trait-where-clause.rs:14:5
|
||||
--> $DIR/trait-where-clause.rs:16:5
|
||||
|
|
||||
LL | T::b();
|
||||
| ^ the trait `Bar` is not implemented for `T`
|
||||
@ -15,13 +39,13 @@ LL | fn test1<T: Foo + Bar>() {
|
||||
| +++++
|
||||
|
||||
error[E0277]: the trait bound `T: Bar` is not satisfied
|
||||
--> $DIR/trait-where-clause.rs:16:12
|
||||
--> $DIR/trait-where-clause.rs:18:12
|
||||
|
|
||||
LL | T::c::<T>();
|
||||
| ^ the trait `Bar` is not implemented for `T`
|
||||
|
|
||||
note: required by a bound in `Foo::c`
|
||||
--> $DIR/trait-where-clause.rs:9:13
|
||||
--> $DIR/trait-where-clause.rs:10:13
|
||||
|
|
||||
LL | fn c<T: ~const Bar>();
|
||||
| ^^^^^^^^^^ required by this bound in `Foo::c`
|
||||
@ -30,6 +54,6 @@ help: consider further restricting this bound
|
||||
LL | fn test1<T: Foo + Bar>() {
|
||||
| +++++
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
Loading…
Reference in New Issue
Block a user