Skip to content

Commit 02f7937

Browse files
Wip
1 parent 0bd13c3 commit 02f7937

File tree

38 files changed

+438
-521
lines changed

38 files changed

+438
-521
lines changed

compiler/rustc_ast/src/ast.rs

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ use rustc_span::source_map::{Spanned, respan};
3434
use rustc_span::{ByteSymbol, DUMMY_SP, ErrorGuaranteed, Ident, Span, Symbol, kw, sym};
3535
use thin_vec::{ThinVec, thin_vec};
3636

37+
use crate::attr::data_structures::CfgEntry;
3738
pub use crate::format::*;
3839
use crate::token::{self, CommentKind, Delimiter};
3940
use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, TokenStream};
@@ -3390,7 +3391,7 @@ impl NormalAttr {
33903391
item: AttrItem {
33913392
unsafety: Safety::Default,
33923393
path: Path::from_ident(ident),
3393-
args: AttrArgs::Empty,
3394+
args: AttrItemKind::Unparsed(AttrArgs::Empty),
33943395
tokens: None,
33953396
},
33963397
tokens: None,
@@ -3402,11 +3403,48 @@ impl NormalAttr {
34023403
pub struct AttrItem {
34033404
pub unsafety: Safety,
34043405
pub path: Path,
3405-
pub args: AttrArgs,
3406+
pub args: AttrItemKind,
34063407
// Tokens for the meta item, e.g. just the `foo` within `#[foo]` or `#![foo]`.
34073408
pub tokens: Option<LazyAttrTokenStream>,
34083409
}
34093410

3411+
/// Some attributes are stored in a parsed form, for performance reasons.
3412+
/// Their arguments don't have to be reparsed everytime they're used
3413+
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
3414+
pub enum AttrItemKind {
3415+
Parsed(EarlyParsedAttribute),
3416+
Unparsed(AttrArgs),
3417+
}
3418+
3419+
impl AttrItemKind {
3420+
pub fn unparsed(self) -> Option<AttrArgs> {
3421+
match self {
3422+
AttrItemKind::Unparsed(args) => Some(args),
3423+
AttrItemKind::Parsed(_) => None,
3424+
}
3425+
}
3426+
3427+
pub fn unparsed_ref(&self) -> Option<&AttrArgs> {
3428+
match self {
3429+
AttrItemKind::Unparsed(args) => Some(args),
3430+
AttrItemKind::Parsed(_) => None,
3431+
}
3432+
}
3433+
3434+
pub fn span(&self) -> Option<Span> {
3435+
match self {
3436+
AttrItemKind::Unparsed(args) => args.span(),
3437+
AttrItemKind::Parsed(_) => None,
3438+
}
3439+
}
3440+
}
3441+
3442+
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
3443+
pub enum EarlyParsedAttribute {
3444+
CfgTrace(CfgEntry),
3445+
CfgAttrTrace,
3446+
}
3447+
34103448
impl AttrItem {
34113449
pub fn is_valid_for_outer_style(&self) -> bool {
34123450
self.path == sym::cfg_attr
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
use std::fmt;
2+
3+
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
4+
use rustc_span::{Span, Symbol};
5+
use thin_vec::ThinVec;
6+
7+
use crate::attr::version::RustcVersion;
8+
9+
#[derive(Encodable, Decodable, Clone, Debug, PartialEq, Eq, Hash, HashStable_Generic)]
10+
pub enum CfgEntry {
11+
All(ThinVec<CfgEntry>, Span),
12+
Any(ThinVec<CfgEntry>, Span),
13+
Not(Box<CfgEntry>, Span),
14+
Bool(bool, Span),
15+
NameValue { name: Symbol, value: Option<Symbol>, span: Span },
16+
Version(Option<RustcVersion>, Span),
17+
}
18+
19+
impl CfgEntry {
20+
pub fn lower_spans(&mut self, lower_span: impl Copy + Fn(Span) -> Span) {
21+
match self {
22+
CfgEntry::All(subs, span) | CfgEntry::Any(subs, span) => {
23+
*span = lower_span(*span);
24+
subs.iter_mut().for_each(|sub| sub.lower_spans(lower_span));
25+
}
26+
CfgEntry::Not(sub, span) => {
27+
*span = lower_span(*span);
28+
sub.lower_spans(lower_span);
29+
}
30+
CfgEntry::Bool(_, span)
31+
| CfgEntry::NameValue { span, .. }
32+
| CfgEntry::Version(_, span) => {
33+
*span = lower_span(*span);
34+
}
35+
}
36+
}
37+
38+
pub fn span(&self) -> Span {
39+
let (Self::All(_, span)
40+
| Self::Any(_, span)
41+
| Self::Not(_, span)
42+
| Self::Bool(_, span)
43+
| Self::NameValue { span, .. }
44+
| Self::Version(_, span)) = self;
45+
*span
46+
}
47+
48+
/// Same as `PartialEq` but doesn't check spans and ignore order of cfgs.
49+
pub fn is_equivalent_to(&self, other: &Self) -> bool {
50+
match (self, other) {
51+
(Self::All(a, _), Self::All(b, _)) | (Self::Any(a, _), Self::Any(b, _)) => {
52+
a.len() == b.len() && a.iter().all(|a| b.iter().any(|b| a.is_equivalent_to(b)))
53+
}
54+
(Self::Not(a, _), Self::Not(b, _)) => a.is_equivalent_to(b),
55+
(Self::Bool(a, _), Self::Bool(b, _)) => a == b,
56+
(
57+
Self::NameValue { name: name1, value: value1, .. },
58+
Self::NameValue { name: name2, value: value2, .. },
59+
) => name1 == name2 && value1 == value2,
60+
(Self::Version(a, _), Self::Version(b, _)) => a == b,
61+
_ => false,
62+
}
63+
}
64+
}
65+
66+
impl fmt::Display for CfgEntry {
67+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68+
fn write_entries(
69+
name: &str,
70+
entries: &[CfgEntry],
71+
f: &mut fmt::Formatter<'_>,
72+
) -> fmt::Result {
73+
write!(f, "{name}(")?;
74+
for (nb, entry) in entries.iter().enumerate() {
75+
if nb != 0 {
76+
f.write_str(", ")?;
77+
}
78+
entry.fmt(f)?;
79+
}
80+
f.write_str(")")
81+
}
82+
match self {
83+
Self::All(entries, _) => write_entries("all", entries, f),
84+
Self::Any(entries, _) => write_entries("any", entries, f),
85+
Self::Not(entry, _) => write!(f, "not({entry})"),
86+
Self::Bool(value, _) => write!(f, "{value}"),
87+
Self::NameValue { name, value, .. } => {
88+
match value {
89+
// We use `as_str` and debug display to have characters escaped and `"`
90+
// characters surrounding the string.
91+
Some(value) => write!(f, "{name} = {:?}", value.as_str()),
92+
None => write!(f, "{name}"),
93+
}
94+
}
95+
Self::Version(version, _) => match version {
96+
Some(version) => write!(f, "{version}"),
97+
None => Ok(()),
98+
},
99+
}
100+
}
101+
}

compiler/rustc_ast/src/attr/mod.rs

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
//! Functions dealing with attributes and meta items.
22
3+
pub mod data_structures;
4+
pub mod version;
5+
36
use std::fmt::Debug;
47
use std::sync::atomic::{AtomicU32, Ordering};
58

@@ -8,6 +11,7 @@ use rustc_span::{Ident, Span, Symbol, sym};
811
use smallvec::{SmallVec, smallvec};
912
use thin_vec::{ThinVec, thin_vec};
1013

14+
use crate::AttrItemKind;
1115
use crate::ast::{
1216
AttrArgs, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute, DUMMY_NODE_ID, DelimArgs,
1317
Expr, ExprKind, LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NormalAttr, Path,
@@ -62,6 +66,13 @@ impl Attribute {
6266
}
6367
}
6468

69+
pub fn get_mut_normal_item(&mut self) -> &mut AttrItem {
70+
match &mut self.kind {
71+
AttrKind::Normal(normal) => &mut normal.item,
72+
AttrKind::DocComment(..) => panic!("unexpected doc comment"),
73+
}
74+
}
75+
6576
pub fn unwrap_normal_item(self) -> AttrItem {
6677
match self.kind {
6778
AttrKind::Normal(normal) => normal.item,
@@ -77,7 +88,7 @@ impl AttributeExt for Attribute {
7788

7889
fn value_span(&self) -> Option<Span> {
7990
match &self.kind {
80-
AttrKind::Normal(normal) => match &normal.item.args {
91+
AttrKind::Normal(normal) => match &normal.item.args.unparsed_ref()? {
8192
AttrArgs::Eq { expr, .. } => Some(expr.span),
8293
_ => None,
8394
},
@@ -138,7 +149,7 @@ impl AttributeExt for Attribute {
138149

139150
fn is_word(&self) -> bool {
140151
if let AttrKind::Normal(normal) = &self.kind {
141-
matches!(normal.item.args, AttrArgs::Empty)
152+
matches!(normal.item.args, AttrItemKind::Unparsed(AttrArgs::Empty))
142153
} else {
143154
false
144155
}
@@ -294,7 +305,7 @@ impl AttrItem {
294305
}
295306

296307
pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
297-
match &self.args {
308+
match &self.args.unparsed_ref()? {
298309
AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => {
299310
MetaItemKind::list_from_tokens(args.tokens.clone())
300311
}
@@ -315,7 +326,7 @@ impl AttrItem {
315326
/// #[attr("value")]
316327
/// ```
317328
fn value_str(&self) -> Option<Symbol> {
318-
match &self.args {
329+
match &self.args.unparsed_ref()? {
319330
AttrArgs::Eq { expr, .. } => match expr.kind {
320331
ExprKind::Lit(token_lit) => {
321332
LitKind::from_token_lit(token_lit).ok().and_then(|lit| lit.str())
@@ -339,7 +350,7 @@ impl AttrItem {
339350
/// #[attr("value")]
340351
/// ```
341352
fn value_span(&self) -> Option<Span> {
342-
match &self.args {
353+
match &self.args.unparsed_ref()? {
343354
AttrArgs::Eq { expr, .. } => Some(expr.span),
344355
AttrArgs::Delimited(_) | AttrArgs::Empty => None,
345356
}
@@ -355,7 +366,7 @@ impl AttrItem {
355366
}
356367

357368
pub fn meta_kind(&self) -> Option<MetaItemKind> {
358-
MetaItemKind::from_attr_args(&self.args)
369+
MetaItemKind::from_attr_args(self.args.unparsed_ref()?)
359370
}
360371
}
361372

@@ -690,7 +701,13 @@ fn mk_attr(
690701
args: AttrArgs,
691702
span: Span,
692703
) -> Attribute {
693-
mk_attr_from_item(g, AttrItem { unsafety, path, args, tokens: None }, None, style, span)
704+
mk_attr_from_item(
705+
g,
706+
AttrItem { unsafety, path, args: AttrItemKind::Unparsed(args), tokens: None },
707+
None,
708+
style,
709+
span,
710+
)
694711
}
695712

696713
pub fn mk_attr_from_item(
Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,10 @@
1-
use std::borrow::Cow;
21
use std::fmt::{self, Display};
32
use std::sync::OnceLock;
43

5-
use rustc_error_messages::{DiagArgValue, IntoDiagArg};
6-
use rustc_macros::{
7-
BlobDecodable, Encodable, HashStable_Generic, PrintAttribute, current_rustc_version,
8-
};
9-
10-
use crate::attrs::PrintAttribute;
4+
use rustc_macros::{BlobDecodable, Encodable, HashStable_Generic, current_rustc_version};
115

126
#[derive(Encodable, BlobDecodable, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
13-
#[derive(HashStable_Generic, PrintAttribute)]
7+
#[derive(HashStable_Generic)]
148
pub struct RustcVersion {
159
pub major: u16,
1610
pub minor: u16,
@@ -47,9 +41,3 @@ impl Display for RustcVersion {
4741
write!(formatter, "{}.{}.{}", self.major, self.minor, self.patch)
4842
}
4943
}
50-
51-
impl IntoDiagArg for RustcVersion {
52-
fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
53-
DiagArgValue::Str(Cow::Owned(self.to_string()))
54-
}
55-
}

compiler/rustc_ast/src/visit.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,7 @@ macro_rules! common_visitor_and_walkers {
366366
crate::token::LitKind,
367367
crate::tokenstream::LazyAttrTokenStream,
368368
crate::tokenstream::TokenStream,
369+
EarlyParsedAttribute,
369370
Movability,
370371
Mutability,
371372
Pinnedness,
@@ -457,6 +458,7 @@ macro_rules! common_visitor_and_walkers {
457458
ModSpans,
458459
MutTy,
459460
NormalAttr,
461+
AttrItemKind,
460462
Parens,
461463
ParenthesizedArgs,
462464
PatFieldsRest,

compiler/rustc_ast_pretty/src/pprust/state.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -694,7 +694,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
694694
}
695695
ast::Safety::Default | ast::Safety::Safe(_) => {}
696696
}
697-
match &item.args {
697+
match &item.args.unparsed_ref().expect("Parsed attributes are never printed") {
698698
AttrArgs::Delimited(DelimArgs { dspan: _, delim, tokens }) => self.print_mac_common(
699699
Some(MacHeader::Path(&item.path)),
700700
false,

compiler/rustc_attr_parsing/src/attributes/cfg.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -294,11 +294,9 @@ pub fn parse_cfg_attr(
294294
sess: &Session,
295295
features: Option<&Features>,
296296
) -> Option<(CfgEntry, Vec<(AttrItem, Span)>)> {
297-
match cfg_attr.get_normal_item().args {
298-
ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, ref tokens })
299-
if !tokens.is_empty() =>
300-
{
301-
check_cfg_attr_bad_delim(&sess.psess, dspan, delim);
297+
match cfg_attr.get_normal_item().args.unparsed_ref().unwrap() {
298+
ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, tokens }) if !tokens.is_empty() => {
299+
check_cfg_attr_bad_delim(&sess.psess, *dspan, *delim);
302300
match parse_in(&sess.psess, tokens.clone(), "`cfg_attr` input", |p| {
303301
parse_cfg_attr_internal(p, sess, features, cfg_attr)
304302
}) {
@@ -322,7 +320,7 @@ pub fn parse_cfg_attr(
322320
}
323321
_ => {
324322
let (span, reason) = if let ast::AttrArgs::Delimited(ast::DelimArgs { dspan, .. }) =
325-
cfg_attr.get_normal_item().args
323+
cfg_attr.get_normal_item().args.unparsed_ref()?
326324
{
327325
(dspan.entire(), AttributeParseErrorReason::ExpectedAtLeastOneArgument)
328326
} else {

0 commit comments

Comments
 (0)