about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2024-11-26 17:53:00 +0000
committerEsteban Küber <esteban@kuber.com.ar>2024-12-09 21:55:12 +0000
commit550bcae8aa7859abace52c20b8b9149ae6cb37f1 (patch)
tree0ac51fba8bb64e7dcfedc78876c01df1a8f574e7
parent9ac95c10c09faf50cc22eb97b6e1c59d64053c28 (diff)
downloadrust-550bcae8aa7859abace52c20b8b9149ae6cb37f1.tar.gz
rust-550bcae8aa7859abace52c20b8b9149ae6cb37f1.zip
Detect `struct S(ty = val);`
Emit a specific error for unsupported default field value syntax in tuple structs.
-rw-r--r--compiler/rustc_ast_lowering/messages.ftl3
-rw-r--r--compiler/rustc_ast_lowering/src/errors.rs8
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs33
-rw-r--r--compiler/rustc_parse/src/parser/item.rs18
-rw-r--r--tests/ui/structs/default-field-values-failures.rs2
-rw-r--r--tests/ui/structs/default-field-values-failures.stderr10
6 files changed, 63 insertions, 11 deletions
diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl
index b53cb7a3822..b31e21f5c35 100644
--- a/compiler/rustc_ast_lowering/messages.ftl
+++ b/compiler/rustc_ast_lowering/messages.ftl
@@ -53,6 +53,9 @@ ast_lowering_closure_cannot_be_static = closures cannot be static
 ast_lowering_coroutine_too_many_parameters =
     too many parameters for a coroutine (expected 0 or 1 parameters)
 
+ast_lowering_default_field_in_tuple = default field in tuple struct
+    .label = default fields are only supported on structs
+
 ast_lowering_does_not_support_modifiers =
     the `{$class_name}` register class does not support template modifiers
 
diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs
index 665da14e861..2564d4e2772 100644
--- a/compiler/rustc_ast_lowering/src/errors.rs
+++ b/compiler/rustc_ast_lowering/src/errors.rs
@@ -38,6 +38,14 @@ pub(crate) struct InvalidAbi {
     pub suggestion: Option<InvalidAbiSuggestion>,
 }
 
+#[derive(Diagnostic)]
+#[diag(ast_lowering_default_field_in_tuple)]
+pub(crate) struct TupleStructWithDefault {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
 pub(crate) struct InvalidAbiReason(pub &'static str);
 
 impl Subdiagnostic for InvalidAbiReason {
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 1078aeea22b..7d6c41992eb 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -17,7 +17,10 @@ use smallvec::{SmallVec, smallvec};
 use thin_vec::ThinVec;
 use tracing::instrument;
 
-use super::errors::{InvalidAbi, InvalidAbiReason, InvalidAbiSuggestion, MisplacedRelaxTraitBound};
+use super::errors::{
+    InvalidAbi, InvalidAbiReason, InvalidAbiSuggestion, MisplacedRelaxTraitBound,
+    TupleStructWithDefault,
+};
 use super::{
     AstOwner, FnDeclKind, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode,
     ResolverAstLoweringExt,
@@ -690,13 +693,27 @@ impl<'hir> LoweringContext<'_, 'hir> {
             VariantData::Tuple(fields, id) => {
                 let ctor_id = self.lower_node_id(*id);
                 self.alias_attrs(ctor_id, parent_id);
-                hir::VariantData::Tuple(
-                    self.arena.alloc_from_iter(
-                        fields.iter().enumerate().map(|f| self.lower_field_def(f)),
-                    ),
-                    ctor_id,
-                    self.local_def_id(*id),
-                )
+                let fields = self
+                    .arena
+                    .alloc_from_iter(fields.iter().enumerate().map(|f| self.lower_field_def(f)));
+                for field in &fields[..] {
+                    if let Some(default) = field.default {
+                        // Default values in tuple struct and tuple variants are not allowed by the
+                        // RFC due to concerns about the syntax, both in the item definition and the
+                        // expression. We could in the future allow `struct S(i32 = 0);` and force
+                        // users to construct the value with `let _ = S { .. };`.
+                        if self.tcx.features().default_field_values() {
+                            self.dcx().emit_err(TupleStructWithDefault { span: default.span });
+                        } else {
+                            let _ = self.dcx().span_delayed_bug(
+                                default.span,
+                                "expected `default values on `struct` fields aren't supported` \
+                                 feature-gate error but none was produced",
+                            );
+                        }
+                    }
+                }
+                hir::VariantData::Tuple(fields, ctor_id, self.local_def_id(*id))
             }
             VariantData::Unit(id) => {
                 let ctor_id = self.lower_node_id(*id);
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index f12b4ca249d..58b4bf8980b 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -1836,6 +1836,22 @@ impl<'a> Parser<'a> {
                         return Err(err);
                     }
                 };
+                let mut default = None;
+                if p.token == token::Eq {
+                    let mut snapshot = p.create_snapshot_for_diagnostic();
+                    snapshot.bump();
+                    match snapshot.parse_expr_anon_const() {
+                        Ok(const_expr) => {
+                            let sp = ty.span.shrink_to_hi().to(const_expr.value.span);
+                            p.psess.gated_spans.gate(sym::default_field_values, sp);
+                            p.restore_snapshot(snapshot);
+                            default = Some(const_expr);
+                        }
+                        Err(err) => {
+                            err.cancel();
+                        }
+                    }
+                }
 
                 Ok((
                     FieldDef {
@@ -1845,7 +1861,7 @@ impl<'a> Parser<'a> {
                         ident: None,
                         id: DUMMY_NODE_ID,
                         ty,
-                        default: None,
+                        default,
                         attrs,
                         is_placeholder: false,
                     },
diff --git a/tests/ui/structs/default-field-values-failures.rs b/tests/ui/structs/default-field-values-failures.rs
index c4de4f5cdad..27eff70dd3e 100644
--- a/tests/ui/structs/default-field-values-failures.rs
+++ b/tests/ui/structs/default-field-values-failures.rs
@@ -23,6 +23,8 @@ pub struct Qux<const C: i32> {
     bay: i32 = C,
 }
 
+pub struct Rak(i32 = 42); //~ ERROR default field in tuple struct
+
 impl<const C: i32> Qux<C> {
     const S: S = S;
 }
diff --git a/tests/ui/structs/default-field-values-failures.stderr b/tests/ui/structs/default-field-values-failures.stderr
index bd96777f865..3564c1dc20e 100644
--- a/tests/ui/structs/default-field-values-failures.stderr
+++ b/tests/ui/structs/default-field-values-failures.stderr
@@ -7,6 +7,12 @@ LL |     bat: i32 = <Qux<{ C }> as T>::K,
    = help: const parameters may only be used as standalone arguments, i.e. `C`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
+error: default field in tuple struct
+  --> $DIR/default-field-values-failures.rs:26:22
+   |
+LL | pub struct Rak(i32 = 42);
+   |                      ^^ default fields are only supported on structs
+
 error[E0277]: the trait bound `S: Default` is not satisfied
   --> $DIR/default-field-values-failures.rs:14:5
    |
@@ -24,7 +30,7 @@ LL | pub struct S;
    |
 
 error: missing mandatory field `bar`
-  --> $DIR/default-field-values-failures.rs:45:21
+  --> $DIR/default-field-values-failures.rs:47:21
    |
 LL |     let _ = Bar { .. };
    |                     ^
@@ -35,6 +41,6 @@ error: generic `Self` types are currently not permitted in anonymous constants
 LL |     bar: S = Self::S,
    |              ^^^^
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0277`.