diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index 268153c1cbb31..620bf538a4c6a 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -69,7 +69,15 @@ fn default_struct_substructure( variant_data: &VariantData, type_ident: Ident, ) -> BlockOrExpr { + // FIXME: This is currently needed to avoid a regression with attribute macros after + // derives that incorrectly rely on the generated code using `Unit {}` instead of `Unit`. + // See https://github.com/rust-lang/rust/issues/164078. + if variant_data.fields().is_empty() { + return BlockOrExpr::new_expr(cx.expr_struct_ident(trait_span, type_ident, ThinVec::new())); + } + let expr = match variant_data { + // This is currently unreachable due to the above hack. VariantData::Unit(_) => cx.expr_ident(trait_span, type_ident), VariantData::Tuple(fields, _) => { let exprs = fields diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 789d06722f897..b384a7bcf7dab 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -17,10 +17,10 @@ use rustc_hir_analysis::check::potentially_plural_count; use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, ResolvedStructPath}; use rustc_index::IndexVec; use rustc_infer::infer::{ - BoundRegionConversionTime, DefineOpaqueTypes, InferOk, TypeTrace, relate, + BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk, TypeTrace, relate, }; use rustc_middle::ty::adjustment::AllowTwoPhase; -use rustc_middle::ty::error::{ExpectedFound, TypeError}; +use rustc_middle::ty::error::TypeError; use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt, TypeVisitableExt, Unnormalized}; @@ -292,22 +292,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected_input_tys .into_iter() .zip(formal_input_tys) - // if the expected input type is structurally equal to the formal input type, - // i.e. we've only changed some inference variables around, keep the formal - // input ty as the expected input ty. Usually fudging helps because it gains - // information from a callsite of a function. However, Fudging also sometimes - // loses information, when the original, formal, input type had constraints on it, - // and fudging replaces all inference variables with fresh ones, those constraints - // are discarded. This check makes sure we only keep fudging output if structural - // changes were made to the type. If all that was changed were some typevars, - // we go back to the unfudged formal input type. .map(|(expected_input_ty, formal_input_ty)| { - if same_type_modulo_vars(tcx, expected_input_ty, *formal_input_ty) { - // if they're the same, fall back to the formal input type - *formal_input_ty - } else { - expected_input_ty - } + only_keep_structural_changes( + &self.infcx, + *formal_input_ty, + expected_input_ty, + ) }) .collect() })) @@ -3572,50 +3562,63 @@ enum SuggestionText { DidYouMean, } -fn same_type_modulo_vars<'tcx>(tcx: TyCtxt<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> bool { - struct SameModuloVars<'tcx> { - tcx: TyCtxt<'tcx>, +/// Postprocessing step of fudging: after fudging, any changes from the formal input type to the +/// expected input type are only kept, if they result in structural changes. If the only change is +/// one inference variable changing to another (fresh) inference variable, the formal one is kept, +/// not the fresh one. This avoids cases in which those fresh inference variables are *less* +/// constrained than the original formal ones, and making them fresh has no benefit. +fn only_keep_structural_changes<'tcx>( + infcx: &InferCtxt<'tcx>, + formal: Ty<'tcx>, + expected: Ty<'tcx>, +) -> Ty<'tcx> { + struct OnlyKeepStructuralChanges<'a, 'tcx> { + infcx: &'a InferCtxt<'tcx>, } - impl<'tcx> TypeRelation> for SameModuloVars<'tcx> { + impl<'tcx> TypeRelation> for OnlyKeepStructuralChanges<'_, 'tcx> { fn cx(&self) -> TyCtxt<'tcx> { - self.tcx + self.infcx.tcx } fn relate_ty_args( &mut self, - a_ty: Ty<'tcx>, - _b_ty: Ty<'tcx>, - _ty_def_id: DefId, - a_args: ty::GenericArgsRef<'tcx>, - b_args: ty::GenericArgsRef<'tcx>, - _mk: impl FnOnce(ty::GenericArgsRef<'tcx>) -> Ty<'tcx>, + formal_ty: Ty<'tcx>, + _expected_ty: Ty<'tcx>, + _def_id: DefId, + formal_args: ty::GenericArgsRef<'tcx>, + expected_args: ty::GenericArgsRef<'tcx>, + mk: impl FnOnce(ty::GenericArgsRef<'tcx>) -> Ty<'tcx>, ) -> RelateResult<'tcx, Ty<'tcx>> { - relate::relate_args_invariantly(self, a_args, b_args)?; - Ok(a_ty) + let new_args = relate::relate_args_invariantly(self, formal_args, expected_args)?; + + if new_args == formal_args { Ok(formal_ty) } else { Ok(mk(new_args)) } } fn relate_with_variance>>( &mut self, _variance: ty::Variance, _info: ty::VarianceDiagInfo>, - a: T, - b: T, + formal: T, + expected: T, ) -> RelateResult<'tcx, T> { - self.relate(a, b) + self.relate(formal, expected) } - fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - if a == b { - return Ok(a); + fn tys(&mut self, formal: Ty<'tcx>, expected: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + if formal == expected { + return Ok(formal); } - match (a.kind(), b.kind()) { + match (formal.kind(), expected.kind()) { + // If both are an infer var, keep the formal one. (&ty::Infer(ty::InferTy::TyVar(_)), &ty::Infer(ty::InferTy::TyVar(_))) | (&ty::Infer(ty::InferTy::FloatVar(_)), &ty::Infer(ty::InferTy::FloatVar(_))) - | (&ty::Infer(ty::InferTy::IntVar(_)), &ty::Infer(ty::InferTy::IntVar(_))) => Ok(a), - (&ty::Infer(_), _) | (_, &ty::Infer(_)) => Err(TypeError::Mismatch), + | (&ty::Infer(ty::InferTy::IntVar(_)), &ty::Infer(ty::InferTy::IntVar(_))) => { + Ok(formal) + } + (&ty::Infer(_), _) | (_, &ty::Infer(_)) => Ok(expected), (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(Ty::new_error(self.cx(), guar)), - _ => relate::structurally_relate_tys(self, a, b), + _ => relate::structurally_relate_tys(self, formal, expected), } } @@ -3629,42 +3632,47 @@ fn same_type_modulo_vars<'tcx>(tcx: TyCtxt<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> b fn consts( &mut self, - mut a: ty::Const<'tcx>, - mut b: ty::Const<'tcx>, + mut formal: ty::Const<'tcx>, + mut expected: ty::Const<'tcx>, ) -> RelateResult<'tcx, ty::Const<'tcx>> { - if a == b { - return Ok(a); + if formal == expected { + return Ok(formal); } // Avoid ICEs when in gce, and `structurally_relate_consts` // turns a non-infer const into an infer const - if self.tcx.features().generic_const_exprs() { - a = self.tcx.expand_abstract_consts(a); - b = self.tcx.expand_abstract_consts(b); + if self.cx().features().generic_const_exprs() { + formal = self.cx().expand_abstract_consts(formal); + expected = self.cx().expand_abstract_consts(expected); } - match (a.kind(), b.kind()) { - (ty::ConstKind::Infer(_), ty::ConstKind::Infer(_)) => return Ok(a), - (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => { - return Err(TypeError::ConstMismatch(ExpectedFound::new(a, b))); - } + match (formal.kind(), expected.kind()) { + // If both are an infer var, keep the formal one. + (ty::ConstKind::Infer(_), ty::ConstKind::Infer(_)) => return Ok(formal), + (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => return Ok(formal), + _ => {} } - relate::structurally_relate_consts(self, a, b) + relate::structurally_relate_consts(self, formal, expected) } fn binders( &mut self, - a: ty::Binder<'tcx, T>, - b: ty::Binder<'tcx, T>, + formal: ty::Binder<'tcx, T>, + expected: ty::Binder<'tcx, T>, ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> where T: Relate>, { - Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?)) + Ok(formal.rebind(self.relate(formal.skip_binder(), expected.skip_binder())?)) } } - SameModuloVars { tcx }.relate(a, b).is_ok() + // If it errors for some reason, keep the expected type, not the formal one, keeping the fudging. + let res = OnlyKeepStructuralChanges { infcx }.relate(formal, expected).unwrap_or(expected); + tracing::debug!( + "formal: {formal:?} and expected {expected:?} => only keeping structural changes creates {res:?}" + ); + res } diff --git a/src/llvm-project b/src/llvm-project index aab11ee0ea5ea..915c669d232e4 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit aab11ee0ea5ea9a1d462ad0bc1fae9d9bb643019 +Subproject commit 915c669d232e4cad467ba95ff041041e2e7c3f69 diff --git a/tests/ui/coercion/fudge-inference/fudge-eager-resolve-breakage-3.rs b/tests/ui/coercion/fudge-inference/fudge-eager-resolve-breakage-3.rs new file mode 100644 index 0000000000000..1368e8e019873 --- /dev/null +++ b/tests/ui/coercion/fudge-inference/fudge-eager-resolve-breakage-3.rs @@ -0,0 +1,42 @@ +//@ check-pass +// When we changed from lazy resolving to eager resolving, this was in some cases breaking +// We introduced a workaround in https://github.com/rust-lang/rust/pull/158447 to more often +// avoid breakage. This workaround was not perfect, and we knew this when landing, +// we just had no examples that showed the breakage until this one. +// +// The workaround would try to fudge a formally expected type, but if no structural changes +// to the type happened, would rollback the fudging again, and stuck to the formal expected type. +// +// This rollback behavior worked per function argument, and that's what goes wrong in this +// reproducer: g() is called with two parameters. The 2nd parameter gets fudged, and has a +// structural change (the return type is inferred to unit), so fudging gets accepted, +// not rolled back. In the process, the input of the closure, `x` becomes an unconstrained +// type variable, and type inference fails, despite us knowing that its type is `X` already, +// by the difinion of `g`. + +fn f() -> X { + let v = h(g(X, |x| x.m())); + // ^^^^^^^^^^^^^^ two parameters + v +} + +fn g(_: T, _: fn(T) -> U) -> Y { + loop {} +} + +fn h(_: Y) -> U { + loop {} +} + +struct X; + +impl X { + fn m(self) {} +} + +struct Y { + a: fn(T) -> T, + b: U, +} + +fn main() {} diff --git a/tests/ui/const-generics/const-argument-cross-crate-mismatch.stderr b/tests/ui/const-generics/const-argument-cross-crate-mismatch.stderr index f58821283e19f..1e33dd31a4129 100644 --- a/tests/ui/const-generics/const-argument-cross-crate-mismatch.stderr +++ b/tests/ui/const-generics/const-argument-cross-crate-mismatch.stderr @@ -1,30 +1,29 @@ error[E0308]: mismatched types - --> $DIR/const-argument-cross-crate-mismatch.rs:6:67 + --> $DIR/const-argument-cross-crate-mismatch.rs:6:41 | LL | let _ = const_generic_lib::function(const_generic_lib::Struct([0u8, 1u8])); - | ------------------------- ^^^^^^^^^^ expected an array with a size of 3, found one with a size of 2 - | | - | arguments to this struct are incorrect + | --------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `3`, found `2` + | | + | arguments to this function are incorrect | -note: tuple struct defined here - --> $DIR/auxiliary/const_generic_lib.rs:1:12 + = note: expected struct `Struct<3>` + found struct `Struct<2>` +note: function defined here + --> $DIR/auxiliary/const_generic_lib.rs:5:8 | -LL | pub struct Struct(pub [u8; N]); - | ^^^^^^ +LL | pub fn function(value: Struct<3>) -> u8 { + | ^^^^^^^^ error[E0308]: mismatched types - --> $DIR/const-argument-cross-crate-mismatch.rs:8:65 + --> $DIR/const-argument-cross-crate-mismatch.rs:8:39 | LL | let _: const_generic_lib::Alias = const_generic_lib::Struct([0u8, 1u8, 2u8]); - | ------------------------- ^^^^^^^^^^^^^^^ expected an array with a size of 2, found one with a size of 3 - | | - | arguments to this struct are incorrect + | ------------------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2`, found `3` + | | + | expected due to this | -note: tuple struct defined here - --> $DIR/auxiliary/const_generic_lib.rs:1:12 - | -LL | pub struct Struct(pub [u8; N]); - | ^^^^^^ + = note: expected struct `Struct<2>` + found struct `Struct<3>` error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/generic_const_exprs/issue-62504.full.stderr b/tests/ui/const-generics/generic_const_exprs/issue-62504.full.stderr index b64c1c17df601..cdcfe80093f96 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-62504.full.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-62504.full.stderr @@ -1,17 +1,39 @@ +error: unconstrained generic constant + --> $DIR/issue-62504.rs:18:25 + | +LL | ArrayHolder([0; Self::SIZE]) + | ^^^^^^^^^^ + | +help: try adding a `where` bound + | +LL | pub const fn new() -> Self where [(); Self::SIZE]: { + | +++++++++++++++++++++++ + +error: unconstrained generic constant + --> $DIR/issue-62504.rs:18:9 + | +LL | ArrayHolder([0; Self::SIZE]) + | ^^^^^^^^^^^ + | +help: try adding a `where` bound + | +LL | pub const fn new() -> Self where [(); Self::SIZE]: { + | +++++++++++++++++++++++ + error[E0308]: mismatched types - --> $DIR/issue-62504.rs:18:21 + --> $DIR/issue-62504.rs:18:9 | LL | ArrayHolder([0; Self::SIZE]) - | ^^^^^^^^^^^^^^^ expected `X`, found `Self::SIZE` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `X`, found `Self::SIZE` | = note: expected constant `X` found constant `Self::SIZE` error: unconstrained generic constant - --> $DIR/issue-62504.rs:18:25 + --> $DIR/issue-62504.rs:18:9 | LL | ArrayHolder([0; Self::SIZE]) - | ^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: try adding a `where` bound | @@ -19,7 +41,7 @@ LL | pub const fn new() -> Self where [(); Self::SIZE]: { | +++++++++++++++++++++++ error[E0284]: type annotations needed for `ArrayHolder<_>` - --> $DIR/issue-62504.rs:26:9 + --> $DIR/issue-62504.rs:30:9 | LL | let mut array = ArrayHolder::new(); | ^^^^^^^^^ ----------- type must be known at this point @@ -35,7 +57,7 @@ LL | let mut array: ArrayHolder = ArrayHolder::new(); | ++++++++++++++++ error[E0284]: type annotations needed for `ArrayHolder<_>` - --> $DIR/issue-62504.rs:26:9 + --> $DIR/issue-62504.rs:30:9 | LL | let mut array = ArrayHolder::new(); | ^^^^^^^^^ ------------------ type must be known at this point @@ -52,7 +74,7 @@ help: consider giving `array` an explicit type, where the value of const paramet LL | let mut array: ArrayHolder = ArrayHolder::new(); | ++++++++++++++++ -error: aborting due to 4 previous errors +error: aborting due to 6 previous errors Some errors have detailed explanations: E0284, E0308. For more information about an error, try `rustc --explain E0284`. diff --git a/tests/ui/const-generics/generic_const_exprs/issue-62504.min.stderr b/tests/ui/const-generics/generic_const_exprs/issue-62504.min.stderr index ef4655c8dc21f..8b8e4f87d7381 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-62504.min.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-62504.min.stderr @@ -6,22 +6,35 @@ LL | ArrayHolder([0; Self::SIZE]) | = note: this may fail depending on what value the parameter takes +error: constant expression depends on a generic parameter + --> $DIR/issue-62504.rs:18:9 + | +LL | ArrayHolder([0; Self::SIZE]) + | ^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + error[E0308]: mismatched types - --> $DIR/issue-62504.rs:18:21 + --> $DIR/issue-62504.rs:18:9 | +LL | pub const fn new() -> Self { + | ---- expected `ArrayHolder` because of return type LL | ArrayHolder([0; Self::SIZE]) - | ----------- ^^^^^^^^^^^^^^^ expected an array with a size of X, found one with a size of Self::SIZE - | | - | arguments to this struct are incorrect + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `X`, found `Self::SIZE` | -note: tuple struct defined here - --> $DIR/issue-62504.rs:14:8 + = note: expected struct `ArrayHolder` + found struct `ArrayHolder` + +error: constant expression depends on a generic parameter + --> $DIR/issue-62504.rs:18:9 | -LL | struct ArrayHolder([u32; X]); - | ^^^^^^^^^^^ +LL | ArrayHolder([0; Self::SIZE]) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes error[E0284]: type annotations needed for `ArrayHolder<_>` - --> $DIR/issue-62504.rs:26:9 + --> $DIR/issue-62504.rs:30:9 | LL | let mut array = ArrayHolder::new(); | ^^^^^^^^^ ----------- type must be known at this point @@ -37,7 +50,7 @@ LL | let mut array: ArrayHolder = ArrayHolder::new(); | ++++++++++++++++ error[E0284]: type annotations needed for `ArrayHolder<_>` - --> $DIR/issue-62504.rs:26:9 + --> $DIR/issue-62504.rs:30:9 | LL | let mut array = ArrayHolder::new(); | ^^^^^^^^^ ------------------ type must be known at this point @@ -54,7 +67,7 @@ help: consider giving `array` an explicit type, where the value of const paramet LL | let mut array: ArrayHolder = ArrayHolder::new(); | ++++++++++++++++ -error: aborting due to 4 previous errors +error: aborting due to 6 previous errors Some errors have detailed explanations: E0284, E0308. For more information about an error, try `rustc --explain E0284`. diff --git a/tests/ui/const-generics/generic_const_exprs/issue-62504.rs b/tests/ui/const-generics/generic_const_exprs/issue-62504.rs index f021e1036143b..830838905d378 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-62504.rs +++ b/tests/ui/const-generics/generic_const_exprs/issue-62504.rs @@ -18,7 +18,11 @@ impl ArrayHolder { ArrayHolder([0; Self::SIZE]) //~^ ERROR mismatched types //[full]~^^ ERROR unconstrained generic constant - //[min]~^^^ ERROR constant expression depends on a generic parameter + //[full]~^^^ ERROR unconstrained generic constant + //[full]~^^^^ ERROR unconstrained generic constant + //[min]~^^^^^ ERROR constant expression depends on a generic parameter + //[min]~| ERROR constant expression depends on a generic parameter + //[min]~| ERROR constant expression depends on a generic parameter } } diff --git a/tests/crashes/118603.rs b/tests/ui/const-generics/ice-unevaluated.rs similarity index 97% rename from tests/crashes/118603.rs rename to tests/ui/const-generics/ice-unevaluated.rs index 1a3e3bed59d40..d03b3c34ca5ee 100644 --- a/tests/crashes/118603.rs +++ b/tests/ui/const-generics/ice-unevaluated.rs @@ -1,5 +1,5 @@ -//@ known-bug: #118603 //@ compile-flags: -Copt-level=0 +//@ check-pass // ignore-tidy-file-linelength #![feature(generic_const_exprs)] diff --git a/tests/ui/const-generics/transmute_no_gate.rs b/tests/ui/const-generics/transmute_no_gate.rs index e1ac44390a5f8..72a1358480f81 100644 --- a/tests/ui/const-generics/transmute_no_gate.rs +++ b/tests/ui/const-generics/transmute_no_gate.rs @@ -83,9 +83,11 @@ fn main() { let _ = ident([[0; 8]; 16]); let _ = flatten([[0; 13]; 5]); let _: [[_; 5]; 13] = coagulate([0; 65]); + //~^ ERROR mismatched types let _ = flatten_3d([[[0; 3]; 13]; 5]); let _ = flatten_somewhat([[[0; 3]; 13]; 5]); let _ = known_size([16; 13]); let _: [u16; 5] = condense_bytes([16u8; 10]); + //~^ ERROR mismatched types let _ = singleton_each([16; 10]); } diff --git a/tests/ui/const-generics/transmute_no_gate.stderr b/tests/ui/const-generics/transmute_no_gate.stderr index 9c271b34849c0..01b53dc301cfb 100644 --- a/tests/ui/const-generics/transmute_no_gate.stderr +++ b/tests/ui/const-generics/transmute_no_gate.stderr @@ -1,3 +1,31 @@ +error[E0308]: mismatched types + --> $DIR/transmute_no_gate.rs:85:35 + | +LL | let _: [[_; 5]; 13] = coagulate([0; 65]); + | --------- ^^^^^^^ expected an array with a size of _ * _, found one with a size of 65 + | | + | arguments to this function are incorrect + | +note: function defined here + --> $DIR/transmute_no_gate.rs:25:4 + | +LL | fn coagulate(v: [u32; H*W]) -> [[u32; W];H] { + | ^^^^^^^^^ ------------- + +error[E0308]: mismatched types + --> $DIR/transmute_no_gate.rs:90:36 + | +LL | let _: [u16; 5] = condense_bytes([16u8; 10]); + | -------------- ^^^^^^^^^^ expected an array with a size of _ * 2, found one with a size of 10 + | | + | arguments to this function are incorrect + | +note: function defined here + --> $DIR/transmute_no_gate.rs:57:4 + | +LL | fn condense_bytes(v: [u8; L * 2]) -> [u16; L] { + | ^^^^^^^^^^^^^^ -------------- + error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/transmute_no_gate.rs:7:5 | @@ -79,6 +107,7 @@ LL | std::mem::transmute(v) = note: source type: `[[u32; 2 * H]; W + W]` (this type does not have a fixed size) = note: target type: `[[u32; W + W]; 2 * H]` (this type does not have a fixed size) -error: aborting due to 9 previous errors +error: aborting due to 11 previous errors -For more information about this error, try `rustc --explain E0512`. +Some errors have detailed explanations: E0308, E0512. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/derives/attr-macro-changes-type-kind.rs b/tests/ui/derives/attr-macro-changes-type-kind.rs index 98e05af3b33b6..e655e525a1046 100644 --- a/tests/ui/derives/attr-macro-changes-type-kind.rs +++ b/tests/ui/derives/attr-macro-changes-type-kind.rs @@ -8,7 +8,7 @@ extern crate struct_to_enum; use struct_to_enum::*; -#[derive(Clone, Copy, Default, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] +#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] #[struct_to_enum::phantom] struct Spooky; diff --git a/tests/ui/derives/default/attr-macros-fieldless-types.rs b/tests/ui/derives/default/attr-macros-fieldless-types.rs new file mode 100644 index 0000000000000..9a2e68c50551d --- /dev/null +++ b/tests/ui/derives/default/attr-macros-fieldless-types.rs @@ -0,0 +1,47 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/164078, +//! where some attribute macros relied on the generated code always being +//! `Unit {}` and not `Unit()` or `Unit`. + +//@ check-pass +//@ proc-macro: rewrite-fieldless-type-kind.rs + +extern crate rewrite_fieldless_type_kind; +use rewrite_fieldless_type_kind::*; + +#[derive(Default)] +#[to_unit] +struct UnitToUnit; + +#[derive(Default)] +#[to_tuple] +struct UnitToTuple; + +#[derive(Default)] +#[to_braced] +struct UnitToBraced; + +#[derive(Default)] +#[to_unit] +struct TupleToUnit(); + +#[derive(Default)] +#[to_tuple] +struct TupleToTuple(); + +#[derive(Default)] +#[to_braced] +struct TupleToBraced(); + +#[derive(Default)] +#[to_unit] +struct BracedToUnit {} + +#[derive(Default)] +#[to_tuple] +struct BracedToTuple {} + +#[derive(Default)] +#[to_braced] +struct BracedToBraced {} + +fn main() {} diff --git a/tests/ui/derives/default/auxiliary/rewrite-fieldless-type-kind.rs b/tests/ui/derives/default/auxiliary/rewrite-fieldless-type-kind.rs new file mode 100644 index 0000000000000..f75a03cdba647 --- /dev/null +++ b/tests/ui/derives/default/auxiliary/rewrite-fieldless-type-kind.rs @@ -0,0 +1,20 @@ +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn to_unit(_: TokenStream, struct_item: TokenStream) -> TokenStream { + rewrite(struct_item, ";") +} +#[proc_macro_attribute] +pub fn to_tuple(_: TokenStream, struct_item: TokenStream) -> TokenStream { + rewrite(struct_item, "();") +} +#[proc_macro_attribute] +pub fn to_braced(_: TokenStream, struct_item: TokenStream) -> TokenStream { + rewrite(struct_item, "{}") +} + +fn rewrite(struct_item: TokenStream, suffix: &str) -> TokenStream { + let ident = struct_item.into_iter().nth(1).unwrap(); + format!("struct {ident}{suffix}").parse().unwrap() +} diff --git a/tests/ui/derives/deriving-all-codegen.stdout b/tests/ui/derives/deriving-all-codegen.stdout index 163658d2106dd..865c6e20da91c 100644 --- a/tests/ui/derives/deriving-all-codegen.stdout +++ b/tests/ui/derives/deriving-all-codegen.stdout @@ -46,7 +46,7 @@ impl ::core::fmt::Debug for Empty { #[automatically_derived] impl ::core::default::Default for Empty { #[inline] - fn default() -> Self { Empty } + fn default() -> Self { Empty {} } } #[automatically_derived] impl ::core::hash::Hash for Empty {