Skip to content

ast: Optimize list and value extraction primitives for attributes #107569

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1826,6 +1826,13 @@ pub enum LitKind {
}

impl LitKind {
pub fn str(&self) -> Option<Symbol> {
match *self {
LitKind::Str(s, _) => Some(s),
_ => None,
}
}

/// Returns `true` if this literal is a string.
pub fn is_str(&self) -> bool {
matches!(self, LitKind::Str(..))
Expand Down
66 changes: 43 additions & 23 deletions compiler/rustc_ast/src/attr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,17 +140,14 @@ impl Attribute {

pub fn value_str(&self) -> Option<Symbol> {
match &self.kind {
AttrKind::Normal(normal) => normal.item.meta_kind().and_then(|kind| kind.value_str()),
AttrKind::Normal(normal) => normal.item.value_str(),
AttrKind::DocComment(..) => None,
}
}

pub fn meta_item_list(&self) -> Option<Vec<NestedMetaItem>> {
match &self.kind {
AttrKind::Normal(normal) => match normal.item.meta_kind() {
Some(MetaItemKind::List(list)) => Some(list),
_ => None,
},
AttrKind::Normal(normal) => normal.item.meta_item_list(),
AttrKind::DocComment(..) => None,
}
}
Expand Down Expand Up @@ -216,6 +213,20 @@ impl MetaItem {
}
}

impl AttrArgsEq {
fn value_str(&self) -> Option<Symbol> {
match self {
AttrArgsEq::Ast(expr) => match expr.kind {
ExprKind::Lit(token_lit) => {
LitKind::from_token_lit(token_lit).ok().and_then(|lit| lit.str())
}
_ => None,
},
AttrArgsEq::Hir(lit) => lit.kind.str(),
}
}
}

impl AttrItem {
pub fn span(&self) -> Span {
self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span))
Expand All @@ -228,6 +239,22 @@ impl AttrItem {
pub fn meta_kind(&self) -> Option<MetaItemKind> {
MetaItemKind::from_attr_args(&self.args)
}

fn meta_item_list(&self) -> Option<Vec<NestedMetaItem>> {
match &self.args {
AttrArgs::Delimited(args) if args.delim == MacDelimiter::Parenthesis => {
MetaItemKind::list_from_tokens(args.tokens.clone())
}
AttrArgs::Delimited(_) | AttrArgs::Eq(..) | AttrArgs::Empty => None,
}
}

fn value_str(&self) -> Option<Symbol> {
match &self.args {
AttrArgs::Eq(_, args) => args.value_str(),
AttrArgs::Delimited(_) | AttrArgs::Empty => None,
}
}
}

impl Attribute {
Expand All @@ -247,13 +274,11 @@ impl Attribute {
/// * `#[doc = "doc"]` returns `Some(("doc", CommentKind::Line))`.
/// * `#[doc(...)]` returns `None`.
pub fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> {
match self.kind {
AttrKind::DocComment(kind, data) => Some((data, kind)),
AttrKind::Normal(ref normal) if normal.item.path == sym::doc => normal
.item
.meta_kind()
.and_then(|kind| kind.value_str())
.map(|data| (data, CommentKind::Line)),
match &self.kind {
AttrKind::DocComment(kind, data) => Some((*data, *kind)),
AttrKind::Normal(normal) if normal.item.path == sym::doc => {
normal.item.value_str().map(|s| (s, CommentKind::Line))
}
_ => None,
}
}
Expand All @@ -265,9 +290,7 @@ impl Attribute {
pub fn doc_str(&self) -> Option<Symbol> {
match &self.kind {
AttrKind::DocComment(.., data) => Some(*data),
AttrKind::Normal(normal) if normal.item.path == sym::doc => {
normal.item.meta_kind().and_then(|kind| kind.value_str())
}
AttrKind::Normal(normal) if normal.item.path == sym::doc => normal.item.value_str(),
_ => None,
}
}
Expand Down Expand Up @@ -508,15 +531,12 @@ impl MetaItem {
impl MetaItemKind {
pub fn value_str(&self) -> Option<Symbol> {
match self {
MetaItemKind::NameValue(v) => match v.kind {
LitKind::Str(s, _) => Some(s),
_ => None,
},
MetaItemKind::NameValue(v) => v.kind.str(),
_ => None,
}
}

fn list_from_tokens(tokens: TokenStream) -> Option<MetaItemKind> {
fn list_from_tokens(tokens: TokenStream) -> Option<Vec<NestedMetaItem>> {
let mut tokens = tokens.into_trees().peekable();
let mut result = Vec::new();
while tokens.peek().is_some() {
Expand All @@ -527,7 +547,7 @@ impl MetaItemKind {
_ => return None,
}
}
Some(MetaItemKind::List(result))
Some(result)
}

fn name_value_from_tokens(
Expand All @@ -551,7 +571,7 @@ impl MetaItemKind {
dspan: _,
delim: MacDelimiter::Parenthesis,
tokens,
}) => MetaItemKind::list_from_tokens(tokens.clone()),
}) => MetaItemKind::list_from_tokens(tokens.clone()).map(MetaItemKind::List),
AttrArgs::Delimited(..) => None,
AttrArgs::Eq(_, AttrArgsEq::Ast(expr)) => match expr.kind {
ExprKind::Lit(token_lit) => {
Expand All @@ -573,7 +593,7 @@ impl MetaItemKind {
Some(TokenTree::Delimited(_, Delimiter::Parenthesis, inner_tokens)) => {
let inner_tokens = inner_tokens.clone();
tokens.next();
MetaItemKind::list_from_tokens(inner_tokens)
MetaItemKind::list_from_tokens(inner_tokens).map(MetaItemKind::List)
}
Some(TokenTree::Delimited(..)) => None,
Some(TokenTree::Token(Token { kind: token::Eq, .. }, _)) => {
Expand Down
88 changes: 38 additions & 50 deletions compiler/rustc_codegen_ssa/src/codegen_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,74 +319,62 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
}
}
} else if attr.has_name(sym::instruction_set) {
codegen_fn_attrs.instruction_set = match attr.meta_kind() {
Some(MetaItemKind::List(ref items)) => match items.as_slice() {
[NestedMetaItem::MetaItem(set)] => {
let segments =
set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>();
match segments.as_slice() {
[sym::arm, sym::a32] | [sym::arm, sym::t32] => {
if !tcx.sess.target.has_thumb_interworking {
struct_span_err!(
tcx.sess.diagnostic(),
attr.span,
E0779,
"target does not support `#[instruction_set]`"
)
.emit();
None
} else if segments[1] == sym::a32 {
Some(InstructionSetAttr::ArmA32)
} else if segments[1] == sym::t32 {
Some(InstructionSetAttr::ArmT32)
} else {
unreachable!()
}
}
_ => {
codegen_fn_attrs.instruction_set = attr.meta_item_list().and_then(|l| match &l[..] {
[NestedMetaItem::MetaItem(set)] => {
let segments =
set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>();
match segments.as_slice() {
[sym::arm, sym::a32] | [sym::arm, sym::t32] => {
if !tcx.sess.target.has_thumb_interworking {
struct_span_err!(
tcx.sess.diagnostic(),
attr.span,
E0779,
"invalid instruction set specified",
"target does not support `#[instruction_set]`"
)
.emit();
None
} else if segments[1] == sym::a32 {
Some(InstructionSetAttr::ArmA32)
} else if segments[1] == sym::t32 {
Some(InstructionSetAttr::ArmT32)
} else {
unreachable!()
}
}
_ => {
struct_span_err!(
tcx.sess.diagnostic(),
attr.span,
E0779,
"invalid instruction set specified",
)
.emit();
None
}
}
[] => {
struct_span_err!(
tcx.sess.diagnostic(),
attr.span,
E0778,
"`#[instruction_set]` requires an argument"
)
.emit();
None
}
_ => {
struct_span_err!(
tcx.sess.diagnostic(),
attr.span,
E0779,
"cannot specify more than one instruction set"
)
.emit();
None
}
},
_ => {
}
[] => {
struct_span_err!(
tcx.sess.diagnostic(),
attr.span,
E0778,
"must specify an instruction set"
"`#[instruction_set]` requires an argument"
)
.emit();
None
}
};
_ => {
struct_span_err!(
tcx.sess.diagnostic(),
attr.span,
E0779,
"cannot specify more than one instruction set"
)
.emit();
None
}
})
} else if attr.has_name(sym::repr) {
codegen_fn_attrs.alignment = match attr.meta_item_list() {
Some(items) => match items.as_slice() {
Expand Down
5 changes: 2 additions & 3 deletions compiler/rustc_passes/src/lib_features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//! but are not declared in one single location (unlike lang features), which means we need to
//! collect them instead.

use rustc_ast::{Attribute, MetaItemKind};
use rustc_ast::Attribute;
use rustc_attr::{rust_version_symbol, VERSION_PLACEHOLDER};
use rustc_hir::intravisit::Visitor;
use rustc_middle::hir::nested_filter;
Expand Down Expand Up @@ -42,8 +42,7 @@ impl<'tcx> LibFeatureCollector<'tcx> {
// Find a stability attribute: one of #[stable(…)], #[unstable(…)],
// #[rustc_const_stable(…)], #[rustc_const_unstable(…)] or #[rustc_default_body_unstable].
if let Some(stab_attr) = stab_attrs.iter().find(|stab_attr| attr.has_name(**stab_attr)) {
let meta_kind = attr.meta_kind();
if let Some(MetaItemKind::List(ref metas)) = meta_kind {
if let Some(metas) = attr.meta_item_list() {
let mut feature = None;
let mut since = None;
for meta in metas {
Expand Down