Skip to content

Commit 550bcae

Browse files
committed
Detect struct S(ty = val);
Emit a specific error for unsupported default field value syntax in tuple structs.
1 parent 9ac95c1 commit 550bcae

File tree

6 files changed

+63
-11
lines changed

6 files changed

+63
-11
lines changed

compiler/rustc_ast_lowering/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ ast_lowering_closure_cannot_be_static = closures cannot be static
5353
ast_lowering_coroutine_too_many_parameters =
5454
too many parameters for a coroutine (expected 0 or 1 parameters)
5555
56+
ast_lowering_default_field_in_tuple = default field in tuple struct
57+
.label = default fields are only supported on structs
58+
5659
ast_lowering_does_not_support_modifiers =
5760
the `{$class_name}` register class does not support template modifiers
5861

compiler/rustc_ast_lowering/src/errors.rs

+8
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,14 @@ pub(crate) struct InvalidAbi {
3838
pub suggestion: Option<InvalidAbiSuggestion>,
3939
}
4040

41+
#[derive(Diagnostic)]
42+
#[diag(ast_lowering_default_field_in_tuple)]
43+
pub(crate) struct TupleStructWithDefault {
44+
#[primary_span]
45+
#[label]
46+
pub span: Span,
47+
}
48+
4149
pub(crate) struct InvalidAbiReason(pub &'static str);
4250

4351
impl Subdiagnostic for InvalidAbiReason {

compiler/rustc_ast_lowering/src/item.rs

+25-8
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ use smallvec::{SmallVec, smallvec};
1717
use thin_vec::ThinVec;
1818
use tracing::instrument;
1919

20-
use super::errors::{InvalidAbi, InvalidAbiReason, InvalidAbiSuggestion, MisplacedRelaxTraitBound};
20+
use super::errors::{
21+
InvalidAbi, InvalidAbiReason, InvalidAbiSuggestion, MisplacedRelaxTraitBound,
22+
TupleStructWithDefault,
23+
};
2124
use super::{
2225
AstOwner, FnDeclKind, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode,
2326
ResolverAstLoweringExt,
@@ -690,13 +693,27 @@ impl<'hir> LoweringContext<'_, 'hir> {
690693
VariantData::Tuple(fields, id) => {
691694
let ctor_id = self.lower_node_id(*id);
692695
self.alias_attrs(ctor_id, parent_id);
693-
hir::VariantData::Tuple(
694-
self.arena.alloc_from_iter(
695-
fields.iter().enumerate().map(|f| self.lower_field_def(f)),
696-
),
697-
ctor_id,
698-
self.local_def_id(*id),
699-
)
696+
let fields = self
697+
.arena
698+
.alloc_from_iter(fields.iter().enumerate().map(|f| self.lower_field_def(f)));
699+
for field in &fields[..] {
700+
if let Some(default) = field.default {
701+
// Default values in tuple struct and tuple variants are not allowed by the
702+
// RFC due to concerns about the syntax, both in the item definition and the
703+
// expression. We could in the future allow `struct S(i32 = 0);` and force
704+
// users to construct the value with `let _ = S { .. };`.
705+
if self.tcx.features().default_field_values() {
706+
self.dcx().emit_err(TupleStructWithDefault { span: default.span });
707+
} else {
708+
let _ = self.dcx().span_delayed_bug(
709+
default.span,
710+
"expected `default values on `struct` fields aren't supported` \
711+
feature-gate error but none was produced",
712+
);
713+
}
714+
}
715+
}
716+
hir::VariantData::Tuple(fields, ctor_id, self.local_def_id(*id))
700717
}
701718
VariantData::Unit(id) => {
702719
let ctor_id = self.lower_node_id(*id);

compiler/rustc_parse/src/parser/item.rs

+17-1
Original file line numberDiff line numberDiff line change
@@ -1836,6 +1836,22 @@ impl<'a> Parser<'a> {
18361836
return Err(err);
18371837
}
18381838
};
1839+
let mut default = None;
1840+
if p.token == token::Eq {
1841+
let mut snapshot = p.create_snapshot_for_diagnostic();
1842+
snapshot.bump();
1843+
match snapshot.parse_expr_anon_const() {
1844+
Ok(const_expr) => {
1845+
let sp = ty.span.shrink_to_hi().to(const_expr.value.span);
1846+
p.psess.gated_spans.gate(sym::default_field_values, sp);
1847+
p.restore_snapshot(snapshot);
1848+
default = Some(const_expr);
1849+
}
1850+
Err(err) => {
1851+
err.cancel();
1852+
}
1853+
}
1854+
}
18391855

18401856
Ok((
18411857
FieldDef {
@@ -1845,7 +1861,7 @@ impl<'a> Parser<'a> {
18451861
ident: None,
18461862
id: DUMMY_NODE_ID,
18471863
ty,
1848-
default: None,
1864+
default,
18491865
attrs,
18501866
is_placeholder: false,
18511867
},

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

+2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ pub struct Qux<const C: i32> {
2323
bay: i32 = C,
2424
}
2525

26+
pub struct Rak(i32 = 42); //~ ERROR default field in tuple struct
27+
2628
impl<const C: i32> Qux<C> {
2729
const S: S = S;
2830
}

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

+8-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ LL | bat: i32 = <Qux<{ C }> as T>::K,
77
= help: const parameters may only be used as standalone arguments, i.e. `C`
88
= help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
99

10+
error: default field in tuple struct
11+
--> $DIR/default-field-values-failures.rs:26:22
12+
|
13+
LL | pub struct Rak(i32 = 42);
14+
| ^^ default fields are only supported on structs
15+
1016
error[E0277]: the trait bound `S: Default` is not satisfied
1117
--> $DIR/default-field-values-failures.rs:14:5
1218
|
@@ -24,7 +30,7 @@ LL | pub struct S;
2430
|
2531

2632
error: missing mandatory field `bar`
27-
--> $DIR/default-field-values-failures.rs:45:21
33+
--> $DIR/default-field-values-failures.rs:47:21
2834
|
2935
LL | let _ = Bar { .. };
3036
| ^
@@ -35,6 +41,6 @@ error: generic `Self` types are currently not permitted in anonymous constants
3541
LL | bar: S = Self::S,
3642
| ^^^^
3743

38-
error: aborting due to 4 previous errors
44+
error: aborting due to 5 previous errors
3945

4046
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)