Skip to content

Commit d6a6f74

Browse files
committed
Validate that ~const trait bounds are not applied to associated
functions where it does not make sense to; previously, any associated function could have `~const` trait bounds on generic paramters, which lead to ICEs when these bounds were used on associated functions in non-`impl const` or non-`#[const_trait] trait` blocks.
1 parent 7b4b1b0 commit d6a6f74

File tree

3 files changed

+97
-17
lines changed

3 files changed

+97
-17
lines changed

compiler/rustc_ast_passes/src/ast_validation.rs

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ struct AstValidator<'a> {
5454

5555
in_const_trait_impl: bool,
5656

57+
/// Are we inside a const trait defn?
58+
in_const_trait_defn: bool,
59+
5760
has_proc_macro_decls: bool,
5861

5962
/// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
@@ -85,6 +88,12 @@ impl<'a> AstValidator<'a> {
8588
self.in_const_trait_impl = old_const;
8689
}
8790

91+
fn with_in_trait(&mut self, is_const: bool, f: impl FnOnce(&mut Self)) {
92+
let old = mem::replace(&mut self.in_const_trait_defn, is_const);
93+
f(self);
94+
self.in_const_trait_defn = old;
95+
}
96+
8897
fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
8998
let old = mem::replace(&mut self.is_impl_trait_banned, true);
9099
f(self);
@@ -933,23 +942,26 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
933942
}
934943
}
935944
ItemKind::Trait(box Trait { is_auto, generics, bounds, items, .. }) => {
936-
if *is_auto == IsAuto::Yes {
937-
// Auto traits cannot have generics, super traits nor contain items.
938-
self.deny_generic_params(generics, item.ident.span);
939-
self.deny_super_traits(bounds, item.ident.span);
940-
self.deny_where_clause(&generics.where_clause, item.ident.span);
941-
self.deny_items(items, item.ident.span);
942-
}
945+
let is_const_trait = attr::contains_name(&item.attrs, sym::const_trait);
946+
self.with_in_trait(is_const_trait, |this| {
947+
if *is_auto == IsAuto::Yes {
948+
// Auto traits cannot have generics, super traits nor contain items.
949+
this.deny_generic_params(generics, item.ident.span);
950+
this.deny_super_traits(bounds, item.ident.span);
951+
this.deny_where_clause(&generics.where_clause, item.ident.span);
952+
this.deny_items(items, item.ident.span);
953+
}
943954

944-
// Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
945-
// context for the supertraits.
946-
self.visit_vis(&item.vis);
947-
self.visit_ident(item.ident);
948-
self.visit_generics(generics);
949-
self.with_tilde_const_allowed(|this| {
950-
walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
955+
// Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
956+
// context for the supertraits.
957+
this.visit_vis(&item.vis);
958+
this.visit_ident(item.ident);
959+
this.visit_generics(generics);
960+
this.with_tilde_const_allowed(|this| {
961+
walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
962+
});
963+
walk_list!(this, visit_assoc_item, items, AssocCtxt::Trait);
951964
});
952-
walk_list!(self, visit_assoc_item, items, AssocCtxt::Trait);
953965
walk_list!(self, visit_attribute, &item.attrs);
954966
return; // Avoid visiting again
955967
}
@@ -1277,8 +1289,16 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
12771289
}
12781290

12791291
let tilde_const_allowed =
1280-
matches!(fk.header(), Some(FnHeader { constness: ast::Const::Yes(_), .. }))
1281-
|| matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)));
1292+
if matches!(fk.header(), Some(FnHeader { constness: ast::Const::Yes(_), .. })) {
1293+
true
1294+
} else if let Some(FnCtxt::Assoc(ctxt)) = fk.ctxt() {
1295+
match ctxt {
1296+
AssocCtxt::Trait => self.in_const_trait_defn,
1297+
AssocCtxt::Impl => self.in_const_trait_impl,
1298+
}
1299+
} else {
1300+
false
1301+
};
12821302

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

@@ -1511,6 +1531,7 @@ pub fn check_crate(
15111531
extern_mod: None,
15121532
in_trait_impl: false,
15131533
in_const_trait_impl: false,
1534+
in_const_trait_defn: false,
15141535
has_proc_macro_decls: false,
15151536
outer_impl_trait: None,
15161537
disallow_tilde_const: None,
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#![feature(const_trait_impl, effects)]
2+
3+
#[const_trait]
4+
trait MyTrait {
5+
fn do_something(&self);
6+
}
7+
8+
trait OtherTrait {
9+
fn do_something_else()
10+
where
11+
Self: ~const MyTrait;
12+
//~^ ERROR `~const` is not allowed here
13+
}
14+
15+
struct MyStruct<T>(T);
16+
17+
impl const MyTrait for u32 {
18+
fn do_something(&self) {}
19+
}
20+
21+
impl<T> MyStruct<T> {
22+
pub fn foo(&self)
23+
where
24+
T: ~const MyTrait,
25+
//~^ ERROR `~const` is not allowed here
26+
{
27+
self.0.do_something();
28+
}
29+
}
30+
31+
fn main() {
32+
MyStruct(0u32).foo();
33+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
error: `~const` is not allowed here
2+
--> $DIR/const-bound-on-not-const-associated-fn.rs:11:15
3+
|
4+
LL | Self: ~const MyTrait;
5+
| ^^^^^^^^^^^^^^
6+
|
7+
note: this function is not `const`, so it cannot have `~const` trait bounds
8+
--> $DIR/const-bound-on-not-const-associated-fn.rs:9:8
9+
|
10+
LL | fn do_something_else()
11+
| ^^^^^^^^^^^^^^^^^
12+
13+
error: `~const` is not allowed here
14+
--> $DIR/const-bound-on-not-const-associated-fn.rs:24:12
15+
|
16+
LL | T: ~const MyTrait,
17+
| ^^^^^^^^^^^^^^
18+
|
19+
note: this function is not `const`, so it cannot have `~const` trait bounds
20+
--> $DIR/const-bound-on-not-const-associated-fn.rs:22:12
21+
|
22+
LL | pub fn foo(&self)
23+
| ^^^
24+
25+
error: aborting due to 2 previous errors
26+

0 commit comments

Comments
 (0)