about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorJubilee <workingjubilee@gmail.com>2025-06-17 00:28:17 -0700
committerGitHub <noreply@github.com>2025-06-17 00:28:17 -0700
commitd4f23cdc915a74741e301df41c5eece2d8c78c5e (patch)
treed604e1e0da31675d1cbfffd03683bc34d33e2cf9 /compiler
parentf2e9e2afacb6599c2ec3b0fe00427700a24425eb (diff)
parent2dd9cc113067113453efcff722e3a5c0893a6244 (diff)
downloadrust-d4f23cdc915a74741e301df41c5eece2d8c78c5e.tar.gz
rust-d4f23cdc915a74741e301df41c5eece2d8c78c5e.zip
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
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_ast_lowering/messages.ftl2
-rw-r--r--compiler/rustc_ast_lowering/src/errors.rs7
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs42
3 files changed, 41 insertions, 10 deletions
diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl
index 5ef76fb64aa..50eb7c7ae99 100644
--- a/compiler/rustc_ast_lowering/messages.ftl
+++ b/compiler/rustc_ast_lowering/messages.ftl
@@ -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
diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs
index 576fa9731e9..b444324ef91 100644
--- a/compiler/rustc_ast_lowering/src/errors.rs
+++ b/compiler/rustc_ast_lowering/src/errors.rs
@@ -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,
+}
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 49110c93954..ef27d0ef69b 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -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);