Skip to content

Commit e7e5104

Browse files
committed
Allow inherent const impl blocks
1 parent 2a36d33 commit e7e5104

File tree

8 files changed

+78
-83
lines changed

8 files changed

+78
-83
lines changed

compiler/rustc_ast_passes/src/ast_validation.rs

Lines changed: 62 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,17 @@ enum SelfSemantic {
4848
No,
4949
}
5050

51-
enum TraitOrTraitImpl {
51+
enum TraitOrImpl {
5252
Trait { vis: Span, constness: Const },
5353
TraitImpl { constness: Const, polarity: ImplPolarity, trait_ref_span: Span },
54+
Impl { constness: Const },
5455
}
5556

56-
impl TraitOrTraitImpl {
57+
impl TraitOrImpl {
5758
fn constness(&self) -> Option<Span> {
5859
match self {
5960
Self::Trait { constness: Const::Yes(span), .. }
61+
| Self::Impl { constness: Const::Yes(span), .. }
6062
| Self::TraitImpl { constness: Const::Yes(span), .. } => Some(*span),
6163
_ => None,
6264
}
@@ -70,7 +72,7 @@ struct AstValidator<'a> {
7072
/// The span of the `extern` in an `extern { ... }` block, if any.
7173
extern_mod_span: Option<Span>,
7274

73-
outer_trait_or_trait_impl: Option<TraitOrTraitImpl>,
75+
outer_trait_or_trait_impl: Option<TraitOrImpl>,
7476

7577
has_proc_macro_decls: bool,
7678

@@ -93,18 +95,14 @@ struct AstValidator<'a> {
9395
}
9496

9597
impl<'a> AstValidator<'a> {
96-
fn with_in_trait_impl(
98+
fn with_in_trait_or_impl(
9799
&mut self,
98-
trait_: Option<(Const, ImplPolarity, &'a TraitRef)>,
100+
in_trait_or_impl: Option<TraitOrImpl>,
99101
f: impl FnOnce(&mut Self),
100102
) {
101103
let old = mem::replace(
102104
&mut self.outer_trait_or_trait_impl,
103-
trait_.map(|(constness, polarity, trait_ref)| TraitOrTraitImpl::TraitImpl {
104-
constness,
105-
polarity,
106-
trait_ref_span: trait_ref.path.span,
107-
}),
105+
in_trait_or_impl,
108106
);
109107
f(self);
110108
self.outer_trait_or_trait_impl = old;
@@ -113,7 +111,7 @@ impl<'a> AstValidator<'a> {
113111
fn with_in_trait(&mut self, vis: Span, constness: Const, f: impl FnOnce(&mut Self)) {
114112
let old = mem::replace(
115113
&mut self.outer_trait_or_trait_impl,
116-
Some(TraitOrTraitImpl::Trait { vis, constness }),
114+
Some(TraitOrImpl::Trait { vis, constness }),
117115
);
118116
f(self);
119117
self.outer_trait_or_trait_impl = old;
@@ -247,14 +245,14 @@ impl<'a> AstValidator<'a> {
247245
}
248246
}
249247

250-
fn check_trait_fn_not_const(&self, constness: Const, parent: &TraitOrTraitImpl) {
248+
fn check_trait_fn_not_const(&self, constness: Const, parent: &TraitOrImpl) {
251249
let Const::Yes(span) = constness else {
252250
return;
253251
};
254252

255253
let const_trait_impl = self.features.const_trait_impl();
256254
let make_impl_const_sugg = if const_trait_impl
257-
&& let TraitOrTraitImpl::TraitImpl {
255+
&& let TraitOrImpl::TraitImpl {
258256
constness: Const::No,
259257
polarity: ImplPolarity::Positive,
260258
trait_ref_span,
@@ -269,7 +267,7 @@ impl<'a> AstValidator<'a> {
269267
let map = self.sess.source_map();
270268

271269
let make_trait_const_sugg = if const_trait_impl
272-
&& let &TraitOrTraitImpl::Trait { vis, constness: ast::Const::No } = parent
270+
&& let &TraitOrImpl::Trait { vis, constness: ast::Const::No } = parent
273271
{
274272
Some(map.span_extend_while_whitespace(vis).shrink_to_hi())
275273
} else {
@@ -279,7 +277,7 @@ impl<'a> AstValidator<'a> {
279277
let parent_constness = parent.constness();
280278
self.dcx().emit_err(errors::TraitFnConst {
281279
span,
282-
in_impl: matches!(parent, TraitOrTraitImpl::TraitImpl { .. }),
280+
in_impl: matches!(parent, TraitOrImpl::TraitImpl { .. }),
283281
const_context_label: parent_constness,
284282
remove_const_sugg: (
285283
map.span_extend_while_whitespace(span),
@@ -295,7 +293,7 @@ impl<'a> AstValidator<'a> {
295293
});
296294
}
297295

298-
fn check_async_fn_in_const_trait_or_impl(&self, sig: &FnSig, parent: &TraitOrTraitImpl) {
296+
fn check_async_fn_in_const_trait_or_impl(&self, sig: &FnSig, parent: &TraitOrImpl) {
299297
let Some(const_keyword) = parent.constness() else { return };
300298

301299
let Some(CoroutineKind::Async { span: async_keyword, .. }) = sig.header.coroutine_kind
@@ -305,7 +303,7 @@ impl<'a> AstValidator<'a> {
305303

306304
self.dcx().emit_err(errors::AsyncFnInConstTraitOrTraitImpl {
307305
async_keyword,
308-
in_impl: matches!(parent, TraitOrTraitImpl::TraitImpl { .. }),
306+
in_impl: matches!(parent, TraitOrImpl::TraitImpl { .. }),
309307
const_keyword,
310308
});
311309
}
@@ -1100,24 +1098,46 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
11001098
self.visit_trait_ref(t);
11011099
self.visit_ty(self_ty);
11021100

1103-
self.with_in_trait_impl(Some((*constness, *polarity, t)), |this| {
1104-
walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl { of_trait: true });
1105-
});
1101+
self.with_in_trait_or_impl(
1102+
Some(TraitOrImpl::TraitImpl {
1103+
constness: *constness,
1104+
polarity: *polarity,
1105+
trait_ref_span: t.path.span,
1106+
}),
1107+
|this| {
1108+
walk_list!(
1109+
this,
1110+
visit_assoc_item,
1111+
items,
1112+
AssocCtxt::Impl { of_trait: true }
1113+
);
1114+
},
1115+
);
11061116
}
1107-
ItemKind::Impl(Impl { generics, of_trait: None, self_ty, items, constness: _ }) => {
1117+
ItemKind::Impl(Impl { generics, of_trait: None, self_ty, items, constness }) => {
11081118
self.visit_attrs_vis(&item.attrs, &item.vis);
11091119
self.visibility_not_permitted(
11101120
&item.vis,
11111121
errors::VisibilityNotPermittedNote::IndividualImplItems,
11121122
);
11131123

1114-
self.with_tilde_const(Some(TildeConstReason::Impl { span: item.span }), |this| {
1115-
this.visit_generics(generics)
1116-
});
1124+
let disallowed = matches!(constness, ast::Const::No)
1125+
.then(|| TildeConstReason::Impl { span: item.span });
1126+
1127+
self.with_tilde_const(disallowed, |this| this.visit_generics(generics));
1128+
11171129
self.visit_ty(self_ty);
1118-
self.with_in_trait_impl(None, |this| {
1119-
walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl { of_trait: false });
1120-
});
1130+
self.with_in_trait_or_impl(
1131+
Some(TraitOrImpl::Impl { constness: *constness }),
1132+
|this| {
1133+
walk_list!(
1134+
this,
1135+
visit_assoc_item,
1136+
items,
1137+
AssocCtxt::Impl { of_trait: false }
1138+
);
1139+
},
1140+
);
11211141
}
11221142
ItemKind::Fn(
11231143
func @ box Fn {
@@ -1235,7 +1255,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
12351255
this.visit_generics(generics);
12361256
walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
12371257
});
1238-
self.with_in_trait(item.vis.span, *constness, |this| {
1258+
self.with_in_trait(item.span, *constness, |this| {
12391259
walk_list!(this, visit_assoc_item, items, AssocCtxt::Trait);
12401260
});
12411261
}
@@ -1605,7 +1625,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
16051625
&& self
16061626
.outer_trait_or_trait_impl
16071627
.as_ref()
1608-
.and_then(TraitOrTraitImpl::constness)
1628+
.and_then(TraitOrImpl::constness)
16091629
.is_some();
16101630

16111631
let disallowed = (!tilde_const_allowed).then(|| match fk {
@@ -1672,7 +1692,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
16721692
);
16731693
}
16741694

1675-
if let Some(parent) = &self.outer_trait_or_trait_impl {
1695+
if let Some(parent @ (TraitOrImpl::Trait { .. } | TraitOrImpl::TraitImpl { .. })) =
1696+
&self.outer_trait_or_trait_impl
1697+
{
16761698
self.visibility_not_permitted(&item.vis, errors::VisibilityNotPermittedNote::TraitImpl);
16771699
if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
16781700
self.check_trait_fn_not_const(sig.header.constness, parent);
@@ -1685,7 +1707,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
16851707
}
16861708

16871709
let parent_is_const =
1688-
self.outer_trait_or_trait_impl.as_ref().and_then(TraitOrTraitImpl::constness).is_some();
1710+
self.outer_trait_or_trait_impl.as_ref().and_then(TraitOrImpl::constness).is_some();
16891711

16901712
match &item.kind {
16911713
AssocItemKind::Fn(func)
@@ -1699,19 +1721,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
16991721
}
17001722
AssocItemKind::Type(_) => {
17011723
let disallowed = (!parent_is_const).then(|| match self.outer_trait_or_trait_impl {
1702-
Some(TraitOrTraitImpl::Trait { .. }) => {
1724+
Some(TraitOrImpl::Trait { .. }) => {
17031725
TildeConstReason::TraitAssocTy { span: item.span }
17041726
}
1705-
Some(TraitOrTraitImpl::TraitImpl { .. }) => {
1727+
Some(TraitOrImpl::TraitImpl { .. }) => {
17061728
TildeConstReason::TraitImplAssocTy { span: item.span }
17071729
}
1708-
None => TildeConstReason::InherentAssocTy { span: item.span },
1730+
Some(TraitOrImpl::Impl { .. }) | None => {
1731+
TildeConstReason::InherentAssocTy { span: item.span }
1732+
}
17091733
});
17101734
self.with_tilde_const(disallowed, |this| {
1711-
this.with_in_trait_impl(None, |this| visit::walk_assoc_item(this, item, ctxt))
1735+
this.with_in_trait_or_impl(None, |this| {
1736+
visit::walk_assoc_item(this, item, ctxt)
1737+
})
17121738
})
17131739
}
1714-
_ => self.with_in_trait_impl(None, |this| visit::walk_assoc_item(this, item, ctxt)),
1740+
_ => self.with_in_trait_or_impl(None, |this| visit::walk_assoc_item(this, item, ctxt)),
17151741
}
17161742
}
17171743

compiler/rustc_parse/src/parser/item.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -691,7 +691,7 @@ impl<'a> Parser<'a> {
691691
error("default", "default", def_span).emit();
692692
}
693693
if let Const::Yes(span) = constness {
694-
error("const", "const", span).emit();
694+
self.psess.gated_spans.gate(sym::const_trait_impl, span);
695695
}
696696
(None, self_ty)
697697
}

tests/ui/traits/const-traits/const-impl-norecover.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22

33
struct Foo;
44

5-
const impl Foo { //~ ERROR: inherent impls cannot be const
5+
const impl Foo {
66
fn bar() {}
77
}
88

9+
const _: () = Foo::bar();
10+
//~^ ERROR: cannot call non-const associated function `Foo::bar` in constants
11+
912
fn main() {
1013
// shouldn't error here because we shouldn't have been able to recover above
1114
Foo::bar();
Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
error: inherent impls cannot be const
2-
--> $DIR/const-impl-norecover.rs:5:12
1+
error[E0015]: cannot call non-const associated function `Foo::bar` in constants
2+
--> $DIR/const-impl-norecover.rs:9:15
33
|
4-
LL | const impl Foo {
5-
| ----- ^^^ inherent impl for this type
6-
| |
7-
| const because of this
4+
LL | const _: () = Foo::bar();
5+
| ^^^^^^^^^^
86
|
9-
= note: only trait implementations may be annotated with `const`
7+
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
108

119
error: aborting due to 1 previous error
1210

11+
For more information about this error, try `rustc --explain E0015`.
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
#![feature(const_trait_impl)]
22
#![allow(bare_trait_objects)]
33

4+
//@ check-pass
5+
46
struct S;
57
trait T {}
68

79
impl const S {}
8-
//~^ ERROR inherent impls cannot be const
910

1011
impl const dyn T {}
11-
//~^ ERROR inherent impls cannot be const
1212

1313
fn main() {}

tests/ui/traits/const-traits/inherent-impl.stderr

Lines changed: 0 additions & 22 deletions
This file was deleted.

tests/ui/traits/const-traits/span-bug-issue-121418.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ struct S;
44
trait T {}
55

66
impl const dyn T {
7-
//~^ ERROR inherent impls cannot be const
87
pub const fn new() -> std::sync::Mutex<dyn T> {}
98
//~^ ERROR mismatched types
109
//~| ERROR cannot be known at compilation time
Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,5 @@
1-
error: inherent impls cannot be const
2-
--> $DIR/span-bug-issue-121418.rs:6:12
3-
|
4-
LL | impl const dyn T {
5-
| ----- ^^^^^ inherent impl for this type
6-
| |
7-
| const because of this
8-
|
9-
= note: only trait implementations may be annotated with `const`
10-
111
error[E0277]: the size for values of type `(dyn T + 'static)` cannot be known at compilation time
12-
--> $DIR/span-bug-issue-121418.rs:8:27
2+
--> $DIR/span-bug-issue-121418.rs:7:27
133
|
144
LL | pub const fn new() -> std::sync::Mutex<dyn T> {}
155
| ^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
@@ -20,7 +10,7 @@ note: required because it appears within the type `std::sync::Mutex<(dyn T + 'st
2010
= note: the return type of a function must have a statically known size
2111

2212
error[E0308]: mismatched types
23-
--> $DIR/span-bug-issue-121418.rs:8:27
13+
--> $DIR/span-bug-issue-121418.rs:7:27
2414
|
2515
LL | pub const fn new() -> std::sync::Mutex<dyn T> {}
2616
| --- ^^^^^^^^^^^^^^^^^^^^^^^ expected `Mutex<dyn T>`, found `()`
@@ -30,7 +20,7 @@ LL | pub const fn new() -> std::sync::Mutex<dyn T> {}
3020
= note: expected struct `std::sync::Mutex<(dyn T + 'static)>`
3121
found unit type `()`
3222

33-
error: aborting due to 3 previous errors
23+
error: aborting due to 2 previous errors
3424

3525
Some errors have detailed explanations: E0277, E0308.
3626
For more information about an error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)