Rollup merge of #142570 - jieyouxu:disunion, r=estebank
Reject union default field values Fixes rust-lang/rust#142555. The [`default_field_values` RFC][rfc] does not specify that default field values may be used on `union`s, and it's not clear how default field values may be used with `union`s without an design extension to the RFC. So, for now, reject trying to use default field values with `union`s. ### Review notes - The first commit adds the `union` with default field values test case to `tests/ui/structs/default-field-values/failures.rs`, where `union`s with default field values are currently accepted. - The second commit rejects trying to supply default field values to `union` definitions. - When `default_field_values` feature gate is disabled, we show the feature gate error when the user tries to write `union`s with default field values. When the feature gate is enabled, we reject this usage with > unions cannot have default field values ``@rustbot`` label: +F-default_field_values [rfc]: https://rust-lang.github.io/rfcs/3681-default-field-values.html
This commit is contained in:
commit
d4f23cdc91
7 changed files with 115 additions and 36 deletions
|
|
@ -179,6 +179,8 @@ ast_lowering_underscore_expr_lhs_assign =
|
|||
in expressions, `_` can only be used on the left-hand side of an assignment
|
||||
.label = `_` not allowed here
|
||||
|
||||
ast_lowering_union_default_field_values = unions cannot have default field values
|
||||
|
||||
ast_lowering_unstable_inline_assembly = inline assembly is not stable yet on this architecture
|
||||
ast_lowering_unstable_inline_assembly_label_operand_with_outputs =
|
||||
using both label and output operands for inline assembly is unstable
|
||||
|
|
|
|||
|
|
@ -475,3 +475,10 @@ pub(crate) struct UseConstGenericArg {
|
|||
#[suggestion_part(code = "{other_args}")]
|
||||
pub call_args: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_union_default_field_values)]
|
||||
pub(crate) struct UnionWithDefault {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ use tracing::instrument;
|
|||
|
||||
use super::errors::{
|
||||
InvalidAbi, InvalidAbiSuggestion, MisplacedRelaxTraitBound, TupleStructWithDefault,
|
||||
UnionWithDefault,
|
||||
};
|
||||
use super::stability::{enabled_names, gate_unstable_abi};
|
||||
use super::{
|
||||
|
|
@ -316,7 +317,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| {
|
||||
this.arena.alloc_from_iter(
|
||||
enum_definition.variants.iter().map(|x| this.lower_variant(x)),
|
||||
enum_definition.variants.iter().map(|x| this.lower_variant(i, x)),
|
||||
)
|
||||
},
|
||||
);
|
||||
|
|
@ -328,7 +329,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
generics,
|
||||
id,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| this.lower_variant_data(hir_id, struct_def),
|
||||
|this| this.lower_variant_data(hir_id, i, struct_def),
|
||||
);
|
||||
hir::ItemKind::Struct(ident, generics, struct_def)
|
||||
}
|
||||
|
|
@ -338,7 +339,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
generics,
|
||||
id,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| this.lower_variant_data(hir_id, vdata),
|
||||
|this| this.lower_variant_data(hir_id, i, vdata),
|
||||
);
|
||||
hir::ItemKind::Union(ident, generics, vdata)
|
||||
}
|
||||
|
|
@ -714,13 +715,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
fn lower_variant(&mut self, v: &Variant) -> hir::Variant<'hir> {
|
||||
fn lower_variant(&mut self, item_kind: &ItemKind, v: &Variant) -> hir::Variant<'hir> {
|
||||
let hir_id = self.lower_node_id(v.id);
|
||||
self.lower_attrs(hir_id, &v.attrs, v.span);
|
||||
hir::Variant {
|
||||
hir_id,
|
||||
def_id: self.local_def_id(v.id),
|
||||
data: self.lower_variant_data(hir_id, &v.data),
|
||||
data: self.lower_variant_data(hir_id, item_kind, &v.data),
|
||||
disr_expr: v.disr_expr.as_ref().map(|e| self.lower_anon_const_to_anon_const(e)),
|
||||
ident: self.lower_ident(v.ident),
|
||||
span: self.lower_span(v.span),
|
||||
|
|
@ -730,15 +731,36 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
fn lower_variant_data(
|
||||
&mut self,
|
||||
parent_id: hir::HirId,
|
||||
item_kind: &ItemKind,
|
||||
vdata: &VariantData,
|
||||
) -> hir::VariantData<'hir> {
|
||||
match vdata {
|
||||
VariantData::Struct { fields, recovered } => hir::VariantData::Struct {
|
||||
fields: self
|
||||
VariantData::Struct { fields, recovered } => {
|
||||
let fields = self
|
||||
.arena
|
||||
.alloc_from_iter(fields.iter().enumerate().map(|f| self.lower_field_def(f))),
|
||||
recovered: *recovered,
|
||||
},
|
||||
.alloc_from_iter(fields.iter().enumerate().map(|f| self.lower_field_def(f)));
|
||||
|
||||
if let ItemKind::Union(..) = item_kind {
|
||||
for field in &fields[..] {
|
||||
if let Some(default) = field.default {
|
||||
// Unions cannot derive `Default`, and it's not clear how to use default
|
||||
// field values of unions if that was supported. Therefore, blanket reject
|
||||
// trying to use field values with unions.
|
||||
if self.tcx.features().default_field_values() {
|
||||
self.dcx().emit_err(UnionWithDefault { span: default.span });
|
||||
} else {
|
||||
let _ = self.dcx().span_delayed_bug(
|
||||
default.span,
|
||||
"expected union default field values feature gate error but none \
|
||||
was produced",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hir::VariantData::Struct { fields, recovered: *recovered }
|
||||
}
|
||||
VariantData::Tuple(fields, id) => {
|
||||
let ctor_id = self.lower_node_id(*id);
|
||||
self.alias_attrs(ctor_id, parent_id);
|
||||
|
|
|
|||
|
|
@ -58,6 +58,16 @@ pub enum OptEnum {
|
|||
}
|
||||
}
|
||||
|
||||
// Default field values may not be used on `union`s (at least, this is not described in the accepted
|
||||
// RFC, and it's not currently clear how to extend the design to do so). We emit a feature gate
|
||||
// error when the feature is not enabled, but syntactically reject default field values when used
|
||||
// with unions when the feature is enabled. This can be adjusted if there's an acceptable design
|
||||
// extension, or just unconditionally reject always.
|
||||
union U {
|
||||
x: i32 = 0, //~ ERROR default values on fields are experimental
|
||||
y: f32 = 0.0, //~ ERROR default values on fields are experimental
|
||||
}
|
||||
|
||||
fn main () {
|
||||
let x = Foo { .. }; //~ ERROR base expression required after `..`
|
||||
let y = Foo::default();
|
||||
|
|
|
|||
|
|
@ -124,8 +124,28 @@ LL | optional: () = (),
|
|||
= help: add `#![feature(default_field_values)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: default values on fields are experimental
|
||||
--> $DIR/feature-gate-default-field-values.rs:67:11
|
||||
|
|
||||
LL | x: i32 = 0,
|
||||
| ^^^^
|
||||
|
|
||||
= note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information
|
||||
= help: add `#![feature(default_field_values)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: default values on fields are experimental
|
||||
--> $DIR/feature-gate-default-field-values.rs:68:11
|
||||
|
|
||||
LL | y: f32 = 0.0,
|
||||
| ^^^^^^
|
||||
|
|
||||
= note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information
|
||||
= help: add `#![feature(default_field_values)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0797]: base expression required after `..`
|
||||
--> $DIR/feature-gate-default-field-values.rs:62:21
|
||||
--> $DIR/feature-gate-default-field-values.rs:72:21
|
||||
|
|
||||
LL | let x = Foo { .. };
|
||||
| ^
|
||||
|
|
@ -140,7 +160,7 @@ LL | let x = Foo { ../* expr */ };
|
|||
| ++++++++++
|
||||
|
||||
error[E0797]: base expression required after `..`
|
||||
--> $DIR/feature-gate-default-field-values.rs:64:29
|
||||
--> $DIR/feature-gate-default-field-values.rs:74:29
|
||||
|
|
||||
LL | let z = Foo { baz: 1, .. };
|
||||
| ^
|
||||
|
|
@ -155,7 +175,7 @@ LL | let z = Foo { baz: 1, ../* expr */ };
|
|||
| ++++++++++
|
||||
|
||||
error[E0797]: base expression required after `..`
|
||||
--> $DIR/feature-gate-default-field-values.rs:70:26
|
||||
--> $DIR/feature-gate-default-field-values.rs:80:26
|
||||
|
|
||||
LL | let x = Bar::Foo { .. };
|
||||
| ^
|
||||
|
|
@ -170,7 +190,7 @@ LL | let x = Bar::Foo { ../* expr */ };
|
|||
| ++++++++++
|
||||
|
||||
error[E0797]: base expression required after `..`
|
||||
--> $DIR/feature-gate-default-field-values.rs:72:34
|
||||
--> $DIR/feature-gate-default-field-values.rs:82:34
|
||||
|
|
||||
LL | let z = Bar::Foo { baz: 1, .. };
|
||||
| ^
|
||||
|
|
@ -185,7 +205,7 @@ LL | let z = Bar::Foo { baz: 1, ../* expr */ };
|
|||
| ++++++++++
|
||||
|
||||
error[E0797]: base expression required after `..`
|
||||
--> $DIR/feature-gate-default-field-values.rs:78:31
|
||||
--> $DIR/feature-gate-default-field-values.rs:88:31
|
||||
|
|
||||
LL | let x = Qux::<i32, 4> { .. };
|
||||
| ^
|
||||
|
|
@ -200,7 +220,7 @@ LL | let x = Qux::<i32, 4> { ../* expr */ };
|
|||
| ++++++++++
|
||||
|
||||
error[E0797]: base expression required after `..`
|
||||
--> $DIR/feature-gate-default-field-values.rs:79:73
|
||||
--> $DIR/feature-gate-default-field-values.rs:89:73
|
||||
|
|
||||
LL | assert!(matches!(Qux::<i32, 4> { bar: S, baz: 42, bat: 2, bay: 4, .. }, x));
|
||||
| ^
|
||||
|
|
@ -215,7 +235,7 @@ LL | assert!(matches!(Qux::<i32, 4> { bar: S, baz: 42, bat: 2, bay: 4, ../*
|
|||
| ++++++++++
|
||||
|
||||
error[E0797]: base expression required after `..`
|
||||
--> $DIR/feature-gate-default-field-values.rs:82:38
|
||||
--> $DIR/feature-gate-default-field-values.rs:92:38
|
||||
|
|
||||
LL | let y = Opt { mandatory: None, .. };
|
||||
| ^
|
||||
|
|
@ -230,7 +250,7 @@ LL | let y = Opt { mandatory: None, ../* expr */ };
|
|||
| ++++++++++
|
||||
|
||||
error[E0797]: base expression required after `..`
|
||||
--> $DIR/feature-gate-default-field-values.rs:86:47
|
||||
--> $DIR/feature-gate-default-field-values.rs:96:47
|
||||
|
|
||||
LL | assert!(matches!(Opt { mandatory: None, .. }, z));
|
||||
| ^
|
||||
|
|
@ -245,7 +265,7 @@ LL | assert!(matches!(Opt { mandatory: None, ../* expr */ }, z));
|
|||
| ++++++++++
|
||||
|
||||
error[E0797]: base expression required after `..`
|
||||
--> $DIR/feature-gate-default-field-values.rs:88:30
|
||||
--> $DIR/feature-gate-default-field-values.rs:98:30
|
||||
|
|
||||
LL | assert!(matches!(Opt { .. }, z));
|
||||
| ^
|
||||
|
|
@ -256,7 +276,7 @@ LL | assert!(matches!(Opt { ../* expr */ }, z));
|
|||
| ++++++++++
|
||||
|
||||
error[E0797]: base expression required after `..`
|
||||
--> $DIR/feature-gate-default-field-values.rs:90:44
|
||||
--> $DIR/feature-gate-default-field-values.rs:100:44
|
||||
|
|
||||
LL | assert!(matches!(Opt { optional: (), .. }, z));
|
||||
| ^
|
||||
|
|
@ -267,7 +287,7 @@ LL | assert!(matches!(Opt { optional: (), ../* expr */ }, z));
|
|||
| ++++++++++
|
||||
|
||||
error[E0797]: base expression required after `..`
|
||||
--> $DIR/feature-gate-default-field-values.rs:92:61
|
||||
--> $DIR/feature-gate-default-field-values.rs:102:61
|
||||
|
|
||||
LL | assert!(matches!(Opt { optional: (), mandatory: None, .. }, z));
|
||||
| ^
|
||||
|
|
@ -279,7 +299,7 @@ LL + assert!(matches!(Opt { optional: (), mandatory: None, }, z));
|
|||
|
|
||||
|
||||
error[E0797]: base expression required after `..`
|
||||
--> $DIR/feature-gate-default-field-values.rs:94:51
|
||||
--> $DIR/feature-gate-default-field-values.rs:104:51
|
||||
|
|
||||
LL | let y = OptEnum::Variant { mandatory: None, .. };
|
||||
| ^
|
||||
|
|
@ -294,7 +314,7 @@ LL | let y = OptEnum::Variant { mandatory: None, ../* expr */ };
|
|||
| ++++++++++
|
||||
|
||||
error[E0797]: base expression required after `..`
|
||||
--> $DIR/feature-gate-default-field-values.rs:98:60
|
||||
--> $DIR/feature-gate-default-field-values.rs:108:60
|
||||
|
|
||||
LL | assert!(matches!(OptEnum::Variant { mandatory: None, .. }, z));
|
||||
| ^
|
||||
|
|
@ -309,7 +329,7 @@ LL | assert!(matches!(OptEnum::Variant { mandatory: None, ../* expr */ }, z)
|
|||
| ++++++++++
|
||||
|
||||
error[E0797]: base expression required after `..`
|
||||
--> $DIR/feature-gate-default-field-values.rs:100:43
|
||||
--> $DIR/feature-gate-default-field-values.rs:110:43
|
||||
|
|
||||
LL | assert!(matches!(OptEnum::Variant { .. }, z));
|
||||
| ^
|
||||
|
|
@ -320,7 +340,7 @@ LL | assert!(matches!(OptEnum::Variant { ../* expr */ }, z));
|
|||
| ++++++++++
|
||||
|
||||
error[E0797]: base expression required after `..`
|
||||
--> $DIR/feature-gate-default-field-values.rs:102:57
|
||||
--> $DIR/feature-gate-default-field-values.rs:112:57
|
||||
|
|
||||
LL | assert!(matches!(OptEnum::Variant { optional: (), .. }, z));
|
||||
| ^
|
||||
|
|
@ -331,7 +351,7 @@ LL | assert!(matches!(OptEnum::Variant { optional: (), ../* expr */ }, z));
|
|||
| ++++++++++
|
||||
|
||||
error[E0797]: base expression required after `..`
|
||||
--> $DIR/feature-gate-default-field-values.rs:104:74
|
||||
--> $DIR/feature-gate-default-field-values.rs:114:74
|
||||
|
|
||||
LL | assert!(matches!(OptEnum::Variant { optional: (), mandatory: None, .. }, z));
|
||||
| ^
|
||||
|
|
@ -342,7 +362,7 @@ LL - assert!(matches!(OptEnum::Variant { optional: (), mandatory: None, .. }
|
|||
LL + assert!(matches!(OptEnum::Variant { optional: (), mandatory: None, }, z));
|
||||
|
|
||||
|
||||
error: aborting due to 29 previous errors
|
||||
error: aborting due to 31 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0658, E0797.
|
||||
For more information about an error, try `rustc --explain E0658`.
|
||||
|
|
|
|||
|
|
@ -49,6 +49,12 @@ enum E {
|
|||
Variant {} //~ ERROR the `#[default]` attribute may only be used on unit enum variants
|
||||
}
|
||||
|
||||
union U
|
||||
{
|
||||
x: i32 = 1, //~ ERROR unions cannot have default field values
|
||||
y: f32 = 2., //~ ERROR unions cannot have default field values
|
||||
}
|
||||
|
||||
fn main () {
|
||||
let _ = Foo { .. }; // ok
|
||||
let _ = Foo::default(); // ok
|
||||
|
|
|
|||
|
|
@ -12,6 +12,18 @@ error: default fields are not supported in tuple structs
|
|||
LL | pub struct Rak(i32 = 42);
|
||||
| ^^ default fields are only supported on structs
|
||||
|
||||
error: unions cannot have default field values
|
||||
--> $DIR/failures.rs:54:14
|
||||
|
|
||||
LL | x: i32 = 1,
|
||||
| ^
|
||||
|
||||
error: unions cannot have default field values
|
||||
--> $DIR/failures.rs:55:14
|
||||
|
|
||||
LL | y: f32 = 2.,
|
||||
| ^^
|
||||
|
||||
error[E0277]: the trait bound `S: Default` is not satisfied
|
||||
--> $DIR/failures.rs:16:5
|
||||
|
|
||||
|
|
@ -28,19 +40,19 @@ LL | pub struct S;
|
|||
|
|
||||
|
||||
error: missing field `bar` in initializer
|
||||
--> $DIR/failures.rs:55:19
|
||||
--> $DIR/failures.rs:61:19
|
||||
|
|
||||
LL | let _ = Bar { .. };
|
||||
| ^ fields that do not have a defaulted value must be provided explicitly
|
||||
|
||||
error: missing field `bar` in initializer
|
||||
--> $DIR/failures.rs:56:27
|
||||
--> $DIR/failures.rs:62:27
|
||||
|
|
||||
LL | let _ = Bar { baz: 0, .. };
|
||||
| ^ fields that do not have a defaulted value must be provided explicitly
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/failures.rs:60:17
|
||||
--> $DIR/failures.rs:66:17
|
||||
|
|
||||
LL | let _ = Rak(..);
|
||||
| --- ^^ expected `i32`, found `RangeFull`
|
||||
|
|
@ -53,19 +65,19 @@ note: tuple struct defined here
|
|||
LL | pub struct Rak(i32 = 42);
|
||||
| ^^^
|
||||
help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals; it is instead interpreted as a `std::ops::RangeFull` literal
|
||||
--> $DIR/failures.rs:60:17
|
||||
--> $DIR/failures.rs:66:17
|
||||
|
|
||||
LL | let _ = Rak(..);
|
||||
| ^^
|
||||
|
||||
error[E0061]: this struct takes 1 argument but 2 arguments were supplied
|
||||
--> $DIR/failures.rs:62:13
|
||||
--> $DIR/failures.rs:68:13
|
||||
|
|
||||
LL | let _ = Rak(0, ..);
|
||||
| ^^^ -- unexpected argument #2 of type `RangeFull`
|
||||
|
|
||||
help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals; it is instead interpreted as a `std::ops::RangeFull` literal
|
||||
--> $DIR/failures.rs:62:20
|
||||
--> $DIR/failures.rs:68:20
|
||||
|
|
||||
LL | let _ = Rak(0, ..);
|
||||
| ^^
|
||||
|
|
@ -81,13 +93,13 @@ LL + let _ = Rak(0);
|
|||
|
|
||||
|
||||
error[E0061]: this struct takes 1 argument but 2 arguments were supplied
|
||||
--> $DIR/failures.rs:64:13
|
||||
--> $DIR/failures.rs:70:13
|
||||
|
|
||||
LL | let _ = Rak(.., 0);
|
||||
| ^^^ -- unexpected argument #1 of type `RangeFull`
|
||||
|
|
||||
help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals; it is instead interpreted as a `std::ops::RangeFull` literal
|
||||
--> $DIR/failures.rs:64:17
|
||||
--> $DIR/failures.rs:70:17
|
||||
|
|
||||
LL | let _ = Rak(.., 0);
|
||||
| ^^
|
||||
|
|
@ -102,7 +114,7 @@ LL - let _ = Rak(.., 0);
|
|||
LL + let _ = Rak(0);
|
||||
|
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
error: aborting due to 10 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0061, E0277, E0308.
|
||||
For more information about an error, try `rustc --explain E0061`.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue