Allow only a single accepter per attribute
This commit is contained in:
parent
06cafcbe08
commit
fd7ff90f70
2 changed files with 40 additions and 36 deletions
|
|
@ -1,5 +1,6 @@
|
|||
use std::cell::RefCell;
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::btree_map::Entry;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::sync::LazyLock;
|
||||
|
||||
|
|
@ -61,7 +62,7 @@ use crate::target_checking::AllowedTargets;
|
|||
type GroupType<S> = LazyLock<GroupTypeInner<S>>;
|
||||
|
||||
pub(super) struct GroupTypeInner<S: Stage> {
|
||||
pub(super) accepters: BTreeMap<&'static [Symbol], Vec<GroupTypeInnerAccept<S>>>,
|
||||
pub(super) accepters: BTreeMap<&'static [Symbol], GroupTypeInnerAccept<S>>,
|
||||
}
|
||||
|
||||
pub(super) struct GroupTypeInnerAccept<S: Stage> {
|
||||
|
|
@ -101,7 +102,7 @@ macro_rules! attribute_parsers {
|
|||
@[$stage: ty] pub(crate) static $name: ident = [$($names: ty),* $(,)?];
|
||||
) => {
|
||||
pub(crate) static $name: GroupType<$stage> = LazyLock::new(|| {
|
||||
let mut accepters = BTreeMap::<_, Vec<GroupTypeInnerAccept<$stage>>>::new();
|
||||
let mut accepters = BTreeMap::<_, GroupTypeInnerAccept<$stage>>::new();
|
||||
$(
|
||||
{
|
||||
thread_local! {
|
||||
|
|
@ -109,19 +110,24 @@ macro_rules! attribute_parsers {
|
|||
};
|
||||
|
||||
for (path, template, accept_fn) in <$names>::ATTRIBUTES {
|
||||
accepters.entry(*path).or_default().push(GroupTypeInnerAccept {
|
||||
template: *template,
|
||||
accept_fn: Box::new(|cx, args| {
|
||||
STATE_OBJECT.with_borrow_mut(|s| {
|
||||
accept_fn(s, cx, args)
|
||||
})
|
||||
}),
|
||||
allowed_targets: <$names as crate::attributes::AttributeParser<$stage>>::ALLOWED_TARGETS,
|
||||
finalizer: Box::new(|cx| {
|
||||
let state = STATE_OBJECT.take();
|
||||
state.finalize(cx)
|
||||
}),
|
||||
});
|
||||
match accepters.entry(*path) {
|
||||
Entry::Vacant(e) => {
|
||||
e.insert(GroupTypeInnerAccept {
|
||||
template: *template,
|
||||
accept_fn: Box::new(|cx, args| {
|
||||
STATE_OBJECT.with_borrow_mut(|s| {
|
||||
accept_fn(s, cx, args)
|
||||
})
|
||||
}),
|
||||
allowed_targets: <$names as crate::attributes::AttributeParser<$stage>>::ALLOWED_TARGETS,
|
||||
finalizer: Box::new(|cx| {
|
||||
let state = STATE_OBJECT.take();
|
||||
state.finalize(cx)
|
||||
})
|
||||
});
|
||||
}
|
||||
Entry::Occupied(_) => panic!("Attribute {path:?} has multiple accepters"),
|
||||
}
|
||||
}
|
||||
}
|
||||
)*
|
||||
|
|
|
|||
|
|
@ -327,7 +327,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
let parts =
|
||||
n.item.path.segments.iter().map(|seg| seg.ident.name).collect::<Vec<_>>();
|
||||
|
||||
if let Some(accepts) = S::parsers().accepters.get(parts.as_slice()) {
|
||||
if let Some(accept) = S::parsers().accepters.get(parts.as_slice()) {
|
||||
let Some(args) = ArgParser::from_attr_args(
|
||||
args,
|
||||
&parts,
|
||||
|
|
@ -368,28 +368,26 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
continue;
|
||||
}
|
||||
|
||||
for accept in accepts {
|
||||
let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext {
|
||||
shared: SharedContext {
|
||||
cx: self,
|
||||
target_span,
|
||||
target,
|
||||
emit_lint: &mut emit_lint,
|
||||
},
|
||||
attr_span,
|
||||
inner_span: lower_span(n.item.span()),
|
||||
attr_style: attr.style,
|
||||
parsed_description: ParsedDescription::Attribute,
|
||||
template: &accept.template,
|
||||
attr_path: attr_path.clone(),
|
||||
};
|
||||
let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext {
|
||||
shared: SharedContext {
|
||||
cx: self,
|
||||
target_span,
|
||||
target,
|
||||
emit_lint: &mut emit_lint,
|
||||
},
|
||||
attr_span,
|
||||
inner_span: lower_span(n.item.span()),
|
||||
attr_style: attr.style,
|
||||
parsed_description: ParsedDescription::Attribute,
|
||||
template: &accept.template,
|
||||
attr_path: attr_path.clone(),
|
||||
};
|
||||
|
||||
(accept.accept_fn)(&mut cx, &args);
|
||||
finalizers.push(&accept.finalizer);
|
||||
(accept.accept_fn)(&mut cx, &args);
|
||||
finalizers.push(&accept.finalizer);
|
||||
|
||||
if !matches!(cx.stage.should_emit(), ShouldEmit::Nothing) {
|
||||
Self::check_target(&accept.allowed_targets, target, &mut cx);
|
||||
}
|
||||
if !matches!(cx.stage.should_emit(), ShouldEmit::Nothing) {
|
||||
Self::check_target(&accept.allowed_targets, target, &mut cx);
|
||||
}
|
||||
} else {
|
||||
// If we're here, we must be compiling a tool attribute... Or someone
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue