Skip to content

Commit e284934

Browse files
committed
Reject union default field values
1 parent 32c0cb0 commit e284934

File tree

7 files changed

+103
-30
lines changed

7 files changed

+103
-30
lines changed

compiler/rustc_ast_lowering/messages.ftl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,8 @@ ast_lowering_underscore_expr_lhs_assign =
179179
in expressions, `_` can only be used on the left-hand side of an assignment
180180
.label = `_` not allowed here
181181
182+
ast_lowering_union_default_field_values = unions cannot have default field values
183+
182184
ast_lowering_unstable_inline_assembly = inline assembly is not stable yet on this architecture
183185
ast_lowering_unstable_inline_assembly_label_operand_with_outputs =
184186
using both label and output operands for inline assembly is unstable

compiler/rustc_ast_lowering/src/errors.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,3 +475,10 @@ pub(crate) struct UseConstGenericArg {
475475
#[suggestion_part(code = "{other_args}")]
476476
pub call_args: Span,
477477
}
478+
479+
#[derive(Diagnostic)]
480+
#[diag(ast_lowering_union_default_field_values)]
481+
pub(crate) struct UnionWithDefault {
482+
#[primary_span]
483+
pub span: Span,
484+
}

compiler/rustc_ast_lowering/src/item.rs

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use tracing::instrument;
1717

1818
use super::errors::{
1919
InvalidAbi, InvalidAbiSuggestion, MisplacedRelaxTraitBound, TupleStructWithDefault,
20+
UnionWithDefault,
2021
};
2122
use super::stability::{enabled_names, gate_unstable_abi};
2223
use super::{
@@ -316,7 +317,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
316317
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
317318
|this| {
318319
this.arena.alloc_from_iter(
319-
enum_definition.variants.iter().map(|x| this.lower_variant(x)),
320+
enum_definition.variants.iter().map(|x| this.lower_variant(i, x)),
320321
)
321322
},
322323
);
@@ -328,7 +329,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
328329
generics,
329330
id,
330331
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
331-
|this| this.lower_variant_data(hir_id, struct_def),
332+
|this| this.lower_variant_data(hir_id, i, struct_def),
332333
);
333334
hir::ItemKind::Struct(ident, generics, struct_def)
334335
}
@@ -338,7 +339,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
338339
generics,
339340
id,
340341
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
341-
|this| this.lower_variant_data(hir_id, vdata),
342+
|this| this.lower_variant_data(hir_id, i, vdata),
342343
);
343344
hir::ItemKind::Union(ident, generics, vdata)
344345
}
@@ -714,13 +715,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
714715
}
715716
}
716717

717-
fn lower_variant(&mut self, v: &Variant) -> hir::Variant<'hir> {
718+
fn lower_variant(&mut self, item_kind: &ItemKind, v: &Variant) -> hir::Variant<'hir> {
718719
let hir_id = self.lower_node_id(v.id);
719720
self.lower_attrs(hir_id, &v.attrs, v.span);
720721
hir::Variant {
721722
hir_id,
722723
def_id: self.local_def_id(v.id),
723-
data: self.lower_variant_data(hir_id, &v.data),
724+
data: self.lower_variant_data(hir_id, item_kind, &v.data),
724725
disr_expr: v.disr_expr.as_ref().map(|e| self.lower_anon_const_to_anon_const(e)),
725726
ident: self.lower_ident(v.ident),
726727
span: self.lower_span(v.span),
@@ -730,15 +731,36 @@ impl<'hir> LoweringContext<'_, 'hir> {
730731
fn lower_variant_data(
731732
&mut self,
732733
parent_id: hir::HirId,
734+
item_kind: &ItemKind,
733735
vdata: &VariantData,
734736
) -> hir::VariantData<'hir> {
735737
match vdata {
736-
VariantData::Struct { fields, recovered } => hir::VariantData::Struct {
737-
fields: self
738+
VariantData::Struct { fields, recovered } => {
739+
let fields = self
738740
.arena
739-
.alloc_from_iter(fields.iter().enumerate().map(|f| self.lower_field_def(f))),
740-
recovered: *recovered,
741-
},
741+
.alloc_from_iter(fields.iter().enumerate().map(|f| self.lower_field_def(f)));
742+
743+
if let ItemKind::Union(..) = item_kind {
744+
for field in &fields[..] {
745+
if let Some(default) = field.default {
746+
// Unions cannot derive `Default`, and it's not clear how to use default
747+
// field values of unions if that was supported. Therefore, blanket reject
748+
// trying to use field values with unions.
749+
if self.tcx.features().default_field_values() {
750+
self.dcx().emit_err(UnionWithDefault { span: default.span });
751+
} else {
752+
let _ = self.dcx().span_delayed_bug(
753+
default.span,
754+
"expected union default values feature gater error but none was \
755+
produced",
756+
);
757+
}
758+
}
759+
}
760+
}
761+
762+
hir::VariantData::Struct { fields, recovered: *recovered }
763+
}
742764
VariantData::Tuple(fields, id) => {
743765
let ctor_id = self.lower_node_id(*id);
744766
self.alias_attrs(ctor_id, parent_id);

tests/ui/feature-gates/feature-gate-default-field-values.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,16 @@ pub enum OptEnum {
5858
}
5959
}
6060

61+
// Default field values may not be used on `union`s (at least, this is not described in the accepted
62+
// RFC, and it's not currently clear how to extend the design to do so). We emit a feature gate
63+
// error when the feature is not enabled, but syntactically reject default field values when used
64+
// with unions when the feature is enabled. This can be adjusted if there's an acceptable design
65+
// extension, or just unconditionally reject always.
66+
union U {
67+
x: i32 = 0, //~ ERROR default values on fields are experimental
68+
y: f32 = 0.0, //~ ERROR default values on fields are experimental
69+
}
70+
6171
fn main () {
6272
let x = Foo { .. }; //~ ERROR base expression required after `..`
6373
let y = Foo::default();

tests/ui/feature-gates/feature-gate-default-field-values.stderr

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,28 @@ LL | optional: () = (),
124124
= help: add `#![feature(default_field_values)]` to the crate attributes to enable
125125
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
126126

127+
error[E0658]: default values on fields are experimental
128+
--> $DIR/feature-gate-default-field-values.rs:67:11
129+
|
130+
LL | x: i32 = 0,
131+
| ^^^^
132+
|
133+
= note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information
134+
= help: add `#![feature(default_field_values)]` to the crate attributes to enable
135+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
136+
137+
error[E0658]: default values on fields are experimental
138+
--> $DIR/feature-gate-default-field-values.rs:68:11
139+
|
140+
LL | y: f32 = 0.0,
141+
| ^^^^^^
142+
|
143+
= note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information
144+
= help: add `#![feature(default_field_values)]` to the crate attributes to enable
145+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
146+
127147
error[E0797]: base expression required after `..`
128-
--> $DIR/feature-gate-default-field-values.rs:62:21
148+
--> $DIR/feature-gate-default-field-values.rs:72:21
129149
|
130150
LL | let x = Foo { .. };
131151
| ^
@@ -140,7 +160,7 @@ LL | let x = Foo { ../* expr */ };
140160
| ++++++++++
141161

142162
error[E0797]: base expression required after `..`
143-
--> $DIR/feature-gate-default-field-values.rs:64:29
163+
--> $DIR/feature-gate-default-field-values.rs:74:29
144164
|
145165
LL | let z = Foo { baz: 1, .. };
146166
| ^
@@ -155,7 +175,7 @@ LL | let z = Foo { baz: 1, ../* expr */ };
155175
| ++++++++++
156176

157177
error[E0797]: base expression required after `..`
158-
--> $DIR/feature-gate-default-field-values.rs:70:26
178+
--> $DIR/feature-gate-default-field-values.rs:80:26
159179
|
160180
LL | let x = Bar::Foo { .. };
161181
| ^
@@ -170,7 +190,7 @@ LL | let x = Bar::Foo { ../* expr */ };
170190
| ++++++++++
171191

172192
error[E0797]: base expression required after `..`
173-
--> $DIR/feature-gate-default-field-values.rs:72:34
193+
--> $DIR/feature-gate-default-field-values.rs:82:34
174194
|
175195
LL | let z = Bar::Foo { baz: 1, .. };
176196
| ^
@@ -185,7 +205,7 @@ LL | let z = Bar::Foo { baz: 1, ../* expr */ };
185205
| ++++++++++
186206

187207
error[E0797]: base expression required after `..`
188-
--> $DIR/feature-gate-default-field-values.rs:78:31
208+
--> $DIR/feature-gate-default-field-values.rs:88:31
189209
|
190210
LL | let x = Qux::<i32, 4> { .. };
191211
| ^
@@ -200,7 +220,7 @@ LL | let x = Qux::<i32, 4> { ../* expr */ };
200220
| ++++++++++
201221

202222
error[E0797]: base expression required after `..`
203-
--> $DIR/feature-gate-default-field-values.rs:79:73
223+
--> $DIR/feature-gate-default-field-values.rs:89:73
204224
|
205225
LL | assert!(matches!(Qux::<i32, 4> { bar: S, baz: 42, bat: 2, bay: 4, .. }, x));
206226
| ^
@@ -215,7 +235,7 @@ LL | assert!(matches!(Qux::<i32, 4> { bar: S, baz: 42, bat: 2, bay: 4, ../*
215235
| ++++++++++
216236

217237
error[E0797]: base expression required after `..`
218-
--> $DIR/feature-gate-default-field-values.rs:82:38
238+
--> $DIR/feature-gate-default-field-values.rs:92:38
219239
|
220240
LL | let y = Opt { mandatory: None, .. };
221241
| ^
@@ -230,7 +250,7 @@ LL | let y = Opt { mandatory: None, ../* expr */ };
230250
| ++++++++++
231251

232252
error[E0797]: base expression required after `..`
233-
--> $DIR/feature-gate-default-field-values.rs:86:47
253+
--> $DIR/feature-gate-default-field-values.rs:96:47
234254
|
235255
LL | assert!(matches!(Opt { mandatory: None, .. }, z));
236256
| ^
@@ -245,7 +265,7 @@ LL | assert!(matches!(Opt { mandatory: None, ../* expr */ }, z));
245265
| ++++++++++
246266

247267
error[E0797]: base expression required after `..`
248-
--> $DIR/feature-gate-default-field-values.rs:88:30
268+
--> $DIR/feature-gate-default-field-values.rs:98:30
249269
|
250270
LL | assert!(matches!(Opt { .. }, z));
251271
| ^
@@ -256,7 +276,7 @@ LL | assert!(matches!(Opt { ../* expr */ }, z));
256276
| ++++++++++
257277

258278
error[E0797]: base expression required after `..`
259-
--> $DIR/feature-gate-default-field-values.rs:90:44
279+
--> $DIR/feature-gate-default-field-values.rs:100:44
260280
|
261281
LL | assert!(matches!(Opt { optional: (), .. }, z));
262282
| ^
@@ -267,7 +287,7 @@ LL | assert!(matches!(Opt { optional: (), ../* expr */ }, z));
267287
| ++++++++++
268288

269289
error[E0797]: base expression required after `..`
270-
--> $DIR/feature-gate-default-field-values.rs:92:61
290+
--> $DIR/feature-gate-default-field-values.rs:102:61
271291
|
272292
LL | assert!(matches!(Opt { optional: (), mandatory: None, .. }, z));
273293
| ^
@@ -279,7 +299,7 @@ LL + assert!(matches!(Opt { optional: (), mandatory: None, }, z));
279299
|
280300

281301
error[E0797]: base expression required after `..`
282-
--> $DIR/feature-gate-default-field-values.rs:94:51
302+
--> $DIR/feature-gate-default-field-values.rs:104:51
283303
|
284304
LL | let y = OptEnum::Variant { mandatory: None, .. };
285305
| ^
@@ -294,7 +314,7 @@ LL | let y = OptEnum::Variant { mandatory: None, ../* expr */ };
294314
| ++++++++++
295315

296316
error[E0797]: base expression required after `..`
297-
--> $DIR/feature-gate-default-field-values.rs:98:60
317+
--> $DIR/feature-gate-default-field-values.rs:108:60
298318
|
299319
LL | assert!(matches!(OptEnum::Variant { mandatory: None, .. }, z));
300320
| ^
@@ -309,7 +329,7 @@ LL | assert!(matches!(OptEnum::Variant { mandatory: None, ../* expr */ }, z)
309329
| ++++++++++
310330

311331
error[E0797]: base expression required after `..`
312-
--> $DIR/feature-gate-default-field-values.rs:100:43
332+
--> $DIR/feature-gate-default-field-values.rs:110:43
313333
|
314334
LL | assert!(matches!(OptEnum::Variant { .. }, z));
315335
| ^
@@ -320,7 +340,7 @@ LL | assert!(matches!(OptEnum::Variant { ../* expr */ }, z));
320340
| ++++++++++
321341

322342
error[E0797]: base expression required after `..`
323-
--> $DIR/feature-gate-default-field-values.rs:102:57
343+
--> $DIR/feature-gate-default-field-values.rs:112:57
324344
|
325345
LL | assert!(matches!(OptEnum::Variant { optional: (), .. }, z));
326346
| ^
@@ -331,7 +351,7 @@ LL | assert!(matches!(OptEnum::Variant { optional: (), ../* expr */ }, z));
331351
| ++++++++++
332352

333353
error[E0797]: base expression required after `..`
334-
--> $DIR/feature-gate-default-field-values.rs:104:74
354+
--> $DIR/feature-gate-default-field-values.rs:114:74
335355
|
336356
LL | assert!(matches!(OptEnum::Variant { optional: (), mandatory: None, .. }, z));
337357
| ^
@@ -342,7 +362,7 @@ LL - assert!(matches!(OptEnum::Variant { optional: (), mandatory: None, .. }
342362
LL + assert!(matches!(OptEnum::Variant { optional: (), mandatory: None, }, z));
343363
|
344364

345-
error: aborting due to 29 previous errors
365+
error: aborting due to 31 previous errors
346366

347367
Some errors have detailed explanations: E0658, E0797.
348368
For more information about an error, try `rustc --explain E0658`.

tests/ui/structs/default-field-values/failures.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ enum E {
5151

5252
union U
5353
{
54-
x: i32 = 1,
55-
y: f32 = 2.,
54+
x: i32 = 1, //~ ERROR unions cannot have default field values
55+
y: f32 = 2., //~ ERROR unions cannot have default field values
5656
}
5757

5858
fn main () {

tests/ui/structs/default-field-values/failures.stderr

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,18 @@ error: default fields are not supported in tuple structs
1212
LL | pub struct Rak(i32 = 42);
1313
| ^^ default fields are only supported on structs
1414

15+
error: unions cannot have default field values
16+
--> $DIR/failures.rs:54:14
17+
|
18+
LL | x: i32 = 1,
19+
| ^
20+
21+
error: unions cannot have default field values
22+
--> $DIR/failures.rs:55:14
23+
|
24+
LL | y: f32 = 2.,
25+
| ^^
26+
1527
error[E0277]: the trait bound `S: Default` is not satisfied
1628
--> $DIR/failures.rs:16:5
1729
|
@@ -102,7 +114,7 @@ LL - let _ = Rak(.., 0);
102114
LL + let _ = Rak(0);
103115
|
104116

105-
error: aborting due to 8 previous errors
117+
error: aborting due to 10 previous errors
106118

107119
Some errors have detailed explanations: E0061, E0277, E0308.
108120
For more information about an error, try `rustc --explain E0061`.

0 commit comments

Comments
 (0)