mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
Rollup merge of #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 ```
This commit is contained in:
commit
7e1ce54b22
@ -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);
|
||||
}
|
||||
@ -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();
|
||||
|
||||
@ -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",
|
||||
)
|
||||
@ -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<_> =
|
||||
@ -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,
|
||||
|
21
tests/ui/structs/default-field-values/empty-struct.rs
Normal file
21
tests/ui/structs/default-field-values/empty-struct.rs
Normal file
@ -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
tests/ui/structs/default-field-values/empty-struct.stderr
Normal file
26
tests/ui/structs/default-field-values/empty-struct.stderr
Normal file
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user