Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 462c1c8

Browse files
committed
generate code for subdiagnostic fields in the second match
1 parent 3655175 commit 462c1c8

File tree

2 files changed

+63
-27
lines changed

2 files changed

+63
-27
lines changed

compiler/rustc_macros/src/diagnostics/diagnostic.rs

Lines changed: 56 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -71,31 +71,46 @@ impl<'a> SessionDiagnosticDerive<'a> {
7171
}
7272
};
7373

74+
// Keep track of which fields are subdiagnostics
75+
let mut subdiagnostics = std::collections::HashSet::new();
76+
7477
// Generates calls to `span_label` and similar functions based on the attributes
7578
// on fields. Code for suggestions uses formatting machinery and the value of
7679
// other fields - because any given field can be referenced multiple times, it
7780
// should be accessed through a borrow. When passing fields to `set_arg` (which
7881
// happens below) for Fluent, we want to move the data, so that has to happen
7982
// in a separate pass over the fields.
80-
let attrs = structure.each(|field_binding| {
81-
let field = field_binding.ast();
82-
let result = field.attrs.iter().map(|attr| {
83-
builder
84-
.generate_field_attr_code(
85-
attr,
86-
FieldInfo {
87-
vis: &field.vis,
88-
binding: field_binding,
89-
ty: &field.ty,
90-
span: &field.span(),
91-
},
92-
)
93-
.unwrap_or_else(|v| v.to_compile_error())
83+
let attrs = structure
84+
.clone()
85+
// Remove the fields that have a `subdiagnostic` attribute.
86+
.filter(|field_binding| {
87+
field_binding.ast().attrs.iter().all(|attr| {
88+
"subdiagnostic" != attr.path.segments.last().unwrap().ident.to_string()
89+
|| {
90+
subdiagnostics.insert(field_binding.binding.clone());
91+
false
92+
}
93+
})
94+
})
95+
.each(|field_binding| {
96+
let field = field_binding.ast();
97+
let result = field.attrs.iter().map(|attr| {
98+
builder
99+
.generate_field_attr_code(
100+
attr,
101+
FieldInfo {
102+
vis: &field.vis,
103+
binding: field_binding,
104+
ty: &field.ty,
105+
span: &field.span(),
106+
},
107+
)
108+
.unwrap_or_else(|v| v.to_compile_error())
109+
});
110+
111+
quote! { #(#result);* }
94112
});
95113

96-
quote! { #(#result);* }
97-
});
98-
99114
// When generating `set_arg` calls, move data rather than borrow it to avoid
100115
// requiring clones - this must therefore be the last use of each field (for
101116
// example, any formatting machinery that might refer to a field should be
@@ -107,7 +122,7 @@ impl<'a> SessionDiagnosticDerive<'a> {
107122
// need to be passed as an argument to the diagnostic. But when a field has no
108123
// attributes then it must be passed as an argument to the diagnostic so that
109124
// it can be referred to by Fluent messages.
110-
if field.attrs.is_empty() {
125+
let tokens = if field.attrs.is_empty() {
111126
let diag = &builder.diag;
112127
let ident = field_binding.ast().ident.as_ref().unwrap();
113128
quote! {
@@ -118,6 +133,27 @@ impl<'a> SessionDiagnosticDerive<'a> {
118133
}
119134
} else {
120135
quote! {}
136+
};
137+
// If this field had a subdiagnostic attribute, we generate the code here to
138+
// avoid binding it twice.
139+
if subdiagnostics.contains(&field_binding.binding) {
140+
let result = field.attrs.iter().map(|attr| {
141+
builder
142+
.generate_field_attr_code(
143+
attr,
144+
FieldInfo {
145+
vis: &field.vis,
146+
binding: field_binding,
147+
ty: &field.ty,
148+
span: &field.span(),
149+
},
150+
)
151+
.unwrap_or_else(|v| v.to_compile_error())
152+
});
153+
154+
quote! { #(#result);* #tokens }
155+
} else {
156+
tokens
121157
}
122158
});
123159

@@ -359,6 +395,8 @@ impl SessionDiagnosticDeriveBuilder {
359395
let (binding, needs_destructure) = match (name.as_str(), &inner_ty) {
360396
// `primary_span` can accept a `Vec<Span>` so don't destructure that.
361397
("primary_span", FieldInnerTy::Vec(_)) => (quote! { #field_binding.clone() }, false),
398+
// `subdiagnostics` are not derefed because they are bound by value.
399+
("subdiagnostic", _) => (quote! { #field_binding }, true),
362400
_ => (quote! { *#field_binding }, true),
363401
};
364402

compiler/rustc_parse/src/parser/diagnostics.rs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -254,23 +254,23 @@ struct AmbiguousPlus {
254254

255255
#[derive(SessionDiagnostic)]
256256
#[error(code = "E0178", slug = "parser-maybe-recover-from-bad-type-plus")]
257-
struct BadTypePlus<'a> {
257+
struct BadTypePlus {
258258
pub ty: String,
259259
#[primary_span]
260260
pub span: Span,
261261
#[subdiagnostic]
262-
pub sub: BadTypePlusSub<'a>,
262+
pub sub: BadTypePlusSub,
263263
}
264264

265-
#[derive(SessionSubdiagnostic, Clone, Copy)]
266-
pub enum BadTypePlusSub<'a> {
265+
#[derive(SessionSubdiagnostic)]
266+
pub enum BadTypePlusSub {
267267
#[suggestion(
268268
slug = "parser-add-paren",
269269
code = "{sum_with_parens}",
270270
applicability = "machine-applicable"
271271
)]
272272
AddParen {
273-
sum_with_parens: &'a str,
273+
sum_with_parens: String,
274274
#[primary_span]
275275
span: Span,
276276
},
@@ -1289,11 +1289,9 @@ impl<'a> Parser<'a> {
12891289
let bounds = self.parse_generic_bounds(None)?;
12901290
let sum_span = ty.span.to(self.prev_token.span);
12911291

1292-
let sum_with_parens: String;
1293-
12941292
let sub = match ty.kind {
12951293
TyKind::Rptr(ref lifetime, ref mut_ty) => {
1296-
sum_with_parens = pprust::to_string(|s| {
1294+
let sum_with_parens = pprust::to_string(|s| {
12971295
s.s.word("&");
12981296
s.print_opt_lifetime(lifetime);
12991297
s.print_mutability(mut_ty.mutbl, false);
@@ -1303,7 +1301,7 @@ impl<'a> Parser<'a> {
13031301
s.pclose()
13041302
});
13051303

1306-
BadTypePlusSub::AddParen { sum_with_parens: &sum_with_parens, span: sum_span }
1304+
BadTypePlusSub::AddParen { sum_with_parens, span: sum_span }
13071305
}
13081306
TyKind::Ptr(..) | TyKind::BareFn(..) => BadTypePlusSub::ForgotParen { span: sum_span },
13091307
_ => BadTypePlusSub::ExpectPath { span: sum_span },

0 commit comments

Comments
 (0)