Skip to content

Commit 326231c

Browse files
committed
refactor target checking, move out of context.rs and rename MaybeWarn to Policy
1 parent bdb74ba commit 326231c

28 files changed

+414
-382
lines changed

Cargo.lock

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3480,7 +3480,6 @@ dependencies = [
34803480
name = "rustc_attr_parsing"
34813481
version = "0.0.0"
34823482
dependencies = [
3483-
"itertools",
34843483
"rustc_abi",
34853484
"rustc_ast",
34863485
"rustc_ast_pretty",

compiler/rustc_attr_parsing/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ edition = "2024"
55

66
[dependencies]
77
# tidy-alphabetical-start
8-
itertools = "0.12"
98
rustc_abi = { path = "../rustc_abi" }
109
rustc_ast = { path = "../rustc_ast" }
1110
rustc_ast_pretty = { path = "../rustc_ast_pretty" }

compiler/rustc_attr_parsing/src/attributes/util.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1+
use rustc_ast::LitKind;
12
use rustc_ast::attr::{AttributeExt, first_attr_value_str_by_name};
23
use rustc_feature::is_builtin_attr_name;
34
use rustc_hir::RustcVersion;
45
use rustc_span::{Symbol, sym};
56

7+
use crate::context::{AcceptContext, Stage};
8+
use crate::parser::ArgParser;
9+
610
/// Parse a rustc version number written inside string literal in an attribute,
711
/// like appears in `since = "1.0.0"`. Suffixes like "-dev" and "-nightly" are
812
/// not accepted in this position, unlike when parsing CFG_RELEASE.
@@ -56,3 +60,32 @@ pub fn is_doc_alias_attrs_contain_symbol<'tcx, T: AttributeExt + 'tcx>(
5660
}
5761
false
5862
}
63+
64+
/// Parse a single integer.
65+
///
66+
/// Used by attributes that take a single integer as argument, such as
67+
/// `#[link_ordinal]` and `#[rustc_layout_scalar_valid_range_start]`.
68+
/// `cx` is the context given to the attribute.
69+
/// `args` is the parser for the attribute arguments.
70+
pub(crate) fn parse_single_integer<S: Stage>(
71+
cx: &mut AcceptContext<'_, '_, S>,
72+
args: &ArgParser<'_>,
73+
) -> Option<u128> {
74+
let Some(list) = args.list() else {
75+
cx.expected_list(cx.attr_span);
76+
return None;
77+
};
78+
let Some(single) = list.single() else {
79+
cx.expected_single_argument(list.span);
80+
return None;
81+
};
82+
let Some(lit) = single.lit() else {
83+
cx.expected_integer_literal(single.span());
84+
return None;
85+
};
86+
let LitKind::Int(num, _ty) = lit.kind else {
87+
cx.expected_integer_literal(single.span());
88+
return None;
89+
};
90+
Some(num.0)
91+
}

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 15 additions & 263 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,13 @@ use std::collections::BTreeMap;
33
use std::ops::{Deref, DerefMut};
44
use std::sync::LazyLock;
55

6-
use itertools::Itertools;
76
use private::Sealed;
8-
use rustc_ast::{self as ast, LitKind, MetaItemLit, NodeId};
7+
use rustc_ast::{self as ast, MetaItemLit, NodeId};
98
use rustc_errors::{DiagCtxtHandle, Diagnostic};
109
use rustc_feature::{AttributeTemplate, Features};
1110
use rustc_hir::attrs::AttributeKind;
1211
use rustc_hir::lints::{AttributeLint, AttributeLintKind};
13-
use rustc_hir::{
14-
AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirId, MethodKind, Target,
15-
};
12+
use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirId, Target};
1613
use rustc_session::Session;
1714
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
1815

@@ -64,11 +61,9 @@ use crate::attributes::traits::{
6461
};
6562
use crate::attributes::transparency::TransparencyParser;
6663
use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs};
67-
use crate::context::MaybeWarn::{Allow, Error, Warn};
6864
use crate::parser::{ArgParser, MetaItemParser, PathParser};
69-
use crate::session_diagnostics::{
70-
AttributeParseError, AttributeParseErrorReason, InvalidTarget, UnknownMetaItem,
71-
};
65+
use crate::session_diagnostics::{AttributeParseError, AttributeParseErrorReason, UnknownMetaItem};
66+
use crate::target_checking::AllowedTargets;
7267

7368
type GroupType<S> = LazyLock<GroupTypeInner<S>>;
7469

@@ -651,69 +646,11 @@ impl ShouldEmit {
651646
}
652647
}
653648

654-
#[derive(Debug)]
655-
pub(crate) enum AllowedTargets {
656-
AllowList(&'static [MaybeWarn]),
657-
AllowListWarnRest(&'static [MaybeWarn]),
658-
}
659-
660-
pub(crate) enum AllowedResult {
661-
Allowed,
662-
Warn,
663-
Error,
664-
}
665-
666-
impl AllowedTargets {
667-
pub(crate) fn is_allowed(&self, target: Target) -> AllowedResult {
668-
match self {
669-
AllowedTargets::AllowList(list) => {
670-
if list.contains(&Allow(target)) {
671-
AllowedResult::Allowed
672-
} else if list.contains(&Warn(target)) {
673-
AllowedResult::Warn
674-
} else {
675-
AllowedResult::Error
676-
}
677-
}
678-
AllowedTargets::AllowListWarnRest(list) => {
679-
if list.contains(&Allow(target)) {
680-
AllowedResult::Allowed
681-
} else if list.contains(&Error(target)) {
682-
AllowedResult::Error
683-
} else {
684-
AllowedResult::Warn
685-
}
686-
}
687-
}
688-
}
689-
690-
pub(crate) fn allowed_targets(&self) -> Vec<Target> {
691-
match self {
692-
AllowedTargets::AllowList(list) => list,
693-
AllowedTargets::AllowListWarnRest(list) => list,
694-
}
695-
.iter()
696-
.filter_map(|target| match target {
697-
Allow(target) => Some(*target),
698-
Warn(_) => None,
699-
Error(_) => None,
700-
})
701-
.collect()
702-
}
703-
}
704-
705-
#[derive(Debug, Eq, PartialEq)]
706-
pub(crate) enum MaybeWarn {
707-
Allow(Target),
708-
Warn(Target),
709-
Error(Target),
710-
}
711-
712649
/// Context created once, for example as part of the ast lowering
713650
/// context, through which all attributes can be lowered.
714651
pub struct AttributeParser<'sess, S: Stage = Late> {
715652
pub(crate) tools: Vec<Symbol>,
716-
features: Option<&'sess Features>,
653+
pub(crate) features: Option<&'sess Features>,
717654
sess: &'sess Session,
718655
stage: S,
719656

@@ -900,9 +837,9 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
900837
let parser = MetaItemParser::from_attr(n, self.dcx());
901838
let path = parser.path();
902839
let args = parser.args();
903-
let parts = path.segments().map(|i| i.name).collect::<Vec<_>>();
840+
let path_parts = path.segments().map(|i| i.name).collect::<Vec<_>>();
904841

905-
if let Some(accepts) = S::parsers().accepters.get(parts.as_slice()) {
842+
if let Some(accepts) = S::parsers().accepters.get(path_parts.as_slice()) {
906843
for accept in accepts {
907844
let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext {
908845
shared: SharedContext {
@@ -919,44 +856,14 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
919856
(accept.accept_fn)(&mut cx, args);
920857

921858
if self.stage.should_emit().should_emit() {
922-
match accept.allowed_targets.is_allowed(target) {
923-
AllowedResult::Allowed => {}
924-
AllowedResult::Warn => {
925-
let allowed_targets =
926-
accept.allowed_targets.allowed_targets();
927-
let (applied, only) = allowed_targets_applied(
928-
allowed_targets,
929-
target,
930-
self.features,
931-
);
932-
emit_lint(AttributeLint {
933-
id: target_id,
934-
span: attr.span,
935-
kind: AttributeLintKind::InvalidTarget {
936-
name: parts[0],
937-
target,
938-
only: if only { "only " } else { "" },
939-
applied,
940-
},
941-
});
942-
}
943-
AllowedResult::Error => {
944-
let allowed_targets =
945-
accept.allowed_targets.allowed_targets();
946-
let (applied, only) = allowed_targets_applied(
947-
allowed_targets,
948-
target,
949-
self.features,
950-
);
951-
self.dcx().emit_err(InvalidTarget {
952-
span: attr.span,
953-
name: parts[0],
954-
target: target.plural_name(),
955-
only: if only { "only " } else { "" },
956-
applied,
957-
});
958-
}
959-
}
859+
self.check_target(
860+
path.get_attribute_path(),
861+
attr.span,
862+
&accept.allowed_targets,
863+
target,
864+
target_id,
865+
&mut emit_lint,
866+
);
960867
}
961868
}
962869
} else {
@@ -1044,158 +951,3 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
1044951
}
1045952
}
1046953
}
1047-
1048-
/// Takes a list of `allowed_targets` for an attribute, and the `target` the attribute was applied to.
1049-
/// Does some heuristic-based filtering to remove uninteresting targets, and formats the targets into a string
1050-
pub(crate) fn allowed_targets_applied(
1051-
mut allowed_targets: Vec<Target>,
1052-
target: Target,
1053-
features: Option<&Features>,
1054-
) -> (String, bool) {
1055-
// Remove unstable targets from `allowed_targets` if their features are not enabled
1056-
if let Some(features) = features {
1057-
if !features.fn_delegation() {
1058-
allowed_targets.retain(|t| !matches!(t, Target::Delegation { .. }));
1059-
}
1060-
if !features.stmt_expr_attributes() {
1061-
allowed_targets.retain(|t| !matches!(t, Target::Expression | Target::Statement));
1062-
}
1063-
}
1064-
1065-
// We define groups of "similar" targets.
1066-
// If at least two of the targets are allowed, and the `target` is not in the group,
1067-
// we collapse the entire group to a single entry to simplify the target list
1068-
const FUNCTION_LIKE: &[Target] = &[
1069-
Target::Fn,
1070-
Target::Closure,
1071-
Target::ForeignFn,
1072-
Target::Method(MethodKind::Inherent),
1073-
Target::Method(MethodKind::Trait { body: false }),
1074-
Target::Method(MethodKind::Trait { body: true }),
1075-
Target::Method(MethodKind::TraitImpl),
1076-
];
1077-
const METHOD_LIKE: &[Target] = &[
1078-
Target::Method(MethodKind::Inherent),
1079-
Target::Method(MethodKind::Trait { body: false }),
1080-
Target::Method(MethodKind::Trait { body: true }),
1081-
Target::Method(MethodKind::TraitImpl),
1082-
];
1083-
const IMPL_LIKE: &[Target] =
1084-
&[Target::Impl { of_trait: false }, Target::Impl { of_trait: true }];
1085-
const ADT_LIKE: &[Target] = &[Target::Struct, Target::Enum];
1086-
1087-
let mut added_fake_targets = Vec::new();
1088-
filter_targets(
1089-
&mut allowed_targets,
1090-
FUNCTION_LIKE,
1091-
"functions",
1092-
target,
1093-
&mut added_fake_targets,
1094-
);
1095-
filter_targets(&mut allowed_targets, METHOD_LIKE, "methods", target, &mut added_fake_targets);
1096-
filter_targets(&mut allowed_targets, IMPL_LIKE, "impl blocks", target, &mut added_fake_targets);
1097-
filter_targets(&mut allowed_targets, ADT_LIKE, "data types", target, &mut added_fake_targets);
1098-
1099-
// If there is now only 1 target left, show that as the only possible target
1100-
(
1101-
added_fake_targets
1102-
.iter()
1103-
.copied()
1104-
.chain(allowed_targets.iter().map(|t| t.plural_name()))
1105-
.join(", "),
1106-
allowed_targets.len() + added_fake_targets.len() == 1,
1107-
)
1108-
}
1109-
1110-
fn filter_targets(
1111-
allowed_targets: &mut Vec<Target>,
1112-
target_group: &'static [Target],
1113-
target_group_name: &'static str,
1114-
target: Target,
1115-
added_fake_targets: &mut Vec<&'static str>,
1116-
) {
1117-
if target_group.contains(&target) {
1118-
return;
1119-
}
1120-
if allowed_targets.iter().filter(|at| target_group.contains(at)).count() < 2 {
1121-
return;
1122-
}
1123-
allowed_targets.retain(|t| !target_group.contains(t));
1124-
added_fake_targets.push(target_group_name);
1125-
}
1126-
1127-
/// This is the list of all targets to which a attribute can be applied
1128-
/// This is used for:
1129-
/// - `rustc_dummy`, which can be applied to all targets
1130-
/// - Attributes that are not parted to the new target system yet can use this list as a placeholder
1131-
pub(crate) const ALL_TARGETS: &'static [MaybeWarn] = &[
1132-
Allow(Target::ExternCrate),
1133-
Allow(Target::Use),
1134-
Allow(Target::Static),
1135-
Allow(Target::Const),
1136-
Allow(Target::Fn),
1137-
Allow(Target::Closure),
1138-
Allow(Target::Mod),
1139-
Allow(Target::ForeignMod),
1140-
Allow(Target::GlobalAsm),
1141-
Allow(Target::TyAlias),
1142-
Allow(Target::Enum),
1143-
Allow(Target::Variant),
1144-
Allow(Target::Struct),
1145-
Allow(Target::Field),
1146-
Allow(Target::Union),
1147-
Allow(Target::Trait),
1148-
Allow(Target::TraitAlias),
1149-
Allow(Target::Impl { of_trait: false }),
1150-
Allow(Target::Impl { of_trait: true }),
1151-
Allow(Target::Expression),
1152-
Allow(Target::Statement),
1153-
Allow(Target::Arm),
1154-
Allow(Target::AssocConst),
1155-
Allow(Target::Method(MethodKind::Inherent)),
1156-
Allow(Target::Method(MethodKind::Trait { body: false })),
1157-
Allow(Target::Method(MethodKind::Trait { body: true })),
1158-
Allow(Target::Method(MethodKind::TraitImpl)),
1159-
Allow(Target::AssocTy),
1160-
Allow(Target::ForeignFn),
1161-
Allow(Target::ForeignStatic),
1162-
Allow(Target::ForeignTy),
1163-
Allow(Target::MacroDef),
1164-
Allow(Target::Param),
1165-
Allow(Target::PatField),
1166-
Allow(Target::ExprField),
1167-
Allow(Target::WherePredicate),
1168-
Allow(Target::MacroCall),
1169-
Allow(Target::Crate),
1170-
Allow(Target::Delegation { mac: false }),
1171-
Allow(Target::Delegation { mac: true }),
1172-
];
1173-
1174-
/// Parse a single integer.
1175-
///
1176-
/// Used by attributes that take a single integer as argument, such as
1177-
/// `#[link_ordinal]` and `#[rustc_layout_scalar_valid_range_start]`.
1178-
/// `cx` is the context given to the attribute.
1179-
/// `args` is the parser for the attribute arguments.
1180-
pub(crate) fn parse_single_integer<S: Stage>(
1181-
cx: &mut AcceptContext<'_, '_, S>,
1182-
args: &ArgParser<'_>,
1183-
) -> Option<u128> {
1184-
let Some(list) = args.list() else {
1185-
cx.expected_list(cx.attr_span);
1186-
return None;
1187-
};
1188-
let Some(single) = list.single() else {
1189-
cx.expected_single_argument(list.span);
1190-
return None;
1191-
};
1192-
let Some(lit) = single.lit() else {
1193-
cx.expected_integer_literal(single.span());
1194-
return None;
1195-
};
1196-
let LitKind::Int(num, _ty) = lit.kind else {
1197-
cx.expected_integer_literal(single.span());
1198-
return None;
1199-
};
1200-
Some(num.0)
1201-
}

compiler/rustc_attr_parsing/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ pub(crate) mod context;
8989
mod lints;
9090
pub mod parser;
9191
mod session_diagnostics;
92+
mod target_checking;
9293

9394
pub use attributes::cfg::{CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg_attr};
9495
pub use attributes::cfg_old::*;

0 commit comments

Comments
 (0)