diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index be4e2210c5ee4..922a5bd297ace 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -1,4 +1,5 @@ use rustc_ast::{LitIntType, LitKind, MetaItemLit}; +use rustc_session::errors; use super::prelude::*; use super::util::parse_single_integer; @@ -13,6 +14,52 @@ impl NoArgsAttributeParser for RustcMainParser { const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcMain; } +pub(crate) struct RustcMustImplementOneOfParser; + +impl SingleAttributeParser for RustcMustImplementOneOfParser { + const PATH: &[Symbol] = &[sym::rustc_must_implement_one_of]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]); + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; + const TEMPLATE: AttributeTemplate = template!(List: &["function1, function2, ..."]); + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { + let Some(list) = args.list() else { + cx.expected_list(cx.attr_span, args); + return None; + }; + + let mut fn_names = ThinVec::new(); + + let inputs: Vec<_> = list.mixed().collect(); + + if inputs.len() < 2 { + cx.expected_list_with_num_args_or_more(2, list.span); + return None; + } + + let mut errored = false; + for argument in inputs { + let Some(meta) = argument.meta_item() else { + cx.expected_identifier(argument.span()); + return None; + }; + + let Some(ident) = meta.ident() else { + cx.dcx().emit_err(errors::MustBeNameOfAssociatedFunction { span: meta.span() }); + errored = true; + continue; + }; + + fn_names.push(ident); + } + if errored { + return None; + } + + Some(AttributeKind::RustcMustImplementOneOf { attr_span: cx.attr_span, fn_names }) + } +} + pub(crate) struct RustcNeverReturnsNullPointerParser; impl NoArgsAttributeParser for RustcNeverReturnsNullPointerParser { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index df4970d8aa90c..1113da0dd5db8 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -63,8 +63,9 @@ use crate::attributes::rustc_internal::{ RustcLayoutScalarValidRangeEndParser, RustcLayoutScalarValidRangeStartParser, RustcLegacyConstGenericsParser, RustcLintDiagnosticsParser, RustcLintOptDenyFieldAccessParser, RustcLintOptTyParser, RustcLintQueryInstabilityParser, - RustcLintUntrackedQueryInformationParser, RustcMainParser, RustcNeverReturnsNullPointerParser, - RustcNoImplicitAutorefsParser, RustcObjectLifetimeDefaultParser, RustcScalableVectorParser, + RustcLintUntrackedQueryInformationParser, RustcMainParser, RustcMustImplementOneOfParser, + RustcNeverReturnsNullPointerParser, RustcNoImplicitAutorefsParser, + RustcObjectLifetimeDefaultParser, RustcScalableVectorParser, RustcSimdMonomorphizeLaneLimitParser, }; use crate::attributes::semantics::MayDangleParser; @@ -215,6 +216,7 @@ attribute_parsers!( Single, Single, Single, + Single, Single, Single, Single, @@ -490,6 +492,17 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { self.emit_parse_error(span, AttributeParseErrorReason::ExpectedList) } + pub(crate) fn expected_list_with_num_args_or_more( + &self, + args: usize, + span: Span, + ) -> ErrorGuaranteed { + self.emit_parse_error( + span, + AttributeParseErrorReason::ExpectedListWithNumArgsOrMore { args }, + ) + } + pub(crate) fn expected_list_or_no_args(&self, span: Span) -> ErrorGuaranteed { self.emit_parse_error(span, AttributeParseErrorReason::ExpectedListOrNoArgs) } diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 9551744d5ec53..474f848038d1e 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -8,7 +8,9 @@ use std::fmt::{Debug, Display}; use rustc_ast::token::{self, Delimiter, MetaVarKind}; use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{AttrArgs, Expr, ExprKind, LitKind, MetaItemLit, Path, StmtKind, UnOp}; +use rustc_ast::{ + AttrArgs, Expr, ExprKind, LitKind, MetaItemLit, Path, PathSegment, StmtKind, UnOp, +}; use rustc_ast_pretty::pprust; use rustc_errors::{Diag, PResult}; use rustc_hir::{self as hir, AttrPath}; @@ -256,6 +258,11 @@ impl Debug for MetaItemParser { } impl MetaItemParser { + /// For a single-segment meta item, returns its name; otherwise, returns `None`. + pub fn ident(&self) -> Option { + if let [PathSegment { ident, .. }] = self.path.0.segments[..] { Some(ident) } else { None } + } + pub fn span(&self) -> Span { if let Some(other) = self.args.span() { self.path.borrow().span().with_hi(other.hi()) diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 73b65193fd349..dfa72effa689d 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -520,6 +520,9 @@ pub(crate) enum AttributeParseErrorReason<'a> { ExpectedSingleArgument, ExpectedList, ExpectedListOrNoArgs, + ExpectedListWithNumArgsOrMore { + args: usize, + }, ExpectedNameValueOrNoArgs, UnexpectedLiteral, ExpectedNameValue(Option), @@ -596,6 +599,9 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> { AttributeParseErrorReason::ExpectedListOrNoArgs => { diag.span_label(self.span, "expected a list or no arguments here"); } + AttributeParseErrorReason::ExpectedListWithNumArgsOrMore { args } => { + diag.span_label(self.span, format!("expected {args} or more items")); + } AttributeParseErrorReason::ExpectedNameValueOrNoArgs => { diag.span_label(self.span, "didn't expect a list here"); } diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index e9f9b2445deb8..2c6c0d59b9786 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -949,6 +949,9 @@ pub enum AttributeKind { /// Represents `#[rustc_main]`. RustcMain, + /// Represents `#[rustc_must_implement_one_of]` + RustcMustImplementOneOf { attr_span: Span, fn_names: ThinVec }, + /// Represents `#[rustc_never_returns_null_ptr]` RustcNeverReturnsNullPointer, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 68456dfe4c293..7ab23c6207d60 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -100,6 +100,7 @@ impl AttributeKind { RustcLintQueryInstability => Yes, RustcLintUntrackedQueryInformation => Yes, RustcMain => No, + RustcMustImplementOneOf { .. } => No, RustcNeverReturnsNullPointer => Yes, RustcNoImplicitAutorefs => Yes, RustcObjectLifetimeDefault => No, diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 8022a48ee1379..416a6b19edfc8 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -208,14 +208,6 @@ hir_analysis_field_already_declared_previous_nested = .previous_decl_label = `{$field_name}` first declared here in this unnamed field .previous_nested_field_decl_note = field `{$field_name}` first declared here -hir_analysis_function_not_found_in_trait = function not found in this trait - -hir_analysis_function_not_have_default_implementation = function doesn't have a default implementation - .note = required by this annotation - -hir_analysis_functions_names_duplicated = functions names are duplicated - .note = all `#[rustc_must_implement_one_of]` arguments must be unique - hir_analysis_generic_args_on_overridden_impl = could not resolve generic parameters on overridden impl hir_analysis_impl_not_marked_default = `{$ident}` specializes an item from a parent `impl`, but that item is not marked `default` @@ -381,16 +373,6 @@ hir_analysis_missing_type_params = *[other] parameters } must be specified on the object type -hir_analysis_must_be_name_of_associated_function = must be a name of an associated function - -hir_analysis_must_implement_not_function = not a function - -hir_analysis_must_implement_not_function_note = all `#[rustc_must_implement_one_of]` arguments must be associated function names - -hir_analysis_must_implement_not_function_span_note = required by this annotation - -hir_analysis_must_implement_one_of_attribute = the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args - hir_analysis_no_variant_named = no variant named `{$ident}` found for enum `{$ty}` hir_analysis_not_supported_delegation = {$descr} diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index a81df02f023fc..ad66003a6bf91 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1340,9 +1340,7 @@ fn check_impl_items_against_trait<'tcx>( } if let Some(missing_items) = must_implement_one_of { - let attr_span = tcx - .get_attr(trait_ref.def_id, sym::rustc_must_implement_one_of) - .map(|attr| attr.span()); + let attr_span = find_attr!(tcx.get_all_attrs(trait_ref.def_id), AttributeKind::RustcMustImplementOneOf {attr_span, ..} => *attr_span); missing_items_must_implement_one_of_err( tcx, diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 2e06684e0c7a8..9343bcd27a339 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -22,7 +22,6 @@ use std::ops::Bound; use rustc_abi::{ExternAbi, Size}; use rustc_ast::Recovered; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; -use rustc_data_structures::unord::UnordMap; use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, E0228, ErrorGuaranteed, StashKey, struct_span_code_err, }; @@ -916,84 +915,15 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { } else { ty::trait_def::TraitSpecializationKind::None }; - let must_implement_one_of = attrs - .iter() - .find(|attr| attr.has_name(sym::rustc_must_implement_one_of)) - // Check that there are at least 2 arguments of `#[rustc_must_implement_one_of]` - // and that they are all identifiers - .and_then(|attr| match attr.meta_item_list() { - Some(items) if items.len() < 2 => { - tcx.dcx().emit_err(errors::MustImplementOneOfAttribute { span: attr.span() }); - - None - } - Some(items) => items - .into_iter() - .map(|item| item.ident().ok_or(item.span())) - .collect::, _>>() - .map_err(|span| { - tcx.dcx().emit_err(errors::MustBeNameOfAssociatedFunction { span }); - }) - .ok() - .zip(Some(attr.span())), - // Error is reported by `rustc_attr!` - None => None, - }) - // Check that all arguments of `#[rustc_must_implement_one_of]` reference - // functions in the trait with default implementations - .and_then(|(list, attr_span)| { - let errors = list.iter().filter_map(|ident| { - let item = tcx - .associated_items(def_id) - .filter_by_name_unhygienic(ident.name) - .find(|item| item.ident(tcx) == *ident); - - match item { - Some(item) if matches!(item.kind, ty::AssocKind::Fn { .. }) => { - if !item.defaultness(tcx).has_value() { - tcx.dcx().emit_err(errors::FunctionNotHaveDefaultImplementation { - span: tcx.def_span(item.def_id), - note_span: attr_span, - }); - return Some(()); - } - - return None; - } - Some(item) => { - tcx.dcx().emit_err(errors::MustImplementNotFunction { - span: tcx.def_span(item.def_id), - span_note: errors::MustImplementNotFunctionSpanNote { span: attr_span }, - note: errors::MustImplementNotFunctionNote {}, - }); - } - None => { - tcx.dcx().emit_err(errors::FunctionNotFoundInTrait { span: ident.span }); - } - } - - Some(()) - }); - - (errors.count() == 0).then_some(list) - }) - // Check for duplicates - .and_then(|list| { - let mut set: UnordMap = Default::default(); - let mut no_dups = true; - - for ident in &*list { - if let Some(dup) = set.insert(ident.name, ident.span) { - tcx.dcx() - .emit_err(errors::FunctionNamesDuplicated { spans: vec![dup, ident.span] }); - - no_dups = false; - } - } - - no_dups.then_some(list) - }); + let must_implement_one_of = find_attr!( + attrs, + AttributeKind::RustcMustImplementOneOf { fn_names, .. } => + fn_names + .iter() + .cloned() + .collect::>() + ); let deny_explicit_impl = find_attr!(attrs, AttributeKind::DenyExplicitImpl(_)); let implement_via_object = !find_attr!(attrs, AttributeKind::DoNotImplementViaObject(_)); diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 8e17a49625205..b388396ac4fcd 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -741,66 +741,6 @@ pub(crate) struct ParenSugarAttribute { pub span: Span, } -#[derive(Diagnostic)] -#[diag(hir_analysis_must_implement_one_of_attribute)] -pub(crate) struct MustImplementOneOfAttribute { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(hir_analysis_must_be_name_of_associated_function)] -pub(crate) struct MustBeNameOfAssociatedFunction { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(hir_analysis_function_not_have_default_implementation)] -pub(crate) struct FunctionNotHaveDefaultImplementation { - #[primary_span] - pub span: Span, - #[note] - pub note_span: Span, -} - -#[derive(Diagnostic)] -#[diag(hir_analysis_must_implement_not_function)] -pub(crate) struct MustImplementNotFunction { - #[primary_span] - pub span: Span, - #[subdiagnostic] - pub span_note: MustImplementNotFunctionSpanNote, - #[subdiagnostic] - pub note: MustImplementNotFunctionNote, -} - -#[derive(Subdiagnostic)] -#[note(hir_analysis_must_implement_not_function_span_note)] -pub(crate) struct MustImplementNotFunctionSpanNote { - #[primary_span] - pub span: Span, -} - -#[derive(Subdiagnostic)] -#[note(hir_analysis_must_implement_not_function_note)] -pub(crate) struct MustImplementNotFunctionNote {} - -#[derive(Diagnostic)] -#[diag(hir_analysis_function_not_found_in_trait)] -pub(crate) struct FunctionNotFoundInTrait { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(hir_analysis_functions_names_duplicated)] -#[note] -pub(crate) struct FunctionNamesDuplicated { - #[primary_span] - pub spans: Vec, -} - #[derive(Diagnostic)] #[diag(hir_analysis_simd_ffi_highly_experimental)] #[help] diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index cf069b364be8a..94996c0adb470 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -236,6 +236,14 @@ passes_feature_previously_declared = passes_feature_stable_twice = feature `{$feature}` is declared stable since {$since}, but was previously declared stable since {$prev_since} +passes_function_not_found_in_trait = function not found in this trait + +passes_function_not_have_default_implementation = function doesn't have a default implementation + .note = required by this annotation + +passes_functions_names_duplicated = functions names are duplicated + .note = all `#[rustc_must_implement_one_of]` arguments must be unique + passes_has_incoherent_inherent_impl = `rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits .label = only adts, extern types and traits are supported @@ -370,6 +378,12 @@ passes_multiple_rustc_main = .first = first `#[rustc_main]` function .additional = additional `#[rustc_main]` function +passes_must_implement_not_function = not a function + +passes_must_implement_not_function_note = all `#[rustc_must_implement_one_of]` arguments must be associated function names + +passes_must_implement_not_function_span_note = required by this annotation + passes_must_not_suspend = `must_not_suspend` attribute should be applied to a struct, enum, union, or trait .label = is not a struct, enum, union, or trait @@ -484,10 +498,6 @@ passes_sanitize_attribute_not_allowed = .no_body = function has no body .help = sanitize attribute can be applied to a function (with body), impl block, or module -passes_should_be_applied_to_trait = - attribute should be applied to a trait - .label = not a trait - passes_trait_impl_const_stability_mismatch = const stability on the impl does not match the const stability on the trait passes_trait_impl_const_stability_mismatch_impl_stable = this impl is (implicitly) stable... passes_trait_impl_const_stability_mismatch_impl_unstable = this impl is unstable... diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 7822614a05cb1..771823064ca62 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -14,6 +14,7 @@ use rustc_ast::{AttrStyle, MetaItemKind, ast}; use rustc_attr_parsing::{AttributeParser, Late}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::thin_vec::ThinVec; +use rustc_data_structures::unord::UnordMap; use rustc_errors::{DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey}; use rustc_feature::{ ACCEPTED_LANG_FEATURES, AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, @@ -47,7 +48,7 @@ use rustc_session::lint::builtin::{ }; use rustc_session::parse::feature_err; use rustc_span::edition::Edition; -use rustc_span::{BytePos, DUMMY_SP, Span, Symbol, sym}; +use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, sym}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs}; use rustc_trait_selection::traits::ObligationCtxt; @@ -219,6 +220,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::EiiImpls(impls)) => { self.check_eii_impl(impls, target) }, + Attribute::Parsed(AttributeKind::RustcMustImplementOneOf { attr_span, fn_names }) => { + self.check_rustc_must_implement_one_of(*attr_span, fn_names, hir_id,target) + }, Attribute::Parsed( AttributeKind::EiiExternTarget { .. } | AttributeKind::EiiExternItem @@ -315,7 +319,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | [sym::rustc_dirty, ..] | [sym::rustc_if_this_changed, ..] | [sym::rustc_then_this_would_need, ..] => self.check_rustc_dirty_clean(attr), - [sym::rustc_must_implement_one_of, ..] => self.check_must_be_applied_to_trait(attr.span(), span, target), [sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target), [sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target), [sym::rustc_has_incoherent_inherent_impls, ..] => { @@ -445,6 +448,67 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.check_mix_no_mangle_export(hir_id, attrs); } + fn check_rustc_must_implement_one_of( + &self, + attr_span: Span, + list: &ThinVec, + hir_id: HirId, + target: Target, + ) { + // ICE on test `ui/traits/default-method/rustc_must_implement_one_of_misuse.rs` + // if i remove this check + if !matches!(target, Target::Trait) { + // How did we get here?? + return; + } + + let Some(owner_id) = hir_id.as_owner() else { + return; + }; + let def_id = owner_id.def_id; + + let items = self.tcx.associated_items(def_id); + // Check that all arguments of `#[rustc_must_implement_one_of]` reference + // functions in the trait with default implementations + for ident in list { + let item = items + .filter_by_name_unhygienic(ident.name) + .find(|item| item.ident(self.tcx) == *ident); + + match item { + Some(item) if matches!(item.kind, ty::AssocKind::Fn { .. }) => { + if !item.defaultness(self.tcx).has_value() { + self.tcx.dcx().emit_err(errors::FunctionNotHaveDefaultImplementation { + span: self.tcx.def_span(item.def_id), + note_span: attr_span, + }); + } + } + Some(item) => { + self.dcx().emit_err(errors::MustImplementNotFunction { + span: self.tcx.def_span(item.def_id), + span_note: errors::MustImplementNotFunctionSpanNote { span: attr_span }, + note: errors::MustImplementNotFunctionNote {}, + }); + } + None => { + self.dcx().emit_err(errors::FunctionNotFoundInTrait { span: ident.span }); + } + } + } + // Check for duplicates + + let mut set: UnordMap = Default::default(); + + for ident in &*list { + if let Some(dup) = set.insert(ident.name, ident.span) { + self.tcx + .dcx() + .emit_err(errors::FunctionNamesDuplicated { spans: vec![dup, ident.span] }); + } + } + } + fn check_eii_impl(&self, impls: &[EiiImpl], target: Target) { for EiiImpl { span, inner_span, eii_macro, impl_marked_unsafe, is_default: _ } in impls { match target { @@ -1221,16 +1285,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - /// Checks if the attribute is applied to a trait. - fn check_must_be_applied_to_trait(&self, attr_span: Span, defn_span: Span, target: Target) { - match target { - Target::Trait => {} - _ => { - self.dcx().emit_err(errors::AttrShouldBeAppliedToTrait { attr_span, defn_span }); - } - } - } - /// Checks if the `#[repr]` attributes on `item` are valid. fn check_repr( &self, diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 2b817c6dd106e..af5cb29b83d04 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -89,15 +89,6 @@ pub(crate) struct NonExhaustiveWithDefaultFieldValues { pub defn_span: Span, } -#[derive(Diagnostic)] -#[diag(passes_should_be_applied_to_trait)] -pub(crate) struct AttrShouldBeAppliedToTrait { - #[primary_span] - pub attr_span: Span, - #[label] - pub defn_span: Span, -} - #[derive(Diagnostic)] #[diag(passes_doc_alias_bad_location)] pub(crate) struct DocAliasBadLocation<'a> { @@ -1323,3 +1314,49 @@ pub(crate) struct DuplicateEiiImpls { #[help] pub help: (), } + +#[derive(Diagnostic)] +#[diag(passes_function_not_have_default_implementation)] +pub(crate) struct FunctionNotHaveDefaultImplementation { + #[primary_span] + pub span: Span, + #[note] + pub note_span: Span, +} + +#[derive(Diagnostic)] +#[diag(passes_must_implement_not_function)] +pub(crate) struct MustImplementNotFunction { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub span_note: MustImplementNotFunctionSpanNote, + #[subdiagnostic] + pub note: MustImplementNotFunctionNote, +} + +#[derive(Subdiagnostic)] +#[note(passes_must_implement_not_function_span_note)] +pub(crate) struct MustImplementNotFunctionSpanNote { + #[primary_span] + pub span: Span, +} + +#[derive(Subdiagnostic)] +#[note(passes_must_implement_not_function_note)] +pub(crate) struct MustImplementNotFunctionNote {} + +#[derive(Diagnostic)] +#[diag(passes_function_not_found_in_trait)] +pub(crate) struct FunctionNotFoundInTrait { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(passes_functions_names_duplicated)] +#[note] +pub(crate) struct FunctionNamesDuplicated { + #[primary_span] + pub spans: Vec, +} diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl index 2fdce628f0c99..eff55e8e02a2e 100644 --- a/compiler/rustc_session/messages.ftl +++ b/compiler/rustc_session/messages.ftl @@ -81,6 +81,8 @@ session_invalid_num_literal_suffix = invalid suffix `{$suffix}` for number liter session_linker_plugin_lto_windows_not_supported = linker plugin based LTO is not supported together with `-C prefer-dynamic` when targeting Windows-like targets +session_must_be_name_of_associated_function = must be a name of an associated function + session_not_circumvent_feature = `-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature gates, except when testing error paths in the CTFE engine session_not_supported = not supported diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 1f2d386a23cbc..6fd86aec7ad98 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -82,6 +82,13 @@ pub(crate) struct CliFeatureDiagnosticHelp { pub(crate) feature: Symbol, } +#[derive(Diagnostic)] +#[diag(session_must_be_name_of_associated_function)] +pub struct MustBeNameOfAssociatedFunction { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(session_not_circumvent_feature)] pub(crate) struct NotCircumventFeature; diff --git a/tests/ui/traits/default-method/rustc_must_implement_one_of_misuse.rs b/tests/ui/traits/default-method/rustc_must_implement_one_of_misuse.rs index 9b2e489c54251..82d0fa36d7ecb 100644 --- a/tests/ui/traits/default-method/rustc_must_implement_one_of_misuse.rs +++ b/tests/ui/traits/default-method/rustc_must_implement_one_of_misuse.rs @@ -12,7 +12,7 @@ trait Tr1 { } #[rustc_must_implement_one_of(a)] -//~^ ERROR the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args +//~^ ERROR malformed trait Tr2 { fn a() {} } @@ -36,11 +36,11 @@ trait Tr5 { } #[rustc_must_implement_one_of(abc, xyz)] -//~^ ERROR attribute should be applied to a trait +//~^ ERROR `#[rustc_must_implement_one_of]` attribute cannot be used on functions fn function() {} #[rustc_must_implement_one_of(abc, xyz)] -//~^ ERROR attribute should be applied to a trait +//~^ ERROR `#[rustc_must_implement_one_of]` attribute cannot be used on structs struct Struct {} fn main() {} diff --git a/tests/ui/traits/default-method/rustc_must_implement_one_of_misuse.stderr b/tests/ui/traits/default-method/rustc_must_implement_one_of_misuse.stderr index cf197d035b38f..0d854b4594fa8 100644 --- a/tests/ui/traits/default-method/rustc_must_implement_one_of_misuse.stderr +++ b/tests/ui/traits/default-method/rustc_must_implement_one_of_misuse.stderr @@ -1,26 +1,36 @@ -error: malformed `rustc_must_implement_one_of` attribute input +error[E0539]: malformed `rustc_must_implement_one_of` attribute input + --> $DIR/rustc_must_implement_one_of_misuse.rs:14:1 + | +LL | #[rustc_must_implement_one_of(a)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---^ + | | | + | | expected 2 or more items + | help: must be of the form: `#[rustc_must_implement_one_of(function1, function2, ...)]` + +error[E0539]: malformed `rustc_must_implement_one_of` attribute input --> $DIR/rustc_must_implement_one_of_misuse.rs:20:1 | LL | #[rustc_must_implement_one_of] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_must_implement_one_of(function1, function2, ...)]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected this to be a list + | help: must be of the form: `#[rustc_must_implement_one_of(function1, function2, ...)]` -error: attribute should be applied to a trait +error: `#[rustc_must_implement_one_of]` attribute cannot be used on functions --> $DIR/rustc_must_implement_one_of_misuse.rs:38:1 | LL | #[rustc_must_implement_one_of(abc, xyz)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | fn function() {} - | ---------------- not a trait + | + = help: `#[rustc_must_implement_one_of]` can only be applied to traits -error: attribute should be applied to a trait +error: `#[rustc_must_implement_one_of]` attribute cannot be used on structs --> $DIR/rustc_must_implement_one_of_misuse.rs:42:1 | LL | #[rustc_must_implement_one_of(abc, xyz)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | struct Struct {} - | ---------------- not a trait + | + = help: `#[rustc_must_implement_one_of]` can only be applied to traits error: function not found in this trait --> $DIR/rustc_must_implement_one_of_misuse.rs:3:31 @@ -40,12 +50,6 @@ error: function not found in this trait LL | #[rustc_must_implement_one_of(a, b)] | ^ -error: the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args - --> $DIR/rustc_must_implement_one_of_misuse.rs:14:1 - | -LL | #[rustc_must_implement_one_of(a)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: not a function --> $DIR/rustc_must_implement_one_of_misuse.rs:26:5 | @@ -98,3 +102,4 @@ LL | #[rustc_must_implement_one_of(a, b)] error: aborting due to 11 previous errors +For more information about this error, try `rustc --explain E0539`.