Skip to content

Commit 00157d4

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

File tree

8 files changed

+78
-86
lines changed

8 files changed

+78
-86
lines changed

compiler/rustc_ast_passes/src/ast_validation.rs

Lines changed: 62 additions & 39 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,27 +95,20 @@ 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
) {
101-
let old = mem::replace(
102-
&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-
}),
108-
);
103+
let old = mem::replace(&mut self.outer_trait_or_trait_impl, in_trait_or_impl);
109104
f(self);
110105
self.outer_trait_or_trait_impl = old;
111106
}
112107

113108
fn with_in_trait(&mut self, vis: Span, constness: Const, f: impl FnOnce(&mut Self)) {
114109
let old = mem::replace(
115110
&mut self.outer_trait_or_trait_impl,
116-
Some(TraitOrTraitImpl::Trait { vis, constness }),
111+
Some(TraitOrImpl::Trait { vis, constness }),
117112
);
118113
f(self);
119114
self.outer_trait_or_trait_impl = old;
@@ -247,14 +242,14 @@ impl<'a> AstValidator<'a> {
247242
}
248243
}
249244

250-
fn check_trait_fn_not_const(&self, constness: Const, parent: &TraitOrTraitImpl) {
245+
fn check_trait_fn_not_const(&self, constness: Const, parent: &TraitOrImpl) {
251246
let Const::Yes(span) = constness else {
252247
return;
253248
};
254249

255250
let const_trait_impl = self.features.const_trait_impl();
256251
let make_impl_const_sugg = if const_trait_impl
257-
&& let TraitOrTraitImpl::TraitImpl {
252+
&& let TraitOrImpl::TraitImpl {
258253
constness: Const::No,
259254
polarity: ImplPolarity::Positive,
260255
trait_ref_span,
@@ -269,7 +264,7 @@ impl<'a> AstValidator<'a> {
269264
let map = self.sess.source_map();
270265

271266
let make_trait_const_sugg = if const_trait_impl
272-
&& let &TraitOrTraitImpl::Trait { vis, constness: ast::Const::No } = parent
267+
&& let &TraitOrImpl::Trait { vis, constness: ast::Const::No } = parent
273268
{
274269
Some(map.span_extend_while_whitespace(vis).shrink_to_hi())
275270
} else {
@@ -279,7 +274,7 @@ impl<'a> AstValidator<'a> {
279274
let parent_constness = parent.constness();
280275
self.dcx().emit_err(errors::TraitFnConst {
281276
span,
282-
in_impl: matches!(parent, TraitOrTraitImpl::TraitImpl { .. }),
277+
in_impl: matches!(parent, TraitOrImpl::TraitImpl { .. }),
283278
const_context_label: parent_constness,
284279
remove_const_sugg: (
285280
map.span_extend_while_whitespace(span),
@@ -295,7 +290,7 @@ impl<'a> AstValidator<'a> {
295290
});
296291
}
297292

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

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

306301
self.dcx().emit_err(errors::AsyncFnInConstTraitOrTraitImpl {
307302
async_keyword,
308-
in_impl: matches!(parent, TraitOrTraitImpl::TraitImpl { .. }),
303+
in_impl: matches!(parent, TraitOrImpl::TraitImpl { .. }),
309304
const_keyword,
310305
});
311306
}
@@ -1100,24 +1095,46 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
11001095
self.visit_trait_ref(t);
11011096
self.visit_ty(self_ty);
11021097

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-
});
1098+
self.with_in_trait_or_impl(
1099+
Some(TraitOrImpl::TraitImpl {
1100+
constness: *constness,
1101+
polarity: *polarity,
1102+
trait_ref_span: t.path.span,
1103+
}),
1104+
|this| {
1105+
walk_list!(
1106+
this,
1107+
visit_assoc_item,
1108+
items,
1109+
AssocCtxt::Impl { of_trait: true }
1110+
);
1111+
},
1112+
);
11061113
}
1107-
ItemKind::Impl(Impl { generics, of_trait: None, self_ty, items, constness: _ }) => {
1114+
ItemKind::Impl(Impl { generics, of_trait: None, self_ty, items, constness }) => {
11081115
self.visit_attrs_vis(&item.attrs, &item.vis);
11091116
self.visibility_not_permitted(
11101117
&item.vis,
11111118
errors::VisibilityNotPermittedNote::IndividualImplItems,
11121119
);
11131120

1114-
self.with_tilde_const(Some(TildeConstReason::Impl { span: item.span }), |this| {
1115-
this.visit_generics(generics)
1116-
});
1121+
let disallowed = matches!(constness, ast::Const::No)
1122+
.then(|| TildeConstReason::Impl { span: item.span });
1123+
1124+
self.with_tilde_const(disallowed, |this| this.visit_generics(generics));
1125+
11171126
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-
});
1127+
self.with_in_trait_or_impl(
1128+
Some(TraitOrImpl::Impl { constness: *constness }),
1129+
|this| {
1130+
walk_list!(
1131+
this,
1132+
visit_assoc_item,
1133+
items,
1134+
AssocCtxt::Impl { of_trait: false }
1135+
);
1136+
},
1137+
);
11211138
}
11221139
ItemKind::Fn(
11231140
func @ box Fn {
@@ -1235,7 +1252,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
12351252
this.visit_generics(generics);
12361253
walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
12371254
});
1238-
self.with_in_trait(item.vis.span, *constness, |this| {
1255+
self.with_in_trait(item.span, *constness, |this| {
12391256
walk_list!(this, visit_assoc_item, items, AssocCtxt::Trait);
12401257
});
12411258
}
@@ -1605,7 +1622,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
16051622
&& self
16061623
.outer_trait_or_trait_impl
16071624
.as_ref()
1608-
.and_then(TraitOrTraitImpl::constness)
1625+
.and_then(TraitOrImpl::constness)
16091626
.is_some();
16101627

16111628
let disallowed = (!tilde_const_allowed).then(|| match fk {
@@ -1672,7 +1689,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
16721689
);
16731690
}
16741691

1675-
if let Some(parent) = &self.outer_trait_or_trait_impl {
1692+
if let Some(parent @ (TraitOrImpl::Trait { .. } | TraitOrImpl::TraitImpl { .. })) =
1693+
&self.outer_trait_or_trait_impl
1694+
{
16761695
self.visibility_not_permitted(&item.vis, errors::VisibilityNotPermittedNote::TraitImpl);
16771696
if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
16781697
self.check_trait_fn_not_const(sig.header.constness, parent);
@@ -1685,7 +1704,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
16851704
}
16861705

16871706
let parent_is_const =
1688-
self.outer_trait_or_trait_impl.as_ref().and_then(TraitOrTraitImpl::constness).is_some();
1707+
self.outer_trait_or_trait_impl.as_ref().and_then(TraitOrImpl::constness).is_some();
16891708

16901709
match &item.kind {
16911710
AssocItemKind::Fn(func)
@@ -1699,19 +1718,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
16991718
}
17001719
AssocItemKind::Type(_) => {
17011720
let disallowed = (!parent_is_const).then(|| match self.outer_trait_or_trait_impl {
1702-
Some(TraitOrTraitImpl::Trait { .. }) => {
1721+
Some(TraitOrImpl::Trait { .. }) => {
17031722
TildeConstReason::TraitAssocTy { span: item.span }
17041723
}
1705-
Some(TraitOrTraitImpl::TraitImpl { .. }) => {
1724+
Some(TraitOrImpl::TraitImpl { .. }) => {
17061725
TildeConstReason::TraitImplAssocTy { span: item.span }
17071726
}
1708-
None => TildeConstReason::InherentAssocTy { span: item.span },
1727+
Some(TraitOrImpl::Impl { .. }) | None => {
1728+
TildeConstReason::InherentAssocTy { span: item.span }
1729+
}
17091730
});
17101731
self.with_tilde_const(disallowed, |this| {
1711-
this.with_in_trait_impl(None, |this| visit::walk_assoc_item(this, item, ctxt))
1732+
this.with_in_trait_or_impl(None, |this| {
1733+
visit::walk_assoc_item(this, item, ctxt)
1734+
})
17121735
})
17131736
}
1714-
_ => self.with_in_trait_impl(None, |this| visit::walk_assoc_item(this, item, ctxt)),
1737+
_ => self.with_in_trait_or_impl(None, |this| visit::walk_assoc_item(this, item, ctxt)),
17151738
}
17161739
}
17171740

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)