Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions compiler/rustc_builtin_macros/src/deriving/clone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ fn cs_clone_simple(
&[sym::clone, sym::AssertParamIsCopy],
);
} else {
match substr {
match substr.fields {
StaticStruct(vdata, ..) => {
process_variant(vdata);
}
Expand All @@ -169,18 +169,17 @@ fn cs_clone(cx: &ExtCtxt<'_>, trait_span: Span, substr: Substructure<'_>) -> Blo
cx.expr_call_global(field.span, fn_path.clone(), args)
};

let self_ident = Ident::new(kw::SelfUpper, trait_span);
let ctor_path;
let all_fields;
let vdata;
match substr {
match substr.fields {
Struct(vdata_, af) => {
ctor_path = cx.path(trait_span, vec![self_ident]);
ctor_path = cx.path(trait_span, vec![substr.type_ident]);
all_fields = af;
vdata = vdata_;
}
EnumMatching(.., variant, af) => {
ctor_path = cx.path(trait_span, vec![self_ident, variant.ident]);
ctor_path = cx.path(trait_span, vec![substr.type_ident, variant.ident]);
all_fields = af;
vdata = &variant.data;
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_builtin_macros/src/deriving/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ fn show_substructure(
return BlockOrExpr::new_expr(cx.expr_ok(span, cx.expr_tuple(span, ThinVec::new())));
}

let (ident, vdata, fields) = match substr {
let (ident, vdata, fields) = match substr.fields {
Struct(vdata, fields) => (type_ident, vdata, fields),
EnumMatching(v, fields) => (v.ident, &v.data, fields),
AllFieldlessEnum(enum_def) => return show_fieldless_enum(cx, span, enum_def, type_ident),
Expand Down
11 changes: 6 additions & 5 deletions compiler/rustc_builtin_macros/src/deriving/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ pub(crate) fn expand_deriving_default(
attributes: thin_vec![cx.attr_word(sym::inline, span)],
fieldless_variants_strategy: FieldlessVariantsStrategy::Default,
combine_substructure: combine_substructure(|cx, trait_span, substr| {
match substr {
match substr.fields {
StaticStruct(variant_data) => {
default_struct_substructure(cx, trait_span, variant_data)
default_struct_substructure(cx, trait_span, variant_data, substr.type_ident)
}
StaticEnum(enum_def) => {
default_enum_substructure(cx, trait_span, enum_def, item.span)
Expand Down Expand Up @@ -67,15 +67,16 @@ fn default_struct_substructure(
cx: &ExtCtxt<'_>,
trait_span: Span,
variant_data: &VariantData,
type_ident: Ident,
) -> BlockOrExpr {
let expr = match variant_data {
VariantData::Unit(_) => cx.expr_ident(trait_span, Ident::new(kw::SelfUpper, trait_span)),
VariantData::Unit(_) => cx.expr_ident(trait_span, type_ident),
VariantData::Tuple(fields, _) => {
let exprs = fields
.iter()
.map(|field| default_call(cx, field.span.with_ctxt(trait_span.ctxt())))
.collect();
cx.expr_call_ident(trait_span, Ident::new(kw::SelfUpper, trait_span), exprs)
cx.expr_call_ident(trait_span, type_ident, exprs)
}
VariantData::Struct { fields, .. } => {
let default_fields = fields
Expand All @@ -95,7 +96,7 @@ fn default_struct_substructure(
cx.field_imm(span, field.ident.unwrap(), value)
})
.collect();
cx.expr_struct_ident(trait_span, Ident::new(kw::SelfUpper, trait_span), default_fields)
cx.expr_struct_ident(trait_span, type_ident, default_fields)
}
};
BlockOrExpr::new_expr(expr)
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_builtin_macros/src/deriving/eq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ fn cs_total_eq_assert(cx: &ExtCtxt<'_>, trait_span: Span, substr: Substructure<'
}
};

match substr {
match substr.fields {
StaticStruct(vdata, ..) => {
process_variant(vdata);
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_builtin_macros/src/deriving/from.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ pub(crate) fn expand_deriving_from(
};

let self_kw = Ident::new(kw::SelfUpper, span);
let expr: Box<ast::Expr> = match substructure {
let expr: Box<ast::Expr> = match substructure.fields {
StaticStruct(variant) => match variant {
// Self { field: value }
VariantData::Struct { .. } => cx.expr_struct_ident(
Expand Down
77 changes: 60 additions & 17 deletions compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@
use std::ops::Not;
use std::vec;

pub(crate) use Substructure::*;
pub(crate) use SubstructureFields::*;
pub(crate) use rustc_ast as ast;
use rustc_ast::token::{IdentKind, LitKind, Token, TokenKind};
use rustc_ast::tokenstream::{DelimSpan, Spacing, TokenTree};
Expand Down Expand Up @@ -281,8 +281,16 @@ pub(crate) struct FieldInfo {
pub maybe_scalar: bool,
}

pub(crate) struct Substructure<'a> {
pub fields: SubstructureFields<'a>,
// FIXME: this is currently required to avoid issues with attribute macros after derives,
// such as https://github.com/rust-lang/rust/issues/163800.
// Ideally we would just use `Self` instead.
pub type_ident: Ident,
}

/// A summary of the possible sets of fields.
pub(crate) enum Substructure<'a> {
pub(crate) enum SubstructureFields<'a> {
/// A non-static method where `Self` is a struct.
Struct(&'a ast::VariantData, Vec<FieldInfo>),

Expand Down Expand Up @@ -474,9 +482,15 @@ impl<'a> TraitDef<'a> {
let fields = struct_def.fields().iter();
let methods = self.methods.iter().filter_map(|method_def| {
let body = if from_scratch || method_def.is_static() {
method_def.call_substructure_method(cx, span, StaticStruct(struct_def))
method_def.call_substructure_method(
cx,
span,
StaticStruct(struct_def),
*ident,
)
} else {
method_def.expand_struct_method_body(cx, span, struct_def, is_packed)
method_def
.expand_struct_method_body(cx, span, struct_def, is_packed, *ident)
};

method_def.create_method(cx, span, body)
Expand All @@ -494,9 +508,9 @@ impl<'a> TraitDef<'a> {
let fields = enum_def.variants.iter().flat_map(|variant| variant.data.fields());
let methods = self.methods.iter().filter_map(|method_def| {
let body = if from_scratch || method_def.is_static() {
method_def.call_substructure_method(cx, span, StaticEnum(enum_def))
method_def.call_substructure_method(cx, span, StaticEnum(enum_def), *ident)
} else {
method_def.expand_enum_method_body(cx, span, enum_def)
method_def.expand_enum_method_body(cx, span, enum_def, *ident)
};

method_def.create_method(cx, span, body)
Expand Down Expand Up @@ -778,9 +792,10 @@ impl<'a> MethodDef<'a> {
&self,
cx: &ExtCtxt<'_>,
span: Span,
substructure: Substructure<'_>,
fields: SubstructureFields<'_>,
type_ident: Ident,
) -> BlockOrExpr {
(self.combine_substructure)(cx, span, substructure)
(self.combine_substructure)(cx, span, Substructure { fields, type_ident })
}

fn is_static(&self) -> bool {
Expand Down Expand Up @@ -906,12 +921,13 @@ impl<'a> MethodDef<'a> {
span: Span,
struct_def: &'b VariantData,
is_packed: bool,
type_ident: Ident,
) -> BlockOrExpr {
let selflike_args = self.get_selflike_args(cx, span);

let selflike_fields =
create_struct_field_access_fields(span, cx, &selflike_args, struct_def, is_packed);
self.call_substructure_method(cx, span, Struct(struct_def, selflike_fields))
self.call_substructure_method(cx, span, Struct(struct_def, selflike_fields), type_ident)
}

/// ```
Expand Down Expand Up @@ -954,6 +970,7 @@ impl<'a> MethodDef<'a> {
cx: &ExtCtxt<'_>,
span: Span,
enum_def: &'b EnumDef,
type_ident: Ident,
) -> BlockOrExpr {
let variants = &enum_def.variants;

Expand Down Expand Up @@ -989,17 +1006,32 @@ impl<'a> MethodDef<'a> {
// If the type is fieldless and the trait uses the discriminant and
// there are multiple variants, we need just an operation on
// the discriminant(s).
return self.call_substructure_method(cx, span, EnumDiscr(None));
return self.call_substructure_method(
cx,
span,
EnumDiscr(None),
type_ident,
);
}
FieldlessVariantsStrategy::SpecializeIfAllVariantsFieldless => {
return self.call_substructure_method(cx, span, AllFieldlessEnum(enum_def));
return self.call_substructure_method(
cx,
span,
AllFieldlessEnum(enum_def),
type_ident,
);
}
FieldlessVariantsStrategy::Default => (),
}
} else if let [variant] = variants.as_slice() {
// If there is a single variant, we don't need an operation on
// the discriminant(s). Just use the most degenerate result.
return self.call_substructure_method(cx, span, EnumMatching(variant, Vec::new()));
return self.call_substructure_method(
cx,
span,
EnumMatching(variant, Vec::new()),
type_ident,
);
}
}

Expand Down Expand Up @@ -1039,8 +1071,9 @@ impl<'a> MethodDef<'a> {
// Self arg, assuming all are instances of VariantK.
// Build up code associated with such a case.
let substructure = EnumMatching(variant, fields);
let arm_expr =
self.call_substructure_method(cx, span, substructure).into_expr(cx, span);
let arm_expr = self
.call_substructure_method(cx, span, substructure, type_ident)
.into_expr(cx, span);

cx.arm(span, single_pat, arm_expr)
})
Expand All @@ -1052,8 +1085,13 @@ impl<'a> MethodDef<'a> {
Some(v) if unify_fieldless_variants => {
// We need a default case that handles all the fieldless variants.
Some(
self.call_substructure_method(cx, span, EnumMatching(v, Vec::new()))
.into_expr(cx, span),
self.call_substructure_method(
cx,
span,
EnumMatching(v, Vec::new()),
type_ident,
)
.into_expr(cx, span),
)
}
_ if variants.len() > 1 && selflike_args.len() > 1 => {
Expand Down Expand Up @@ -1090,7 +1128,12 @@ impl<'a> MethodDef<'a> {
// is enough.
if unify_fieldless_variants && variants.len() > 1 {
// Combine a discriminant check with the match.
self.call_substructure_method(cx, span, EnumDiscr(Some(get_match_expr(selflike_args))))
self.call_substructure_method(
cx,
span,
EnumDiscr(Some(get_match_expr(selflike_args))),
type_ident,
)
} else {
BlockOrExpr(ThinVec::new(), Some(get_match_expr(selflike_args)))
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_builtin_macros/src/deriving/hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ fn hash_substructure(cx: &ExtCtxt<'_>, span: Span, substr: Substructure<'_>) ->
cx.stmt_expr(expr)
};

let (stmts, match_expr) = match substr {
let (stmts, match_expr) = match substr.fields {
Struct(_, fields) | EnumMatching(.., fields) => {
let stmts =
fields.into_iter().map(|field| call_hash(field.span, field.self_expr)).collect();
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_builtin_macros/src/deriving/partial_eq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ fn get_substructure_equality_expr(
span: Span,
substructure: Substructure<'_>,
) -> BlockOrExpr {
BlockOrExpr::new_expr(match substructure {
BlockOrExpr::new_expr(match substructure.fields {
EnumMatching(.., fields) | Struct(.., fields) => {
let combine = move |acc, field: &FieldInfo| {
let rhs = field
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_builtin_macros/src/deriving/partial_ord.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ pub(crate) fn cmp_body(
}
};

match substructure {
match substructure.fields {
EnumMatching(.., all_fields) | Struct(_, all_fields) => {
let op = |old, field: FieldInfo| {
// The basic case: a field expression for one or more selflike args. E.g.
Expand Down
15 changes: 15 additions & 0 deletions tests/ui/derives/attr-macro-changes-type-kind.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//! Regression test for https://github.com/rust-lang/rust/issues/163800,
//! where the generated code always referred to `Self`, which was invalid
//! when an attribute macro rewrites the type to an enum.

//@ check-pass
//@ proc-macro: struct-to-enum.rs

extern crate struct_to_enum;
use struct_to_enum::*;

#[derive(Clone, Copy, Default, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)]
#[struct_to_enum::phantom]
struct Spooky<T>;

fn main() {}
18 changes: 18 additions & 0 deletions tests/ui/derives/auxiliary/struct-to-enum.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
extern crate proc_macro;
use proc_macro::TokenStream;

#[proc_macro_attribute]
pub fn phantom(_: TokenStream, _: TokenStream) -> TokenStream {
"
mod __value_Spooky {
pub use super::Spooky::Spooky;
}
pub enum Spooky<T> {
__Phantom(std::marker::PhantomData<T>),
Spooky,
}
pub use self::__value_Spooky::*;
"
.parse()
.unwrap()
}
Loading
Loading