Skip to content

Commit f8ebb53

Browse files
committed
Allow inherent const impl blocks
1 parent c61304a commit f8ebb53

File tree

8 files changed

+82
-96
lines changed

8 files changed

+82
-96
lines changed

compiler/rustc_ast_passes/src/ast_validation.rs

Lines changed: 66 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,17 @@ enum SelfSemantic {
4747
No,
4848
}
4949

50-
enum TraitOrTraitImpl {
50+
enum TraitOrImpl {
5151
Trait { span: Span, constness: Const },
5252
TraitImpl { constness: Const, polarity: ImplPolarity, trait_ref_span: Span },
53+
Impl { constness: Const },
5354
}
5455

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

72-
outer_trait_or_trait_impl: Option<TraitOrTraitImpl>,
74+
outer_trait_or_trait_impl: Option<TraitOrImpl>,
7375

7476
has_proc_macro_decls: bool,
7577

@@ -92,28 +94,12 @@ struct AstValidator<'a> {
9294
}
9395

9496
impl<'a> AstValidator<'a> {
95-
fn with_in_trait_impl(
97+
fn with_in_trait_or_impl(
9698
&mut self,
97-
trait_: Option<(Const, ImplPolarity, &'a TraitRef)>,
99+
in_trait_or_impl: Option<TraitOrImpl>,
98100
f: impl FnOnce(&mut Self),
99101
) {
100-
let old = mem::replace(
101-
&mut self.outer_trait_or_trait_impl,
102-
trait_.map(|(constness, polarity, trait_ref)| TraitOrTraitImpl::TraitImpl {
103-
constness,
104-
polarity,
105-
trait_ref_span: trait_ref.path.span,
106-
}),
107-
);
108-
f(self);
109-
self.outer_trait_or_trait_impl = old;
110-
}
111-
112-
fn with_in_trait(&mut self, span: Span, constness: Const, f: impl FnOnce(&mut Self)) {
113-
let old = mem::replace(
114-
&mut self.outer_trait_or_trait_impl,
115-
Some(TraitOrTraitImpl::Trait { span, constness }),
116-
);
102+
let old = mem::replace(&mut self.outer_trait_or_trait_impl, in_trait_or_impl);
117103
f(self);
118104
self.outer_trait_or_trait_impl = old;
119105
}
@@ -246,14 +232,14 @@ impl<'a> AstValidator<'a> {
246232
}
247233
}
248234

249-
fn check_trait_fn_not_const(&self, constness: Const, parent: &TraitOrTraitImpl) {
235+
fn check_trait_fn_not_const(&self, constness: Const, parent: &TraitOrImpl) {
250236
let Const::Yes(span) = constness else {
251237
return;
252238
};
253239

254240
let const_trait_impl = self.features.const_trait_impl();
255241
let make_impl_const_sugg = if const_trait_impl
256-
&& let TraitOrTraitImpl::TraitImpl {
242+
&& let TraitOrImpl::TraitImpl {
257243
constness: Const::No,
258244
polarity: ImplPolarity::Positive,
259245
trait_ref_span,
@@ -266,7 +252,7 @@ impl<'a> AstValidator<'a> {
266252
};
267253

268254
let make_trait_const_sugg = if const_trait_impl
269-
&& let TraitOrTraitImpl::Trait { span, constness: ast::Const::No } = parent
255+
&& let TraitOrImpl::Trait { span, constness: ast::Const::No } = parent
270256
{
271257
Some(span.shrink_to_lo())
272258
} else {
@@ -276,7 +262,7 @@ impl<'a> AstValidator<'a> {
276262
let parent_constness = parent.constness();
277263
self.dcx().emit_err(errors::TraitFnConst {
278264
span,
279-
in_impl: matches!(parent, TraitOrTraitImpl::TraitImpl { .. }),
265+
in_impl: matches!(parent, TraitOrImpl::TraitImpl { .. }),
280266
const_context_label: parent_constness,
281267
remove_const_sugg: (
282268
self.sess.source_map().span_extend_while_whitespace(span),
@@ -292,7 +278,7 @@ impl<'a> AstValidator<'a> {
292278
});
293279
}
294280

295-
fn check_async_fn_in_const_trait_or_impl(&self, sig: &FnSig, parent: &TraitOrTraitImpl) {
281+
fn check_async_fn_in_const_trait_or_impl(&self, sig: &FnSig, parent: &TraitOrImpl) {
296282
let Some(const_keyword) = parent.constness() else { return };
297283

298284
let Some(CoroutineKind::Async { span: async_keyword, .. }) = sig.header.coroutine_kind
@@ -302,7 +288,7 @@ impl<'a> AstValidator<'a> {
302288

303289
self.dcx().emit_err(errors::AsyncFnInConstTraitOrTraitImpl {
304290
async_keyword,
305-
in_impl: matches!(parent, TraitOrTraitImpl::TraitImpl { .. }),
291+
in_impl: matches!(parent, TraitOrImpl::TraitImpl { .. }),
306292
const_keyword,
307293
});
308294
}
@@ -1041,24 +1027,46 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
10411027
self.visit_trait_ref(t);
10421028
self.visit_ty(self_ty);
10431029

1044-
self.with_in_trait_impl(Some((*constness, *polarity, t)), |this| {
1045-
walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl { of_trait: true });
1046-
});
1030+
self.with_in_trait_or_impl(
1031+
Some(TraitOrImpl::TraitImpl {
1032+
constness: *constness,
1033+
polarity: *polarity,
1034+
trait_ref_span: t.path.span,
1035+
}),
1036+
|this| {
1037+
walk_list!(
1038+
this,
1039+
visit_assoc_item,
1040+
items,
1041+
AssocCtxt::Impl { of_trait: true }
1042+
);
1043+
},
1044+
);
10471045
}
1048-
ItemKind::Impl(Impl { generics, of_trait: None, self_ty, items, constness: _ }) => {
1046+
ItemKind::Impl(Impl { generics, of_trait: None, self_ty, items, constness }) => {
10491047
self.visit_attrs_vis(&item.attrs, &item.vis);
10501048
self.visibility_not_permitted(
10511049
&item.vis,
10521050
errors::VisibilityNotPermittedNote::IndividualImplItems,
10531051
);
10541052

1055-
self.with_tilde_const(Some(TildeConstReason::Impl { span: item.span }), |this| {
1056-
this.visit_generics(generics)
1057-
});
1053+
let disallowed = matches!(constness, ast::Const::No)
1054+
.then(|| TildeConstReason::Impl { span: item.span });
1055+
1056+
self.with_tilde_const(disallowed, |this| this.visit_generics(generics));
1057+
10581058
self.visit_ty(self_ty);
1059-
self.with_in_trait_impl(None, |this| {
1060-
walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl { of_trait: false });
1061-
});
1059+
self.with_in_trait_or_impl(
1060+
Some(TraitOrImpl::Impl { constness: *constness }),
1061+
|this| {
1062+
walk_list!(
1063+
this,
1064+
visit_assoc_item,
1065+
items,
1066+
AssocCtxt::Impl { of_trait: false }
1067+
);
1068+
},
1069+
);
10621070
}
10631071
ItemKind::Fn(
10641072
func @ box Fn {
@@ -1183,9 +1191,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
11831191
this.visit_generics(generics);
11841192
walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
11851193
});
1186-
self.with_in_trait(item.span, constness, |this| {
1187-
walk_list!(this, visit_assoc_item, items, AssocCtxt::Trait);
1188-
});
1194+
self.with_in_trait_or_impl(
1195+
Some(TraitOrImpl::Trait { span: item.span, constness }),
1196+
|this| {
1197+
walk_list!(this, visit_assoc_item, items, AssocCtxt::Trait);
1198+
},
1199+
);
11891200
}
11901201
ItemKind::TraitAlias(box TraitAlias { constness, generics, bounds, .. }) => {
11911202
let disallowed = matches!(constness, ast::Const::No)
@@ -1553,7 +1564,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
15531564
&& self
15541565
.outer_trait_or_trait_impl
15551566
.as_ref()
1556-
.and_then(TraitOrTraitImpl::constness)
1567+
.and_then(TraitOrImpl::constness)
15571568
.is_some();
15581569

15591570
let disallowed = (!tilde_const_allowed).then(|| match fk {
@@ -1620,7 +1631,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
16201631
);
16211632
}
16221633

1623-
if let Some(parent) = &self.outer_trait_or_trait_impl {
1634+
if let Some(parent @ (TraitOrImpl::Trait { .. } | TraitOrImpl::TraitImpl { .. })) =
1635+
&self.outer_trait_or_trait_impl
1636+
{
16241637
self.visibility_not_permitted(&item.vis, errors::VisibilityNotPermittedNote::TraitImpl);
16251638
if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
16261639
self.check_trait_fn_not_const(sig.header.constness, parent);
@@ -1633,7 +1646,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
16331646
}
16341647

16351648
let parent_is_const =
1636-
self.outer_trait_or_trait_impl.as_ref().and_then(TraitOrTraitImpl::constness).is_some();
1649+
self.outer_trait_or_trait_impl.as_ref().and_then(TraitOrImpl::constness).is_some();
16371650

16381651
match &item.kind {
16391652
AssocItemKind::Fn(func)
@@ -1647,19 +1660,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
16471660
}
16481661
AssocItemKind::Type(_) => {
16491662
let disallowed = (!parent_is_const).then(|| match self.outer_trait_or_trait_impl {
1650-
Some(TraitOrTraitImpl::Trait { .. }) => {
1663+
Some(TraitOrImpl::Trait { .. }) => {
16511664
TildeConstReason::TraitAssocTy { span: item.span }
16521665
}
1653-
Some(TraitOrTraitImpl::TraitImpl { .. }) => {
1666+
Some(TraitOrImpl::TraitImpl { .. }) => {
16541667
TildeConstReason::TraitImplAssocTy { span: item.span }
16551668
}
1656-
None => TildeConstReason::InherentAssocTy { span: item.span },
1669+
Some(TraitOrImpl::Impl { .. }) | None => {
1670+
TildeConstReason::InherentAssocTy { span: item.span }
1671+
}
16571672
});
16581673
self.with_tilde_const(disallowed, |this| {
1659-
this.with_in_trait_impl(None, |this| visit::walk_assoc_item(this, item, ctxt))
1674+
this.with_in_trait_or_impl(None, |this| {
1675+
visit::walk_assoc_item(this, item, ctxt)
1676+
})
16601677
})
16611678
}
1662-
_ => self.with_in_trait_impl(None, |this| visit::walk_assoc_item(this, item, ctxt)),
1679+
_ => self.with_in_trait_or_impl(None, |this| visit::walk_assoc_item(this, item, ctxt)),
16631680
}
16641681
}
16651682

compiler/rustc_parse/src/parser/item.rs

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

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)