Skip to content

Commit a0cd3c6

Browse files
committed
Generate From impl even if there is not exactly a single field
1 parent d285ddf commit a0cd3c6

File tree

1 file changed

+18
-16
lines changed
  • compiler/rustc_builtin_macros/src/deriving

1 file changed

+18
-16
lines changed

compiler/rustc_builtin_macros/src/deriving/from.rs

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
use rustc_ast as ast;
22
use rustc_ast::{ItemKind, VariantData};
3-
use rustc_expand::base::{Annotatable, ExtCtxt};
4-
use rustc_span::{kw, sym, Ident, Span};
3+
use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt};
4+
use rustc_span::{Ident, Span, kw, sym};
55
use thin_vec::thin_vec;
66

77
use crate::deriving::generic::ty::{Bounds, Path, PathKind, Ty};
88
use crate::deriving::generic::{
9-
combine_substructure, BlockOrExpr, FieldlessVariantsStrategy, MethodDef, SubstructureFields,
10-
TraitDef,
9+
BlockOrExpr, FieldlessVariantsStrategy, MethodDef, SubstructureFields, TraitDef,
10+
combine_substructure,
1111
};
1212
use crate::deriving::pathvec_std;
1313
use crate::errors;
@@ -22,6 +22,7 @@ pub(crate) fn expand_deriving_from(
2222
push: &mut dyn FnMut(Annotatable),
2323
is_const: bool,
2424
) {
25+
// #[derive(From)] is currently usable only on structs with exactly one field.
2526
let field = match &item {
2627
Annotatable::Item(item) => match &item.kind {
2728
ItemKind::Struct(_, _, data) => match data.fields() {
@@ -33,18 +34,14 @@ pub(crate) fn expand_deriving_from(
3334
_ => None,
3435
};
3536

36-
// Make sure that the derive is only invoked on single-field [tuple] structs.
37-
// From this point below, we know that there is exactly one field.
38-
let Some(field) = field else {
39-
cx.dcx().emit_err(errors::DeriveFromWrongTarget { span });
40-
return;
37+
let from_type = match &field {
38+
Some(field) => Ty::AstTy(field.ty.clone()),
39+
// We don't have a type to put into From<...> if we don't have a single field, so just put
40+
// unit there.
41+
None => Ty::Unit,
4142
};
42-
43-
let path = Path::new_(
44-
pathvec_std!(convert::From),
45-
vec![Box::new(Ty::AstTy(field.ty.clone()))],
46-
PathKind::Std,
47-
);
43+
let path =
44+
Path::new_(pathvec_std!(convert::From), vec![Box::new(from_type.clone())], PathKind::Std);
4845

4946
// Generate code like this:
5047
//
@@ -67,11 +64,16 @@ pub(crate) fn expand_deriving_from(
6764
name: sym::from,
6865
generics: Bounds { bounds: vec![] },
6966
explicit_self: false,
70-
nonself_args: vec![(Ty::AstTy(field.ty), sym::value)],
67+
nonself_args: vec![(from_type, sym::value)],
7168
ret_ty: Ty::Self_,
7269
attributes: thin_vec![cx.attr_word(sym::inline, span)],
7370
fieldless_variants_strategy: FieldlessVariantsStrategy::Default,
7471
combine_substructure: combine_substructure(Box::new(|cx, span, substructure| {
72+
let Some(field) = &field else {
73+
let error = cx.dcx().emit_err(errors::DeriveFromWrongTarget { span });
74+
return BlockOrExpr::new_expr(DummyResult::raw_expr(span, Some(error)));
75+
};
76+
7577
let self_kw = Ident::new(kw::SelfUpper, span);
7678
let expr: Box<ast::Expr> = match substructure.fields {
7779
SubstructureFields::StaticStruct(variant, _) => match variant {

0 commit comments

Comments
 (0)