diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:19:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:19:43 +0000 |
commit | 3e3e70d529d8c7d7c4d7bc4fefc9f109393b9245 (patch) | |
tree | daf049b282ab10e8c3d03e409b3cd84ff3f7690c /compiler/rustc_ast | |
parent | Adding debian version 1.68.2+dfsg1-1. (diff) | |
download | rustc-3e3e70d529d8c7d7c4d7bc4fefc9f109393b9245.tar.xz rustc-3e3e70d529d8c7d7c4d7bc4fefc9f109393b9245.zip |
Merging upstream version 1.69.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_ast')
-rw-r--r-- | compiler/rustc_ast/Cargo.toml | 3 | ||||
-rw-r--r-- | compiler/rustc_ast/src/ast.rs | 106 | ||||
-rw-r--r-- | compiler/rustc_ast/src/attr/mod.rs | 622 | ||||
-rw-r--r-- | compiler/rustc_ast/src/format.rs | 272 | ||||
-rw-r--r-- | compiler/rustc_ast/src/lib.rs | 3 | ||||
-rw-r--r-- | compiler/rustc_ast/src/mut_visit.rs | 58 | ||||
-rw-r--r-- | compiler/rustc_ast/src/tokenstream.rs | 42 | ||||
-rw-r--r-- | compiler/rustc_ast/src/util/comments.rs | 33 | ||||
-rw-r--r-- | compiler/rustc_ast/src/util/parser.rs | 6 | ||||
-rw-r--r-- | compiler/rustc_ast/src/util/unicode.rs | 2 | ||||
-rw-r--r-- | compiler/rustc_ast/src/visit.rs | 13 |
11 files changed, 759 insertions, 401 deletions
diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml index 9253b7e68..f0632ac92 100644 --- a/compiler/rustc_ast/Cargo.toml +++ b/compiler/rustc_ast/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" [dependencies] bitflags = "1.2.1" +memchr = "2.5.0" rustc_data_structures = { path = "../rustc_data_structures" } rustc_index = { path = "../rustc_index" } rustc_lexer = { path = "../rustc_lexer" } @@ -14,5 +15,5 @@ rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec = "0.2.9" +thin-vec = "0.2.12" tracing = "0.1" diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 9317579f7..03c375c46 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -18,6 +18,7 @@ //! - [`Attribute`]: Metadata associated with item. //! - [`UnOp`], [`BinOp`], and [`BinOpKind`]: Unary and binary operators. +pub use crate::format::*; pub use crate::util::parser::ExprPrecedence; pub use GenericArgs::*; pub use UnsafeSource::*; @@ -208,7 +209,7 @@ pub struct AngleBracketedArgs { /// The overall span. pub span: Span, /// The comma separated parts in the `<...>`. - pub args: Vec<AngleBracketedArg>, + pub args: ThinVec<AngleBracketedArg>, } /// Either an argument for a parameter e.g., `'a`, `Vec<u8>`, `0`, @@ -252,7 +253,7 @@ pub struct ParenthesizedArgs { pub span: Span, /// `(A, B)` - pub inputs: Vec<P<Ty>>, + pub inputs: ThinVec<P<Ty>>, /// ```text /// Foo(A, B) -> C @@ -383,7 +384,7 @@ impl GenericParam { /// a function, enum, trait, etc. #[derive(Clone, Encodable, Decodable, Debug)] pub struct Generics { - pub params: Vec<GenericParam>, + pub params: ThinVec<GenericParam>, pub where_clause: WhereClause, pub span: Span, } @@ -391,7 +392,7 @@ pub struct Generics { impl Default for Generics { /// Creates an instance of `Generics`. fn default() -> Generics { - Generics { params: Vec::new(), where_clause: Default::default(), span: DUMMY_SP } + Generics { params: ThinVec::new(), where_clause: Default::default(), span: DUMMY_SP } } } @@ -402,13 +403,13 @@ pub struct WhereClause { /// if we parsed no predicates (e.g. `struct Foo where {}`). /// This allows us to pretty-print accurately. pub has_where_token: bool, - pub predicates: Vec<WherePredicate>, + pub predicates: ThinVec<WherePredicate>, pub span: Span, } impl Default for WhereClause { fn default() -> WhereClause { - WhereClause { has_where_token: false, predicates: Vec::new(), span: DUMMY_SP } + WhereClause { has_where_token: false, predicates: ThinVec::new(), span: DUMMY_SP } } } @@ -440,7 +441,7 @@ impl WherePredicate { pub struct WhereBoundPredicate { pub span: Span, /// Any generics from a `for` binding. - pub bound_generic_params: Vec<GenericParam>, + pub bound_generic_params: ThinVec<GenericParam>, /// The type being bounded. pub bounded_ty: P<Ty>, /// Trait and lifetime bounds (`Clone + Send + 'static`). @@ -470,7 +471,7 @@ pub struct WhereEqPredicate { #[derive(Clone, Encodable, Decodable, Debug)] pub struct Crate { pub attrs: AttrVec, - pub items: Vec<P<Item>>, + pub items: ThinVec<P<Item>>, pub spans: ModSpans, /// Must be equal to `CRATE_NODE_ID` after the crate root is expanded, but may hold /// expansion placeholders or an unassigned value (`DUMMY_NODE_ID`) before that. @@ -502,7 +503,7 @@ pub enum MetaItemKind { /// List meta item. /// /// E.g., `#[derive(..)]`, where the field represents the `..`. - List(Vec<NestedMetaItem>), + List(ThinVec<NestedMetaItem>), /// Name value meta item. /// @@ -530,7 +531,7 @@ pub enum NestedMetaItem { #[derive(Clone, Encodable, Decodable, Debug)] pub struct Block { /// The statements in the block. - pub stmts: Vec<Stmt>, + pub stmts: ThinVec<Stmt>, pub id: NodeId, /// Distinguishes between `unsafe { ... }` and `{ ... }`. pub rules: BlockCheckMode, @@ -580,7 +581,7 @@ impl Pat { // A tuple pattern `(P0, .., Pn)` can be reparsed as `(T0, .., Tn)` // assuming `T0` to `Tn` are all syntactically valid as types. PatKind::Tuple(pats) => { - let mut tys = Vec::with_capacity(pats.len()); + let mut tys = ThinVec::with_capacity(pats.len()); // FIXME(#48994) - could just be collected into an Option<Vec> for pat in pats { tys.push(pat.to_ty()?); @@ -721,14 +722,14 @@ pub enum PatKind { /// A struct or struct variant pattern (e.g., `Variant {x, y, ..}`). /// The `bool` is `true` in the presence of a `..`. - Struct(Option<P<QSelf>>, Path, Vec<PatField>, /* recovered */ bool), + Struct(Option<P<QSelf>>, Path, ThinVec<PatField>, /* recovered */ bool), /// A tuple struct/variant pattern (`Variant(x, y, .., z)`). - TupleStruct(Option<P<QSelf>>, Path, Vec<P<Pat>>), + TupleStruct(Option<P<QSelf>>, Path, ThinVec<P<Pat>>), /// An or-pattern `A | B | C`. /// Invariant: `pats.len() >= 2`. - Or(Vec<P<Pat>>), + Or(ThinVec<P<Pat>>), /// A possibly qualified path pattern. /// Unqualified path patterns `A::B::C` can legally refer to variants, structs, constants @@ -737,7 +738,7 @@ pub enum PatKind { Path(Option<P<QSelf>>, Path), /// A tuple pattern (`(a, b)`). - Tuple(Vec<P<Pat>>), + Tuple(ThinVec<P<Pat>>), /// A `box` pattern. Box(P<Pat>), @@ -752,7 +753,7 @@ pub enum PatKind { Range(Option<P<Expr>>, Option<P<Expr>>, Spanned<RangeEnd>), /// A slice pattern `[a, b, c]`. - Slice(Vec<P<Pat>>), + Slice(ThinVec<P<Pat>>), /// A rest pattern `..`. /// @@ -1168,7 +1169,7 @@ impl Expr { pub fn to_bound(&self) -> Option<GenericBound> { match &self.kind { ExprKind::Path(None, path) => Some(GenericBound::Trait( - PolyTraitRef::new(Vec::new(), path.clone(), self.span), + PolyTraitRef::new(ThinVec::new(), path.clone(), self.span), TraitBoundModifier::None, )), _ => None, @@ -1203,7 +1204,7 @@ impl Expr { ExprKind::Array(exprs) if exprs.len() == 1 => exprs[0].to_ty().map(TyKind::Slice)?, ExprKind::Tup(exprs) => { - let tys = exprs.iter().map(|expr| expr.to_ty()).collect::<Option<Vec<_>>>()?; + let tys = exprs.iter().map(|expr| expr.to_ty()).collect::<Option<ThinVec<_>>>()?; TyKind::Tup(tys) } @@ -1269,6 +1270,7 @@ impl Expr { ExprKind::Try(..) => ExprPrecedence::Try, ExprKind::Yield(..) => ExprPrecedence::Yield, ExprKind::Yeet(..) => ExprPrecedence::Yeet, + ExprKind::FormatArgs(..) => ExprPrecedence::FormatArgs, ExprKind::Err => ExprPrecedence::Err, } } @@ -1335,7 +1337,7 @@ pub struct MethodCall { /// The receiver, e.g. `x`. pub receiver: P<Expr>, /// The arguments, e.g. `a, b, c`. - pub args: Vec<P<Expr>>, + pub args: ThinVec<P<Expr>>, /// The span of the function, without the dot and receiver e.g. `foo::<Bar, /// Baz>(a, b, c)`. pub span: Span, @@ -1355,7 +1357,7 @@ pub enum StructRest { pub struct StructExpr { pub qself: Option<P<QSelf>>, pub path: Path, - pub fields: Vec<ExprField>, + pub fields: ThinVec<ExprField>, pub rest: StructRest, } @@ -1364,7 +1366,7 @@ pub enum ExprKind { /// A `box x` expression. Box(P<Expr>), /// An array (`[a, b, c, d]`) - Array(Vec<P<Expr>>), + Array(ThinVec<P<Expr>>), /// Allow anonymous constants from an inline `const` block ConstBlock(AnonConst), /// A function call @@ -1373,11 +1375,11 @@ pub enum ExprKind { /// and the second field is the list of arguments. /// This also represents calling the constructor of /// tuple-like ADTs such as tuple structs and enum variants. - Call(P<Expr>, Vec<P<Expr>>), + Call(P<Expr>, ThinVec<P<Expr>>), /// A method call (e.g. `x.foo::<Bar, Baz>(a, b, c)`). MethodCall(Box<MethodCall>), /// A tuple (e.g., `(a, b, c, d)`). - Tup(Vec<P<Expr>>), + Tup(ThinVec<P<Expr>>), /// A binary operation (e.g., `a + b`, `a * b`). Binary(BinOp, P<Expr>, P<Expr>), /// A unary operation (e.g., `!x`, `*x`). @@ -1412,7 +1414,7 @@ pub enum ExprKind { /// `'label: loop { block }` Loop(P<Block>, Option<Label>, Span), /// A `match` block. - Match(P<Expr>, Vec<Arm>), + Match(P<Expr>, ThinVec<Arm>), /// A closure (e.g., `move |a, b, c| a + b + c`). Closure(Box<Closure>), /// A block (`'label: { ... }`). @@ -1499,6 +1501,9 @@ pub enum ExprKind { /// with a `ByteStr` literal. IncludedBytes(Lrc<[u8]>), + /// A `format_args!()` expression. + FormatArgs(P<FormatArgs>), + /// Placeholder for an expression that wasn't syntactically well formed in some way. Err, } @@ -1569,7 +1574,7 @@ pub enum ClosureBinder { /// for<'a, 'b> |_: &'a (), _: &'b ()| { ... } /// ^^^^^^ -- this /// ``` - generic_params: P<[GenericParam]>, + generic_params: ThinVec<GenericParam>, }, } @@ -1821,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(..)) @@ -2044,7 +2056,7 @@ impl Ty { pub struct BareFnTy { pub unsafety: Unsafe, pub ext: Extern, - pub generic_params: Vec<GenericParam>, + pub generic_params: ThinVec<GenericParam>, pub decl: P<FnDecl>, /// Span of the `fn(...) -> ...` part. pub decl_span: Span, @@ -2066,7 +2078,7 @@ pub enum TyKind { /// The never type (`!`). Never, /// A tuple (`(A, B, C, D,...)`). - Tup(Vec<P<Ty>>), + Tup(ThinVec<P<Ty>>), /// A path (`module::module::...::Type`), optionally /// "qualified", e.g., `<Vec<T> as SomeTrait>::SomeType`. /// @@ -2351,7 +2363,7 @@ impl Param { /// which contains metadata about function safety, asyncness, constness and ABI. #[derive(Clone, Encodable, Decodable, Debug)] pub struct FnDecl { - pub inputs: Vec<Param>, + pub inputs: ThinVec<Param>, pub output: FnRetTy, } @@ -2463,7 +2475,7 @@ pub enum ModKind { /// or with definition outlined to a separate file `mod foo;` and already loaded from it. /// The inner span is from the first token past `{` to the last token until `}`, /// or from the first to the last token in the loaded file. - Loaded(Vec<P<Item>>, Inline, ModSpans), + Loaded(ThinVec<P<Item>>, Inline, ModSpans), /// Module with definition outlined to a separate file `mod foo;` but not yet loaded from it. Unloaded, } @@ -2485,12 +2497,12 @@ pub struct ForeignMod { /// semantically by Rust. pub unsafety: Unsafe, pub abi: Option<StrLit>, - pub items: Vec<P<ForeignItem>>, + pub items: ThinVec<P<ForeignItem>>, } #[derive(Clone, Encodable, Decodable, Debug)] pub struct EnumDef { - pub variants: Vec<Variant>, + pub variants: ThinVec<Variant>, } /// Enum variant. #[derive(Clone, Encodable, Decodable, Debug)] @@ -2520,7 +2532,7 @@ pub enum UseTreeKind { /// `use prefix` or `use prefix as rename` Simple(Option<Ident>), /// `use prefix::{...}` - Nested(Vec<(UseTree, NodeId)>), + Nested(ThinVec<(UseTree, NodeId)>), /// `use prefix::*` Glob, } @@ -2624,7 +2636,7 @@ pub struct TraitRef { #[derive(Clone, Encodable, Decodable, Debug)] pub struct PolyTraitRef { /// The `'a` in `for<'a> Foo<&'a T>`. - pub bound_generic_params: Vec<GenericParam>, + pub bound_generic_params: ThinVec<GenericParam>, /// The `Foo<&'a T>` in `<'a> Foo<&'a T>`. pub trait_ref: TraitRef, @@ -2633,7 +2645,7 @@ pub struct PolyTraitRef { } impl PolyTraitRef { - pub fn new(generic_params: Vec<GenericParam>, path: Path, span: Span) -> Self { + pub fn new(generic_params: ThinVec<GenericParam>, path: Path, span: Span) -> Self { PolyTraitRef { bound_generic_params: generic_params, trait_ref: TraitRef { path, ref_id: DUMMY_NODE_ID }, @@ -2683,11 +2695,11 @@ pub enum VariantData { /// Struct variant. /// /// E.g., `Bar { .. }` as in `enum Foo { Bar { .. } }`. - Struct(Vec<FieldDef>, bool), + Struct(ThinVec<FieldDef>, bool), /// Tuple variant. /// /// E.g., `Bar(..)` as in `enum Foo { Bar(..) }`. - Tuple(Vec<FieldDef>, NodeId), + Tuple(ThinVec<FieldDef>, NodeId), /// Unit variant. /// /// E.g., `Bar = ..` as in `enum Foo { Bar = .. }`. @@ -2814,7 +2826,7 @@ pub struct Trait { pub is_auto: IsAuto, pub generics: Generics, pub bounds: GenericBounds, - pub items: Vec<P<AssocItem>>, + pub items: ThinVec<P<AssocItem>>, } /// The location of a where clause on a `TyAlias` (`Span`) and whether there was @@ -2862,7 +2874,7 @@ pub struct Impl { /// The trait being implemented, if any. pub of_trait: Option<TraitRef>, pub self_ty: P<Ty>, - pub items: Vec<P<AssocItem>>, + pub items: ThinVec<P<AssocItem>>, } #[derive(Clone, Encodable, Decodable, Debug)] @@ -3100,26 +3112,26 @@ mod size_asserts { static_assert_size!(AssocItem, 104); static_assert_size!(AssocItemKind, 32); static_assert_size!(Attribute, 32); - static_assert_size!(Block, 48); + static_assert_size!(Block, 32); static_assert_size!(Expr, 72); static_assert_size!(ExprKind, 40); - static_assert_size!(Fn, 184); + static_assert_size!(Fn, 152); static_assert_size!(ForeignItem, 96); static_assert_size!(ForeignItemKind, 24); static_assert_size!(GenericArg, 24); - static_assert_size!(GenericBound, 72); - static_assert_size!(Generics, 72); - static_assert_size!(Impl, 184); - static_assert_size!(Item, 184); - static_assert_size!(ItemKind, 112); + static_assert_size!(GenericBound, 56); + static_assert_size!(Generics, 40); + static_assert_size!(Impl, 136); + static_assert_size!(Item, 136); + static_assert_size!(ItemKind, 64); static_assert_size!(LitKind, 24); static_assert_size!(Local, 72); static_assert_size!(MetaItemLit, 40); static_assert_size!(Param, 40); - static_assert_size!(Pat, 88); + static_assert_size!(Pat, 72); static_assert_size!(Path, 24); static_assert_size!(PathSegment, 24); - static_assert_size!(PatKind, 64); + static_assert_size!(PatKind, 48); static_assert_size!(Stmt, 32); static_assert_size!(StmtKind, 16); static_assert_size!(Ty, 64); diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index c6b6207b3..2e83b3e62 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -20,7 +20,7 @@ use std::iter; use std::ops::BitXor; #[cfg(debug_assertions)] use std::sync::atomic::{AtomicU32, Ordering}; -use thin_vec::thin_vec; +use thin_vec::{thin_vec, ThinVec}; pub struct MarkedAttrs(GrowableBitSet<AttrId>); @@ -40,84 +40,65 @@ impl MarkedAttrs { } } -impl NestedMetaItem { - /// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem`. - pub fn meta_item(&self) -> Option<&MetaItem> { - match self { - NestedMetaItem::MetaItem(item) => Some(item), - _ => None, - } - } +pub struct AttrIdGenerator(WorkerLocal<Cell<u32>>); - /// Returns the `MetaItemLit` if `self` is a `NestedMetaItem::Literal`s. - pub fn lit(&self) -> Option<&MetaItemLit> { - match self { - NestedMetaItem::Lit(lit) => Some(lit), - _ => None, - } - } +#[cfg(debug_assertions)] +static MAX_ATTR_ID: AtomicU32 = AtomicU32::new(u32::MAX); - /// Returns `true` if this list item is a MetaItem with a name of `name`. - pub fn has_name(&self, name: Symbol) -> bool { - self.meta_item().map_or(false, |meta_item| meta_item.has_name(name)) - } +impl AttrIdGenerator { + pub fn new() -> Self { + // We use `(index as u32).reverse_bits()` to initialize the + // starting value of AttrId in each worker thread. + // The `index` is the index of the worker thread. + // This ensures that the AttrId generated in each thread is unique. + AttrIdGenerator(WorkerLocal::new(|index| { + let index: u32 = index.try_into().unwrap(); - /// For a single-segment meta item, returns its name; otherwise, returns `None`. - pub fn ident(&self) -> Option<Ident> { - self.meta_item().and_then(|meta_item| meta_item.ident()) - } - pub fn name_or_empty(&self) -> Symbol { - self.ident().unwrap_or_else(Ident::empty).name - } + #[cfg(debug_assertions)] + { + let max_id = ((index + 1).next_power_of_two() - 1).bitxor(u32::MAX).reverse_bits(); + MAX_ATTR_ID.fetch_min(max_id, Ordering::Release); + } - /// Gets the string value if `self` is a `MetaItem` and the `MetaItem` is a - /// `MetaItemKind::NameValue` variant containing a string, otherwise `None`. - pub fn value_str(&self) -> Option<Symbol> { - self.meta_item().and_then(|meta_item| meta_item.value_str()) + Cell::new(index.reverse_bits()) + })) } - /// Returns a name and single literal value tuple of the `MetaItem`. - pub fn name_value_literal(&self) -> Option<(Symbol, &MetaItemLit)> { - self.meta_item().and_then(|meta_item| { - meta_item.meta_item_list().and_then(|meta_item_list| { - if meta_item_list.len() == 1 - && let Some(ident) = meta_item.ident() - && let Some(lit) = meta_item_list[0].lit() - { - return Some((ident.name, lit)); - } - None - }) - }) - } + pub fn mk_attr_id(&self) -> AttrId { + let id = self.0.get(); - /// Gets a list of inner meta items from a list `MetaItem` type. - pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { - self.meta_item().and_then(|meta_item| meta_item.meta_item_list()) - } + // Ensure the assigned attr_id does not overlap the bits + // representing the number of threads. + #[cfg(debug_assertions)] + assert!(id <= MAX_ATTR_ID.load(Ordering::Acquire)); - /// Returns `true` if the variant is `MetaItem`. - pub fn is_meta_item(&self) -> bool { - self.meta_item().is_some() + self.0.set(id + 1); + AttrId::from_u32(id) } +} - /// Returns `true` if `self` is a `MetaItem` and the meta item is a word. - pub fn is_word(&self) -> bool { - self.meta_item().map_or(false, |meta_item| meta_item.is_word()) +impl Attribute { + pub fn get_normal_item(&self) -> &AttrItem { + match &self.kind { + AttrKind::Normal(normal) => &normal.item, + AttrKind::DocComment(..) => panic!("unexpected doc comment"), + } } - /// See [`MetaItem::name_value_literal_span`]. - pub fn name_value_literal_span(&self) -> Option<Span> { - self.meta_item()?.name_value_literal_span() + pub fn unwrap_normal_item(self) -> AttrItem { + match self.kind { + AttrKind::Normal(normal) => normal.into_inner().item, + AttrKind::DocComment(..) => panic!("unexpected doc comment"), + } } -} -impl Attribute { - #[inline] - pub fn has_name(&self, name: Symbol) -> bool { - match &self.kind { - AttrKind::Normal(normal) => normal.item.path == name, - AttrKind::DocComment(..) => false, + /// Returns `true` if it is a sugared doc comment (`///` or `//!` for example). + /// So `#[doc = "doc"]` (which is a doc comment) and `#[doc(...)]` (which is not + /// a doc comment) will return `false`. + pub fn is_doc_comment(&self) -> bool { + match self.kind { + AttrKind::Normal(..) => false, + AttrKind::DocComment(..) => true, } } @@ -138,20 +119,11 @@ impl Attribute { self.ident().unwrap_or_else(Ident::empty).name } - pub fn value_str(&self) -> Option<Symbol> { - match &self.kind { - AttrKind::Normal(normal) => normal.item.meta_kind().and_then(|kind| kind.value_str()), - AttrKind::DocComment(..) => None, - } - } - - pub fn meta_item_list(&self) -> Option<Vec<NestedMetaItem>> { + #[inline] + pub fn has_name(&self, name: Symbol) -> bool { match &self.kind { - AttrKind::Normal(normal) => match normal.item.meta_kind() { - Some(MetaItemKind::List(list)) => Some(list), - _ => None, - }, - AttrKind::DocComment(..) => None, + AttrKind::Normal(normal) => normal.item.path == name, + AttrKind::DocComment(..) => false, } } @@ -162,82 +134,18 @@ impl Attribute { false } } -} - -impl MetaItem { - /// For a single-segment meta item, returns its name; otherwise, returns `None`. - pub fn ident(&self) -> Option<Ident> { - if self.path.segments.len() == 1 { Some(self.path.segments[0].ident) } else { None } - } - pub fn name_or_empty(&self) -> Symbol { - self.ident().unwrap_or_else(Ident::empty).name - } - /// ```text - /// Example: - /// #[attribute(name = "value")] - /// ^^^^^^^^^^^^^^ - /// ``` - pub fn name_value_literal(&self) -> Option<&MetaItemLit> { + pub fn meta_item_list(&self) -> Option<ThinVec<NestedMetaItem>> { match &self.kind { - MetaItemKind::NameValue(v) => Some(v), - _ => None, + AttrKind::Normal(normal) => normal.item.meta_item_list(), + AttrKind::DocComment(..) => None, } } pub fn value_str(&self) -> Option<Symbol> { - self.kind.value_str() - } - - pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { match &self.kind { - MetaItemKind::List(l) => Some(&**l), - _ => None, - } - } - - pub fn is_word(&self) -> bool { - matches!(self.kind, MetaItemKind::Word) - } - - pub fn has_name(&self, name: Symbol) -> bool { - self.path == name - } - - /// This is used in case you want the value span instead of the whole attribute. Example: - /// - /// ```text - /// #[doc(alias = "foo")] - /// ``` - /// - /// In here, it'll return a span for `"foo"`. - pub fn name_value_literal_span(&self) -> Option<Span> { - Some(self.name_value_literal()?.span) - } -} - -impl AttrItem { - pub fn span(&self) -> Span { - self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span)) - } - - pub fn meta(&self, span: Span) -> Option<MetaItem> { - Some(MetaItem { path: self.path.clone(), kind: self.meta_kind()?, span }) - } - - pub fn meta_kind(&self) -> Option<MetaItemKind> { - MetaItemKind::from_attr_args(&self.args) - } -} - -impl Attribute { - /// Returns `true` if it is a sugared doc comment (`///` or `//!` for example). - /// So `#[doc = "doc"]` (which is a doc comment) and `#[doc(...)]` (which is not - /// a doc comment) will return `false`. - pub fn is_doc_comment(&self) -> bool { - match self.kind { - AttrKind::Normal(..) => false, - AttrKind::DocComment(..) => true, + AttrKind::Normal(normal) => normal.item.value_str(), + AttrKind::DocComment(..) => None, } } @@ -247,13 +155,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, } } @@ -265,9 +171,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, } } @@ -276,20 +180,6 @@ impl Attribute { self.doc_str().map_or(false, |s| comments::may_have_doc_links(s.as_str())) } - pub fn get_normal_item(&self) -> &AttrItem { - match &self.kind { - AttrKind::Normal(normal) => &normal.item, - AttrKind::DocComment(..) => panic!("unexpected doc comment"), - } - } - - pub fn unwrap_normal_item(self) -> AttrItem { - match self.kind { - AttrKind::Normal(normal) => normal.into_inner().item, - AttrKind::DocComment(..) => panic!("unexpected doc comment"), - } - } - /// Extracts the MetaItem from inside this Attribute. pub fn meta(&self) -> Option<MetaItem> { match &self.kind { @@ -321,130 +211,102 @@ impl Attribute { } } -pub struct AttrIdGenerator(WorkerLocal<Cell<u32>>); - -#[cfg(debug_assertions)] -static MAX_ATTR_ID: AtomicU32 = AtomicU32::new(u32::MAX); - -impl AttrIdGenerator { - pub fn new() -> Self { - // We use `(index as u32).reverse_bits()` to initialize the - // starting value of AttrId in each worker thread. - // The `index` is the index of the worker thread. - // This ensures that the AttrId generated in each thread is unique. - AttrIdGenerator(WorkerLocal::new(|index| { - let index: u32 = index.try_into().unwrap(); +impl AttrItem { + pub fn span(&self) -> Span { + self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span)) + } - #[cfg(debug_assertions)] - { - let max_id = ((index + 1).next_power_of_two() - 1).bitxor(u32::MAX).reverse_bits(); - MAX_ATTR_ID.fetch_min(max_id, Ordering::Release); + fn meta_item_list(&self) -> Option<ThinVec<NestedMetaItem>> { + match &self.args { + AttrArgs::Delimited(args) if args.delim == MacDelimiter::Parenthesis => { + MetaItemKind::list_from_tokens(args.tokens.clone()) } - - Cell::new(index.reverse_bits()) - })) + AttrArgs::Delimited(_) | AttrArgs::Eq(..) | AttrArgs::Empty => None, + } } - pub fn mk_attr_id(&self) -> AttrId { - let id = self.0.get(); + fn value_str(&self) -> Option<Symbol> { + match &self.args { + AttrArgs::Eq(_, args) => args.value_str(), + AttrArgs::Delimited(_) | AttrArgs::Empty => None, + } + } - // Ensure the assigned attr_id does not overlap the bits - // representing the number of threads. - #[cfg(debug_assertions)] - assert!(id <= MAX_ATTR_ID.load(Ordering::Acquire)); + pub fn meta(&self, span: Span) -> Option<MetaItem> { + Some(MetaItem { path: self.path.clone(), kind: self.meta_kind()?, span }) + } - self.0.set(id + 1); - AttrId::from_u32(id) + pub fn meta_kind(&self) -> Option<MetaItemKind> { + MetaItemKind::from_attr_args(&self.args) } } -pub fn mk_attr( - g: &AttrIdGenerator, - style: AttrStyle, - path: Path, - args: AttrArgs, - span: Span, -) -> Attribute { - mk_attr_from_item(g, AttrItem { path, args, tokens: None }, None, style, span) +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(), + } + } } -pub fn mk_attr_from_item( - g: &AttrIdGenerator, - item: AttrItem, - tokens: Option<LazyAttrTokenStream>, - style: AttrStyle, - span: Span, -) -> Attribute { - Attribute { - kind: AttrKind::Normal(P(NormalAttr { item, tokens })), - id: g.mk_attr_id(), - style, - span, +impl MetaItem { + /// For a single-segment meta item, returns its name; otherwise, returns `None`. + pub fn ident(&self) -> Option<Ident> { + if self.path.segments.len() == 1 { Some(self.path.segments[0].ident) } else { None } } -} -pub fn mk_attr_word(g: &AttrIdGenerator, style: AttrStyle, name: Symbol, span: Span) -> Attribute { - let path = Path::from_ident(Ident::new(name, span)); - let args = AttrArgs::Empty; - mk_attr(g, style, path, args, span) -} + pub fn name_or_empty(&self) -> Symbol { + self.ident().unwrap_or_else(Ident::empty).name + } -pub fn mk_attr_name_value_str( - g: &AttrIdGenerator, - style: AttrStyle, - name: Symbol, - val: Symbol, - span: Span, -) -> Attribute { - let lit = token::Lit::new(token::Str, escape_string_symbol(val), None); - let expr = P(Expr { - id: DUMMY_NODE_ID, - kind: ExprKind::Lit(lit), - span, - attrs: AttrVec::new(), - tokens: None, - }); - let path = Path::from_ident(Ident::new(name, span)); - let args = AttrArgs::Eq(span, AttrArgsEq::Ast(expr)); - mk_attr(g, style, path, args, span) -} + pub fn has_name(&self, name: Symbol) -> bool { + self.path == name + } -pub fn mk_attr_nested_word( - g: &AttrIdGenerator, - style: AttrStyle, - outer: Symbol, - inner: Symbol, - span: Span, -) -> Attribute { - let inner_tokens = TokenStream::new(vec![TokenTree::Token( - Token::from_ast_ident(Ident::new(inner, span)), - Spacing::Alone, - )]); - let outer_ident = Ident::new(outer, span); - let path = Path::from_ident(outer_ident); - let attr_args = AttrArgs::Delimited(DelimArgs { - dspan: DelimSpan::from_single(span), - delim: MacDelimiter::Parenthesis, - tokens: inner_tokens, - }); - mk_attr(g, style, path, attr_args, span) -} + pub fn is_word(&self) -> bool { + matches!(self.kind, MetaItemKind::Word) + } -pub fn mk_doc_comment( - g: &AttrIdGenerator, - comment_kind: CommentKind, - style: AttrStyle, - data: Symbol, - span: Span, -) -> Attribute { - Attribute { kind: AttrKind::DocComment(comment_kind, data), id: g.mk_attr_id(), style, span } -} + pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { + match &self.kind { + MetaItemKind::List(l) => Some(&**l), + _ => None, + } + } -pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool { - items.iter().any(|item| item.has_name(name)) -} + /// ```text + /// Example: + /// #[attribute(name = "value")] + /// ^^^^^^^^^^^^^^ + /// ``` + pub fn name_value_literal(&self) -> Option<&MetaItemLit> { + match &self.kind { + MetaItemKind::NameValue(v) => Some(v), + _ => None, + } + } + + /// This is used in case you want the value span instead of the whole attribute. Example: + /// + /// ```text + /// #[doc(alias = "foo")] + /// ``` + /// + /// In here, it'll return a span for `"foo"`. + pub fn name_value_literal_span(&self) -> Option<Span> { + Some(self.name_value_literal()?.span) + } + + pub fn value_str(&self) -> Option<Symbol> { + self.kind.value_str() + } -impl MetaItem { fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItem> where I: Iterator<Item = TokenTree>, @@ -508,17 +370,14 @@ 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<ThinVec<NestedMetaItem>> { let mut tokens = tokens.into_trees().peekable(); - let mut result = Vec::new(); + let mut result = ThinVec::new(); while tokens.peek().is_some() { let item = NestedMetaItem::from_tokens(&mut tokens)?; result.push(item); @@ -527,7 +386,7 @@ impl MetaItemKind { _ => return None, } } - Some(MetaItemKind::List(result)) + Some(result) } fn name_value_from_tokens( @@ -544,6 +403,24 @@ impl MetaItemKind { } } + fn from_tokens( + tokens: &mut iter::Peekable<impl Iterator<Item = TokenTree>>, + ) -> Option<MetaItemKind> { + match tokens.peek() { + Some(TokenTree::Delimited(_, Delimiter::Parenthesis, inner_tokens)) => { + let inner_tokens = inner_tokens.clone(); + tokens.next(); + MetaItemKind::list_from_tokens(inner_tokens).map(MetaItemKind::List) + } + Some(TokenTree::Delimited(..)) => None, + Some(TokenTree::Token(Token { kind: token::Eq, .. }, _)) => { + tokens.next(); + MetaItemKind::name_value_from_tokens(tokens) + } + _ => Some(MetaItemKind::Word), + } + } + fn from_attr_args(args: &AttrArgs) -> Option<MetaItemKind> { match args { AttrArgs::Empty => Some(MetaItemKind::Word), @@ -551,7 +428,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) => { @@ -565,24 +442,6 @@ impl MetaItemKind { AttrArgs::Eq(_, AttrArgsEq::Hir(lit)) => Some(MetaItemKind::NameValue(lit.clone())), } } - - fn from_tokens( - tokens: &mut iter::Peekable<impl Iterator<Item = TokenTree>>, - ) -> Option<MetaItemKind> { - match tokens.peek() { - Some(TokenTree::Delimited(_, Delimiter::Parenthesis, inner_tokens)) => { - let inner_tokens = inner_tokens.clone(); - tokens.next(); - MetaItemKind::list_from_tokens(inner_tokens) - } - Some(TokenTree::Delimited(..)) => None, - Some(TokenTree::Token(Token { kind: token::Eq, .. }, _)) => { - tokens.next(); - MetaItemKind::name_value_from_tokens(tokens) - } - _ => Some(MetaItemKind::Word), - } - } } impl NestedMetaItem { @@ -593,6 +452,77 @@ impl NestedMetaItem { } } + /// For a single-segment meta item, returns its name; otherwise, returns `None`. + pub fn ident(&self) -> Option<Ident> { + self.meta_item().and_then(|meta_item| meta_item.ident()) + } + + pub fn name_or_empty(&self) -> Symbol { + self.ident().unwrap_or_else(Ident::empty).name + } + + /// Returns `true` if this list item is a MetaItem with a name of `name`. + pub fn has_name(&self, name: Symbol) -> bool { + self.meta_item().map_or(false, |meta_item| meta_item.has_name(name)) + } + + /// Returns `true` if `self` is a `MetaItem` and the meta item is a word. + pub fn is_word(&self) -> bool { + self.meta_item().map_or(false, |meta_item| meta_item.is_word()) + } + + /// Gets a list of inner meta items from a list `MetaItem` type. + pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { + self.meta_item().and_then(|meta_item| meta_item.meta_item_list()) + } + + /// Returns a name and single literal value tuple of the `MetaItem`. + pub fn name_value_literal(&self) -> Option<(Symbol, &MetaItemLit)> { + self.meta_item().and_then(|meta_item| { + meta_item.meta_item_list().and_then(|meta_item_list| { + if meta_item_list.len() == 1 + && let Some(ident) = meta_item.ident() + && let Some(lit) = meta_item_list[0].lit() + { + return Some((ident.name, lit)); + } + None + }) + }) + } + + /// See [`MetaItem::name_value_literal_span`]. + pub fn name_value_literal_span(&self) -> Option<Span> { + self.meta_item()?.name_value_literal_span() + } + + /// Gets the string value if `self` is a `MetaItem` and the `MetaItem` is a + /// `MetaItemKind::NameValue` variant containing a string, otherwise `None`. + pub fn value_str(&self) -> Option<Symbol> { + self.meta_item().and_then(|meta_item| meta_item.value_str()) + } + + /// Returns the `MetaItemLit` if `self` is a `NestedMetaItem::Literal`s. + pub fn lit(&self) -> Option<&MetaItemLit> { + match self { + NestedMetaItem::Lit(lit) => Some(lit), + _ => None, + } + } + + /// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem`. + pub fn meta_item(&self) -> Option<&MetaItem> { + match self { + NestedMetaItem::MetaItem(item) => Some(item), + _ => None, + } + } + + /// Returns `true` if the variant is `MetaItem`. + pub fn is_meta_item(&self) -> bool { + self.meta_item().is_some() + } + fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<NestedMetaItem> where I: Iterator<Item = TokenTree>, @@ -614,3 +544,89 @@ impl NestedMetaItem { MetaItem::from_tokens(tokens).map(NestedMetaItem::MetaItem) } } + +pub fn mk_doc_comment( + g: &AttrIdGenerator, + comment_kind: CommentKind, + style: AttrStyle, + data: Symbol, + span: Span, +) -> Attribute { + Attribute { kind: AttrKind::DocComment(comment_kind, data), id: g.mk_attr_id(), style, span } +} + +pub fn mk_attr( + g: &AttrIdGenerator, + style: AttrStyle, + path: Path, + args: AttrArgs, + span: Span, +) -> Attribute { + mk_attr_from_item(g, AttrItem { path, args, tokens: None }, None, style, span) +} + +pub fn mk_attr_from_item( + g: &AttrIdGenerator, + item: AttrItem, + tokens: Option<LazyAttrTokenStream>, + style: AttrStyle, + span: Span, +) -> Attribute { + Attribute { + kind: AttrKind::Normal(P(NormalAttr { item, tokens })), + id: g.mk_attr_id(), + style, + span, + } +} + +pub fn mk_attr_word(g: &AttrIdGenerator, style: AttrStyle, name: Symbol, span: Span) -> Attribute { + let path = Path::from_ident(Ident::new(name, span)); + let args = AttrArgs::Empty; + mk_attr(g, style, path, args, span) +} + +pub fn mk_attr_nested_word( + g: &AttrIdGenerator, + style: AttrStyle, + outer: Symbol, + inner: Symbol, + span: Span, +) -> Attribute { + let inner_tokens = TokenStream::new(vec![TokenTree::Token( + Token::from_ast_ident(Ident::new(inner, span)), + Spacing::Alone, + )]); + let outer_ident = Ident::new(outer, span); + let path = Path::from_ident(outer_ident); + let attr_args = AttrArgs::Delimited(DelimArgs { + dspan: DelimSpan::from_single(span), + delim: MacDelimiter::Parenthesis, + tokens: inner_tokens, + }); + mk_attr(g, style, path, attr_args, span) +} + +pub fn mk_attr_name_value_str( + g: &AttrIdGenerator, + style: AttrStyle, + name: Symbol, + val: Symbol, + span: Span, +) -> Attribute { + let lit = token::Lit::new(token::Str, escape_string_symbol(val), None); + let expr = P(Expr { + id: DUMMY_NODE_ID, + kind: ExprKind::Lit(lit), + span, + attrs: AttrVec::new(), + tokens: None, + }); + let path = Path::from_ident(Ident::new(name, span)); + let args = AttrArgs::Eq(span, AttrArgsEq::Ast(expr)); + mk_attr(g, style, path, args, span) +} + +pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool { + items.iter().any(|item| item.has_name(name)) +} diff --git a/compiler/rustc_ast/src/format.rs b/compiler/rustc_ast/src/format.rs new file mode 100644 index 000000000..d021bea5e --- /dev/null +++ b/compiler/rustc_ast/src/format.rs @@ -0,0 +1,272 @@ +use crate::ptr::P; +use crate::Expr; +use rustc_data_structures::fx::FxHashMap; +use rustc_span::symbol::{Ident, Symbol}; +use rustc_span::Span; + +// Definitions: +// +// format_args!("hello {abc:.xyz$}!!", abc="world"); +// └──────────────────────────────────────────────┘ +// FormatArgs +// +// format_args!("hello {abc:.xyz$}!!", abc="world"); +// └─────────┘ +// argument +// +// format_args!("hello {abc:.xyz$}!!", abc="world"); +// └───────────────────┘ +// template +// +// format_args!("hello {abc:.xyz$}!!", abc="world"); +// └────┘└─────────┘└┘ +// pieces +// +// format_args!("hello {abc:.xyz$}!!", abc="world"); +// └────┘ └┘ +// literal pieces +// +// format_args!("hello {abc:.xyz$}!!", abc="world"); +// └─────────┘ +// placeholder +// +// format_args!("hello {abc:.xyz$}!!", abc="world"); +// └─┘ └─┘ +// positions (could be names, numbers, empty, or `*`) + +/// (Parsed) format args. +/// +/// Basically the "AST" for a complete `format_args!()`. +/// +/// E.g., `format_args!("hello {name}");`. +#[derive(Clone, Encodable, Decodable, Debug)] +pub struct FormatArgs { + pub span: Span, + pub template: Vec<FormatArgsPiece>, + pub arguments: FormatArguments, +} + +/// A piece of a format template string. +/// +/// E.g. "hello" or "{name}". +#[derive(Clone, Encodable, Decodable, Debug)] +pub enum FormatArgsPiece { + Literal(Symbol), + Placeholder(FormatPlaceholder), +} + +/// The arguments to format_args!(). +/// +/// E.g. `1, 2, name="ferris", n=3`, +/// but also implicit captured arguments like `x` in `format_args!("{x}")`. +#[derive(Clone, Encodable, Decodable, Debug)] +pub struct FormatArguments { + arguments: Vec<FormatArgument>, + num_unnamed_args: usize, + num_explicit_args: usize, + names: FxHashMap<Symbol, usize>, +} + +// FIXME: Rustdoc has trouble proving Send/Sync for this. See #106930. +#[cfg(parallel_compiler)] +unsafe impl Sync for FormatArguments {} +#[cfg(parallel_compiler)] +unsafe impl Send for FormatArguments {} + +impl FormatArguments { + pub fn new() -> Self { + Self { + arguments: Vec::new(), + names: FxHashMap::default(), + num_unnamed_args: 0, + num_explicit_args: 0, + } + } + + pub fn add(&mut self, arg: FormatArgument) -> usize { + let index = self.arguments.len(); + if let Some(name) = arg.kind.ident() { + self.names.insert(name.name, index); + } else if self.names.is_empty() { + // Only count the unnamed args before the first named arg. + // (Any later ones are errors.) + self.num_unnamed_args += 1; + } + if !matches!(arg.kind, FormatArgumentKind::Captured(..)) { + // This is an explicit argument. + // Make sure that all arguments so far are explcit. + assert_eq!( + self.num_explicit_args, + self.arguments.len(), + "captured arguments must be added last" + ); + self.num_explicit_args += 1; + } + self.arguments.push(arg); + index + } + + pub fn by_name(&self, name: Symbol) -> Option<(usize, &FormatArgument)> { + let i = *self.names.get(&name)?; + Some((i, &self.arguments[i])) + } + + pub fn by_index(&self, i: usize) -> Option<&FormatArgument> { + (i < self.num_explicit_args).then(|| &self.arguments[i]) + } + + pub fn unnamed_args(&self) -> &[FormatArgument] { + &self.arguments[..self.num_unnamed_args] + } + + pub fn named_args(&self) -> &[FormatArgument] { + &self.arguments[self.num_unnamed_args..self.num_explicit_args] + } + + pub fn explicit_args(&self) -> &[FormatArgument] { + &self.arguments[..self.num_explicit_args] + } + + pub fn all_args(&self) -> &[FormatArgument] { + &self.arguments[..] + } + + pub fn all_args_mut(&mut self) -> &mut [FormatArgument] { + &mut self.arguments[..] + } +} + +#[derive(Clone, Encodable, Decodable, Debug)] +pub struct FormatArgument { + pub kind: FormatArgumentKind, + pub expr: P<Expr>, +} + +#[derive(Clone, Encodable, Decodable, Debug)] +pub enum FormatArgumentKind { + /// `format_args(…, arg)` + Normal, + /// `format_args(…, arg = 1)` + Named(Ident), + /// `format_args("… {arg} …")` + Captured(Ident), +} + +impl FormatArgumentKind { + pub fn ident(&self) -> Option<Ident> { + match self { + &Self::Normal => None, + &Self::Named(id) => Some(id), + &Self::Captured(id) => Some(id), + } + } +} + +#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)] +pub struct FormatPlaceholder { + /// Index into [`FormatArgs::arguments`]. + pub argument: FormatArgPosition, + /// The span inside the format string for the full `{…}` placeholder. + pub span: Option<Span>, + /// `{}`, `{:?}`, or `{:x}`, etc. + pub format_trait: FormatTrait, + /// `{}` or `{:.5}` or `{:-^20}`, etc. + pub format_options: FormatOptions, +} + +#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)] +pub struct FormatArgPosition { + /// Which argument this position refers to (Ok), + /// or would've referred to if it existed (Err). + pub index: Result<usize, usize>, + /// What kind of position this is. See [`FormatArgPositionKind`]. + pub kind: FormatArgPositionKind, + /// The span of the name or number. + pub span: Option<Span>, +} + +#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)] +pub enum FormatArgPositionKind { + /// `{}` or `{:.*}` + Implicit, + /// `{1}` or `{:1$}` or `{:.1$}` + Number, + /// `{a}` or `{:a$}` or `{:.a$}` + Named, +} + +#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq, Hash)] +pub enum FormatTrait { + /// `{}` + Display, + /// `{:?}` + Debug, + /// `{:e}` + LowerExp, + /// `{:E}` + UpperExp, + /// `{:o}` + Octal, + /// `{:p}` + Pointer, + /// `{:b}` + Binary, + /// `{:x}` + LowerHex, + /// `{:X}` + UpperHex, +} + +#[derive(Clone, Encodable, Decodable, Default, Debug, PartialEq, Eq)] +pub struct FormatOptions { + /// The width. E.g. `{:5}` or `{:width$}`. + pub width: Option<FormatCount>, + /// The precision. E.g. `{:.5}` or `{:.precision$}`. + pub precision: Option<FormatCount>, + /// The alignment. E.g. `{:>}` or `{:<}` or `{:^}`. + pub alignment: Option<FormatAlignment>, + /// The fill character. E.g. the `.` in `{:.>10}`. + pub fill: Option<char>, + /// The `+` or `-` flag. + pub sign: Option<FormatSign>, + /// The `#` flag. + pub alternate: bool, + /// The `0` flag. E.g. the `0` in `{:02x}`. + pub zero_pad: bool, + /// The `x` or `X` flag (for `Debug` only). E.g. the `x` in `{:x?}`. + pub debug_hex: Option<FormatDebugHex>, +} + +#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)] +pub enum FormatSign { + /// The `+` flag. + Plus, + /// The `-` flag. + Minus, +} + +#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)] +pub enum FormatDebugHex { + /// The `x` flag in `{:x?}`. + Lower, + /// The `X` flag in `{:X?}`. + Upper, +} + +#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)] +pub enum FormatAlignment { + /// `{:<}` + Left, + /// `{:>}` + Right, + /// `{:^}` + Center, +} + +#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)] +pub enum FormatCount { + /// `{:5}` or `{:.5}` + Literal(usize), + /// `{:.*}`, `{:.5$}`, or `{:a$}`, etc. + Argument(FormatArgPosition), +} diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 9c1dfeb1a..23c32fa96 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -16,7 +16,6 @@ #![feature(let_chains)] #![feature(min_specialization)] #![feature(negative_impls)] -#![feature(slice_internals)] #![feature(stmt_expr_attributes)] #![recursion_limit = "256"] #![deny(rustc::untranslatable_diagnostic)] @@ -42,6 +41,7 @@ pub mod ast_traits; pub mod attr; pub mod entry; pub mod expand; +pub mod format; pub mod mut_visit; pub mod node_id; pub mod ptr; @@ -51,6 +51,7 @@ pub mod visit; pub use self::ast::*; pub use self::ast_traits::{AstDeref, AstNodeWrapper, HasAttrs, HasNodeId, HasSpan, HasTokens}; +pub use self::format::*; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 77f342d1e..7dcb03b4c 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -17,10 +17,10 @@ use rustc_data_structures::sync::Lrc; use rustc_span::source_map::Spanned; use rustc_span::symbol::Ident; use rustc_span::Span; - use smallvec::{smallvec, Array, SmallVec}; use std::ops::DerefMut; use std::{panic, ptr}; +use thin_vec::ThinVec; pub trait ExpectOne<A: Array> { fn expect_one(self, err: &'static str) -> A::Item; @@ -297,6 +297,10 @@ pub trait MutVisitor: Sized { fn visit_inline_asm_sym(&mut self, sym: &mut InlineAsmSym) { noop_visit_inline_asm_sym(sym, self) } + + fn visit_format_args(&mut self, fmt: &mut FormatArgs) { + noop_visit_format_args(fmt, self) + } } /// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful @@ -333,6 +337,17 @@ where // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. #[inline] +pub fn visit_thin_vec<T, F>(elems: &mut ThinVec<T>, mut visit_elem: F) +where + F: FnMut(&mut T), +{ + for elem in elems { + visit_elem(elem); + } +} + +// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. +#[inline] pub fn visit_opt<T, F>(opt: &mut Option<T>, mut visit_elem: F) where F: FnMut(&mut T), @@ -355,6 +370,11 @@ pub fn visit_exprs<T: MutVisitor>(exprs: &mut Vec<P<Expr>>, vis: &mut T) { } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. +pub fn visit_thin_exprs<T: MutVisitor>(exprs: &mut ThinVec<P<Expr>>, vis: &mut T) { + exprs.flat_map_in_place(|expr| vis.filter_map_expr(expr)) +} + +// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. pub fn visit_bounds<T: MutVisitor>(bounds: &mut GenericBounds, vis: &mut T) { visit_vec(bounds, |bound| vis.visit_param_bound(bound)); } @@ -470,7 +490,7 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) { vis.visit_fn_decl(decl); vis.visit_span(decl_span); } - TyKind::Tup(tys) => visit_vec(tys, |ty| vis.visit_ty(ty)), + TyKind::Tup(tys) => visit_thin_vec(tys, |ty| vis.visit_ty(ty)), TyKind::Paren(ty) => vis.visit_ty(ty), TyKind::Path(qself, path) => { vis.visit_qself(qself); @@ -557,7 +577,7 @@ pub fn noop_visit_angle_bracketed_parameter_data<T: MutVisitor>( vis: &mut T, ) { let AngleBracketedArgs { args, span } = data; - visit_vec(args, |arg| match arg { + visit_thin_vec(args, |arg| match arg { AngleBracketedArg::Arg(arg) => vis.visit_generic_arg(arg), AngleBracketedArg::Constraint(constraint) => vis.visit_constraint(constraint), }); @@ -569,7 +589,7 @@ pub fn noop_visit_parenthesized_parameter_data<T: MutVisitor>( vis: &mut T, ) { let ParenthesizedArgs { inputs, output, span, .. } = args; - visit_vec(inputs, |input| vis.visit_ty(input)); + visit_thin_vec(inputs, |input| vis.visit_ty(input)); noop_visit_fn_ret_ty(output, vis); vis.visit_span(span); } @@ -632,7 +652,7 @@ pub fn noop_visit_meta_item<T: MutVisitor>(mi: &mut MetaItem, vis: &mut T) { let MetaItem { path: _, kind, span } = mi; match kind { MetaItemKind::Word => {} - MetaItemKind::List(mis) => visit_vec(mis, |mi| vis.visit_meta_list_item(mi)), + MetaItemKind::List(mis) => visit_thin_vec(mis, |mi| vis.visit_meta_list_item(mi)), MetaItemKind::NameValue(_s) => {} } vis.visit_span(span); @@ -835,9 +855,7 @@ pub fn noop_visit_closure_binder<T: MutVisitor>(binder: &mut ClosureBinder, vis: match binder { ClosureBinder::NotPresent => {} ClosureBinder::For { span: _, generic_params } => { - let mut vec = std::mem::take(generic_params).into_vec(); - vec.flat_map_in_place(|param| vis.flat_map_generic_param(param)); - *generic_params = P::from_vec(vec); + generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); } } } @@ -915,7 +933,7 @@ pub fn noop_visit_generics<T: MutVisitor>(generics: &mut Generics, vis: &mut T) pub fn noop_visit_where_clause<T: MutVisitor>(wc: &mut WhereClause, vis: &mut T) { let WhereClause { has_where_token: _, predicates, span } = wc; - visit_vec(predicates, |predicate| vis.visit_where_predicate(predicate)); + visit_thin_vec(predicates, |predicate| vis.visit_where_predicate(predicate)); vis.visit_span(span); } @@ -1223,7 +1241,7 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) { PatKind::TupleStruct(qself, path, elems) => { vis.visit_qself(qself); vis.visit_path(path); - visit_vec(elems, |elem| vis.visit_pat(elem)); + visit_thin_vec(elems, |elem| vis.visit_pat(elem)); } PatKind::Path(qself, path) => { vis.visit_qself(qself); @@ -1242,7 +1260,7 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) { vis.visit_span(span); } PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => { - visit_vec(elems, |elem| vis.visit_pat(elem)) + visit_thin_vec(elems, |elem| vis.visit_pat(elem)) } PatKind::Paren(inner) => vis.visit_pat(inner), PatKind::MacCall(mac) => vis.visit_mac_call(mac), @@ -1284,13 +1302,22 @@ pub fn noop_visit_inline_asm_sym<T: MutVisitor>( vis.visit_path(path); } +pub fn noop_visit_format_args<T: MutVisitor>(fmt: &mut FormatArgs, vis: &mut T) { + for arg in fmt.arguments.all_args_mut() { + if let FormatArgumentKind::Named(name) = &mut arg.kind { + vis.visit_ident(name); + } + vis.visit_expr(&mut arg.expr); + } +} + pub fn noop_visit_expr<T: MutVisitor>( Expr { kind, id, span, attrs, tokens }: &mut Expr, vis: &mut T, ) { match kind { ExprKind::Box(expr) => vis.visit_expr(expr), - ExprKind::Array(exprs) => visit_exprs(exprs, vis), + ExprKind::Array(exprs) => visit_thin_exprs(exprs, vis), ExprKind::ConstBlock(anon_const) => { vis.visit_anon_const(anon_const); } @@ -1298,10 +1325,10 @@ pub fn noop_visit_expr<T: MutVisitor>( vis.visit_expr(expr); vis.visit_anon_const(count); } - ExprKind::Tup(exprs) => visit_exprs(exprs, vis), + ExprKind::Tup(exprs) => visit_thin_exprs(exprs, vis), ExprKind::Call(f, args) => { vis.visit_expr(f); - visit_exprs(args, vis); + visit_thin_exprs(args, vis); } ExprKind::MethodCall(box MethodCall { seg: PathSegment { ident, id, args: seg_args }, @@ -1313,7 +1340,7 @@ pub fn noop_visit_expr<T: MutVisitor>( vis.visit_id(id); visit_opt(seg_args, |args| vis.visit_generic_args(args)); vis.visit_method_receiver_expr(receiver); - visit_exprs(call_args, vis); + visit_thin_exprs(call_args, vis); vis.visit_span(span); } ExprKind::Binary(_binop, lhs, rhs) => { @@ -1425,6 +1452,7 @@ pub fn noop_visit_expr<T: MutVisitor>( visit_opt(expr, |expr| vis.visit_expr(expr)); } ExprKind::InlineAsm(asm) => vis.visit_inline_asm(asm), + ExprKind::FormatArgs(fmt) => vis.visit_format_args(fmt), ExprKind::MacCall(mac) => vis.visit_mac_call(mac), ExprKind::Struct(se) => { let StructExpr { qself, path, fields, rest } = se.deref_mut(); diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index fabd43a16..f0a6a5e07 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -41,7 +41,8 @@ use std::{fmt, iter}; /// Nothing special happens to misnamed or misplaced `SubstNt`s. #[derive(Debug, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)] pub enum TokenTree { - /// A single token. + /// A single token. Should never be `OpenDelim` or `CloseDelim`, because + /// delimiters are implicitly represented by `Delimited`. Token(Token, Spacing), /// A delimited sequence of token trees. Delimited(DelimSpan, Delimiter, TokenStream), @@ -388,12 +389,12 @@ impl TokenStream { self.0.len() } - pub fn trees(&self) -> CursorRef<'_> { - CursorRef::new(self) + pub fn trees(&self) -> RefTokenTreeCursor<'_> { + RefTokenTreeCursor::new(self) } - pub fn into_trees(self) -> Cursor { - Cursor::new(self) + pub fn into_trees(self) -> TokenTreeCursor { + TokenTreeCursor::new(self) } /// Compares two `TokenStream`s, checking equality without regarding span information. @@ -551,16 +552,17 @@ impl TokenStream { } } -/// By-reference iterator over a [`TokenStream`]. +/// By-reference iterator over a [`TokenStream`], that produces `&TokenTree` +/// items. #[derive(Clone)] -pub struct CursorRef<'t> { +pub struct RefTokenTreeCursor<'t> { stream: &'t TokenStream, index: usize, } -impl<'t> CursorRef<'t> { +impl<'t> RefTokenTreeCursor<'t> { fn new(stream: &'t TokenStream) -> Self { - CursorRef { stream, index: 0 } + RefTokenTreeCursor { stream, index: 0 } } pub fn look_ahead(&self, n: usize) -> Option<&TokenTree> { @@ -568,7 +570,7 @@ impl<'t> CursorRef<'t> { } } -impl<'t> Iterator for CursorRef<'t> { +impl<'t> Iterator for RefTokenTreeCursor<'t> { type Item = &'t TokenTree; fn next(&mut self) -> Option<&'t TokenTree> { @@ -579,15 +581,16 @@ impl<'t> Iterator for CursorRef<'t> { } } -/// Owning by-value iterator over a [`TokenStream`]. +/// Owning by-value iterator over a [`TokenStream`], that produces `TokenTree` +/// items. // FIXME: Many uses of this can be replaced with by-reference iterator to avoid clones. #[derive(Clone)] -pub struct Cursor { +pub struct TokenTreeCursor { pub stream: TokenStream, index: usize, } -impl Iterator for Cursor { +impl Iterator for TokenTreeCursor { type Item = TokenTree; fn next(&mut self) -> Option<TokenTree> { @@ -598,9 +601,9 @@ impl Iterator for Cursor { } } -impl Cursor { +impl TokenTreeCursor { fn new(stream: TokenStream) -> Self { - Cursor { stream, index: 0 } + TokenTreeCursor { stream, index: 0 } } #[inline] @@ -614,6 +617,15 @@ impl Cursor { pub fn look_ahead(&self, n: usize) -> Option<&TokenTree> { self.stream.0.get(self.index + n) } + + // Replace the previously obtained token tree with `tts`, and rewind to + // just before them. + pub fn replace_prev_and_rewind(&mut self, tts: Vec<TokenTree>) { + assert!(self.index > 0); + self.index -= 1; + let stream = Lrc::make_mut(&mut self.stream.0); + stream.splice(self.index..self.index + 1, tts); + } } #[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)] diff --git a/compiler/rustc_ast/src/util/comments.rs b/compiler/rustc_ast/src/util/comments.rs index 275ed02c2..eece99a3e 100644 --- a/compiler/rustc_ast/src/util/comments.rs +++ b/compiler/rustc_ast/src/util/comments.rs @@ -58,23 +58,24 @@ pub fn beautify_doc_string(data: Symbol, kind: CommentKind) -> Symbol { // In case we have doc comments like `/**` or `/*!`, we want to remove stars if they are // present. However, we first need to strip the empty lines so they don't get in the middle // when we try to compute the "horizontal trim". - let lines = if kind == CommentKind::Block { - // Whatever happens, we skip the first line. - let mut i = lines - .get(0) - .map(|l| if l.trim_start().starts_with('*') { 0 } else { 1 }) - .unwrap_or(0); - let mut j = lines.len(); - - while i < j && lines[i].trim().is_empty() { - i += 1; - } - while j > i && lines[j - 1].trim().is_empty() { - j -= 1; + let lines = match kind { + CommentKind::Block => { + // Whatever happens, we skip the first line. + let mut i = lines + .get(0) + .map(|l| if l.trim_start().starts_with('*') { 0 } else { 1 }) + .unwrap_or(0); + let mut j = lines.len(); + + while i < j && lines[i].trim().is_empty() { + i += 1; + } + while j > i && lines[j - 1].trim().is_empty() { + j -= 1; + } + &lines[i..j] } - &lines[i..j] - } else { - lines + CommentKind::Line => lines, }; for line in lines { diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs index 4f7099c7b..3a0af04f9 100644 --- a/compiler/rustc_ast/src/util/parser.rs +++ b/compiler/rustc_ast/src/util/parser.rs @@ -225,7 +225,7 @@ impl AssocOp { AssignOp(_) | // `{ 42 } +=` As | // `{ 42 } as usize` // Equal | // `{ 42 } == { 42 }` Accepting these here would regress incorrect - // NotEqual | // `{ 42 } != { 42 } struct literals parser recovery. + // NotEqual | // `{ 42 } != { 42 }` struct literals parser recovery. Colon, // `{ 42 }: usize` ) } @@ -271,6 +271,7 @@ pub enum ExprPrecedence { Try, InlineAsm, Mac, + FormatArgs, Array, Repeat, @@ -335,7 +336,8 @@ impl ExprPrecedence { | ExprPrecedence::Index | ExprPrecedence::Try | ExprPrecedence::InlineAsm - | ExprPrecedence::Mac => PREC_POSTFIX, + | ExprPrecedence::Mac + | ExprPrecedence::FormatArgs => PREC_POSTFIX, // Never need parens ExprPrecedence::Array diff --git a/compiler/rustc_ast/src/util/unicode.rs b/compiler/rustc_ast/src/util/unicode.rs index 0eae791b2..6f57d66b2 100644 --- a/compiler/rustc_ast/src/util/unicode.rs +++ b/compiler/rustc_ast/src/util/unicode.rs @@ -17,7 +17,7 @@ pub fn contains_text_flow_control_chars(s: &str) -> bool { // U+2069 - E2 81 A9 let mut bytes = s.as_bytes(); loop { - match core::slice::memchr::memchr(0xE2, bytes) { + match memchr::memchr(0xE2, bytes) { Some(idx) => { // bytes are valid UTF-8 -> E2 must be followed by two bytes let ch = &bytes[idx..idx + 3]; diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index e8823eff8..bdb1879ec 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -242,6 +242,9 @@ pub trait Visitor<'ast>: Sized { fn visit_inline_asm(&mut self, asm: &'ast InlineAsm) { walk_inline_asm(self, asm) } + fn visit_format_args(&mut self, fmt: &'ast FormatArgs) { + walk_format_args(self, fmt) + } fn visit_inline_asm_sym(&mut self, sym: &'ast InlineAsmSym) { walk_inline_asm_sym(self, sym) } @@ -756,6 +759,15 @@ pub fn walk_inline_asm_sym<'a, V: Visitor<'a>>(visitor: &mut V, sym: &'a InlineA visitor.visit_path(&sym.path, sym.id); } +pub fn walk_format_args<'a, V: Visitor<'a>>(visitor: &mut V, fmt: &'a FormatArgs) { + for arg in fmt.arguments.all_args() { + if let FormatArgumentKind::Named(name) = arg.kind { + visitor.visit_ident(name); + } + visitor.visit_expr(&arg.expr); + } +} + pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { walk_list!(visitor, visit_attribute, expression.attrs.iter()); @@ -896,6 +908,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { ExprKind::MacCall(mac) => visitor.visit_mac_call(mac), ExprKind::Paren(subexpression) => visitor.visit_expr(subexpression), ExprKind::InlineAsm(asm) => visitor.visit_inline_asm(asm), + ExprKind::FormatArgs(f) => visitor.visit_format_args(f), ExprKind::Yield(optional_expression) => { walk_list!(visitor, visit_expr, optional_expression); } |