Skip to content

Commit

Permalink
Unrolled build for rust-lang#135703
Browse files Browse the repository at this point in the history
Rollup merge of rust-lang#135703 - estebank:empty-dfv, r=compiler-errors

Disallow `A { .. }` if `A` has no fields

```
error: `A` has no fields, `..` needs at least one default field in the struct definition
  --> $DIR/empty-struct.rs:16:17
   |
LL |     let _ = A { .. };
   |             -   ^^
   |             |
   |             this type has no fields
```
  • Loading branch information
rust-timer authored Jan 19, 2025
2 parents 01706e1 + 27f079a commit 4658c97
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 8 deletions.
33 changes: 25 additions & 8 deletions compiler/rustc_hir_typeck/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1991,18 +1991,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
adt_ty: Ty<'tcx>,
expected: Expectation<'tcx>,
expr: &hir::Expr<'_>,
span: Span,
path_span: Span,
variant: &'tcx ty::VariantDef,
hir_fields: &'tcx [hir::ExprField<'tcx>],
base_expr: &'tcx hir::StructTailExpr<'tcx>,
) {
let tcx = self.tcx;

let adt_ty = self.try_structurally_resolve_type(span, adt_ty);
let adt_ty = self.try_structurally_resolve_type(path_span, adt_ty);
let adt_ty_hint = expected.only_has_type(self).and_then(|expected| {
self.fudge_inference_if_ok(|| {
let ocx = ObligationCtxt::new(self);
ocx.sup(&self.misc(span), self.param_env, expected, adt_ty)?;
ocx.sup(&self.misc(path_span), self.param_env, expected, adt_ty)?;
if !ocx.select_where_possible().is_empty() {
return Err(TypeError::Mismatch);
}
Expand All @@ -2012,11 +2012,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
});
if let Some(adt_ty_hint) = adt_ty_hint {
// re-link the variables that the fudging above can create.
self.demand_eqtype(span, adt_ty_hint, adt_ty);
self.demand_eqtype(path_span, adt_ty_hint, adt_ty);
}

let ty::Adt(adt, args) = adt_ty.kind() else {
span_bug!(span, "non-ADT passed to check_expr_struct_fields");
span_bug!(path_span, "non-ADT passed to check_expr_struct_fields");
};
let adt_kind = adt.adt_kind();

Expand Down Expand Up @@ -2107,7 +2107,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if adt_kind == AdtKind::Union && hir_fields.len() != 1 {
struct_span_code_err!(
self.dcx(),
span,
path_span,
E0784,
"union expressions should have exactly one field",
)
Expand Down Expand Up @@ -2167,6 +2167,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
});
return;
}
if variant.fields.is_empty() {
let mut err = self.dcx().struct_span_err(
span,
format!(
"`{adt_ty}` has no fields, `..` needs at least one default field in the \
struct definition",
),
);
err.span_label(path_span, "this type has no fields");
err.emit();
}
if !missing_mandatory_fields.is_empty() {
let s = pluralize!(missing_mandatory_fields.len());
let fields: Vec<_> =
Expand Down Expand Up @@ -2316,11 +2327,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.collect();

if !private_fields.is_empty() {
self.report_private_fields(adt_ty, span, expr.span, private_fields, hir_fields);
self.report_private_fields(
adt_ty,
path_span,
expr.span,
private_fields,
hir_fields,
);
} else {
self.report_missing_fields(
adt_ty,
span,
path_span,
remaining_fields,
variant,
hir_fields,
Expand Down
21 changes: 21 additions & 0 deletions tests/ui/structs/default-field-values/empty-struct.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#![feature(default_field_values)]

// If an API wants users to always use `..` even if they specify all the fields, they should use a
// sentinel field. As of now, that field can't be made private so it is only constructable with this
// syntax, but this might change in the future.

struct A {}
struct B();
struct C;
struct D {
x: i32,
}
struct E(i32);

fn main() {
let _ = A { .. }; //~ ERROR has no fields
let _ = B { .. }; //~ ERROR has no fields
let _ = C { .. }; //~ ERROR has no fields
let _ = D { x: 0, .. };
let _ = E { 0: 0, .. };
}
26 changes: 26 additions & 0 deletions tests/ui/structs/default-field-values/empty-struct.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
error: `A` has no fields, `..` needs at least one default field in the struct definition
--> $DIR/empty-struct.rs:16:17
|
LL | let _ = A { .. };
| - ^^
| |
| this type has no fields

error: `B` has no fields, `..` needs at least one default field in the struct definition
--> $DIR/empty-struct.rs:17:17
|
LL | let _ = B { .. };
| - ^^
| |
| this type has no fields

error: `C` has no fields, `..` needs at least one default field in the struct definition
--> $DIR/empty-struct.rs:18:17
|
LL | let _ = C { .. };
| - ^^
| |
| this type has no fields

error: aborting due to 3 previous errors

0 comments on commit 4658c97

Please sign in to comment.