Skip to content

Commit 12368ec

Browse files
committed
Port #[rustc_must_implement_one_of] to attribute parser
1 parent 91dec80 commit 12368ec

File tree

16 files changed

+240
-207
lines changed

16 files changed

+240
-207
lines changed

compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use rustc_ast::{LitIntType, LitKind, MetaItemLit};
2+
use rustc_session::errors;
23

34
use super::prelude::*;
45
use super::util::parse_single_integer;
@@ -13,6 +14,52 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcMainParser {
1314
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcMain;
1415
}
1516

17+
pub(crate) struct RustcMustImplementOneOfParser;
18+
19+
impl<S: Stage> SingleAttributeParser<S> for RustcMustImplementOneOfParser {
20+
const PATH: &[Symbol] = &[sym::rustc_must_implement_one_of];
21+
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
22+
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
23+
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
24+
const TEMPLATE: AttributeTemplate = template!(List: &["function1, function2, ..."]);
25+
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
26+
let Some(list) = args.list() else {
27+
cx.expected_list(cx.attr_span, args);
28+
return None;
29+
};
30+
31+
let mut fn_names = ThinVec::new();
32+
33+
let inputs: Vec<_> = list.mixed().collect();
34+
35+
if inputs.len() < 2 {
36+
cx.expected_list_with_num_args_or_more(2, list.span);
37+
return None;
38+
}
39+
40+
let mut errored = false;
41+
for argument in inputs {
42+
let Some(meta) = argument.meta_item() else {
43+
cx.expected_identifier(argument.span());
44+
return None;
45+
};
46+
47+
let Some(ident) = meta.ident() else {
48+
cx.dcx().emit_err(errors::MustBeNameOfAssociatedFunction { span: meta.span() });
49+
errored = true;
50+
continue;
51+
};
52+
53+
fn_names.push(ident);
54+
}
55+
if errored {
56+
return None;
57+
}
58+
59+
Some(AttributeKind::RustcMustImplementOneOf { attr_span: cx.attr_span, fn_names })
60+
}
61+
}
62+
1663
pub(crate) struct RustcNeverReturnsNullPointerParser;
1764

1865
impl<S: Stage> NoArgsAttributeParser<S> for RustcNeverReturnsNullPointerParser {

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,9 @@ use crate::attributes::rustc_internal::{
6363
RustcLayoutScalarValidRangeEndParser, RustcLayoutScalarValidRangeStartParser,
6464
RustcLegacyConstGenericsParser, RustcLintDiagnosticsParser, RustcLintOptDenyFieldAccessParser,
6565
RustcLintOptTyParser, RustcLintQueryInstabilityParser,
66-
RustcLintUntrackedQueryInformationParser, RustcMainParser, RustcNeverReturnsNullPointerParser,
67-
RustcNoImplicitAutorefsParser, RustcObjectLifetimeDefaultParser, RustcScalableVectorParser,
66+
RustcLintUntrackedQueryInformationParser, RustcMainParser, RustcMustImplementOneOfParser,
67+
RustcNeverReturnsNullPointerParser, RustcNoImplicitAutorefsParser,
68+
RustcObjectLifetimeDefaultParser, RustcScalableVectorParser,
6869
RustcSimdMonomorphizeLaneLimitParser,
6970
};
7071
use crate::attributes::semantics::MayDangleParser;
@@ -215,6 +216,7 @@ attribute_parsers!(
215216
Single<RustcLayoutScalarValidRangeStartParser>,
216217
Single<RustcLegacyConstGenericsParser>,
217218
Single<RustcLintOptDenyFieldAccessParser>,
219+
Single<RustcMustImplementOneOfParser>,
218220
Single<RustcObjectLifetimeDefaultParser>,
219221
Single<RustcScalableVectorParser>,
220222
Single<RustcSimdMonomorphizeLaneLimitParser>,
@@ -490,8 +492,15 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
490492
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedList)
491493
}
492494

493-
pub(crate) fn expected_list_with_num_args_or_more(&self, args: usize, span: Span) -> ErrorGuaranteed {
494-
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedListWithNumArgsOrMore { args})
495+
pub(crate) fn expected_list_with_num_args_or_more(
496+
&self,
497+
args: usize,
498+
span: Span,
499+
) -> ErrorGuaranteed {
500+
self.emit_parse_error(
501+
span,
502+
AttributeParseErrorReason::ExpectedListWithNumArgsOrMore { args },
503+
)
495504
}
496505

497506
pub(crate) fn expected_list_or_no_args(&self, span: Span) -> ErrorGuaranteed {

compiler/rustc_attr_parsing/src/parser.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ use std::fmt::{Debug, Display};
88

99
use rustc_ast::token::{self, Delimiter, MetaVarKind};
1010
use rustc_ast::tokenstream::TokenStream;
11-
use rustc_ast::{AttrArgs, Expr, ExprKind, LitKind, MetaItemLit, Path, StmtKind, UnOp};
11+
use rustc_ast::{
12+
AttrArgs, Expr, ExprKind, LitKind, MetaItemLit, Path, PathSegment, StmtKind, UnOp,
13+
};
1214
use rustc_ast_pretty::pprust;
1315
use rustc_errors::{Diag, PResult};
1416
use rustc_hir::{self as hir, AttrPath};
@@ -256,6 +258,11 @@ impl Debug for MetaItemParser {
256258
}
257259

258260
impl MetaItemParser {
261+
/// For a single-segment meta item, returns its name; otherwise, returns `None`.
262+
pub fn ident(&self) -> Option<Ident> {
263+
if let [PathSegment { ident, .. }] = self.path.0.segments[..] { Some(ident) } else { None }
264+
}
265+
259266
pub fn span(&self) -> Span {
260267
if let Some(other) = self.args.span() {
261268
self.path.borrow().span().with_hi(other.hi())

compiler/rustc_hir/src/attrs/data_structures.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -949,6 +949,9 @@ pub enum AttributeKind {
949949
/// Represents `#[rustc_main]`.
950950
RustcMain,
951951

952+
/// Represents `#[rustc_must_implement_one_of]`
953+
RustcMustImplementOneOf { attr_span: Span, fn_names: ThinVec<Ident> },
954+
952955
/// Represents `#[rustc_never_returns_null_ptr]`
953956
RustcNeverReturnsNullPointer,
954957

compiler/rustc_hir/src/attrs/encode_cross_crate.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ impl AttributeKind {
100100
RustcLintQueryInstability => Yes,
101101
RustcLintUntrackedQueryInformation => Yes,
102102
RustcMain => No,
103+
RustcMustImplementOneOf { .. } => No,
103104
RustcNeverReturnsNullPointer => Yes,
104105
RustcNoImplicitAutorefs => Yes,
105106
RustcObjectLifetimeDefault => No,

compiler/rustc_hir_analysis/messages.ftl

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -208,14 +208,6 @@ hir_analysis_field_already_declared_previous_nested =
208208
.previous_decl_label = `{$field_name}` first declared here in this unnamed field
209209
.previous_nested_field_decl_note = field `{$field_name}` first declared here
210210
211-
hir_analysis_function_not_found_in_trait = function not found in this trait
212-
213-
hir_analysis_function_not_have_default_implementation = function doesn't have a default implementation
214-
.note = required by this annotation
215-
216-
hir_analysis_functions_names_duplicated = functions names are duplicated
217-
.note = all `#[rustc_must_implement_one_of]` arguments must be unique
218-
219211
hir_analysis_generic_args_on_overridden_impl = could not resolve generic parameters on overridden impl
220212
221213
hir_analysis_impl_not_marked_default = `{$ident}` specializes an item from a parent `impl`, but that item is not marked `default`
@@ -381,15 +373,6 @@ hir_analysis_missing_type_params =
381373
*[other] parameters
382374
} must be specified on the object type
383375
384-
hir_analysis_must_be_name_of_associated_function = must be a name of an associated function
385-
386-
hir_analysis_must_implement_not_function = not a function
387-
388-
hir_analysis_must_implement_not_function_note = all `#[rustc_must_implement_one_of]` arguments must be associated function names
389-
390-
hir_analysis_must_implement_not_function_span_note = required by this annotation
391-
392-
hir_analysis_must_implement_one_of_attribute = the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args
393376
394377
hir_analysis_no_variant_named = no variant named `{$ident}` found for enum `{$ty}`
395378

compiler/rustc_hir_analysis/src/check/check.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1340,9 +1340,7 @@ fn check_impl_items_against_trait<'tcx>(
13401340
}
13411341

13421342
if let Some(missing_items) = must_implement_one_of {
1343-
let attr_span = tcx
1344-
.get_attr(trait_ref.def_id, sym::rustc_must_implement_one_of)
1345-
.map(|attr| attr.span());
1343+
let attr_span = find_attr!(tcx.get_all_attrs(trait_ref.def_id), AttributeKind::RustcMustImplementOneOf {attr_span, ..} => *attr_span);
13461344

13471345
missing_items_must_implement_one_of_err(
13481346
tcx,

compiler/rustc_hir_analysis/src/collect.rs

Lines changed: 8 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ use std::ops::Bound;
2222
use rustc_abi::{ExternAbi, Size};
2323
use rustc_ast::Recovered;
2424
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
25-
use rustc_data_structures::unord::UnordMap;
2625
use rustc_errors::{
2726
Applicability, Diag, DiagCtxtHandle, E0228, ErrorGuaranteed, StashKey, struct_span_code_err,
2827
};
@@ -916,84 +915,15 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
916915
} else {
917916
ty::trait_def::TraitSpecializationKind::None
918917
};
919-
let must_implement_one_of = attrs
920-
.iter()
921-
.find(|attr| attr.has_name(sym::rustc_must_implement_one_of))
922-
// Check that there are at least 2 arguments of `#[rustc_must_implement_one_of]`
923-
// and that they are all identifiers
924-
.and_then(|attr| match attr.meta_item_list() {
925-
Some(items) if items.len() < 2 => {
926-
tcx.dcx().emit_err(errors::MustImplementOneOfAttribute { span: attr.span() });
927-
928-
None
929-
}
930-
Some(items) => items
931-
.into_iter()
932-
.map(|item| item.ident().ok_or(item.span()))
933-
.collect::<Result<Box<[_]>, _>>()
934-
.map_err(|span| {
935-
tcx.dcx().emit_err(errors::MustBeNameOfAssociatedFunction { span });
936-
})
937-
.ok()
938-
.zip(Some(attr.span())),
939-
// Error is reported by `rustc_attr!`
940-
None => None,
941-
})
942-
// Check that all arguments of `#[rustc_must_implement_one_of]` reference
943-
// functions in the trait with default implementations
944-
.and_then(|(list, attr_span)| {
945-
let errors = list.iter().filter_map(|ident| {
946-
let item = tcx
947-
.associated_items(def_id)
948-
.filter_by_name_unhygienic(ident.name)
949-
.find(|item| item.ident(tcx) == *ident);
950-
951-
match item {
952-
Some(item) if matches!(item.kind, ty::AssocKind::Fn { .. }) => {
953-
if !item.defaultness(tcx).has_value() {
954-
tcx.dcx().emit_err(errors::FunctionNotHaveDefaultImplementation {
955-
span: tcx.def_span(item.def_id),
956-
note_span: attr_span,
957-
});
958918

959-
return Some(());
960-
}
961-
962-
return None;
963-
}
964-
Some(item) => {
965-
tcx.dcx().emit_err(errors::MustImplementNotFunction {
966-
span: tcx.def_span(item.def_id),
967-
span_note: errors::MustImplementNotFunctionSpanNote { span: attr_span },
968-
note: errors::MustImplementNotFunctionNote {},
969-
});
970-
}
971-
None => {
972-
tcx.dcx().emit_err(errors::FunctionNotFoundInTrait { span: ident.span });
973-
}
974-
}
975-
976-
Some(())
977-
});
978-
979-
(errors.count() == 0).then_some(list)
980-
})
981-
// Check for duplicates
982-
.and_then(|list| {
983-
let mut set: UnordMap<Symbol, Span> = Default::default();
984-
let mut no_dups = true;
985-
986-
for ident in &*list {
987-
if let Some(dup) = set.insert(ident.name, ident.span) {
988-
tcx.dcx()
989-
.emit_err(errors::FunctionNamesDuplicated { spans: vec![dup, ident.span] });
990-
991-
no_dups = false;
992-
}
993-
}
994-
995-
no_dups.then_some(list)
996-
});
919+
let must_implement_one_of = find_attr!(
920+
attrs,
921+
AttributeKind::RustcMustImplementOneOf { fn_names, .. } =>
922+
fn_names
923+
.iter()
924+
.cloned()
925+
.collect::<Box<[_]>>()
926+
);
997927

998928
let deny_explicit_impl = find_attr!(attrs, AttributeKind::DenyExplicitImpl(_));
999929
let implement_via_object = !find_attr!(attrs, AttributeKind::DoNotImplementViaObject(_));

compiler/rustc_hir_analysis/src/errors.rs

Lines changed: 0 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -741,66 +741,6 @@ pub(crate) struct ParenSugarAttribute {
741741
pub span: Span,
742742
}
743743

744-
#[derive(Diagnostic)]
745-
#[diag(hir_analysis_must_implement_one_of_attribute)]
746-
pub(crate) struct MustImplementOneOfAttribute {
747-
#[primary_span]
748-
pub span: Span,
749-
}
750-
751-
#[derive(Diagnostic)]
752-
#[diag(hir_analysis_must_be_name_of_associated_function)]
753-
pub(crate) struct MustBeNameOfAssociatedFunction {
754-
#[primary_span]
755-
pub span: Span,
756-
}
757-
758-
#[derive(Diagnostic)]
759-
#[diag(hir_analysis_function_not_have_default_implementation)]
760-
pub(crate) struct FunctionNotHaveDefaultImplementation {
761-
#[primary_span]
762-
pub span: Span,
763-
#[note]
764-
pub note_span: Span,
765-
}
766-
767-
#[derive(Diagnostic)]
768-
#[diag(hir_analysis_must_implement_not_function)]
769-
pub(crate) struct MustImplementNotFunction {
770-
#[primary_span]
771-
pub span: Span,
772-
#[subdiagnostic]
773-
pub span_note: MustImplementNotFunctionSpanNote,
774-
#[subdiagnostic]
775-
pub note: MustImplementNotFunctionNote,
776-
}
777-
778-
#[derive(Subdiagnostic)]
779-
#[note(hir_analysis_must_implement_not_function_span_note)]
780-
pub(crate) struct MustImplementNotFunctionSpanNote {
781-
#[primary_span]
782-
pub span: Span,
783-
}
784-
785-
#[derive(Subdiagnostic)]
786-
#[note(hir_analysis_must_implement_not_function_note)]
787-
pub(crate) struct MustImplementNotFunctionNote {}
788-
789-
#[derive(Diagnostic)]
790-
#[diag(hir_analysis_function_not_found_in_trait)]
791-
pub(crate) struct FunctionNotFoundInTrait {
792-
#[primary_span]
793-
pub span: Span,
794-
}
795-
796-
#[derive(Diagnostic)]
797-
#[diag(hir_analysis_functions_names_duplicated)]
798-
#[note]
799-
pub(crate) struct FunctionNamesDuplicated {
800-
#[primary_span]
801-
pub spans: Vec<Span>,
802-
}
803-
804744
#[derive(Diagnostic)]
805745
#[diag(hir_analysis_simd_ffi_highly_experimental)]
806746
#[help]

compiler/rustc_passes/messages.ftl

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,14 @@ passes_feature_previously_declared =
236236
passes_feature_stable_twice =
237237
feature `{$feature}` is declared stable since {$since}, but was previously declared stable since {$prev_since}
238238
239+
passes_function_not_found_in_trait = function not found in this trait
240+
241+
passes_function_not_have_default_implementation = function doesn't have a default implementation
242+
.note = required by this annotation
243+
244+
passes_functions_names_duplicated = functions names are duplicated
245+
.note = all `#[rustc_must_implement_one_of]` arguments must be unique
246+
239247
passes_has_incoherent_inherent_impl =
240248
`rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits
241249
.label = only adts, extern types and traits are supported
@@ -370,6 +378,12 @@ passes_multiple_rustc_main =
370378
.first = first `#[rustc_main]` function
371379
.additional = additional `#[rustc_main]` function
372380
381+
passes_must_implement_not_function = not a function
382+
383+
passes_must_implement_not_function_note = all `#[rustc_must_implement_one_of]` arguments must be associated function names
384+
385+
passes_must_implement_not_function_span_note = required by this annotation
386+
373387
passes_must_not_suspend =
374388
`must_not_suspend` attribute should be applied to a struct, enum, union, or trait
375389
.label = is not a struct, enum, union, or trait
@@ -484,10 +498,6 @@ passes_sanitize_attribute_not_allowed =
484498
.no_body = function has no body
485499
.help = sanitize attribute can be applied to a function (with body), impl block, or module
486500
487-
passes_should_be_applied_to_trait =
488-
attribute should be applied to a trait
489-
.label = not a trait
490-
491501
passes_trait_impl_const_stability_mismatch = const stability on the impl does not match the const stability on the trait
492502
passes_trait_impl_const_stability_mismatch_impl_stable = this impl is (implicitly) stable...
493503
passes_trait_impl_const_stability_mismatch_impl_unstable = this impl is unstable...

0 commit comments

Comments
 (0)