diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs index 7520df43bf4cc..4f4cca5fc1c5e 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs @@ -1,13 +1,112 @@ +use rustc_ast::mut_visit::{self, MutVisitor}; use rustc_ast::{self as ast, MetaItem, Safety}; use rustc_data_structures::fx::FxHashSet; use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::{Span, sym}; +use rustc_span::{Ident, Span, kw, sym}; use thin_vec::{ThinVec, thin_vec}; -use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use crate::deriving::path_std; +struct ReplaceSelfTyVisitor(Box); +impl MutVisitor for ReplaceSelfTyVisitor { + fn visit_ty(&mut self, ty: &mut ast::Ty) { + if let ast::TyKind::Path(None, path) = &mut ty.kind + && let [first, rest @ ..] = &path.segments[..] + && *first == kw::SelfUpper + { + if rest.is_empty() { + // Just `Self` — replace the whole type + *ty = *self.0.clone(); + } else { + // `Self::Something` — splice concrete type's segments in + let ast::TyKind::Path(_, concrete_path) = &self.0.kind else { + unreachable!("expected Self type to be a path"); + }; + let mut new_segments = concrete_path.segments.clone(); + new_segments.extend_from_slice(rest); + path.segments = new_segments; + mut_visit::walk_ty(self, ty); + } + } else { + mut_visit::walk_ty(self, ty); + } + } + fn visit_expr(&mut self, expr: &mut ast::Expr) { + if let ast::ExprKind::Path(None, path) = &mut expr.kind + && let [first, rest @ ..] = &*path.segments + && *first == kw::SelfUpper + { + let ast::TyKind::Path(_, concrete_path) = &self.0.kind else { + unreachable!("expected Self type to be a path"); + }; + let mut new_segments = concrete_path.segments.clone(); + new_segments.extend_from_slice(rest); + path.segments = new_segments; + } + mut_visit::walk_expr(self, expr); + } +} + +struct RespanGenericsVisitor(Span); +impl MutVisitor for RespanGenericsVisitor { + fn visit_generics(&mut self, generics: &mut ast::Generics) { + generics.where_clause.span = self.0.with_ctxt(generics.where_clause.span.ctxt()); + generics.span = self.0.with_ctxt(generics.span.ctxt()); + // generic parameter declarations don't need to be respanned, so we visit the where clause + // predicates next + for predicate in &mut generics.where_clause.predicates { + self.visit_where_predicate(predicate); + } + } + fn visit_where_predicate(&mut self, predicate: &mut ast::WherePredicate) { + predicate.span = self.0.with_ctxt(predicate.span.ctxt()); + mut_visit::walk_where_predicate(self, predicate); + } + fn visit_where_predicate_kind(&mut self, kind: &mut ast::WherePredicateKind) { + match kind { + ast::WherePredicateKind::BoundPredicate(bound_predicate) => { + bound_predicate.bounded_ty.span = + self.0.with_ctxt(bound_predicate.bounded_ty.span.ctxt()); + } + ast::WherePredicateKind::EqPredicate(eq_predicate) => { + eq_predicate.lhs_ty.span = self.0.with_ctxt(eq_predicate.lhs_ty.span.ctxt()); + eq_predicate.rhs_ty.span = self.0.with_ctxt(eq_predicate.rhs_ty.span.ctxt()); + } + ast::WherePredicateKind::RegionPredicate(_) => {} + } + mut_visit::walk_where_predicate_kind(self, kind); + } + fn visit_param_bound( + &mut self, + bound: &mut rustc_ast::GenericBound, + _ctxt: rustc_ast::visit::BoundKind, + ) { + match bound { + ast::GenericBound::Trait(poly_trait_ref) => { + poly_trait_ref.span = self.0.with_ctxt(poly_trait_ref.span.ctxt()); + } + ast::GenericBound::Outlives(_) => {} + ast::GenericBound::Use(_, _) => {} + } + ast::mut_visit::walk_param_bound(self, bound); + } +} + +struct StripConstTraitBoundsVisitor; +impl MutVisitor for StripConstTraitBoundsVisitor { + fn visit_param_bound( + &mut self, + bound: &mut rustc_ast::GenericBound, + _ctxt: rustc_ast::visit::BoundKind, + ) { + if let ast::GenericBound::Trait(poly_trait_ref) = bound { + poly_trait_ref.modifiers.constness = ast::BoundConstness::Never; + } + mut_visit::walk_param_bound(self, bound); + } +} + pub(crate) fn expand_deriving_eq( cx: &ExtCtxt<'_>, span: Span, @@ -18,6 +117,9 @@ pub(crate) fn expand_deriving_eq( ) { let span = cx.with_def_site_ctxt(span); + let mut fn_generics = ast::Generics { span, ..Default::default() }; + let mut self_ty = None; + let trait_def = TraitDef { span, path: path_std!(cmp::Eq), @@ -25,38 +127,121 @@ pub(crate) fn expand_deriving_eq( needs_copy_as_bound_if_packed: true, additional_bounds: Vec::new(), supports_unions: true, - methods: vec![MethodDef { - name: sym::assert_fields_are_eq, - generics: Bounds::empty(), - explicit_self: true, - nonself_args: vec![], - ret_ty: Unit, - attributes: thin_vec![ - // This method will never be called, so doing codegen etc. for it is unnecessary. - // We prevent this by adding `#[inline]`, which improves compile-time. - cx.attr_word(sym::inline, span), - cx.attr_nested_word(sym::doc, sym::hidden, span), - cx.attr_nested_word(sym::coverage, sym::off, span), - ], - fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - cs_total_eq_assert(a, b, c) - })), - }], + methods: Vec::new(), associated_types: Vec::new(), is_const, is_staged_api_crate: cx.ecfg.features.staged_api(), safety: Safety::Default, document: true, }; - trait_def.expand_ext(cx, mitem, item, push, true) + trait_def.expand_ext( + cx, + mitem, + item, + &mut |mut a| { + let Annotatable::Item(item) = &mut a else { + unreachable!("should have emitted an Item in trait_def.expand_ext"); + }; + let ast::ItemKind::Impl(imp) = &mut item.kind else { + unreachable!("should have emitted an Impl in trait_def.expand_ext"); + }; + use ast::mut_visit::MutVisitor; + RespanGenericsVisitor(span).visit_generics(&mut imp.generics); + fn_generics = imp.generics.clone(); + self_ty = Some(imp.self_ty.clone()); + push(a) + }, + true, + ); + + let self_ty = + self_ty.unwrap_or_else(|| cx.dcx().span_bug(span, "missing self type in `derive(Eq)`")); + let assert_stmts = + eq_assert_stmts_from_item(cx, span, item, ReplaceSelfTyVisitor(self_ty.clone())); + + // Skip generating `assert_fields_are_eq` impl if there are no assertions to make + if assert_stmts.is_empty() { + return; + } + + StripConstTraitBoundsVisitor.visit_generics(&mut fn_generics); + push(Annotatable::Item(expand_const_item_block(cx, span, fn_generics, self_ty, assert_stmts))); +} + +fn expand_const_item_block( + cx: &ExtCtxt<'_>, + span: Span, + fn_generics: ast::Generics, + self_ty: Box, + assert_stmts: ThinVec, +) -> Box { + // We need a dummy const pointer to Self argument to ensure well-formedness of the Self type. + // This doesn't add overhead because the fn itself is never called, and in fact should not + // even have any runtime code generated for it as it's an inline const fn. + let const_self_ptr_ty = + cx.ty(span, ast::TyKind::Ptr(ast::MutTy { mutbl: ast::Mutability::Not, ty: self_ty })); + let fn_args = thin_vec![cx.param(span, Ident::new(kw::Underscore, span), const_self_ptr_ty)]; + let fn_sig = ast::FnSig { + header: ast::FnHeader { + constness: ast::Const::Yes(span), + coroutine_kind: None, + safety: ast::Safety::Default, + ext: ast::Extern::None, + }, + decl: cx.fn_decl(fn_args, ast::FnRetTy::Default(span)), + span, + }; + + cx.item( + span, + ast::AttrVec::new(), + ast::ItemKind::ConstBlock(ast::ConstBlockItem { + span, + id: ast::DUMMY_NODE_ID, + block: cx.block( + span, + thin_vec![cx.stmt_item( + span, + Box::new(ast::Item { + span, + id: ast::DUMMY_NODE_ID, + attrs: thin_vec![ + cx.attr_nested_word(sym::doc, sym::hidden, span), + cx.attr_nested_word(sym::coverage, sym::off, span), + // This function will never be called, so doing codegen etc. for it is + // unnecessary. We prevent this by adding `#[inline]`, which improves + // compile-time. + cx.attr_word(sym::inline, span), + ], + vis: ast::Visibility { + kind: ast::VisibilityKind::Inherited, + span, + tokens: None, + }, + tokens: None, + kind: ast::ItemKind::Fn(Box::new(ast::Fn { + defaultness: ast::Defaultness::Implicit, + ident: Ident::new(sym::assert_fields_are_eq, span), + generics: fn_generics, + sig: fn_sig, + contract: None, + define_opaque: None, + body: Some(cx.block(span, assert_stmts)), + eii_impls: ThinVec::new(), + })) + }) + ),], + ), + }), + ) } -fn cs_total_eq_assert( +fn eq_assert_stmts_from_item( cx: &ExtCtxt<'_>, - trait_span: Span, - substr: &Substructure<'_>, -) -> BlockOrExpr { + span: Span, + item: &Annotatable, + mut replace_self_ty: ReplaceSelfTyVisitor, +) -> ThinVec { let mut stmts = ThinVec::new(); let mut seen_type_names = FxHashSet::default(); let mut process_variant = |variant: &ast::VariantData| { @@ -69,28 +254,36 @@ fn cs_total_eq_assert( { // Already produced an assertion for this type. } else { + use ast::mut_visit::MutVisitor; + let mut field_ty = field.ty.clone(); + replace_self_ty.visit_ty(&mut field_ty); // let _: AssertParamIsEq; super::assert_ty_bounds( cx, &mut stmts, - field.ty.clone(), + field_ty, field.span, &[sym::cmp, sym::AssertParamIsEq], ); } } }; - - match *substr.fields { - StaticStruct(vdata, ..) => { - process_variant(vdata); - } - StaticEnum(enum_def, ..) => { - for variant in &enum_def.variants { - process_variant(&variant.data); + match item { + Annotatable::Item(item) => match &item.kind { + ast::ItemKind::Struct(_, _, vdata) => { + process_variant(vdata); } - } - _ => cx.dcx().span_bug(trait_span, "unexpected substructure in `derive(Eq)`"), + ast::ItemKind::Enum(_, _, enum_def) => { + for variant in &enum_def.variants { + process_variant(&variant.data); + } + } + ast::ItemKind::Union(_, _, vdata) => { + process_variant(vdata); + } + _ => cx.dcx().span_bug(span, "unexpected item in `derive(Eq)`"), + }, + _ => cx.dcx().span_bug(span, "unexpected item in `derive(Eq)`"), } - BlockOrExpr::new_stmts(stmts) + stmts } diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index b392a9623d050..eee57a5da6170 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -362,10 +362,6 @@ struct TypeParameter { pub(crate) struct BlockOrExpr(ThinVec, Option>); impl BlockOrExpr { - pub(crate) fn new_stmts(stmts: ThinVec) -> BlockOrExpr { - BlockOrExpr(stmts, None) - } - pub(crate) fn new_expr(expr: Box) -> BlockOrExpr { BlockOrExpr(ThinVec::new(), Some(expr)) } diff --git a/tests/ui/deriving/deriving-all-codegen.rs b/tests/ui/deriving/deriving-all-codegen.rs index 9f21831960499..85ea71d6cd562 100644 --- a/tests/ui/deriving/deriving-all-codegen.rs +++ b/tests/ui/deriving/deriving-all-codegen.rs @@ -79,6 +79,10 @@ struct Reorder { b10: &'static *const bool, } +// A struct with a recursive type. +#[derive(PartialEq, Eq, PartialOrd, Ord)] +struct Recursive(Option>); + // A struct that doesn't impl `Copy`, which means it gets the non-trivial // `clone` implemention that clones the fields individually. #[derive(Clone)] @@ -119,6 +123,10 @@ struct Generic { u: U, } +// A generic struct involving a lifetime and an associated type. +#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] +struct GenericLifetime<'a, T: Trait>(&'a T); + // A packed, generic tuple struct involving an associated type. Because it is // packed, a `T: Copy` bound is added to all impls (and where clauses within // them) except for `Default`. This is because we must access fields using @@ -128,6 +136,14 @@ struct Generic { #[repr(packed)] struct PackedGeneric(T, T::A, U); +// A struct with a field referencing an associated constant. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] +struct AssociatedConst([u8; Self::LEN]); + +impl AssociatedConst { + const LEN: usize = 10; +} + // An empty enum. #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] enum Enum0 {} diff --git a/tests/ui/deriving/deriving-all-codegen.stdout b/tests/ui/deriving/deriving-all-codegen.stdout index 94e8b886436df..ef23b1b9bd1ca 100644 --- a/tests/ui/deriving/deriving-all-codegen.stdout +++ b/tests/ui/deriving/deriving-all-codegen.stdout @@ -61,12 +61,7 @@ impl ::core::cmp::PartialEq for Empty { fn eq(&self, other: &Empty) -> bool { true } } #[automatically_derived] -impl ::core::cmp::Eq for Empty { - #[inline] - #[doc(hidden)] - #[coverage(off)] - fn assert_fields_are_eq(&self) {} -} +impl ::core::cmp::Eq for Empty { } #[automatically_derived] impl ::core::cmp::PartialOrd for Empty { #[inline] @@ -138,11 +133,12 @@ impl ::core::cmp::PartialEq for Point { } } #[automatically_derived] -impl ::core::cmp::Eq for Point { - #[inline] +impl ::core::cmp::Eq for Point { } +const { #[doc(hidden)] #[coverage(off)] - fn assert_fields_are_eq(&self) { + #[inline] + const fn assert_fields_are_eq(_: *const Point) { let _: ::core::cmp::AssertParamIsEq; } } @@ -226,11 +222,12 @@ impl ::core::cmp::PartialEq for PackedPoint { } } #[automatically_derived] -impl ::core::cmp::Eq for PackedPoint { - #[inline] +impl ::core::cmp::Eq for PackedPoint { } +const { #[doc(hidden)] #[coverage(off)] - fn assert_fields_are_eq(&self) { + #[inline] + const fn assert_fields_are_eq(_: *const PackedPoint) { let _: ::core::cmp::AssertParamIsEq; } } @@ -309,11 +306,12 @@ impl ::core::cmp::PartialEq for TupleSingleField { fn eq(&self, other: &TupleSingleField) -> bool { self.0 == other.0 } } #[automatically_derived] -impl ::core::cmp::Eq for TupleSingleField { - #[inline] +impl ::core::cmp::Eq for TupleSingleField { } +const { #[doc(hidden)] #[coverage(off)] - fn assert_fields_are_eq(&self) { + #[inline] + const fn assert_fields_are_eq(_: *const TupleSingleField) { let _: ::core::cmp::AssertParamIsEq; } } @@ -384,11 +382,12 @@ impl ::core::cmp::PartialEq for SingleField { fn eq(&self, other: &SingleField) -> bool { self.foo == other.foo } } #[automatically_derived] -impl ::core::cmp::Eq for SingleField { - #[inline] +impl ::core::cmp::Eq for SingleField { } +const { #[doc(hidden)] #[coverage(off)] - fn assert_fields_are_eq(&self) { + #[inline] + const fn assert_fields_are_eq(_: *const SingleField) { let _: ::core::cmp::AssertParamIsEq; } } @@ -489,11 +488,12 @@ impl ::core::cmp::PartialEq for Big { } } #[automatically_derived] -impl ::core::cmp::Eq for Big { - #[inline] +impl ::core::cmp::Eq for Big { } +const { #[doc(hidden)] #[coverage(off)] - fn assert_fields_are_eq(&self) { + #[inline] + const fn assert_fields_are_eq(_: *const Big) { let _: ::core::cmp::AssertParamIsEq; } } @@ -675,6 +675,41 @@ impl ::core::cmp::PartialOrd for Reorder { } } +// A struct with a recursive type. +struct Recursive(Option>); +#[automatically_derived] +impl ::core::marker::StructuralPartialEq for Recursive { } +#[automatically_derived] +impl ::core::cmp::PartialEq for Recursive { + #[inline] + fn eq(&self, other: &Recursive) -> bool { self.0 == other.0 } +} +#[automatically_derived] +impl ::core::cmp::Eq for Recursive { } +const { + #[doc(hidden)] + #[coverage(off)] + #[inline] + const fn assert_fields_are_eq(_: *const Recursive) { + let _: ::core::cmp::AssertParamIsEq>>; + } +} +#[automatically_derived] +impl ::core::cmp::PartialOrd for Recursive { + #[inline] + fn partial_cmp(&self, other: &Recursive) + -> ::core::option::Option<::core::cmp::Ordering> { + ::core::cmp::PartialOrd::partial_cmp(&self.0, &other.0) + } +} +#[automatically_derived] +impl ::core::cmp::Ord for Recursive { + #[inline] + fn cmp(&self, other: &Recursive) -> ::core::cmp::Ordering { + ::core::cmp::Ord::cmp(&self.0, &other.0) + } +} + // A struct that doesn't impl `Copy`, which means it gets the non-trivial // `clone` implemention that clones the fields individually. struct NonCopy(u32); @@ -753,11 +788,12 @@ impl ::core::cmp::PartialEq for Unsized { fn eq(&self, other: &Unsized) -> bool { self.0 == other.0 } } #[automatically_derived] -impl ::core::cmp::Eq for Unsized { - #[inline] +impl ::core::cmp::Eq for Unsized { } +const { #[doc(hidden)] #[coverage(off)] - fn assert_fields_are_eq(&self) { + #[inline] + const fn assert_fields_are_eq(_: *const Unsized) { let _: ::core::cmp::AssertParamIsEq<[u32]>; } } @@ -849,10 +885,14 @@ impl #[automatically_derived] impl ::core::cmp::Eq for Generic where T::A: ::core::cmp::Eq { - #[inline] +} +const { #[doc(hidden)] #[coverage(off)] - fn assert_fields_are_eq(&self) { + #[inline] + const fn assert_fields_are_eq(_: *const Generic) where + T::A: ::core::cmp::Eq { let _: ::core::cmp::AssertParamIsEq; let _: ::core::cmp::AssertParamIsEq; let _: ::core::cmp::AssertParamIsEq; @@ -894,6 +934,86 @@ impl ::core::cmp::Ord for } } +// A generic struct involving a lifetime and an associated type. +struct GenericLifetime<'a, T: Trait>(&'a T); +#[automatically_derived] +impl<'a, T: ::core::clone::Clone + Trait> ::core::clone::Clone for + GenericLifetime<'a, T> { + #[inline] + fn clone(&self) -> GenericLifetime<'a, T> { + GenericLifetime(::core::clone::Clone::clone(&self.0)) + } +} +#[automatically_derived] +impl<'a, T: ::core::marker::Copy + Trait> ::core::marker::Copy for + GenericLifetime<'a, T> { +} +#[automatically_derived] +impl<'a, T: ::core::fmt::Debug + Trait> ::core::fmt::Debug for + GenericLifetime<'a, T> { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + ::core::fmt::Formatter::debug_tuple_field1_finish(f, + "GenericLifetime", &&self.0) + } +} +#[automatically_derived] +impl<'a, T: ::core::default::Default + Trait> ::core::default::Default for + GenericLifetime<'a, T> { + #[inline] + fn default() -> GenericLifetime<'a, T> { + GenericLifetime(::core::default::Default::default()) + } +} +#[automatically_derived] +impl<'a, T: ::core::hash::Hash + Trait> ::core::hash::Hash for + GenericLifetime<'a, T> { + #[inline] + fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) { + ::core::hash::Hash::hash(&self.0, state) + } +} +#[automatically_derived] +impl<'a, T: Trait> ::core::marker::StructuralPartialEq for + GenericLifetime<'a, T> { +} +#[automatically_derived] +impl<'a, T: ::core::cmp::PartialEq + Trait> ::core::cmp::PartialEq for + GenericLifetime<'a, T> { + #[inline] + fn eq(&self, other: &GenericLifetime<'a, T>) -> bool { self.0 == other.0 } +} +#[automatically_derived] +impl<'a, T: ::core::cmp::Eq + Trait> ::core::cmp::Eq for + GenericLifetime<'a, T> { +} +const { + #[doc(hidden)] + #[coverage(off)] + #[inline] + const fn assert_fields_are_eq<'a, T: ::core::cmp::Eq + + Trait>(_: *const GenericLifetime<'a, T>) { + let _: ::core::cmp::AssertParamIsEq<&'a T>; + } +} +#[automatically_derived] +impl<'a, T: ::core::cmp::PartialOrd + Trait> ::core::cmp::PartialOrd for + GenericLifetime<'a, T> { + #[inline] + fn partial_cmp(&self, other: &GenericLifetime<'a, T>) + -> ::core::option::Option<::core::cmp::Ordering> { + ::core::cmp::PartialOrd::partial_cmp(&self.0, &other.0) + } +} +#[automatically_derived] +impl<'a, T: ::core::cmp::Ord + Trait> ::core::cmp::Ord for + GenericLifetime<'a, T> { + #[inline] + fn cmp(&self, other: &GenericLifetime<'a, T>) -> ::core::cmp::Ordering { + ::core::cmp::Ord::cmp(&self.0, &other.0) + } +} + // A packed, generic tuple struct involving an associated type. Because it is // packed, a `T: Copy` bound is added to all impls (and where clauses within // them) except for `Default`. This is because we must access fields using @@ -971,10 +1091,15 @@ impl ::core::cmp::Eq for PackedGeneric where T::A: ::core::cmp::Eq + ::core::marker::Copy { - #[inline] +} +const { #[doc(hidden)] #[coverage(off)] - fn assert_fields_are_eq(&self) { + #[inline] + const fn assert_fields_are_eq(_: *const PackedGeneric) where + T::A: ::core::cmp::Eq + ::core::marker::Copy { let _: ::core::cmp::AssertParamIsEq; let _: ::core::cmp::AssertParamIsEq; let _: ::core::cmp::AssertParamIsEq; @@ -1021,6 +1146,80 @@ impl AssociatedConst { + let _: ::core::clone::AssertParamIsClone<[u8; Self::LEN]>; + *self + } +} +#[automatically_derived] +impl ::core::marker::Copy for AssociatedConst { } +#[automatically_derived] +impl ::core::fmt::Debug for AssociatedConst { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + ::core::fmt::Formatter::debug_tuple_field1_finish(f, + "AssociatedConst", &&self.0) + } +} +#[automatically_derived] +impl ::core::marker::StructuralPartialEq for AssociatedConst { } +#[automatically_derived] +impl ::core::cmp::PartialEq for AssociatedConst { + #[inline] + fn eq(&self, other: &AssociatedConst) -> bool { self.0 == other.0 } +} +#[automatically_derived] +impl ::core::cmp::Eq for AssociatedConst { } +const { + #[doc(hidden)] + #[coverage(off)] + #[inline] + const fn assert_fields_are_eq(_: *const AssociatedConst) { + let _: ::core::cmp::AssertParamIsEq<[u8; AssociatedConst::LEN]>; + } +} +#[automatically_derived] +impl ::core::cmp::PartialOrd for AssociatedConst { + #[inline] + fn partial_cmp(&self, other: &AssociatedConst) + -> ::core::option::Option<::core::cmp::Ordering> { + ::core::cmp::PartialOrd::partial_cmp(&self.0, &other.0) + } +} +#[automatically_derived] +impl ::core::cmp::Ord for AssociatedConst { + #[inline] + fn cmp(&self, other: &AssociatedConst) -> ::core::cmp::Ordering { + ::core::cmp::Ord::cmp(&self.0, &other.0) + } +} +#[automatically_derived] +impl ::core::hash::Hash for AssociatedConst { + #[inline] + fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) { + ::core::hash::Hash::hash(&self.0, state) + } +} +#[automatically_derived] +impl ::core::default::Default for AssociatedConst { + #[inline] + fn default() -> AssociatedConst { + AssociatedConst(::core::default::Default::default()) + } +} + +impl AssociatedConst { + const LEN: usize = 10; +} + // An empty enum. enum Enum0 {} #[automatically_derived] @@ -1055,12 +1254,7 @@ impl ::core::cmp::PartialEq for Enum0 { fn eq(&self, other: &Enum0) -> bool { match *self {} } } #[automatically_derived] -impl ::core::cmp::Eq for Enum0 { - #[inline] - #[doc(hidden)] - #[coverage(off)] - fn assert_fields_are_eq(&self) {} -} +impl ::core::cmp::Eq for Enum0 { } #[automatically_derived] impl ::core::cmp::PartialOrd for Enum0 { #[inline] @@ -1125,11 +1319,12 @@ impl ::core::cmp::PartialEq for Enum1 { } } #[automatically_derived] -impl ::core::cmp::Eq for Enum1 { - #[inline] +impl ::core::cmp::Eq for Enum1 { } +const { #[doc(hidden)] #[coverage(off)] - fn assert_fields_are_eq(&self) { + #[inline] + const fn assert_fields_are_eq(_: *const Enum1) { let _: ::core::cmp::AssertParamIsEq; } } @@ -1191,12 +1386,7 @@ impl ::core::cmp::PartialEq for Fieldless1 { fn eq(&self, other: &Fieldless1) -> bool { true } } #[automatically_derived] -impl ::core::cmp::Eq for Fieldless1 { - #[inline] - #[doc(hidden)] - #[coverage(off)] - fn assert_fields_are_eq(&self) {} -} +impl ::core::cmp::Eq for Fieldless1 { } #[automatically_derived] impl ::core::cmp::PartialOrd for Fieldless1 { #[inline] @@ -1268,12 +1458,7 @@ impl ::core::cmp::PartialEq for Fieldless { } } #[automatically_derived] -impl ::core::cmp::Eq for Fieldless { - #[inline] - #[doc(hidden)] - #[coverage(off)] - fn assert_fields_are_eq(&self) {} -} +impl ::core::cmp::Eq for Fieldless { } #[automatically_derived] impl ::core::cmp::PartialOrd for Fieldless { #[inline] @@ -1378,11 +1563,12 @@ impl ::core::cmp::PartialEq for Mixed { } } #[automatically_derived] -impl ::core::cmp::Eq for Mixed { - #[inline] +impl ::core::cmp::Eq for Mixed { } +const { #[doc(hidden)] #[coverage(off)] - fn assert_fields_are_eq(&self) { + #[inline] + const fn assert_fields_are_eq(_: *const Mixed) { let _: ::core::cmp::AssertParamIsEq; let _: ::core::cmp::AssertParamIsEq>; let _: ::core::cmp::AssertParamIsEq>; @@ -1576,11 +1762,12 @@ impl ::core::cmp::PartialEq for Fielded { } } #[automatically_derived] -impl ::core::cmp::Eq for Fielded { - #[inline] +impl ::core::cmp::Eq for Fielded { } +const { #[doc(hidden)] #[coverage(off)] - fn assert_fields_are_eq(&self) { + #[inline] + const fn assert_fields_are_eq(_: *const Fielded) { let _: ::core::cmp::AssertParamIsEq; let _: ::core::cmp::AssertParamIsEq; let _: ::core::cmp::AssertParamIsEq>; @@ -1699,10 +1886,13 @@ impl #[automatically_derived] impl ::core::cmp::Eq for EnumGeneric { - #[inline] +} +const { #[doc(hidden)] #[coverage(off)] - fn assert_fields_are_eq(&self) { + #[inline] + const fn assert_fields_are_eq(_: *const EnumGeneric) { let _: ::core::cmp::AssertParamIsEq; let _: ::core::cmp::AssertParamIsEq; } diff --git a/tests/ui/duplicate/multiple-types-with-same-name-and-derive.rs b/tests/ui/duplicate/multiple-types-with-same-name-and-derive.rs index e946c0c5350ed..233e5309f9e12 100644 --- a/tests/ui/duplicate/multiple-types-with-same-name-and-derive.rs +++ b/tests/ui/duplicate/multiple-types-with-same-name-and-derive.rs @@ -13,6 +13,7 @@ struct NotSM(T); //~^ ERROR: struct takes 0 generic arguments //~| ERROR: struct takes 0 generic arguments //~| ERROR: struct takes 0 generic arguments +//~| ERROR: struct takes 0 generic arguments //~| ERROR: the name `NotSM` is defined multiple times //~| ERROR: no field `0` diff --git a/tests/ui/duplicate/multiple-types-with-same-name-and-derive.stderr b/tests/ui/duplicate/multiple-types-with-same-name-and-derive.stderr index e80cf35d81e1d..09df35f331f56 100644 --- a/tests/ui/duplicate/multiple-types-with-same-name-and-derive.stderr +++ b/tests/ui/duplicate/multiple-types-with-same-name-and-derive.stderr @@ -21,6 +21,19 @@ note: struct defined here, with 0 generic parameters LL | struct NotSM; | ^^^^^ +error[E0107]: struct takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/multiple-types-with-same-name-and-derive.rs:12:8 + | +LL | struct NotSM(T); + | ^^^^^ expected 0 generic arguments + | +note: struct defined here, with 0 generic parameters + --> $DIR/multiple-types-with-same-name-and-derive.rs:8:8 + | +LL | struct NotSM; + | ^^^^^ + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + error[E0107]: struct takes 0 generic arguments but 1 generic argument was supplied --> $DIR/multiple-types-with-same-name-and-derive.rs:10:10 | @@ -65,7 +78,7 @@ error[E0609]: no field `0` on type `&NotSM` LL | struct NotSM(T); | ^ unknown field -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors Some errors have detailed explanations: E0107, E0428, E0609. For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr b/tests/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr index f90133e9fb1ab..61a4cadb8b119 100644 --- a/tests/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr +++ b/tests/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr @@ -17,11 +17,6 @@ LL | #[derive(Eq, PartialEq)] LL | struct Test { LL | a: &'b str, | ^^ undeclared lifetime - | -help: consider introducing lifetime `'b` here - | -LL | struct Test<'b> { - | ++++ error[E0261]: use of undeclared lifetime name `'b` --> $DIR/undeclared-lifetime-used-in-debug-macro-issue-70152.rs:13:13 diff --git a/tests/ui/stats/macro-stats.stderr b/tests/ui/stats/macro-stats.stderr index e46e7e02862fa..a18c10bf1ee42 100644 --- a/tests/ui/stats/macro-stats.stderr +++ b/tests/ui/stats/macro-stats.stderr @@ -8,7 +8,7 @@ macro-stats #[derive(Hash)] 2 17 8.5 macro-stats q! 1 26 26.0 519 519.0 macro-stats #[derive(Ord)] 1 15 15.0 503 503.0 macro-stats #[derive(Default)] 2 16 8.0 403 201.5 -macro-stats #[derive(Eq)] 1 11 11.0 312 312.0 +macro-stats #[derive(Eq)] 1 12 12.0 335 335.0 macro-stats #[derive(Debug)] 1 8 8.0 277 277.0 macro-stats #[derive(PartialEq)] 1 9 9.0 267 267.0 macro-stats #[derive(Copy)] 1 2 2.0 61 61.0