From ef82007ed7b7833e3efdec0d80712849048c5c1f Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 11 Jul 2025 12:01:11 +0200 Subject: [PATCH 1/3] Port `#[automatically_derived]` to the new attribute parsing infrastructure Signed-off-by: Jonathan Brouwer --- compiler/rustc_ast/src/attr/mod.rs | 5 +++++ .../rustc_attr_data_structures/src/attributes.rs | 3 +++ .../src/encode_cross_crate.rs | 1 + .../src/attributes/lint_helpers.rs | 7 +++++++ compiler/rustc_attr_parsing/src/context.rs | 5 ++++- compiler/rustc_hir/src/hir.rs | 6 ++++++ .../rustc_lint/src/default_could_be_derived.rs | 3 ++- compiler/rustc_lint/src/levels.rs | 2 +- compiler/rustc_middle/src/ty/mod.rs | 4 ++-- .../src/thir/pattern/const_to_pat.rs | 6 ++++-- compiler/rustc_parse/src/validate_attr.rs | 1 + compiler/rustc_passes/src/check_attr.rs | 14 ++++++++++---- compiler/rustc_passes/src/liveness.rs | 4 ++-- 13 files changed, 48 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 44865c493b3b4..4348a4bb120eb 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -217,6 +217,10 @@ impl AttributeExt for Attribute { _ => None, } } + + fn is_automatically_derived_attr(&self) -> bool { + self.has_name(sym::automatically_derived) + } } impl Attribute { @@ -810,6 +814,7 @@ pub trait AttributeExt: Debug { .iter() .any(|kind| self.has_name(*kind)) } + fn is_automatically_derived_attr(&self) -> bool; /// Returns the documentation and its kind if this is a doc comment or a sugared doc comment. /// * `///doc` returns `Some(("doc", CommentKind::Line))`. diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index f61efcf238852..41a9e8feaafab 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -207,6 +207,9 @@ pub enum AttributeKind { /// Represents `#[rustc_as_ptr]` (used by the `dangling_pointers_from_temporaries` lint). AsPtr(Span), + /// Represents `#[automatically_derived]` + AutomaticallyDerived(Span), + /// Represents `#[rustc_default_body_unstable]`. BodyStability { stability: DefaultBodyStability, diff --git a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs index ad587523e0373..b92f0ade3d376 100644 --- a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs +++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs @@ -18,6 +18,7 @@ impl AttributeKind { AllowIncoherentImpl(..) => No, AllowInternalUnstable(..) => Yes, AsPtr(..) => Yes, + AutomaticallyDerived(..) => Yes, BodyStability { .. } => No, CoherenceIsCore => No, Coinductive(..) => No, diff --git a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs index 8ad98c8d1d4ad..0eceff53e8b4c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs +++ b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs @@ -24,3 +24,10 @@ impl NoArgsAttributeParser for PassByValueParser { const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const CREATE: fn(Span) -> AttributeKind = AttributeKind::PassByValue; } + +pub(crate) struct AutomaticallyDerivedParser; +impl NoArgsAttributeParser for AutomaticallyDerivedParser { + const PATH: &[Symbol] = &[sym::automatically_derived]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const CREATE: fn(Span) -> AttributeKind = AttributeKind::AutomaticallyDerived; +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index cc10bb3098a61..0b34fe0a5925a 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -27,7 +27,9 @@ use crate::attributes::link_attrs::{ ExportStableParser, FfiConstParser, FfiPureParser, LinkNameParser, LinkSectionParser, StdInternalSymbolParser, }; -use crate::attributes::lint_helpers::{AsPtrParser, PassByValueParser, PubTransparentParser}; +use crate::attributes::lint_helpers::{ + AsPtrParser, AutomaticallyDerivedParser, PassByValueParser, PubTransparentParser, +}; use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser}; use crate::attributes::must_use::MustUseParser; use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser; @@ -153,6 +155,7 @@ attribute_parsers!( Single, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 0f6f81d7964c4..f655a7e11f023 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1304,6 +1304,7 @@ impl AttributeExt for Attribute { Attribute::Parsed(AttributeKind::DocComment { span, .. }) => *span, Attribute::Parsed(AttributeKind::MayDangle(span)) => *span, Attribute::Parsed(AttributeKind::Ignore { span, .. }) => *span, + Attribute::Parsed(AttributeKind::AutomaticallyDerived(span)) => *span, a => panic!("can't get the span of an arbitrary parsed attribute: {a:?}"), } } @@ -1334,6 +1335,11 @@ impl AttributeExt for Attribute { _ => None, } } + + fn is_automatically_derived_attr(&self) -> bool { + matches!(self, Attribute::Parsed(AttributeKind::AutomaticallyDerived(..))) + } + #[inline] fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> { match &self { diff --git a/compiler/rustc_lint/src/default_could_be_derived.rs b/compiler/rustc_lint/src/default_could_be_derived.rs index 0bc772d081f14..b5fc083a09589 100644 --- a/compiler/rustc_lint/src/default_could_be_derived.rs +++ b/compiler/rustc_lint/src/default_could_be_derived.rs @@ -1,3 +1,4 @@ +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, Diag}; use rustc_hir as hir; @@ -62,7 +63,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived { let hir::ImplItemKind::Fn(_sig, body_id) = impl_item.kind else { return }; let assoc = cx.tcx.associated_item(impl_item.owner_id); let parent = assoc.container_id(cx.tcx); - if cx.tcx.has_attr(parent, sym::automatically_derived) { + if find_attr!(cx.tcx.get_all_attrs(parent), AttributeKind::AutomaticallyDerived(..)) { // We don't care about what `#[derive(Default)]` produces in this lint. return; } diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index c72f8571153a8..16eeb89207bc0 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -644,7 +644,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { ) { let sess = self.sess; for (attr_index, attr) in attrs.iter().enumerate() { - if attr.has_name(sym::automatically_derived) { + if attr.is_automatically_derived_attr() { self.insert( LintId::of(SINGLE_USE_LIFETIMES), LevelAndSource { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 0177a95498bcd..5dbdff76bee37 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -28,7 +28,7 @@ use rustc_abi::{Align, FieldIdx, Integer, IntegerType, ReprFlags, ReprOptions, V use rustc_ast::expand::StrippedCfgItem; use rustc_ast::node_id::NodeMap; pub use rustc_ast_ir::{Movability, Mutability, try_visit}; -use rustc_attr_data_structures::AttributeKind; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -2031,7 +2031,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Check if the given `DefId` is `#\[automatically_derived\]`. pub fn is_automatically_derived(self, def_id: DefId) -> bool { - self.has_attr(def_id, sym::automatically_derived) + find_attr!(self.get_all_attrs(def_id), AttributeKind::AutomaticallyDerived(..)) } /// Looks up the span of `impl_did` if the impl is local; otherwise returns `Err` diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 6d617d43c2a6e..91fcbb9390f7c 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -2,6 +2,7 @@ use core::ops::ControlFlow; use rustc_abi::{FieldIdx, VariantIdx}; use rustc_apfloat::Float; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Diag; use rustc_hir as hir; @@ -15,7 +16,7 @@ use rustc_middle::ty::{ }; use rustc_middle::{mir, span_bug}; use rustc_span::def_id::DefId; -use rustc_span::{DUMMY_SP, Span, sym}; +use rustc_span::{DUMMY_SP, Span}; use rustc_trait_selection::traits::ObligationCause; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use tracing::{debug, instrument, trace}; @@ -495,7 +496,8 @@ fn type_has_partial_eq_impl<'tcx>( let mut structural_peq = false; let mut impl_def_id = None; for def_id in tcx.non_blanket_impls_for_ty(partial_eq_trait_id, ty) { - automatically_derived = tcx.has_attr(def_id, sym::automatically_derived); + automatically_derived = + find_attr!(tcx.get_all_attrs(def_id), AttributeKind::AutomaticallyDerived(..)); impl_def_id = Some(def_id); } for _ in tcx.non_blanket_impls_for_ty(structural_partial_eq_trait_id, ty) { diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index bb5c1e0e653a7..3e80af82bef16 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -316,6 +316,7 @@ pub fn check_builtin_meta_item( | sym::rustc_layout_scalar_valid_range_start | sym::rustc_layout_scalar_valid_range_end | sym::no_implicit_prelude + | sym::automatically_derived ) { return; } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 2c95fead9e801..0924d87726351 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -152,6 +152,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::Confusables { first_span, .. }) => { self.check_confusables(*first_span, target); } + Attribute::Parsed(AttributeKind::AutomaticallyDerived(attr_span)) => self + .check_generic_attr( + hir_id, + sym::automatically_derived, + *attr_span, + target, + Target::Impl, + ), Attribute::Parsed( AttributeKind::Stability { span, .. } | AttributeKind::ConstStability { span, .. }, @@ -335,9 +343,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::should_panic, ..] => { self.check_generic_attr_unparsed(hir_id, attr, target, Target::Fn) } - [sym::automatically_derived, ..] => { - self.check_generic_attr_unparsed(hir_id, attr, target, Target::Impl) - } [sym::proc_macro, ..] => { self.check_proc_macro(hir_id, target, ProcMacroKind::FunctionLike) } @@ -2814,7 +2819,6 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { // resolution for the attribute macro error. const ATTRS_TO_CHECK: &[Symbol] = &[ sym::macro_export, - sym::automatically_derived, sym::rustc_main, sym::derive, sym::test, @@ -2837,6 +2841,8 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { (*first_attr_span, sym::repr) } else if let Attribute::Parsed(AttributeKind::Path(.., span)) = attr { (*span, sym::path) + } else if let Attribute::Parsed(AttributeKind::AutomaticallyDerived(span)) = attr { + (*span, sym::automatically_derived) } else { continue; }; diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 3088e189c2073..7350c6a5a82fc 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -97,7 +97,7 @@ use rustc_middle::query::Providers; use rustc_middle::span_bug; use rustc_middle::ty::{self, RootVariableMinCaptureList, Ty, TyCtxt}; use rustc_session::lint; -use rustc_span::{BytePos, Span, Symbol, sym}; +use rustc_span::{BytePos, Span, Symbol}; use tracing::{debug, instrument}; use self::LiveNodeKind::*; @@ -140,7 +140,7 @@ fn check_liveness(tcx: TyCtxt<'_>, def_id: LocalDefId) { // Don't run unused pass for #[derive()] let parent = tcx.local_parent(def_id); if let DefKind::Impl { .. } = tcx.def_kind(parent) - && tcx.has_attr(parent, sym::automatically_derived) + && find_attr!(tcx.get_all_attrs(parent), AttributeKind::AutomaticallyDerived(..)) { return; } From a1cfca3d074fda4ca475bbbf1fe0100b2464cada Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 11 Jul 2025 12:01:26 +0200 Subject: [PATCH 2/3] Fix clippy & rustdoc-json Signed-off-by: Jonathan Brouwer --- src/librustdoc/clean/types.rs | 3 +++ src/tools/clippy/clippy_lints/src/format_args.rs | 3 ++- .../src/derive_deserialize_allowing_unknown.rs | 2 +- src/tools/clippy/clippy_utils/src/lib.rs | 4 ++-- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index a05aab22f1e16..3ecd41db2ddca 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -796,6 +796,9 @@ impl Item { } Some(format!("#[target_feature({output})]")) } + hir::Attribute::Parsed(AttributeKind::AutomaticallyDerived(..)) => { + Some("#[automatically_derived]".to_string()) + } _ => Some({ let mut s = rustc_hir_pretty::attribute_to_string(&tcx, attr); assert_eq!(s.pop(), Some('\n')); diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs index 0c39aae9ca913..16c58ecb455ea 100644 --- a/src/tools/clippy/clippy_lints/src/format_args.rs +++ b/src/tools/clippy/clippy_lints/src/format_args.rs @@ -30,6 +30,7 @@ use rustc_span::edition::Edition::Edition2021; use rustc_span::{Span, Symbol, sym}; use rustc_trait_selection::infer::TyCtxtInferExt; use rustc_trait_selection::traits::{Obligation, ObligationCause, Selection, SelectionContext}; +use rustc_attr_data_structures::{AttributeKind, find_attr}; declare_clippy_lint! { /// ### What it does @@ -656,7 +657,7 @@ impl<'tcx> FormatArgsExpr<'_, 'tcx> { }; let selection = SelectionContext::new(&infcx).select(&obligation); let derived = if let Ok(Some(Selection::UserDefined(data))) = selection { - tcx.has_attr(data.impl_def_id, sym::automatically_derived) + find_attr!(tcx.get_all_attrs(data.impl_def_id), AttributeKind::AutomaticallyDerived(..)) } else { false }; diff --git a/src/tools/clippy/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs b/src/tools/clippy/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs index a1dacd359a06c..88b099c477f99 100644 --- a/src/tools/clippy/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs +++ b/src/tools/clippy/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs @@ -88,7 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for DeriveDeserializeAllowingUnknown { } // Is it derived? - if !cx.tcx.has_attr(item.owner_id, sym::automatically_derived) { + if !find_attr!(cx.tcx.get_all_attrs(item.owner_id), AttributeKind::AutomaticallyDerived(..)) { return; } diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 98b4c183b1206..36b91b9c43ce1 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1784,9 +1784,9 @@ pub fn in_automatically_derived(tcx: TyCtxt<'_>, id: HirId) -> bool { tcx.hir_parent_owner_iter(id) .filter(|(_, node)| matches!(node, OwnerNode::Item(item) if matches!(item.kind, ItemKind::Impl(_)))) .any(|(id, _)| { - has_attr( + find_attr!( tcx.hir_attrs(tcx.local_def_id_to_hir_id(id.def_id)), - sym::automatically_derived, + AttributeKind::AutomaticallyDerived(..) ) }) } From 68066b90b84b52fa4907c12e708b8418317e2a5d Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 11 Jul 2025 12:01:36 +0200 Subject: [PATCH 3/3] Update uitest stderrs Signed-off-by: Jonathan Brouwer --- tests/ui/attributes/malformed-attrs.stderr | 15 ++++++---- ...43106-gating-of-builtin-attrs-error.stderr | 30 +++++++++---------- .../lint/unused/unused-attr-duplicate.stderr | 24 +++++++-------- 3 files changed, 36 insertions(+), 33 deletions(-) diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index be529df3a4953..6da08b3b56fd2 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -164,12 +164,6 @@ error: malformed `debugger_visualizer` attribute input LL | #[debugger_visualizer] | ^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[debugger_visualizer(natvis_file = "...", gdb_script_file = "...")]` -error: malformed `automatically_derived` attribute input - --> $DIR/malformed-attrs.rs:191:1 - | -LL | #[automatically_derived = 18] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[automatically_derived]` - error: malformed `thread_local` attribute input --> $DIR/malformed-attrs.rs:203:1 | @@ -546,6 +540,15 @@ LL | #[unsafe(ffi_const = 1)] | | didn't expect any arguments here | help: must be of the form: `#[ffi_const]` +error[E0565]: malformed `automatically_derived` attribute input + --> $DIR/malformed-attrs.rs:191:1 + | +LL | #[automatically_derived = 18] + | ^^^^^^^^^^^^^^^^^^^^^^^^----^ + | | | + | | didn't expect any arguments here + | help: must be of the form: `#[automatically_derived]` + error[E0565]: malformed `non_exhaustive` attribute input --> $DIR/malformed-attrs.rs:197:1 | diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr index 49c666f498f58..4cba54bf67c12 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr @@ -121,21 +121,6 @@ LL - #![rustc_main] LL + #[rustc_main] | -error: `automatically_derived` attribute cannot be used at crate level - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:23:1 - | -LL | #![automatically_derived] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | mod inline { - | ------ the inner attribute doesn't annotate this module - | -help: perhaps you meant to use an outer attribute - | -LL - #![automatically_derived] -LL + #[automatically_derived] - | - error: `repr` attribute cannot be used at crate level --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:19:1 | @@ -166,6 +151,21 @@ LL - #![path = "3800"] LL + #[path = "3800"] | +error: `automatically_derived` attribute cannot be used at crate level + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:23:1 + | +LL | #![automatically_derived] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | mod inline { + | ------ the inner attribute doesn't annotate this module + | +help: perhaps you meant to use an outer attribute + | +LL - #![automatically_derived] +LL + #[automatically_derived] + | + error[E0518]: attribute should be applied to function or closure --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:42:17 | diff --git a/tests/ui/lint/unused/unused-attr-duplicate.stderr b/tests/ui/lint/unused/unused-attr-duplicate.stderr index 2310c12c80b56..6db6af823f41e 100644 --- a/tests/ui/lint/unused/unused-attr-duplicate.stderr +++ b/tests/ui/lint/unused/unused-attr-duplicate.stderr @@ -40,18 +40,6 @@ LL | #[should_panic] | ^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -error: unused attribute - --> $DIR/unused-attr-duplicate.rs:70:1 - | -LL | #[automatically_derived] - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute - | -note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:69:1 - | -LL | #[automatically_derived] - | ^^^^^^^^^^^^^^^^^^^^^^^^ - error: unused attribute --> $DIR/unused-attr-duplicate.rs:14:1 | @@ -190,6 +178,18 @@ note: attribute also specified here LL | #[non_exhaustive] | ^^^^^^^^^^^^^^^^^ +error: unused attribute + --> $DIR/unused-attr-duplicate.rs:70:1 + | +LL | #[automatically_derived] + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/unused-attr-duplicate.rs:69:1 + | +LL | #[automatically_derived] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + error: unused attribute --> $DIR/unused-attr-duplicate.rs:74:1 |