Skip to content

Commit b651c1c

Browse files
committed
Check attributes on struct expression fields.
Attributes on struct expression fields were not being checked for validity. This adds the fields as HIR nodes so that `CheckAttrVisitor` can visit those nodes to check their attributes.
1 parent 1b464c7 commit b651c1c

File tree

10 files changed

+47
-18
lines changed

10 files changed

+47
-18
lines changed

compiler/rustc_ast_lowering/src/expr.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1406,8 +1406,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
14061406
}
14071407

14081408
fn lower_expr_field(&mut self, f: &ExprField) -> hir::ExprField<'hir> {
1409+
let hir_id = self.lower_node_id(f.id);
1410+
self.lower_attrs(hir_id, &f.attrs);
14091411
hir::ExprField {
1410-
hir_id: self.next_id(),
1412+
hir_id,
14111413
ident: self.lower_ident(f.ident),
14121414
expr: self.lower_expr(&f.expr),
14131415
span: self.lower_span(f.span),

compiler/rustc_ast_lowering/src/index.rs

+5
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,11 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
224224

225225
fn visit_expr(&mut self, expr: &'hir Expr<'hir>) {
226226
self.insert(expr.span, expr.hir_id, Node::Expr(expr));
227+
if let ExprKind::Struct(_, fields, _) = expr.kind {
228+
for field in fields {
229+
self.insert(field.span, field.hir_id, Node::ExprField(field));
230+
}
231+
}
227232

228233
self.with_parent(expr.hir_id, |this| {
229234
intravisit::walk_expr(this, expr);

compiler/rustc_hir/src/hir.rs

+2
Original file line numberDiff line numberDiff line change
@@ -3332,6 +3332,7 @@ pub enum Node<'hir> {
33323332
Field(&'hir FieldDef<'hir>),
33333333
AnonConst(&'hir AnonConst),
33343334
Expr(&'hir Expr<'hir>),
3335+
ExprField(&'hir ExprField<'hir>),
33353336
Stmt(&'hir Stmt<'hir>),
33363337
PathSegment(&'hir PathSegment<'hir>),
33373338
Ty(&'hir Ty<'hir>),
@@ -3390,6 +3391,7 @@ impl<'hir> Node<'hir> {
33903391
| Node::Ctor(..)
33913392
| Node::Pat(..)
33923393
| Node::PatField(..)
3394+
| Node::ExprField(..)
33933395
| Node::Arm(..)
33943396
| Node::Local(..)
33953397
| Node::Crate(..)

compiler/rustc_hir/src/target.rs

+2
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ pub enum Target {
5757
MacroDef,
5858
Param,
5959
PatField,
60+
ExprField,
6061
}
6162

6263
impl Display for Target {
@@ -185,6 +186,7 @@ impl Target {
185186
Target::MacroDef => "macro def",
186187
Target::Param => "function param",
187188
Target::PatField => "pattern field",
189+
Target::ExprField => "struct field",
188190
}
189191
}
190192
}

compiler/rustc_hir_pretty/src/lib.rs

+16-14
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ impl<'a> State<'a> {
8383
Node::Variant(a) => self.print_variant(a),
8484
Node::AnonConst(a) => self.print_anon_const(a),
8585
Node::Expr(a) => self.print_expr(a),
86+
Node::ExprField(a) => self.print_expr_field(&a),
8687
Node::Stmt(a) => self.print_stmt(a),
8788
Node::PathSegment(a) => self.print_path_segment(a),
8889
Node::Ty(a) => self.print_type(a),
@@ -1124,20 +1125,7 @@ impl<'a> State<'a> {
11241125
) {
11251126
self.print_qpath(qpath, true);
11261127
self.word("{");
1127-
self.commasep_cmnt(
1128-
Consistent,
1129-
fields,
1130-
|s, field| {
1131-
s.ibox(INDENT_UNIT);
1132-
if !field.is_shorthand {
1133-
s.print_ident(field.ident);
1134-
s.word_space(":");
1135-
}
1136-
s.print_expr(field.expr);
1137-
s.end()
1138-
},
1139-
|f| f.span,
1140-
);
1128+
self.commasep_cmnt(Consistent, fields, |s, field| s.print_expr_field(field), |f| f.span);
11411129
if let Some(expr) = wth {
11421130
self.ibox(INDENT_UNIT);
11431131
if !fields.is_empty() {
@@ -1154,6 +1142,20 @@ impl<'a> State<'a> {
11541142
self.word("}");
11551143
}
11561144

1145+
fn print_expr_field(&mut self, field: &hir::ExprField<'_>) {
1146+
if self.attrs(field.hir_id).is_empty() {
1147+
self.space();
1148+
}
1149+
self.cbox(INDENT_UNIT);
1150+
self.print_outer_attributes(&self.attrs(field.hir_id));
1151+
if !field.is_shorthand {
1152+
self.print_ident(field.ident);
1153+
self.word_space(":");
1154+
}
1155+
self.print_expr(&field.expr);
1156+
self.end()
1157+
}
1158+
11571159
fn print_expr_tup(&mut self, exprs: &[hir::Expr<'_>]) {
11581160
self.popen();
11591161
self.commasep_exprs(Inconsistent, exprs);

compiler/rustc_middle/src/hir/map/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ impl<'hir> Map<'hir> {
298298
| Node::TraitRef(_)
299299
| Node::Pat(_)
300300
| Node::PatField(_)
301+
| Node::ExprField(_)
301302
| Node::Local(_)
302303
| Node::Param(_)
303304
| Node::Arm(_)
@@ -1021,6 +1022,7 @@ impl<'hir> Map<'hir> {
10211022
Node::Field(field) => field.span,
10221023
Node::AnonConst(constant) => self.body(constant.body).value.span,
10231024
Node::Expr(expr) => expr.span,
1025+
Node::ExprField(field) => field.span,
10241026
Node::Stmt(stmt) => stmt.span,
10251027
Node::PathSegment(seg) => {
10261028
let ident_span = seg.ident.span;
@@ -1243,6 +1245,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
12431245
}
12441246
Some(Node::AnonConst(_)) => node_str("const"),
12451247
Some(Node::Expr(_)) => node_str("expr"),
1248+
Some(Node::ExprField(_)) => node_str("expr field"),
12461249
Some(Node::Stmt(_)) => node_str("stmt"),
12471250
Some(Node::PathSegment(_)) => node_str("path segment"),
12481251
Some(Node::Ty(_)) => node_str("type"),

compiler/rustc_passes/src/check_attr.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,8 @@ impl CheckAttrVisitor<'_> {
653653
| Target::ForeignTy
654654
| Target::GenericParam(..)
655655
| Target::MacroDef
656-
| Target::PatField => None,
656+
| Target::PatField
657+
| Target::ExprField => None,
657658
} {
658659
tcx.sess.emit_err(errors::DocAliasBadLocation { span, attr_str, location });
659660
return false;
@@ -2064,6 +2065,11 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
20642065
};
20652066

20662067
self.check_attributes(expr.hir_id, expr.span, target, None);
2068+
if let hir::ExprKind::Struct(_, fields, _) = expr.kind {
2069+
for field in fields {
2070+
self.check_attributes(field.hir_id, field.span, Target::PatField, None);
2071+
}
2072+
}
20672073
intravisit::walk_expr(self, expr)
20682074
}
20692075

compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs

+1
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
257257
| hir::Node::TraitRef(..)
258258
| hir::Node::Pat(..)
259259
| hir::Node::PatField(..)
260+
| hir::Node::ExprField(..)
260261
| hir::Node::Arm(..)
261262
| hir::Node::Local(..)
262263
| hir::Node::Ctor(..)

src/test/ui/lint/unused/unused_attributes-must_use.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,6 @@ fn main() {
126126
struct PatternField {
127127
foo: i32,
128128
}
129-
let s = PatternField { foo: 123 };
129+
let s = PatternField { #[must_use] foo: 123 }; //~ ERROR `#[must_use]` has no effect
130130
let PatternField { #[must_use] foo } = s; //~ ERROR `#[must_use]` has no effect
131131
}

src/test/ui/lint/unused/unused_attributes-must_use.stderr

+7-1
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,12 @@ error: `#[must_use]` has no effect when applied to an match arm
105105
LL | #[must_use]
106106
| ^^^^^^^^^^^
107107

108+
error: `#[must_use]` has no effect when applied to a pattern field
109+
--> $DIR/unused_attributes-must_use.rs:129:28
110+
|
111+
LL | let s = PatternField { #[must_use] foo: 123 };
112+
| ^^^^^^^^^^^
113+
108114
error: `#[must_use]` has no effect when applied to a pattern field
109115
--> $DIR/unused_attributes-must_use.rs:130:24
110116
|
@@ -177,5 +183,5 @@ error: unused return value of `Use::get_four` that must be used
177183
LL | ().get_four();
178184
| ^^^^^^^^^^^^^^
179185

180-
error: aborting due to 27 previous errors
186+
error: aborting due to 28 previous errors
181187

0 commit comments

Comments
 (0)