Skip to content

Commit 1367126

Browse files
authored
Rollup merge of rust-lang#151783 - mu001999-contrib:impl/final-method, r=fee1-dead
Implement RFC 3678: Final trait methods Tracking: rust-lang#131179 This PR is based on rust-lang#130802, with some minor changes and conflict resolution. Futhermore, this PR excludes final methods from the vtable of a dyn Trait. And some excerpt from the original PR description: > Implements the surface part of rust-lang/rfcs#3678. > > I'm using the word "method" in the title, but in the diagnostics and the feature gate I used "associated function", since that's more accurate. cc @joshtriplett
2 parents 118df88 + 8c77b6c commit 1367126

57 files changed

Lines changed: 755 additions & 117 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

compiler/rustc_ast/src/ast.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3131,8 +3131,16 @@ pub enum Const {
31313131
/// For details see the [RFC #2532](https://github.com/rust-lang/rfcs/pull/2532).
31323132
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, Walkable)]
31333133
pub enum Defaultness {
3134+
/// Item is unmarked. Implicitly determined based off of position.
3135+
/// For impls, this is `final`; for traits, this is `default`.
3136+
///
3137+
/// If you're expanding an item in a built-in macro or parsing an item
3138+
/// by hand, you probably want to use this.
3139+
Implicit,
3140+
/// `default`
31343141
Default(Span),
3135-
Final,
3142+
/// `final`; per RFC 3678, only trait items may be *explicitly* marked final.
3143+
Final(Span),
31363144
}
31373145

31383146
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic, Walkable)]
@@ -4140,7 +4148,7 @@ impl AssocItemKind {
41404148
| Self::Fn(box Fn { defaultness, .. })
41414149
| Self::Type(box TyAlias { defaultness, .. }) => defaultness,
41424150
Self::MacCall(..) | Self::Delegation(..) | Self::DelegationMac(..) => {
4143-
Defaultness::Final
4151+
Defaultness::Implicit
41444152
}
41454153
}
41464154
}

compiler/rustc_ast_lowering/src/item.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -939,7 +939,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
939939
);
940940
let trait_item_def_id = hir_id.expect_owner();
941941

942-
let (ident, generics, kind, has_default) = match &i.kind {
942+
let (ident, generics, kind, has_value) = match &i.kind {
943943
AssocItemKind::Const(box ConstItem {
944944
ident,
945945
generics,
@@ -1088,13 +1088,17 @@ impl<'hir> LoweringContext<'_, 'hir> {
10881088
}
10891089
};
10901090

1091+
let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value, || {
1092+
hir::Defaultness::Default { has_value }
1093+
});
1094+
10911095
let item = hir::TraitItem {
10921096
owner_id: trait_item_def_id,
10931097
ident: self.lower_ident(ident),
10941098
generics,
10951099
kind,
10961100
span: self.lower_span(i.span),
1097-
defaultness: hir::Defaultness::Default { has_value: has_default },
1101+
defaultness,
10981102
has_delayed_lints: !self.delayed_lints.is_empty(),
10991103
};
11001104
self.arena.alloc(item)
@@ -1122,7 +1126,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
11221126
// `defaultness.has_value()` is never called for an `impl`, always `true` in order
11231127
// to not cause an assertion failure inside the `lower_defaultness` function.
11241128
let has_val = true;
1125-
let (defaultness, defaultness_span) = self.lower_defaultness(defaultness, has_val);
1129+
let (defaultness, defaultness_span) =
1130+
self.lower_defaultness(defaultness, has_val, || hir::Defaultness::Final);
11261131
let modifiers = TraitBoundModifiers {
11271132
constness: BoundConstness::Never,
11281133
asyncness: BoundAsyncness::Normal,
@@ -1151,7 +1156,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
11511156
) -> &'hir hir::ImplItem<'hir> {
11521157
// Since `default impl` is not yet implemented, this is always true in impls.
11531158
let has_value = true;
1154-
let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value);
1159+
let (defaultness, _) =
1160+
self.lower_defaultness(i.kind.defaultness(), has_value, || hir::Defaultness::Final);
11551161
let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
11561162
let attrs = self.lower_attrs(
11571163
hir_id,
@@ -1304,15 +1310,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
13041310
&self,
13051311
d: Defaultness,
13061312
has_value: bool,
1313+
implicit: impl FnOnce() -> hir::Defaultness,
13071314
) -> (hir::Defaultness, Option<Span>) {
13081315
match d {
1316+
Defaultness::Implicit => (implicit(), None),
13091317
Defaultness::Default(sp) => {
13101318
(hir::Defaultness::Default { has_value }, Some(self.lower_span(sp)))
13111319
}
1312-
Defaultness::Final => {
1313-
assert!(has_value);
1314-
(hir::Defaultness::Final, None)
1315-
}
1320+
Defaultness::Final(sp) => (hir::Defaultness::Final, Some(self.lower_span(sp))),
13161321
}
13171322
}
13181323

compiler/rustc_ast_passes/src/ast_validation.rs

Lines changed: 66 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,28 @@ impl TraitOrImpl {
6565
}
6666
}
6767

68+
enum AllowDefault {
69+
Yes,
70+
No,
71+
}
72+
73+
impl AllowDefault {
74+
fn when(b: bool) -> Self {
75+
if b { Self::Yes } else { Self::No }
76+
}
77+
}
78+
79+
enum AllowFinal {
80+
Yes,
81+
No,
82+
}
83+
84+
impl AllowFinal {
85+
fn when(b: bool) -> Self {
86+
if b { Self::Yes } else { Self::No }
87+
}
88+
}
89+
6890
struct AstValidator<'a> {
6991
sess: &'a Session,
7092
features: &'a Features,
@@ -563,10 +585,32 @@ impl<'a> AstValidator<'a> {
563585
}
564586
}
565587

566-
fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
567-
if let Defaultness::Default(def_span) = defaultness {
568-
let span = self.sess.source_map().guess_head_span(span);
569-
self.dcx().emit_err(errors::ForbiddenDefault { span, def_span });
588+
fn check_defaultness(
589+
&self,
590+
span: Span,
591+
defaultness: Defaultness,
592+
allow_default: AllowDefault,
593+
allow_final: AllowFinal,
594+
) {
595+
match defaultness {
596+
Defaultness::Default(def_span) if matches!(allow_default, AllowDefault::No) => {
597+
let span = self.sess.source_map().guess_head_span(span);
598+
self.dcx().emit_err(errors::ForbiddenDefault { span, def_span });
599+
}
600+
Defaultness::Final(def_span) if matches!(allow_final, AllowFinal::No) => {
601+
let span = self.sess.source_map().guess_head_span(span);
602+
self.dcx().emit_err(errors::ForbiddenFinal { span, def_span });
603+
}
604+
_ => (),
605+
}
606+
}
607+
608+
fn check_final_has_body(&self, item: &Item<AssocItemKind>, defaultness: Defaultness) {
609+
if let AssocItemKind::Fn(box Fn { body: None, .. }) = &item.kind
610+
&& let Defaultness::Final(def_span) = defaultness
611+
{
612+
let span = self.sess.source_map().guess_head_span(item.span);
613+
self.dcx().emit_err(errors::ForbiddenFinalWithoutBody { span, def_span });
570614
}
571615
}
572616

@@ -1190,7 +1234,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
11901234
},
11911235
) => {
11921236
self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
1193-
self.check_defaultness(item.span, *defaultness);
1237+
self.check_defaultness(item.span, *defaultness, AllowDefault::No, AllowFinal::No);
11941238

11951239
for EiiImpl { eii_macro_path, .. } in eii_impls {
11961240
self.visit_path(eii_macro_path);
@@ -1360,7 +1404,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
13601404
});
13611405
}
13621406
ItemKind::Const(box ConstItem { defaultness, ident, rhs_kind, .. }) => {
1363-
self.check_defaultness(item.span, *defaultness);
1407+
self.check_defaultness(item.span, *defaultness, AllowDefault::No, AllowFinal::No);
13641408
if !rhs_kind.has_expr() {
13651409
self.dcx().emit_err(errors::ConstWithoutBody {
13661410
span: item.span,
@@ -1398,7 +1442,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
13981442
ItemKind::TyAlias(
13991443
ty_alias @ box TyAlias { defaultness, bounds, after_where_clause, ty, .. },
14001444
) => {
1401-
self.check_defaultness(item.span, *defaultness);
1445+
self.check_defaultness(item.span, *defaultness, AllowDefault::No, AllowFinal::No);
14021446
if ty.is_none() {
14031447
self.dcx().emit_err(errors::TyAliasWithoutBody {
14041448
span: item.span,
@@ -1428,7 +1472,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
14281472
fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
14291473
match &fi.kind {
14301474
ForeignItemKind::Fn(box Fn { defaultness, ident, sig, body, .. }) => {
1431-
self.check_defaultness(fi.span, *defaultness);
1475+
self.check_defaultness(fi.span, *defaultness, AllowDefault::No, AllowFinal::No);
14321476
self.check_foreign_fn_bodyless(*ident, body.as_deref());
14331477
self.check_foreign_fn_headerless(sig.header);
14341478
self.check_foreign_item_ascii_only(*ident);
@@ -1448,7 +1492,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
14481492
ty,
14491493
..
14501494
}) => {
1451-
self.check_defaultness(fi.span, *defaultness);
1495+
self.check_defaultness(fi.span, *defaultness, AllowDefault::No, AllowFinal::No);
14521496
self.check_foreign_kind_bodyless(*ident, "type", ty.as_ref().map(|b| b.span));
14531497
self.check_type_no_bounds(bounds, "`extern` blocks");
14541498
self.check_foreign_ty_genericless(generics, after_where_clause);
@@ -1707,9 +1751,19 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
17071751
self.check_nomangle_item_asciionly(ident, item.span);
17081752
}
17091753

1710-
if ctxt == AssocCtxt::Trait || self.outer_trait_or_trait_impl.is_none() {
1711-
self.check_defaultness(item.span, item.kind.defaultness());
1712-
}
1754+
let defaultness = item.kind.defaultness();
1755+
self.check_defaultness(
1756+
item.span,
1757+
defaultness,
1758+
// `default` is allowed on all associated items in impls.
1759+
AllowDefault::when(matches!(ctxt, AssocCtxt::Impl { .. })),
1760+
// `final` is allowed on all associated *functions* in traits.
1761+
AllowFinal::when(
1762+
ctxt == AssocCtxt::Trait && matches!(item.kind, AssocItemKind::Fn(..)),
1763+
),
1764+
);
1765+
1766+
self.check_final_has_body(item, defaultness);
17131767

17141768
if let AssocCtxt::Impl { .. } = ctxt {
17151769
match &item.kind {

compiler/rustc_ast_passes/src/errors.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,24 @@ pub(crate) struct ForbiddenDefault {
159159
pub def_span: Span,
160160
}
161161

162+
#[derive(Diagnostic)]
163+
#[diag("`final` is only allowed on associated functions in traits")]
164+
pub(crate) struct ForbiddenFinal {
165+
#[primary_span]
166+
pub span: Span,
167+
#[label("`final` because of this")]
168+
pub def_span: Span,
169+
}
170+
171+
#[derive(Diagnostic)]
172+
#[diag("`final` is only allowed on associated functions if they have a body")]
173+
pub(crate) struct ForbiddenFinalWithoutBody {
174+
#[primary_span]
175+
pub span: Span,
176+
#[label("`final` because of this")]
177+
pub def_span: Span,
178+
}
179+
162180
#[derive(Diagnostic)]
163181
#[diag("associated constant in `impl` without body")]
164182
pub(crate) struct AssocConstWithoutBody {

compiler/rustc_ast_passes/src/feature_gate.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
580580
gate_all!(frontmatter, "frontmatters are experimental");
581581
gate_all!(coroutines, "coroutine syntax is experimental");
582582
gate_all!(const_block_items, "const block items are experimental");
583+
gate_all!(final_associated_functions, "`final` on trait functions is experimental");
583584

584585
if !visitor.features.never_patterns() {
585586
if let Some(spans) = spans.get(&sym::never_patterns) {

compiler/rustc_ast_pretty/src/pprust/state/item.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ impl<'a> State<'a> {
5151
expr.as_deref(),
5252
vis,
5353
*safety,
54-
ast::Defaultness::Final,
54+
ast::Defaultness::Implicit,
5555
define_opaque.as_deref(),
5656
),
5757
ast::ForeignItemKind::TyAlias(box ast::TyAlias {
@@ -201,7 +201,7 @@ impl<'a> State<'a> {
201201
body.as_deref(),
202202
&item.vis,
203203
ast::Safety::Default,
204-
ast::Defaultness::Final,
204+
ast::Defaultness::Implicit,
205205
define_opaque.as_deref(),
206206
);
207207
}

compiler/rustc_builtin_macros/src/alloc_error_handler.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span
8383

8484
let body = Some(cx.block_expr(call));
8585
let kind = ItemKind::Fn(Box::new(Fn {
86-
defaultness: ast::Defaultness::Final,
86+
defaultness: ast::Defaultness::Implicit,
8787
sig,
8888
ident: Ident::from_str_and_span(&global_fn_name(ALLOC_ERROR_HANDLER), span),
8989
generics: Generics::default(),

compiler/rustc_builtin_macros/src/autodiff.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ mod llvm_enzyme {
334334

335335
// The first element of it is the name of the function to be generated
336336
let d_fn = Box::new(ast::Fn {
337-
defaultness: ast::Defaultness::Final,
337+
defaultness: ast::Defaultness::Implicit,
338338
sig: d_sig,
339339
ident: first_ident(&meta_item_vec[0]),
340340
generics,

compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ pub(crate) fn expand_deriving_coerce_pointee(
136136
of_trait: Some(Box::new(ast::TraitImplHeader {
137137
safety: ast::Safety::Default,
138138
polarity: ast::ImplPolarity::Positive,
139-
defaultness: ast::Defaultness::Final,
139+
defaultness: ast::Defaultness::Implicit,
140140
trait_ref,
141141
})),
142142
constness: ast::Const::No,
@@ -159,7 +159,7 @@ pub(crate) fn expand_deriving_coerce_pointee(
159159
of_trait: Some(Box::new(ast::TraitImplHeader {
160160
safety: ast::Safety::Default,
161161
polarity: ast::ImplPolarity::Positive,
162-
defaultness: ast::Defaultness::Final,
162+
defaultness: ast::Defaultness::Implicit,
163163
trait_ref,
164164
})),
165165
constness: ast::Const::No,

compiler/rustc_builtin_macros/src/deriving/generic/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -614,7 +614,7 @@ impl<'a> TraitDef<'a> {
614614
},
615615
attrs: ast::AttrVec::new(),
616616
kind: ast::AssocItemKind::Type(Box::new(ast::TyAlias {
617-
defaultness: ast::Defaultness::Final,
617+
defaultness: ast::Defaultness::Implicit,
618618
ident,
619619
generics: Generics::default(),
620620
after_where_clause: ast::WhereClause::default(),
@@ -851,7 +851,7 @@ impl<'a> TraitDef<'a> {
851851
of_trait: Some(Box::new(ast::TraitImplHeader {
852852
safety: self.safety,
853853
polarity: ast::ImplPolarity::Positive,
854-
defaultness: ast::Defaultness::Final,
854+
defaultness: ast::Defaultness::Implicit,
855855
trait_ref,
856856
})),
857857
constness: if self.is_const { ast::Const::Yes(DUMMY_SP) } else { ast::Const::No },
@@ -1073,7 +1073,7 @@ impl<'a> MethodDef<'a> {
10731073
let trait_lo_sp = span.shrink_to_lo();
10741074

10751075
let sig = ast::FnSig { header: ast::FnHeader::default(), decl: fn_decl, span };
1076-
let defaultness = ast::Defaultness::Final;
1076+
let defaultness = ast::Defaultness::Implicit;
10771077

10781078
// Create the method.
10791079
Box::new(ast::AssocItem {

0 commit comments

Comments
 (0)