Skip to content

Commit 052b913

Browse files
authored
Rollup merge of #145550 - nnethercote:derive_from-no-unit, r=Kobzol
Avoid using `()` in `derive(From)` output. Using an error type instead of `()` avoids the duplicated errors on `struct SUnsizedField` in `deriving-from-wrong-target.rs`. It also improves the expanded output from this: ``` struct S2(u32, u32); impl ::core::convert::From<()> for S2 { #[inline] fn from(value: ()) -> S2 { (/*ERROR*/) } } ``` to this: ``` struct S2(u32, u32); impl ::core::convert::From<(/*ERROR*/)> for S2 { #[inline] fn from(value: (/*ERROR*/)) -> S2 { (/*ERROR*/) } } ``` The new code also only matchs on `item.kind` once. r? `@Kobzol`
2 parents 3a4c626 + dda17c5 commit 052b913

File tree

3 files changed

+38
-77
lines changed

3 files changed

+38
-77
lines changed

compiler/rustc_builtin_macros/src/deriving/from.rs

Lines changed: 36 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -27,21 +27,39 @@ pub(crate) fn expand_deriving_from(
2727
cx.dcx().bug("derive(From) used on something else than an item");
2828
};
2929

30-
// #[derive(From)] is currently usable only on structs with exactly one field.
31-
let field = if let ItemKind::Struct(_, _, data) = &item.kind
32-
&& let [field] = data.fields()
33-
{
34-
Some(field.clone())
35-
} else {
36-
None
30+
let err_span = || {
31+
let item_span = item.kind.ident().map(|ident| ident.span).unwrap_or(item.span);
32+
MultiSpan::from_spans(vec![span, item_span])
3733
};
3834

39-
let from_type = match &field {
40-
Some(field) => Ty::AstTy(field.ty.clone()),
41-
// We don't have a type to put into From<...> if we don't have a single field, so just put
42-
// unit there.
43-
None => Ty::Unit,
35+
// `#[derive(From)]` is currently usable only on structs with exactly one field.
36+
let field = match &item.kind {
37+
ItemKind::Struct(_, _, data) => {
38+
if let [field] = data.fields() {
39+
Ok(field.clone())
40+
} else {
41+
let guar = cx.dcx().emit_err(errors::DeriveFromWrongFieldCount {
42+
span: err_span(),
43+
multiple_fields: data.fields().len() > 1,
44+
});
45+
Err(guar)
46+
}
47+
}
48+
ItemKind::Enum(_, _, _) | ItemKind::Union(_, _, _) => {
49+
let guar = cx.dcx().emit_err(errors::DeriveFromWrongTarget {
50+
span: err_span(),
51+
kind: &format!("{} {}", item.kind.article(), item.kind.descr()),
52+
});
53+
Err(guar)
54+
}
55+
_ => cx.dcx().bug("Invalid derive(From) ADT input"),
4456
};
57+
58+
let from_type = Ty::AstTy(match field {
59+
Ok(ref field) => field.ty.clone(),
60+
Err(guar) => cx.ty(span, ast::TyKind::Err(guar)),
61+
});
62+
4563
let path =
4664
Path::new_(pathvec_std!(convert::From), vec![Box::new(from_type.clone())], PathKind::Std);
4765

@@ -71,34 +89,17 @@ pub(crate) fn expand_deriving_from(
7189
attributes: thin_vec![cx.attr_word(sym::inline, span)],
7290
fieldless_variants_strategy: FieldlessVariantsStrategy::Default,
7391
combine_substructure: combine_substructure(Box::new(|cx, span, substructure| {
74-
let Some(field) = &field else {
75-
let item_span = item.kind.ident().map(|ident| ident.span).unwrap_or(item.span);
76-
let err_span = MultiSpan::from_spans(vec![span, item_span]);
77-
let error = match &item.kind {
78-
ItemKind::Struct(_, _, data) => {
79-
cx.dcx().emit_err(errors::DeriveFromWrongFieldCount {
80-
span: err_span,
81-
multiple_fields: data.fields().len() > 1,
82-
})
83-
}
84-
ItemKind::Enum(_, _, _) | ItemKind::Union(_, _, _) => {
85-
cx.dcx().emit_err(errors::DeriveFromWrongTarget {
86-
span: err_span,
87-
kind: &format!("{} {}", item.kind.article(), item.kind.descr()),
88-
})
89-
}
90-
_ => cx.dcx().bug("Invalid derive(From) ADT input"),
91-
};
92-
93-
return BlockOrExpr::new_expr(DummyResult::raw_expr(span, Some(error)));
92+
let field = match field {
93+
Ok(ref field) => field,
94+
Err(guar) => {
95+
return BlockOrExpr::new_expr(DummyResult::raw_expr(span, Some(guar)));
96+
}
9497
};
9598

9699
let self_kw = Ident::new(kw::SelfUpper, span);
97100
let expr: Box<ast::Expr> = match substructure.fields {
98101
SubstructureFields::StaticStruct(variant, _) => match variant {
99-
// Self {
100-
// field: value
101-
// }
102+
// Self { field: value }
102103
VariantData::Struct { .. } => cx.expr_struct_ident(
103104
span,
104105
self_kw,

tests/ui/deriving/deriving-from-wrong-target.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,6 @@ struct S4 {
2828
enum E1 {}
2929

3030
#[derive(From)]
31-
//~^ ERROR the size for values of type `T` cannot be known at compilation time [E0277]
32-
//~| ERROR the size for values of type `T` cannot be known at compilation time [E0277]
3331
struct SUnsizedField<T: ?Sized> {
3432
last: T,
3533
//~^ ERROR the size for values of type `T` cannot be known at compilation time [E0277]

tests/ui/deriving/deriving-from-wrong-target.stderr

Lines changed: 2 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -54,45 +54,7 @@ LL | enum E1 {}
5454
= note: `#[derive(From)]` can only be used on structs with exactly one field
5555

5656
error[E0277]: the size for values of type `T` cannot be known at compilation time
57-
--> $DIR/deriving-from-wrong-target.rs:30:10
58-
|
59-
LL | #[derive(From)]
60-
| ^^^^ doesn't have a size known at compile-time
61-
...
62-
LL | struct SUnsizedField<T: ?Sized> {
63-
| - this type parameter needs to be `Sized`
64-
|
65-
note: required by an implicit `Sized` bound in `From`
66-
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
67-
help: consider removing the `?Sized` bound to make the type parameter `Sized`
68-
|
69-
LL - struct SUnsizedField<T: ?Sized> {
70-
LL + struct SUnsizedField<T> {
71-
|
72-
73-
error[E0277]: the size for values of type `T` cannot be known at compilation time
74-
--> $DIR/deriving-from-wrong-target.rs:30:10
75-
|
76-
LL | #[derive(From)]
77-
| ^^^^ doesn't have a size known at compile-time
78-
...
79-
LL | struct SUnsizedField<T: ?Sized> {
80-
| - this type parameter needs to be `Sized`
81-
|
82-
note: required because it appears within the type `SUnsizedField<T>`
83-
--> $DIR/deriving-from-wrong-target.rs:33:8
84-
|
85-
LL | struct SUnsizedField<T: ?Sized> {
86-
| ^^^^^^^^^^^^^
87-
= note: the return type of a function must have a statically known size
88-
help: consider removing the `?Sized` bound to make the type parameter `Sized`
89-
|
90-
LL - struct SUnsizedField<T: ?Sized> {
91-
LL + struct SUnsizedField<T> {
92-
|
93-
94-
error[E0277]: the size for values of type `T` cannot be known at compilation time
95-
--> $DIR/deriving-from-wrong-target.rs:34:11
57+
--> $DIR/deriving-from-wrong-target.rs:32:11
9658
|
9759
LL | struct SUnsizedField<T: ?Sized> {
9860
| - this type parameter needs to be `Sized`
@@ -110,6 +72,6 @@ help: function arguments must have a statically known size, borrowed types alway
11072
LL | last: &T,
11173
| +
11274

113-
error: aborting due to 8 previous errors
75+
error: aborting due to 6 previous errors
11476

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

0 commit comments

Comments
 (0)