mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-05 03:38:29 +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>,
|
adt_ty: Ty<'tcx>,
|
||||||
expected: Expectation<'tcx>,
|
expected: Expectation<'tcx>,
|
||||||
expr: &hir::Expr<'_>,
|
expr: &hir::Expr<'_>,
|
||||||
span: Span,
|
path_span: Span,
|
||||||
variant: &'tcx ty::VariantDef,
|
variant: &'tcx ty::VariantDef,
|
||||||
hir_fields: &'tcx [hir::ExprField<'tcx>],
|
hir_fields: &'tcx [hir::ExprField<'tcx>],
|
||||||
base_expr: &'tcx hir::StructTailExpr<'tcx>,
|
base_expr: &'tcx hir::StructTailExpr<'tcx>,
|
||||||
) {
|
) {
|
||||||
let tcx = self.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| {
|
let adt_ty_hint = expected.only_has_type(self).and_then(|expected| {
|
||||||
self.fudge_inference_if_ok(|| {
|
self.fudge_inference_if_ok(|| {
|
||||||
let ocx = ObligationCtxt::new(self);
|
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() {
|
if !ocx.select_where_possible().is_empty() {
|
||||||
return Err(TypeError::Mismatch);
|
return Err(TypeError::Mismatch);
|
||||||
}
|
}
|
||||||
@ -2012,11 +2012,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
});
|
});
|
||||||
if let Some(adt_ty_hint) = adt_ty_hint {
|
if let Some(adt_ty_hint) = adt_ty_hint {
|
||||||
// re-link the variables that the fudging above can create.
|
// 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 {
|
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();
|
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 {
|
if adt_kind == AdtKind::Union && hir_fields.len() != 1 {
|
||||||
struct_span_code_err!(
|
struct_span_code_err!(
|
||||||
self.dcx(),
|
self.dcx(),
|
||||||
span,
|
path_span,
|
||||||
E0784,
|
E0784,
|
||||||
"union expressions should have exactly one field",
|
"union expressions should have exactly one field",
|
||||||
)
|
)
|
||||||
@ -2167,6 +2167,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
});
|
});
|
||||||
return;
|
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() {
|
if !missing_mandatory_fields.is_empty() {
|
||||||
let s = pluralize!(missing_mandatory_fields.len());
|
let s = pluralize!(missing_mandatory_fields.len());
|
||||||
let fields: Vec<_> =
|
let fields: Vec<_> =
|
||||||
@ -2316,11 +2327,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
if !private_fields.is_empty() {
|
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 {
|
} else {
|
||||||
self.report_missing_fields(
|
self.report_missing_fields(
|
||||||
adt_ty,
|
adt_ty,
|
||||||
span,
|
path_span,
|
||||||
remaining_fields,
|
remaining_fields,
|
||||||
variant,
|
variant,
|
||||||
hir_fields,
|
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