diff options
Diffstat (limited to '')
31 files changed, 2365 insertions, 1122 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_builtin_macros/src/format/ast.rs b/compiler/rustc_ast/src/format.rs index 01dbffa21..d021bea5e 100644 --- a/compiler/rustc_builtin_macros/src/format/ast.rs +++ b/compiler/rustc_ast/src/format.rs @@ -1,5 +1,5 @@ -use rustc_ast::ptr::P; -use rustc_ast::Expr; +use crate::ptr::P; +use crate::Expr; use rustc_data_structures::fx::FxHashMap; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::Span; @@ -39,7 +39,7 @@ use rustc_span::Span; /// Basically the "AST" for a complete `format_args!()`. /// /// E.g., `format_args!("hello {name}");`. -#[derive(Clone, Debug)] +#[derive(Clone, Encodable, Decodable, Debug)] pub struct FormatArgs { pub span: Span, pub template: Vec<FormatArgsPiece>, @@ -49,7 +49,7 @@ pub struct FormatArgs { /// A piece of a format template string. /// /// E.g. "hello" or "{name}". -#[derive(Clone, Debug)] +#[derive(Clone, Encodable, Decodable, Debug)] pub enum FormatArgsPiece { Literal(Symbol), Placeholder(FormatPlaceholder), @@ -59,7 +59,7 @@ pub enum FormatArgsPiece { /// /// E.g. `1, 2, name="ferris", n=3`, /// but also implicit captured arguments like `x` in `format_args!("{x}")`. -#[derive(Clone, Debug)] +#[derive(Clone, Encodable, Decodable, Debug)] pub struct FormatArguments { arguments: Vec<FormatArgument>, num_unnamed_args: usize, @@ -67,6 +67,12 @@ pub struct FormatArguments { 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 { @@ -121,18 +127,22 @@ impl FormatArguments { &self.arguments[..self.num_explicit_args] } - pub fn into_vec(self) -> Vec<FormatArgument> { - self.arguments + pub fn all_args(&self) -> &[FormatArgument] { + &self.arguments[..] + } + + pub fn all_args_mut(&mut self) -> &mut [FormatArgument] { + &mut self.arguments[..] } } -#[derive(Clone, Debug)] +#[derive(Clone, Encodable, Decodable, Debug)] pub struct FormatArgument { pub kind: FormatArgumentKind, pub expr: P<Expr>, } -#[derive(Clone, Debug)] +#[derive(Clone, Encodable, Decodable, Debug)] pub enum FormatArgumentKind { /// `format_args(…, arg)` Normal, @@ -152,7 +162,7 @@ impl FormatArgumentKind { } } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)] pub struct FormatPlaceholder { /// Index into [`FormatArgs::arguments`]. pub argument: FormatArgPosition, @@ -164,7 +174,7 @@ pub struct FormatPlaceholder { pub format_options: FormatOptions, } -#[derive(Clone, Debug, PartialEq, Eq)] +#[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). @@ -175,7 +185,7 @@ pub struct FormatArgPosition { pub span: Option<Span>, } -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)] pub enum FormatArgPositionKind { /// `{}` or `{:.*}` Implicit, @@ -185,7 +195,7 @@ pub enum FormatArgPositionKind { Named, } -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq, Hash)] pub enum FormatTrait { /// `{}` Display, @@ -207,7 +217,7 @@ pub enum FormatTrait { UpperHex, } -#[derive(Clone, Debug, Default, PartialEq, Eq)] +#[derive(Clone, Encodable, Decodable, Default, Debug, PartialEq, Eq)] pub struct FormatOptions { /// The width. E.g. `{:5}` or `{:width$}`. pub width: Option<FormatCount>, @@ -217,11 +227,33 @@ pub struct FormatOptions { pub alignment: Option<FormatAlignment>, /// The fill character. E.g. the `.` in `{:.>10}`. pub fill: Option<char>, - /// The `+`, `-`, `0`, `#`, `x?` and `X?` flags. - pub flags: u32, + /// 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(Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)] pub enum FormatAlignment { /// `{:<}` Left, @@ -231,7 +263,7 @@ pub enum FormatAlignment { Center, } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)] pub enum FormatCount { /// `{:5}` or `{:.5}` Literal(usize), 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); } diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml index 6a59b9e61..eb2e82d79 100644 --- a/compiler/rustc_ast_lowering/Cargo.toml +++ b/compiler/rustc_ast_lowering/Cargo.toml @@ -7,7 +7,6 @@ edition = "2021" doctest = false [dependencies] -rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_data_structures = { path = "../rustc_data_structures" } @@ -16,10 +15,9 @@ rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_middle = { path = "../rustc_middle" } rustc_macros = { path = "../rustc_macros" } -rustc_query_system = { path = "../rustc_query_system" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } 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_error_messages/locales/en-US/ast_lowering.ftl b/compiler/rustc_ast_lowering/locales/en-US.ftl index 03c88c6c0..3ccd84398 100644 --- a/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl +++ b/compiler/rustc_ast_lowering/locales/en-US.ftl @@ -19,8 +19,8 @@ ast_lowering_remove_parentheses = remove these parentheses ast_lowering_misplaced_impl_trait = `impl Trait` only allowed in function and inherent method return types, not in {$position} -ast_lowering_rustc_box_attribute_error = - #[rustc_box] requires precisely one argument and no other attributes are allowed +ast_lowering_misplaced_assoc_ty_binding = + associated type bounds are only allowed in where clauses and function signatures, not in {$position} ast_lowering_underscore_expr_lhs_assign = in expressions, `_` can only be used on the left-hand side of an assignment diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 21c6a2d26..5e6b6050b 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -79,11 +79,12 @@ pub struct MisplacedImplTrait<'a> { pub position: DiagnosticArgFromDisplay<'a>, } -#[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering_rustc_box_attribute_error)] -pub struct RustcBoxAttributeError { +#[derive(Diagnostic)] +#[diag(ast_lowering_misplaced_assoc_ty_binding)] +pub struct MisplacedAssocTyBinding<'a> { #[primary_span] pub span: Span, + pub position: DiagnosticArgFromDisplay<'a>, } #[derive(Diagnostic, Clone, Copy)] @@ -339,7 +340,7 @@ pub struct InclusiveRangeWithNoEnd { #[derive(Diagnostic, Clone, Copy)] #[diag(ast_lowering_trait_fn_async, code = "E0706")] #[note] -#[note(note2)] +#[note(ast_lowering_note2)] pub struct TraitFnAsync { #[primary_span] pub fn_span: Span, diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index c3611b2f5..ffb30b1b3 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -2,7 +2,7 @@ use super::errors::{ AsyncGeneratorsNotSupported, AsyncNonMoveClosureNotSupported, AwaitOnlyInAsyncFnAndBlocks, BaseExpressionDoubleDot, ClosureCannotBeStatic, FunctionalRecordUpdateDestructuringAssignemnt, GeneratorTooManyParameters, InclusiveRangeWithNoEnd, NotSupportedForLifetimeBinderAsyncClosure, - RustcBoxAttributeError, UnderscoreExprLhsAssign, + UnderscoreExprLhsAssign, }; use super::ResolverAstLoweringExt; use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs}; @@ -16,9 +16,9 @@ use rustc_hir::def::Res; use rustc_hir::definitions::DefPathData; use rustc_session::errors::report_lit_error; use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned}; -use rustc_span::symbol::{sym, Ident}; +use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::DUMMY_SP; -use thin_vec::thin_vec; +use thin_vec::{thin_vec, ThinVec}; impl<'hir> LoweringContext<'_, 'hir> { fn lower_exprs(&mut self, exprs: &[AstP<Expr>]) -> &'hir [hir::Expr<'hir>] { @@ -83,15 +83,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } ExprKind::Tup(elts) => hir::ExprKind::Tup(self.lower_exprs(elts)), ExprKind::Call(f, args) => { - if e.attrs.get(0).map_or(false, |a| a.has_name(sym::rustc_box)) { - if let [inner] = &args[..] && e.attrs.len() == 1 { - let kind = hir::ExprKind::Box(self.lower_expr(&inner)); - return hir::Expr { hir_id, kind, span: self.lower_span(e.span) }; - } else { - self.tcx.sess.emit_err(RustcBoxAttributeError { span: e.span }); - hir::ExprKind::Err - } - } else if let Some(legacy_args) = self.resolver.legacy_const_generic_args(f) { + if let Some(legacy_args) = self.resolver.legacy_const_generic_args(f) { self.lower_legacy_const_generics((**f).clone(), args.clone(), &legacy_args) } else { let f = self.lower_expr(f); @@ -139,13 +131,13 @@ impl<'hir> LoweringContext<'_, 'hir> { ExprKind::Cast(expr, ty) => { let expr = self.lower_expr(expr); let ty = - self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)); + self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Cast)); hir::ExprKind::Cast(expr, ty) } ExprKind::Type(expr, ty) => { let expr = self.lower_expr(expr); let ty = - self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)); + self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Cast)); hir::ExprKind::Type(expr, ty) } ExprKind::AddrOf(k, m, ohs) => { @@ -266,8 +258,8 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), *lims) } ExprKind::Underscore => { - self.tcx.sess.emit_err(UnderscoreExprLhsAssign { span: e.span }); - hir::ExprKind::Err + let guar = self.tcx.sess.emit_err(UnderscoreExprLhsAssign { span: e.span }); + hir::ExprKind::Err(guar) } ExprKind::Path(qself, path) => { let qpath = self.lower_qpath( @@ -294,12 +286,14 @@ impl<'hir> LoweringContext<'_, 'hir> { ExprKind::InlineAsm(asm) => { hir::ExprKind::InlineAsm(self.lower_inline_asm(e.span, asm)) } + ExprKind::FormatArgs(fmt) => self.lower_format_args(e.span, fmt), ExprKind::Struct(se) => { let rest = match &se.rest { StructRest::Base(e) => Some(self.lower_expr(e)), StructRest::Rest(sp) => { - self.tcx.sess.emit_err(BaseExpressionDoubleDot { span: *sp }); - Some(&*self.arena.alloc(self.expr_err(*sp))) + let guar = + self.tcx.sess.emit_err(BaseExpressionDoubleDot { span: *sp }); + Some(&*self.arena.alloc(self.expr_err(*sp, guar))) } StructRest::None => None, }; @@ -317,7 +311,9 @@ impl<'hir> LoweringContext<'_, 'hir> { ) } ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()), - ExprKind::Err => hir::ExprKind::Err, + ExprKind::Err => hir::ExprKind::Err( + self.tcx.sess.delay_span_bug(e.span, "lowered ExprKind::Err"), + ), ExprKind::Try(sub_expr) => self.lower_expr_try(e.span, sub_expr), ExprKind::Paren(_) | ExprKind::ForLoop(..) => unreachable!("already handled"), @@ -366,7 +362,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_legacy_const_generics( &mut self, mut f: Expr, - args: Vec<AstP<Expr>>, + args: ThinVec<AstP<Expr>>, legacy_args_idx: &[usize], ) -> hir::ExprKind<'hir> { let ExprKind::Path(None, path) = &mut f.kind else { @@ -375,7 +371,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // Split the arguments into const generics and normal arguments let mut real_args = vec![]; - let mut generic_args = vec![]; + let mut generic_args = ThinVec::new(); for (idx, arg) in args.into_iter().enumerate() { if legacy_args_idx.contains(&idx) { let parent_def_id = self.current_hir_id_owner; @@ -760,7 +756,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.expr_ident_mut(span, task_context_ident, task_context_hid) } else { // Use of `await` outside of an async context, we cannot use `task_context` here. - self.expr_err(span) + self.expr_err(span, self.tcx.sess.delay_span_bug(span, "no task_context hir id")) }; let new_unchecked = self.expr_call_lang_item_fn_mut( span, @@ -1735,7 +1731,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.expr(span, hir::ExprKind::DropTemps(expr)) } - fn expr_match( + pub(super) fn expr_match( &mut self, span: Span, arg: &'hir hir::Expr<'hir>, @@ -1763,7 +1759,44 @@ impl<'hir> LoweringContext<'_, 'hir> { self.arena.alloc(self.expr(sp, hir::ExprKind::Tup(&[]))) } - fn expr_call_mut( + pub(super) fn expr_usize(&mut self, sp: Span, value: usize) -> hir::Expr<'hir> { + self.expr( + sp, + hir::ExprKind::Lit(hir::Lit { + span: sp, + node: ast::LitKind::Int( + value as u128, + ast::LitIntType::Unsigned(ast::UintTy::Usize), + ), + }), + ) + } + + pub(super) fn expr_u32(&mut self, sp: Span, value: u32) -> hir::Expr<'hir> { + self.expr( + sp, + hir::ExprKind::Lit(hir::Lit { + span: sp, + node: ast::LitKind::Int(value.into(), ast::LitIntType::Unsigned(ast::UintTy::U32)), + }), + ) + } + + pub(super) fn expr_char(&mut self, sp: Span, value: char) -> hir::Expr<'hir> { + self.expr(sp, hir::ExprKind::Lit(hir::Lit { span: sp, node: ast::LitKind::Char(value) })) + } + + pub(super) fn expr_str(&mut self, sp: Span, value: Symbol) -> hir::Expr<'hir> { + self.expr( + sp, + hir::ExprKind::Lit(hir::Lit { + span: sp, + node: ast::LitKind::Str(value, ast::StrStyle::Cooked), + }), + ) + } + + pub(super) fn expr_call_mut( &mut self, span: Span, e: &'hir hir::Expr<'hir>, @@ -1772,7 +1805,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.expr(span, hir::ExprKind::Call(e, args)) } - fn expr_call( + pub(super) fn expr_call( &mut self, span: Span, e: &'hir hir::Expr<'hir>, @@ -1814,6 +1847,27 @@ impl<'hir> LoweringContext<'_, 'hir> { ) } + /// `<LangItem>::name` + pub(super) fn expr_lang_item_type_relative( + &mut self, + span: Span, + lang_item: hir::LangItem, + name: Symbol, + ) -> hir::Expr<'hir> { + let path = hir::ExprKind::Path(hir::QPath::TypeRelative( + self.arena.alloc(self.ty( + span, + hir::TyKind::Path(hir::QPath::LangItem(lang_item, self.lower_span(span), None)), + )), + self.arena.alloc(hir::PathSegment::new( + Ident::new(name, span), + self.next_id(), + Res::Err, + )), + )); + self.expr(span, path) + } + pub(super) fn expr_ident( &mut self, sp: Span, @@ -1872,12 +1926,25 @@ impl<'hir> LoweringContext<'_, 'hir> { self.expr(b.span, hir::ExprKind::Block(b, None)) } + pub(super) fn expr_array_ref( + &mut self, + span: Span, + elements: &'hir [hir::Expr<'hir>], + ) -> hir::Expr<'hir> { + let addrof = hir::ExprKind::AddrOf( + hir::BorrowKind::Ref, + hir::Mutability::Not, + self.arena.alloc(self.expr(span, hir::ExprKind::Array(elements))), + ); + self.expr(span, addrof) + } + pub(super) fn expr(&mut self, span: Span, kind: hir::ExprKind<'hir>) -> hir::Expr<'hir> { let hir_id = self.next_id(); hir::Expr { hir_id, kind, span: self.lower_span(span) } } - fn expr_field( + pub(super) fn expr_field( &mut self, ident: Ident, expr: &'hir hir::Expr<'hir>, @@ -1892,7 +1959,11 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - fn arm(&mut self, pat: &'hir hir::Pat<'hir>, expr: &'hir hir::Expr<'hir>) -> hir::Arm<'hir> { + pub(super) fn arm( + &mut self, + pat: &'hir hir::Pat<'hir>, + expr: &'hir hir::Expr<'hir>, + ) -> hir::Arm<'hir> { hir::Arm { hir_id: self.next_id(), pat, diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs new file mode 100644 index 000000000..4095e225a --- /dev/null +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -0,0 +1,411 @@ +use super::LoweringContext; +use rustc_ast as ast; +use rustc_ast::visit::{self, Visitor}; +use rustc_ast::*; +use rustc_data_structures::fx::FxIndexSet; +use rustc_hir as hir; +use rustc_span::{ + sym, + symbol::{kw, Ident}, + Span, +}; + +impl<'hir> LoweringContext<'_, 'hir> { + pub(crate) fn lower_format_args(&mut self, sp: Span, fmt: &FormatArgs) -> hir::ExprKind<'hir> { + expand_format_args(self, sp, fmt) + } +} + +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +enum ArgumentType { + Format(FormatTrait), + Usize, +} + +/// Generate a hir expression representing an argument to a format_args invocation. +/// +/// Generates: +/// +/// ```text +/// <core::fmt::ArgumentV1>::new_…(arg) +/// ``` +fn make_argument<'hir>( + ctx: &mut LoweringContext<'_, 'hir>, + sp: Span, + arg: &'hir hir::Expr<'hir>, + ty: ArgumentType, +) -> hir::Expr<'hir> { + use ArgumentType::*; + use FormatTrait::*; + let new_fn = ctx.arena.alloc(ctx.expr_lang_item_type_relative( + sp, + hir::LangItem::FormatArgument, + match ty { + Format(Display) => sym::new_display, + Format(Debug) => sym::new_debug, + Format(LowerExp) => sym::new_lower_exp, + Format(UpperExp) => sym::new_upper_exp, + Format(Octal) => sym::new_octal, + Format(Pointer) => sym::new_pointer, + Format(Binary) => sym::new_binary, + Format(LowerHex) => sym::new_lower_hex, + Format(UpperHex) => sym::new_upper_hex, + Usize => sym::from_usize, + }, + )); + ctx.expr_call_mut(sp, new_fn, std::slice::from_ref(arg)) +} + +/// Generate a hir expression for a format_args Count. +/// +/// Generates: +/// +/// ```text +/// <core::fmt::rt::v1::Count>::Is(…) +/// ``` +/// +/// or +/// +/// ```text +/// <core::fmt::rt::v1::Count>::Param(…) +/// ``` +/// +/// or +/// +/// ```text +/// <core::fmt::rt::v1::Count>::Implied +/// ``` +fn make_count<'hir>( + ctx: &mut LoweringContext<'_, 'hir>, + sp: Span, + count: &Option<FormatCount>, + argmap: &mut FxIndexSet<(usize, ArgumentType)>, +) -> hir::Expr<'hir> { + match count { + Some(FormatCount::Literal(n)) => { + let count_is = ctx.arena.alloc(ctx.expr_lang_item_type_relative( + sp, + hir::LangItem::FormatCount, + sym::Is, + )); + let value = ctx.arena.alloc_from_iter([ctx.expr_usize(sp, *n)]); + ctx.expr_call_mut(sp, count_is, value) + } + Some(FormatCount::Argument(arg)) => { + if let Ok(arg_index) = arg.index { + let (i, _) = argmap.insert_full((arg_index, ArgumentType::Usize)); + let count_param = ctx.arena.alloc(ctx.expr_lang_item_type_relative( + sp, + hir::LangItem::FormatCount, + sym::Param, + )); + let value = ctx.arena.alloc_from_iter([ctx.expr_usize(sp, i)]); + ctx.expr_call_mut(sp, count_param, value) + } else { + ctx.expr( + sp, + hir::ExprKind::Err( + ctx.tcx.sess.delay_span_bug(sp, "lowered bad format_args count"), + ), + ) + } + } + None => ctx.expr_lang_item_type_relative(sp, hir::LangItem::FormatCount, sym::Implied), + } +} + +/// Generate a hir expression for a format_args placeholder specification. +/// +/// Generates +/// +/// ```text +/// <core::fmt::rt::v1::Argument::new( +/// …usize, // position +/// '…', // fill +/// <core::fmt::rt::v1::Alignment>::…, // alignment +/// …u32, // flags +/// <core::fmt::rt::v1::Count::…>, // width +/// <core::fmt::rt::v1::Count::…>, // precision +/// ) +/// ``` +fn make_format_spec<'hir>( + ctx: &mut LoweringContext<'_, 'hir>, + sp: Span, + placeholder: &FormatPlaceholder, + argmap: &mut FxIndexSet<(usize, ArgumentType)>, +) -> hir::Expr<'hir> { + let position = match placeholder.argument.index { + Ok(arg_index) => { + let (i, _) = + argmap.insert_full((arg_index, ArgumentType::Format(placeholder.format_trait))); + ctx.expr_usize(sp, i) + } + Err(_) => ctx.expr( + sp, + hir::ExprKind::Err(ctx.tcx.sess.delay_span_bug(sp, "lowered bad format_args count")), + ), + }; + let &FormatOptions { + ref width, + ref precision, + alignment, + fill, + sign, + alternate, + zero_pad, + debug_hex, + } = &placeholder.format_options; + let fill = ctx.expr_char(sp, fill.unwrap_or(' ')); + let align = ctx.expr_lang_item_type_relative( + sp, + hir::LangItem::FormatAlignment, + match alignment { + Some(FormatAlignment::Left) => sym::Left, + Some(FormatAlignment::Right) => sym::Right, + Some(FormatAlignment::Center) => sym::Center, + None => sym::Unknown, + }, + ); + // This needs to match `FlagV1` in library/core/src/fmt/mod.rs. + let flags: u32 = ((sign == Some(FormatSign::Plus)) as u32) + | ((sign == Some(FormatSign::Minus)) as u32) << 1 + | (alternate as u32) << 2 + | (zero_pad as u32) << 3 + | ((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 4 + | ((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 5; + let flags = ctx.expr_u32(sp, flags); + let precision = make_count(ctx, sp, &precision, argmap); + let width = make_count(ctx, sp, &width, argmap); + let format_placeholder_new = ctx.arena.alloc(ctx.expr_lang_item_type_relative( + sp, + hir::LangItem::FormatPlaceholder, + sym::new, + )); + let args = ctx.arena.alloc_from_iter([position, fill, align, flags, precision, width]); + ctx.expr_call_mut(sp, format_placeholder_new, args) +} + +fn expand_format_args<'hir>( + ctx: &mut LoweringContext<'_, 'hir>, + macsp: Span, + fmt: &FormatArgs, +) -> hir::ExprKind<'hir> { + let lit_pieces = + ctx.arena.alloc_from_iter(fmt.template.iter().enumerate().filter_map(|(i, piece)| { + match piece { + &FormatArgsPiece::Literal(s) => Some(ctx.expr_str(fmt.span, s)), + &FormatArgsPiece::Placeholder(_) => { + // Inject empty string before placeholders when not already preceded by a literal piece. + if i == 0 || matches!(fmt.template[i - 1], FormatArgsPiece::Placeholder(_)) { + Some(ctx.expr_str(fmt.span, kw::Empty)) + } else { + None + } + } + } + })); + let lit_pieces = ctx.expr_array_ref(fmt.span, lit_pieces); + + // Whether we'll use the `Arguments::new_v1_formatted` form (true), + // or the `Arguments::new_v1` form (false). + let mut use_format_options = false; + + // Create a list of all _unique_ (argument, format trait) combinations. + // E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (1, Display)] + let mut argmap = FxIndexSet::default(); + for piece in &fmt.template { + let FormatArgsPiece::Placeholder(placeholder) = piece else { continue }; + if placeholder.format_options != Default::default() { + // Can't use basic form if there's any formatting options. + use_format_options = true; + } + if let Ok(index) = placeholder.argument.index { + if !argmap.insert((index, ArgumentType::Format(placeholder.format_trait))) { + // Duplicate (argument, format trait) combination, + // which we'll only put once in the args array. + use_format_options = true; + } + } + } + + let format_options = use_format_options.then(|| { + // Generate: + // &[format_spec_0, format_spec_1, format_spec_2] + let elements: Vec<_> = fmt + .template + .iter() + .filter_map(|piece| { + let FormatArgsPiece::Placeholder(placeholder) = piece else { return None }; + Some(make_format_spec(ctx, macsp, placeholder, &mut argmap)) + }) + .collect(); + ctx.expr_array_ref(macsp, ctx.arena.alloc_from_iter(elements)) + }); + + let arguments = fmt.arguments.all_args(); + + // If the args array contains exactly all the original arguments once, + // in order, we can use a simple array instead of a `match` construction. + // However, if there's a yield point in any argument except the first one, + // we don't do this, because an ArgumentV1 cannot be kept across yield points. + // + // This is an optimization, speeding up compilation about 1-2% in some cases. + // See https://github.com/rust-lang/rust/pull/106770#issuecomment-1380790609 + let use_simple_array = argmap.len() == arguments.len() + && argmap.iter().enumerate().all(|(i, &(j, _))| i == j) + && arguments.iter().skip(1).all(|arg| !may_contain_yield_point(&arg.expr)); + + let args = if use_simple_array { + // Generate: + // &[ + // <core::fmt::ArgumentV1>::new_display(&arg0), + // <core::fmt::ArgumentV1>::new_lower_hex(&arg1), + // <core::fmt::ArgumentV1>::new_debug(&arg2), + // … + // ] + let elements: Vec<_> = arguments + .iter() + .zip(argmap) + .map(|(arg, (_, ty))| { + let sp = arg.expr.span.with_ctxt(macsp.ctxt()); + let arg = ctx.lower_expr(&arg.expr); + let ref_arg = ctx.arena.alloc(ctx.expr( + sp, + hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, arg), + )); + make_argument(ctx, sp, ref_arg, ty) + }) + .collect(); + ctx.expr_array_ref(macsp, ctx.arena.alloc_from_iter(elements)) + } else { + // Generate: + // &match (&arg0, &arg1, &…) { + // args => [ + // <core::fmt::ArgumentV1>::new_display(args.0), + // <core::fmt::ArgumentV1>::new_lower_hex(args.1), + // <core::fmt::ArgumentV1>::new_debug(args.0), + // … + // ] + // } + let args_ident = Ident::new(sym::args, macsp); + let (args_pat, args_hir_id) = ctx.pat_ident(macsp, args_ident); + let args = ctx.arena.alloc_from_iter(argmap.iter().map(|&(arg_index, ty)| { + if let Some(arg) = arguments.get(arg_index) { + let sp = arg.expr.span.with_ctxt(macsp.ctxt()); + let args_ident_expr = ctx.expr_ident(macsp, args_ident, args_hir_id); + let arg = ctx.arena.alloc(ctx.expr( + sp, + hir::ExprKind::Field( + args_ident_expr, + Ident::new(sym::integer(arg_index), macsp), + ), + )); + make_argument(ctx, sp, arg, ty) + } else { + ctx.expr( + macsp, + hir::ExprKind::Err( + ctx.tcx.sess.delay_span_bug(macsp, format!("no arg at {arg_index}")), + ), + ) + } + })); + let elements: Vec<_> = arguments + .iter() + .map(|arg| { + let arg_expr = ctx.lower_expr(&arg.expr); + ctx.expr( + arg.expr.span.with_ctxt(macsp.ctxt()), + hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, arg_expr), + ) + }) + .collect(); + let args_tuple = ctx + .arena + .alloc(ctx.expr(macsp, hir::ExprKind::Tup(ctx.arena.alloc_from_iter(elements)))); + let array = ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Array(args))); + let match_arms = ctx.arena.alloc_from_iter([ctx.arm(args_pat, array)]); + let match_expr = ctx.arena.alloc(ctx.expr_match( + macsp, + args_tuple, + match_arms, + hir::MatchSource::FormatArgs, + )); + ctx.expr( + macsp, + hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, match_expr), + ) + }; + + if let Some(format_options) = format_options { + // Generate: + // <core::fmt::Arguments>::new_v1_formatted( + // lit_pieces, + // args, + // format_options, + // unsafe { ::core::fmt::UnsafeArg::new() } + // ) + let new_v1_formatted = ctx.arena.alloc(ctx.expr_lang_item_type_relative( + macsp, + hir::LangItem::FormatArguments, + sym::new_v1_formatted, + )); + let unsafe_arg_new = ctx.arena.alloc(ctx.expr_lang_item_type_relative( + macsp, + hir::LangItem::FormatUnsafeArg, + sym::new, + )); + let unsafe_arg_new_call = ctx.expr_call(macsp, unsafe_arg_new, &[]); + let hir_id = ctx.next_id(); + let unsafe_arg = ctx.expr_block(ctx.arena.alloc(hir::Block { + stmts: &[], + expr: Some(unsafe_arg_new_call), + hir_id, + rules: hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::CompilerGenerated), + span: macsp, + targeted_by_break: false, + })); + let args = ctx.arena.alloc_from_iter([lit_pieces, args, format_options, unsafe_arg]); + hir::ExprKind::Call(new_v1_formatted, args) + } else { + // Generate: + // <core::fmt::Arguments>::new_v1( + // lit_pieces, + // args, + // ) + let new_v1 = ctx.arena.alloc(ctx.expr_lang_item_type_relative( + macsp, + hir::LangItem::FormatArguments, + sym::new_v1, + )); + let new_args = ctx.arena.alloc_from_iter([lit_pieces, args]); + hir::ExprKind::Call(new_v1, new_args) + } +} + +fn may_contain_yield_point(e: &ast::Expr) -> bool { + struct MayContainYieldPoint(bool); + + impl Visitor<'_> for MayContainYieldPoint { + fn visit_expr(&mut self, e: &ast::Expr) { + if let ast::ExprKind::Await(_) | ast::ExprKind::Yield(_) = e.kind { + self.0 = true; + } else { + visit::walk_expr(self, e); + } + } + + fn visit_mac_call(&mut self, _: &ast::MacCall) { + // Macros should be expanded at this point. + unreachable!("unexpanded macro in ast lowering"); + } + + fn visit_item(&mut self, _: &ast::Item) { + // Do not recurse into nested items. + } + } + + let mut visitor = MayContainYieldPoint(false); + visitor.visit_expr(e); + visitor.0 +} diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index 63033085b..f7fe0d771 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -275,19 +275,6 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }); } - fn visit_fn( - &mut self, - fk: intravisit::FnKind<'hir>, - fd: &'hir FnDecl<'hir>, - b: BodyId, - _: Span, - id: HirId, - ) { - assert_eq!(self.owner, id.owner); - assert_eq!(self.parent_node, id.local_id); - intravisit::walk_fn(self, fk, fd, b, id); - } - fn visit_block(&mut self, block: &'hir Block<'hir>) { self.insert(block.span, block.hir_id, Node::Block(block)); self.with_parent(block.hir_id, |this| { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 5d2589cb2..41295f2b7 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -7,13 +7,14 @@ use rustc_ast::ptr::P; use rustc_ast::visit::AssocCtxt; use rustc_ast::*; use rustc_data_structures::sorted_map::SortedMap; +use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; use rustc_hir::PredicateOrigin; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::ty::{DefIdTree, ResolverAstLowering, TyCtxt}; -use rustc_span::lev_distance::find_best_match_for_name; +use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::source_map::DesugaringKind; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{Span, Symbol}; @@ -67,7 +68,6 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { current_hir_id_owner: hir::CRATE_OWNER_ID, item_local_id_counter: hir::ItemLocalId::new(0), node_id_to_local_id: Default::default(), - local_id_to_def_id: SortedMap::new(), trait_map: Default::default(), // Lowering state. @@ -285,7 +285,7 @@ impl<'hir> LoweringContext<'_, 'hir> { .alloc_from_iter(fm.items.iter().map(|x| self.lower_foreign_item_ref(x))), }, ItemKind::GlobalAsm(asm) => hir::ItemKind::GlobalAsm(self.lower_inline_asm(span, asm)), - ItemKind::TyAlias(box TyAlias { generics, where_clauses, ty: Some(ty), .. }) => { + ItemKind::TyAlias(box TyAlias { generics, where_clauses, ty, .. }) => { // We lower // // type Foo = impl Trait @@ -300,18 +300,16 @@ impl<'hir> LoweringContext<'_, 'hir> { &generics, id, &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), - |this| this.lower_ty(ty, &ImplTraitContext::TypeAliasesOpaqueTy), - ); - hir::ItemKind::TyAlias(ty, generics) - } - ItemKind::TyAlias(box TyAlias { generics, where_clauses, ty: None, .. }) => { - let mut generics = generics.clone(); - add_ty_alias_where_clause(&mut generics, *where_clauses, true); - let (generics, ty) = self.lower_generics( - &generics, - id, - &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), - |this| this.arena.alloc(this.ty(span, hir::TyKind::Err)), + |this| match ty { + None => { + let guar = this.tcx.sess.delay_span_bug( + span, + "expected to lower type alias type, but it was missing", + ); + this.arena.alloc(this.ty(span, hir::TyKind::Err(guar))) + } + Some(ty) => this.lower_ty(ty, &ImplTraitContext::TypeAliasesOpaqueTy), + }, ); hir::ItemKind::TyAlias(ty, generics) } @@ -379,8 +377,10 @@ impl<'hir> LoweringContext<'_, 'hir> { ) }); - let lowered_ty = this - .lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)); + let lowered_ty = this.lower_ty( + ty, + &ImplTraitContext::Disallowed(ImplTraitPosition::ImplSelf), + ); (trait_ref, lowered_ty) }); @@ -459,7 +459,7 @@ impl<'hir> LoweringContext<'_, 'hir> { span: Span, body: Option<&Expr>, ) -> (&'hir hir::Ty<'hir>, hir::BodyId) { - let ty = self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)); + let ty = self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); (ty, self.lower_const_body(span, body)) } @@ -609,8 +609,8 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ForeignItemKind::Fn(fn_dec, fn_args, generics) } ForeignItemKind::Static(t, m, _) => { - let ty = - self.lower_ty(t, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)); + let ty = self + .lower_ty(t, &ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy)); hir::ForeignItemKind::Static(ty, *m) } ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type, @@ -680,11 +680,11 @@ impl<'hir> LoweringContext<'_, 'hir> { qself, path, ParamMode::ExplicitNamed, // no `'_` in declarations (Issue #61124) - &ImplTraitContext::Disallowed(ImplTraitPosition::Path), + &ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy), ); self.arena.alloc(t) } else { - self.lower_ty(&f.ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)) + self.lower_ty(&f.ty, &ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy)) }; let hir_id = self.lower_node_id(f.id); self.lower_attrs(hir_id, &f.attrs); @@ -709,7 +709,8 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, kind, has_default) = match &i.kind { AssocItemKind::Const(_, ty, default) => { - let ty = self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)); + let ty = + self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); let body = default.as_ref().map(|x| self.lower_const_body(i.span, Some(x))); (hir::Generics::empty(), hir::TraitItemKind::Const(ty, body), body.is_some()) } @@ -747,7 +748,10 @@ impl<'hir> LoweringContext<'_, 'hir> { &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { let ty = ty.as_ref().map(|x| { - this.lower_ty(x, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)) + this.lower_ty( + x, + &ImplTraitContext::Disallowed(ImplTraitPosition::AssocTy), + ) }); hir::TraitItemKind::Type( this.lower_param_bounds( @@ -793,8 +797,8 @@ impl<'hir> LoweringContext<'_, 'hir> { } /// Construct `ExprKind::Err` for the given `span`. - pub(crate) fn expr_err(&mut self, span: Span) -> hir::Expr<'hir> { - self.expr(span, hir::ExprKind::Err) + pub(crate) fn expr_err(&mut self, span: Span, guar: ErrorGuaranteed) -> hir::Expr<'hir> { + self.expr(span, hir::ExprKind::Err(guar)) } fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> { @@ -806,7 +810,8 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, kind) = match &i.kind { AssocItemKind::Const(_, ty, expr) => { - let ty = self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)); + let ty = + self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); ( hir::Generics::empty(), hir::ImplItemKind::Const(ty, self.lower_const_body(i.span, expr.as_deref())), @@ -841,7 +846,11 @@ impl<'hir> LoweringContext<'_, 'hir> { &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| match ty { None => { - let ty = this.arena.alloc(this.ty(i.span, hir::TyKind::Err)); + let guar = this.tcx.sess.delay_span_bug( + i.span, + "expected to lower associated type, but it was missing", + ); + let ty = this.arena.alloc(this.ty(i.span, hir::TyKind::Err(guar))); hir::ImplItemKind::Type(ty) } Some(ty) => { @@ -967,7 +976,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_block_expr_opt(&mut self, span: Span, block: Option<&Block>) -> hir::Expr<'hir> { match block { Some(block) => self.lower_block_expr(block), - None => self.expr_err(span), + None => self.expr_err(span, self.tcx.sess.delay_span_bug(span, "no block")), } } @@ -977,7 +986,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &[], match expr { Some(expr) => this.lower_expr_mut(expr), - None => this.expr_err(span), + None => this.expr_err(span, this.tcx.sess.delay_span_bug(span, "no block")), }, ) }) @@ -1330,13 +1339,19 @@ impl<'hir> LoweringContext<'_, 'hir> { .map(|predicate| self.lower_where_predicate(predicate)), ); - let mut params: SmallVec<[hir::GenericParam<'hir>; 4]> = - self.lower_generic_params_mut(&generics.params).collect(); + let mut params: SmallVec<[hir::GenericParam<'hir>; 4]> = self + .lower_generic_params_mut(&generics.params, hir::GenericParamSource::Generics) + .collect(); // Introduce extra lifetimes if late resolution tells us to. let extra_lifetimes = self.resolver.take_extra_lifetime_params(parent_node_id); params.extend(extra_lifetimes.into_iter().filter_map(|(ident, node_id, res)| { - self.lifetime_res_to_generic_param(ident, node_id, res) + self.lifetime_res_to_generic_param( + ident, + node_id, + res, + hir::GenericParamSource::Generics, + ) })); let has_where_clause_predicates = !generics.where_clause.predicates.is_empty(); @@ -1440,9 +1455,10 @@ impl<'hir> LoweringContext<'_, 'hir> { span, }) => hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { hir_id: self.next_id(), - bound_generic_params: self.lower_generic_params(bound_generic_params), + bound_generic_params: self + .lower_generic_params(bound_generic_params, hir::GenericParamSource::Binder), bounded_ty: self - .lower_ty(bounded_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)), + .lower_ty(bounded_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Bound)), bounds: self.arena.alloc_from_iter(bounds.iter().map(|bound| { self.lower_param_bound( bound, @@ -1466,9 +1482,9 @@ impl<'hir> LoweringContext<'_, 'hir> { WherePredicate::EqPredicate(WhereEqPredicate { lhs_ty, rhs_ty, span }) => { hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { lhs_ty: self - .lower_ty(lhs_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)), + .lower_ty(lhs_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Bound)), rhs_ty: self - .lower_ty(rhs_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)), + .lower_ty(rhs_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Bound)), span: self.lower_span(*span), }) } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index bc6d2cf12..b20157f2c 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -52,23 +52,28 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::Lrc; -use rustc_errors::{DiagnosticArgFromDisplay, Handler, StashKey}; +use rustc_errors::{ + DiagnosticArgFromDisplay, DiagnosticMessage, Handler, StashKey, SubdiagnosticMessage, +}; use rustc_hir as hir; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; use rustc_hir::definitions::DefPathData; use rustc_hir::{ConstArg, GenericArg, ItemLocalId, ParamName, TraitCandidate}; use rustc_index::vec::{Idx, IndexVec}; -use rustc_middle::span_bug; -use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; +use rustc_macros::fluent_messages; +use rustc_middle::{ + span_bug, + ty::{ResolverAstLowering, TyCtxt}, +}; use rustc_session::parse::feature_err; use rustc_span::hygiene::MacroKind; use rustc_span::source_map::DesugaringKind; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; - use smallvec::SmallVec; use std::collections::hash_map::Entry; +use thin_vec::ThinVec; macro_rules! arena_vec { ($this:expr; $($x:expr),*) => ( @@ -80,12 +85,15 @@ mod asm; mod block; mod errors; mod expr; +mod format; mod index; mod item; mod lifetime_collector; mod pat; mod path; +fluent_messages! { "../locales/en-US.ftl" } + struct LoweringContext<'a, 'hir> { tcx: TyCtxt<'hir>, resolver: &'a mut ResolverAstLowering, @@ -118,7 +126,6 @@ struct LoweringContext<'a, 'hir> { current_hir_id_owner: hir::OwnerId, item_local_id_counter: hir::ItemLocalId, - local_id_to_def_id: SortedMap<ItemLocalId, LocalDefId>, trait_map: FxHashMap<ItemLocalId, Box<[TraitCandidate]>>, impl_trait_defs: Vec<hir::GenericParam<'hir>>, @@ -253,7 +260,6 @@ enum ImplTraitContext { enum ImplTraitPosition { Path, Variable, - Type, Trait, AsyncBlock, Bound, @@ -270,30 +276,43 @@ enum ImplTraitPosition { FnTraitReturn, TraitReturn, ImplReturn, + GenericDefault, + ConstTy, + StaticTy, + AssocTy, + FieldTy, + Cast, + ImplSelf, } impl std::fmt::Display for ImplTraitPosition { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let name = match self { - ImplTraitPosition::Path => "path", - ImplTraitPosition::Variable => "variable binding", - ImplTraitPosition::Type => "type", - ImplTraitPosition::Trait => "trait", - ImplTraitPosition::AsyncBlock => "async block", - ImplTraitPosition::Bound => "bound", - ImplTraitPosition::Generic => "generic", - ImplTraitPosition::ExternFnParam => "`extern fn` param", - ImplTraitPosition::ClosureParam => "closure param", - ImplTraitPosition::PointerParam => "`fn` pointer param", - ImplTraitPosition::FnTraitParam => "`Fn` trait param", - ImplTraitPosition::TraitParam => "trait method param", - ImplTraitPosition::ImplParam => "`impl` method param", - ImplTraitPosition::ExternFnReturn => "`extern fn` return", - ImplTraitPosition::ClosureReturn => "closure return", - ImplTraitPosition::PointerReturn => "`fn` pointer return", - ImplTraitPosition::FnTraitReturn => "`Fn` trait return", - ImplTraitPosition::TraitReturn => "trait method return", - ImplTraitPosition::ImplReturn => "`impl` method return", + ImplTraitPosition::Path => "paths", + ImplTraitPosition::Variable => "variable bindings", + ImplTraitPosition::Trait => "traits", + ImplTraitPosition::AsyncBlock => "async blocks", + ImplTraitPosition::Bound => "bounds", + ImplTraitPosition::Generic => "generics", + ImplTraitPosition::ExternFnParam => "`extern fn` params", + ImplTraitPosition::ClosureParam => "closure params", + ImplTraitPosition::PointerParam => "`fn` pointer params", + ImplTraitPosition::FnTraitParam => "`Fn` trait params", + ImplTraitPosition::TraitParam => "trait method params", + ImplTraitPosition::ImplParam => "`impl` method params", + ImplTraitPosition::ExternFnReturn => "`extern fn` return types", + ImplTraitPosition::ClosureReturn => "closure return types", + ImplTraitPosition::PointerReturn => "`fn` pointer return types", + ImplTraitPosition::FnTraitReturn => "`Fn` trait return types", + ImplTraitPosition::TraitReturn => "trait method return types", + ImplTraitPosition::ImplReturn => "`impl` method return types", + ImplTraitPosition::GenericDefault => "generic parameter defaults", + ImplTraitPosition::ConstTy => "const types", + ImplTraitPosition::StaticTy => "static types", + ImplTraitPosition::AssocTy => "associated types", + ImplTraitPosition::FieldTy => "field types", + ImplTraitPosition::Cast => "cast types", + ImplTraitPosition::ImplSelf => "impl headers", }; write!(f, "{name}") @@ -416,6 +435,7 @@ fn compute_hir_hash( pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> { let sess = tcx.sess; + tcx.ensure().output_filenames(()); let (mut resolver, krate) = tcx.resolver_for_lowering(()).steal(); let ast_index = index_crate(&resolver.node_id_to_def_id, &krate); @@ -565,7 +585,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let current_attrs = std::mem::take(&mut self.attrs); let current_bodies = std::mem::take(&mut self.bodies); let current_node_ids = std::mem::take(&mut self.node_id_to_local_id); - let current_id_to_def_id = std::mem::take(&mut self.local_id_to_def_id); let current_trait_map = std::mem::take(&mut self.trait_map); let current_owner = std::mem::replace(&mut self.current_hir_id_owner, hir::OwnerId { def_id }); @@ -592,7 +611,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.attrs = current_attrs; self.bodies = current_bodies; self.node_id_to_local_id = current_node_ids; - self.local_id_to_def_id = current_id_to_def_id; self.trait_map = current_trait_map; self.current_hir_id_owner = current_owner; self.item_local_id_counter = current_local_counter; @@ -627,7 +645,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> &'hir hir::OwnerInfo<'hir> { let attrs = std::mem::take(&mut self.attrs); let mut bodies = std::mem::take(&mut self.bodies); - let local_id_to_def_id = std::mem::take(&mut self.local_id_to_def_id); let trait_map = std::mem::take(&mut self.trait_map); #[cfg(debug_assertions)] @@ -643,13 +660,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let (hash_including_bodies, hash_without_bodies) = self.hash_owner(node, &bodies); let (nodes, parenting) = index::index_hir(self.tcx.sess, &*self.tcx.definitions_untracked(), node, &bodies); - let nodes = hir::OwnerNodes { - hash_including_bodies, - hash_without_bodies, - nodes, - bodies, - local_id_to_def_id, - }; + let nodes = hir::OwnerNodes { hash_including_bodies, hash_without_bodies, nodes, bodies }; let attrs = { let hash = self.tcx.with_stable_hashing_context(|mut hcx| { let mut stable_hasher = StableHasher::new(); @@ -708,7 +719,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { assert_ne!(local_id, hir::ItemLocalId::new(0)); if let Some(def_id) = self.opt_local_def_id(ast_node_id) { self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id))); - self.local_id_to_def_id.insert(local_id, def_id); } if let Some(traits) = self.resolver.trait_map.remove(&ast_node_id) { @@ -794,6 +804,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ident: Ident, node_id: NodeId, res: LifetimeRes, + source: hir::GenericParamSource, ) -> Option<hir::GenericParam<'hir>> { let (name, kind) = match res { LifetimeRes::Param { .. } => { @@ -827,6 +838,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { pure_wrt_drop: false, kind: hir::GenericParamKind::Lifetime { kind }, colon_span: None, + source, }) } @@ -842,11 +854,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { binder: NodeId, generic_params: &[GenericParam], ) -> &'hir [hir::GenericParam<'hir>] { - let mut generic_params: Vec<_> = self.lower_generic_params_mut(generic_params).collect(); + let mut generic_params: Vec<_> = self + .lower_generic_params_mut(generic_params, hir::GenericParamSource::Binder) + .collect(); let extra_lifetimes = self.resolver.take_extra_lifetime_params(binder); debug!(?extra_lifetimes); generic_params.extend(extra_lifetimes.into_iter().filter_map(|(ident, node_id, res)| { - self.lifetime_res_to_generic_param(ident, node_id, res) + self.lifetime_res_to_generic_param(ident, node_id, res, hir::GenericParamSource::Binder) })); let generic_params = self.arena.alloc_from_iter(generic_params); debug!(?generic_params); @@ -992,8 +1006,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } else { self.arena.alloc(hir::GenericArgs::none()) }; - let itctx_tait = &ImplTraitContext::TypeAliasesOpaqueTy; - let kind = match &constraint.kind { AssocConstraintKind::Equality { term } => { let term = match term { @@ -1003,8 +1015,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::TypeBindingKind::Equality { term } } AssocConstraintKind::Bound { bounds } => { + enum DesugarKind<'a> { + ImplTrait, + Error(&'a ImplTraitPosition), + Bound, + } + // Piggy-back on the `impl Trait` context to figure out the correct behavior. - let (desugar_to_impl_trait, itctx) = match itctx { + let desugar_kind = match itctx { // We are in the return position: // // fn foo() -> impl Iterator<Item: Debug> @@ -1013,7 +1031,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // // fn foo() -> impl Iterator<Item = impl Debug> ImplTraitContext::ReturnPositionOpaqueTy { .. } - | ImplTraitContext::TypeAliasesOpaqueTy { .. } => (true, itctx), + | ImplTraitContext::TypeAliasesOpaqueTy { .. } => DesugarKind::ImplTrait, // We are in the argument position, but within a dyn type: // @@ -1022,15 +1040,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // so desugar to // // fn foo(x: dyn Iterator<Item = impl Debug>) - ImplTraitContext::Universal if self.is_in_dyn_type => (true, itctx), + ImplTraitContext::Universal if self.is_in_dyn_type => DesugarKind::ImplTrait, - // In `type Foo = dyn Iterator<Item: Debug>` we desugar to - // `type Foo = dyn Iterator<Item = impl Debug>` but we have to override the - // "impl trait context" to permit `impl Debug` in this position (it desugars - // then to an opaque type). - // - // FIXME: this is only needed until `impl Trait` is allowed in type aliases. - ImplTraitContext::Disallowed(_) if self.is_in_dyn_type => (true, itctx_tait), + ImplTraitContext::Disallowed(position) if self.is_in_dyn_type => { + DesugarKind::Error(position) + } // We are in the parameter position, but not within a dyn type: // @@ -1039,35 +1053,47 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // so we leave it as is and this gets expanded in astconv to a bound like // `<T as Iterator>::Item: Debug` where `T` is the type parameter for the // `impl Iterator`. - _ => (false, itctx), + _ => DesugarKind::Bound, }; - if desugar_to_impl_trait { - // Desugar `AssocTy: Bounds` into `AssocTy = impl Bounds`. We do this by - // constructing the HIR for `impl bounds...` and then lowering that. - - let impl_trait_node_id = self.next_node_id(); - - self.with_dyn_type_scope(false, |this| { - let node_id = this.next_node_id(); - let ty = this.lower_ty( - &Ty { - id: node_id, - kind: TyKind::ImplTrait(impl_trait_node_id, bounds.clone()), - span: this.lower_span(constraint.span), - tokens: None, - }, - itctx, - ); + match desugar_kind { + DesugarKind::ImplTrait => { + // Desugar `AssocTy: Bounds` into `AssocTy = impl Bounds`. We do this by + // constructing the HIR for `impl bounds...` and then lowering that. - hir::TypeBindingKind::Equality { term: ty.into() } - }) - } else { - // Desugar `AssocTy: Bounds` into a type binding where the - // later desugars into a trait predicate. - let bounds = self.lower_param_bounds(bounds, itctx); + let impl_trait_node_id = self.next_node_id(); + + self.with_dyn_type_scope(false, |this| { + let node_id = this.next_node_id(); + let ty = this.lower_ty( + &Ty { + id: node_id, + kind: TyKind::ImplTrait(impl_trait_node_id, bounds.clone()), + span: this.lower_span(constraint.span), + tokens: None, + }, + itctx, + ); + + hir::TypeBindingKind::Equality { term: ty.into() } + }) + } + DesugarKind::Bound => { + // Desugar `AssocTy: Bounds` into a type binding where the + // later desugars into a trait predicate. + let bounds = self.lower_param_bounds(bounds, itctx); - hir::TypeBindingKind::Constraint { bounds } + hir::TypeBindingKind::Constraint { bounds } + } + DesugarKind::Error(position) => { + let guar = self.tcx.sess.emit_err(errors::MisplacedAssocTyBinding { + span: constraint.span, + position: DiagnosticArgFromDisplay(position), + }); + let err_ty = + &*self.arena.alloc(self.ty(constraint.span, hir::TyKind::Err(guar))); + hir::TypeBindingKind::Equality { term: err_ty.into() } + } } } }; @@ -1204,7 +1230,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| { let bound = this.lower_poly_trait_ref( &PolyTraitRef { - bound_generic_params: vec![], + bound_generic_params: ThinVec::new(), trait_ref: TraitRef { path: path.clone(), ref_id: t.id }, span: t.span }, @@ -1234,7 +1260,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_ty_direct(&mut self, t: &Ty, itctx: &ImplTraitContext) -> hir::Ty<'hir> { let kind = match &t.kind { TyKind::Infer => hir::TyKind::Infer, - TyKind::Err => hir::TyKind::Err, + TyKind::Err => { + hir::TyKind::Err(self.tcx.sess.delay_span_bug(t.span, "TyKind::Err lowered")) + } TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)), TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)), TyKind::Ref(region, mt) => { @@ -1351,8 +1379,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span, ); let ident = Ident::from_str_and_span(&pprust::ty_to_string(t), span); - let (param, bounds, path) = - self.lower_generic_and_bounds(*def_node_id, span, ident, bounds); + let (param, bounds, path) = self.lower_universal_param_and_bounds( + *def_node_id, + span, + ident, + bounds, + ); self.impl_trait_defs.push(param); if let Some(bounds) = bounds { self.impl_trait_bounds.push(bounds); @@ -1360,7 +1392,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { path } ImplTraitContext::FeatureGated(position, feature) => { - self.tcx + let guar = self + .tcx .sess .create_feature_err( MisplacedImplTrait { @@ -1370,24 +1403,24 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { *feature, ) .emit(); - hir::TyKind::Err + hir::TyKind::Err(guar) } ImplTraitContext::Disallowed(position) => { - self.tcx.sess.emit_err(MisplacedImplTrait { + let guar = self.tcx.sess.emit_err(MisplacedImplTrait { span: t.span, position: DiagnosticArgFromDisplay(position), }); - hir::TyKind::Err + hir::TyKind::Err(guar) } } } TyKind::MacCall(_) => panic!("`TyKind::MacCall` should have been expanded by now"), TyKind::CVarArgs => { - self.tcx.sess.delay_span_bug( + let guar = self.tcx.sess.delay_span_bug( t.span, "`TyKind::CVarArgs` should have been handled elsewhere", ); - hir::TyKind::Err + hir::TyKind::Err(guar) } }; @@ -1505,6 +1538,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { pure_wrt_drop: false, kind: hir::GenericParamKind::Lifetime { kind }, colon_span: None, + source: hir::GenericParamSource::Generics, } }, )); @@ -1573,7 +1607,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::OwnerNode::Item(self.arena.alloc(opaque_ty_item)) } - /// Given a `parent_def_id`, a list of `lifetimes_in_bounds and a `remapping` hash to be + /// Given a `parent_def_id`, a list of `lifetimes_in_bounds` and a `remapping` hash to be /// filled, this function creates new definitions for `Param` and `Fresh` lifetimes, inserts the /// new definition, adds it to the remapping with the definition of the given lifetime and /// returns a list of lifetimes to be lowered afterwards. @@ -1962,6 +1996,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { pure_wrt_drop: false, kind: hir::GenericParamKind::Lifetime { kind }, colon_span: None, + source: hir::GenericParamSource::Generics, } }, )); @@ -2127,16 +2162,25 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_generic_params_mut<'s>( &'s mut self, params: &'s [GenericParam], + source: hir::GenericParamSource, ) -> impl Iterator<Item = hir::GenericParam<'hir>> + Captures<'a> + Captures<'s> { - params.iter().map(move |param| self.lower_generic_param(param)) + params.iter().map(move |param| self.lower_generic_param(param, source)) } - fn lower_generic_params(&mut self, params: &[GenericParam]) -> &'hir [hir::GenericParam<'hir>] { - self.arena.alloc_from_iter(self.lower_generic_params_mut(params)) + fn lower_generic_params( + &mut self, + params: &[GenericParam], + source: hir::GenericParamSource, + ) -> &'hir [hir::GenericParam<'hir>] { + self.arena.alloc_from_iter(self.lower_generic_params_mut(params, source)) } #[instrument(level = "trace", skip(self))] - fn lower_generic_param(&mut self, param: &GenericParam) -> hir::GenericParam<'hir> { + fn lower_generic_param( + &mut self, + param: &GenericParam, + source: hir::GenericParamSource, + ) -> hir::GenericParam<'hir> { let (name, kind) = self.lower_generic_param_kind(param); let hir_id = self.lower_node_id(param.id); @@ -2149,6 +2193,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { pure_wrt_drop: self.tcx.sess.contains_name(¶m.attrs, sym::may_dangle), kind, colon_span: param.colon_span.map(|s| self.lower_span(s)), + source, } } @@ -2175,7 +2220,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { GenericParamKind::Type { default, .. } => { let kind = hir::GenericParamKind::Type { default: default.as_ref().map(|x| { - self.lower_ty(x, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)) + self.lower_ty( + x, + &ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault), + ) }), synthetic: false, }; @@ -2183,7 +2231,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { (hir::ParamName::Plain(self.lower_ident(param.ident)), kind) } GenericParamKind::Const { ty, kw_span: _, default } => { - let ty = self.lower_ty(&ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)); + let ty = self.lower_ty( + &ty, + &ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault), + ); let default = default.as_ref().map(|def| self.lower_anon_const(def)); ( hir::ParamName::Plain(self.lower_ident(param.ident)), @@ -2235,7 +2286,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } #[instrument(level = "debug", skip(self), ret)] - fn lower_generic_and_bounds( + fn lower_universal_param_and_bounds( &mut self, node_id: NodeId, span: Span, @@ -2255,6 +2306,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span, kind: hir::GenericParamKind::Type { default: None, synthetic: true }, colon_span: None, + source: hir::GenericParamSource::Generics, }; let preds = self.lower_generic_bound_predicate( diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 06d885a45..2509b7056 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -330,8 +330,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ExprKind::Path(..) if allow_paths => {} ExprKind::Unary(UnOp::Neg, inner) if matches!(inner.kind, ExprKind::Lit(_)) => {} _ => { - self.tcx.sess.emit_err(ArbitraryExpressionInPattern { span: expr.span }); - return self.arena.alloc(self.expr_err(expr.span)); + let guar = self.tcx.sess.emit_err(ArbitraryExpressionInPattern { span: expr.span }); + return self.arena.alloc(self.expr_err(expr.span, guar)); } } self.lower_expr(expr) diff --git a/compiler/rustc_ast_passes/Cargo.toml b/compiler/rustc_ast_passes/Cargo.toml index 37eff9207..8bd212073 100644 --- a/compiler/rustc_ast_passes/Cargo.toml +++ b/compiler/rustc_ast_passes/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] itertools = "0.10.1" -tracing = "0.1" +rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_attr = { path = "../rustc_attr" } rustc_data_structures = { path = "../rustc_data_structures" } @@ -16,4 +16,5 @@ rustc_parse = { path = "../rustc_parse" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } -rustc_ast = { path = "../rustc_ast" } +thin-vec = "0.2.12" +tracing = "0.1" diff --git a/compiler/rustc_ast_passes/locales/en-US.ftl b/compiler/rustc_ast_passes/locales/en-US.ftl new file mode 100644 index 000000000..747bd52b2 --- /dev/null +++ b/compiler/rustc_ast_passes/locales/en-US.ftl @@ -0,0 +1,236 @@ +ast_passes_forbidden_let = + `let` expressions are not supported here + .note = only supported directly in conditions of `if` and `while` expressions + .not_supported_or = `||` operators are not supported in let chain expressions + .not_supported_parentheses = `let`s wrapped in parentheses are not supported in a context with let chains + +ast_passes_forbidden_let_stable = + expected expression, found statement (`let`) + .note = variable declaration using `let` is a statement + +ast_passes_deprecated_where_clause_location = + where clause not allowed here + +ast_passes_keyword_lifetime = + lifetimes cannot use keyword names + +ast_passes_invalid_label = + invalid label name `{$name}` + +ast_passes_invalid_visibility = + unnecessary visibility qualifier + .implied = `pub` not permitted here because it's implied + .individual_impl_items = place qualifiers on individual impl items instead + .individual_foreign_items = place qualifiers on individual foreign items instead + +ast_passes_trait_fn_const = + functions in traits cannot be declared const + .label = functions in traits cannot be const + +ast_passes_forbidden_lifetime_bound = + lifetime bounds cannot be used in this context + +ast_passes_forbidden_non_lifetime_param = + only lifetime parameters can be used in this context + +ast_passes_fn_param_too_many = + function can not have more than {$max_num_args} arguments + +ast_passes_fn_param_c_var_args_only = + C-variadic function must be declared with at least one named argument + +ast_passes_fn_param_c_var_args_not_last = + `...` must be the last argument of a C-variadic function + +ast_passes_fn_param_doc_comment = + documentation comments cannot be applied to function parameters + .label = doc comments are not allowed here + +ast_passes_fn_param_forbidden_attr = + allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + +ast_passes_fn_param_forbidden_self = + `self` parameter is only allowed in associated functions + .label = not semantically valid as function parameter + .note = associated functions are those in `impl` or `trait` definitions + +ast_passes_forbidden_default = + `default` is only allowed on items in trait impls + .label = `default` because of this + +ast_passes_assoc_const_without_body = + associated constant in `impl` without body + .suggestion = provide a definition for the constant + +ast_passes_assoc_fn_without_body = + associated function in `impl` without body + .suggestion = provide a definition for the function + +ast_passes_assoc_type_without_body = + associated type in `impl` without body + .suggestion = provide a definition for the type + +ast_passes_const_without_body = + free constant item without body + .suggestion = provide a definition for the constant + +ast_passes_static_without_body = + free static item without body + .suggestion = provide a definition for the static + +ast_passes_ty_alias_without_body = + free type alias without body + .suggestion = provide a definition for the type + +ast_passes_fn_without_body = + free function without a body + .suggestion = provide a definition for the function + +ast_passes_extern_block_suggestion = if you meant to declare an externally defined function, use an `extern` block + +ast_passes_bound_in_context = bounds on `type`s in {$ctx} have no effect + +ast_passes_extern_types_cannot = `type`s inside `extern` blocks cannot have {$descr} + .suggestion = remove the {$remove_descr} + .label = `extern` block begins here + +ast_passes_extern_keyword_link = for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +ast_passes_body_in_extern = incorrect `{$kind}` inside `extern` block + .cannot_have = cannot have a body + .invalid = the invalid body + .existing = `extern` blocks define existing foreign {$kind}s and {$kind}s inside of them cannot have a body + +ast_passes_fn_body_extern = incorrect function inside `extern` block + .cannot_have = cannot have a body + .suggestion = remove the invalid body + .help = you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block + .label = `extern` blocks define existing foreign functions and functions inside of them cannot have a body + +ast_passes_extern_fn_qualifiers = functions in `extern` blocks cannot have qualifiers + .label = in this `extern` block + .suggestion = remove the qualifiers + +ast_passes_extern_item_ascii = items in `extern` blocks cannot use non-ascii identifiers + .label = in this `extern` block + .note = this limitation may be lifted in the future; see issue #83942 <https://github.com/rust-lang/rust/issues/83942> for more information + +ast_passes_bad_c_variadic = only foreign or `unsafe extern "C"` functions may be C-variadic + +ast_passes_item_underscore = `{$kind}` items in this context need a name + .label = `_` is not a valid name for this `{$kind}` item + +ast_passes_nomangle_ascii = `#[no_mangle]` requires ASCII identifier + +ast_passes_module_nonascii = trying to load file for module `{$name}` with non-ascii identifier name + .help = consider using the `#[path]` attribute to specify filesystem path + +ast_passes_auto_generic = auto traits cannot have generic parameters + .label = auto trait cannot have generic parameters + .suggestion = remove the parameters + +ast_passes_auto_super_lifetime = auto traits cannot have super traits or lifetime bounds + .label = {ast_passes_auto_super_lifetime} + .suggestion = remove the super traits or lifetime bounds + +ast_passes_auto_items = auto traits cannot have associated items + .label = {ast_passes_auto_items} + .suggestion = remove these associated items + +ast_passes_generic_before_constraints = generic arguments must come before the first constraint + .constraints = {$constraint_len -> + [one] constraint + *[other] constraints + } + .args = generic {$args_len -> + [one] argument + *[other] arguments + } + .empty_string = {""}, + .suggestion = move the {$constraint_len -> + [one] constraint + *[other] constraints + } after the generic {$args_len -> + [one] argument + *[other] arguments + } + +ast_passes_pattern_in_fn_pointer = patterns aren't allowed in function pointer types + +ast_passes_trait_object_single_bound = only a single explicit lifetime bound is permitted + +ast_passes_impl_trait_path = `impl Trait` is not allowed in path parameters + +ast_passes_nested_impl_trait = nested `impl Trait` is not allowed + .outer = outer `impl Trait` + .inner = nested `impl Trait` here + +ast_passes_at_least_one_trait = at least one trait must be specified + +ast_passes_extern_without_abi = extern declarations without an explicit ABI are deprecated + +ast_passes_out_of_order_params = {$param_ord} parameters must be declared prior to {$max_param} parameters + .suggestion = reorder the parameters: lifetimes, then consts and types + +ast_passes_obsolete_auto = `impl Trait for .. {"{}"}` is an obsolete syntax + .help = use `auto trait Trait {"{}"}` instead + +ast_passes_unsafe_negative_impl = negative impls cannot be unsafe + .negative = negative because of this + .unsafe = unsafe because of this + +ast_passes_inherent_cannot_be = inherent impls cannot be {$annotation} + .because = {$annotation} because of this + .type = inherent impl for this type + .only_trait = only trait implementations may be annotated with {$annotation} + +ast_passes_unsafe_item = {$kind} cannot be declared unsafe + +ast_passes_fieldless_union = unions cannot have zero fields + +ast_passes_where_after_type_alias = where clauses are not allowed after the type for type aliases + .note = see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information + +ast_passes_generic_default_trailing = generic parameters with a default must be trailing + +ast_passes_nested_lifetimes = nested quantification of lifetimes + +ast_passes_optional_trait_supertrait = `?Trait` is not permitted in supertraits + .note = traits are `?{$path_str}` by default + +ast_passes_optional_trait_object = `?Trait` is not permitted in trait object types + +ast_passes_tilde_const_disallowed = `~const` is not allowed here + .trait = trait objects cannot have `~const` trait bounds + .closure = closures cannot have `~const` trait bounds + .function = this function is not `const`, so it cannot have `~const` trait bounds + +ast_passes_optional_const_exclusive = `~const` and `?` are mutually exclusive + +ast_passes_const_and_async = functions cannot be both `const` and `async` + .const = `const` because of this + .async = `async` because of this + .label = {""} + +ast_passes_pattern_in_foreign = patterns aren't allowed in foreign function declarations + .label = pattern not allowed in foreign function + +ast_passes_pattern_in_bodiless = patterns aren't allowed in functions without bodies + .label = pattern not allowed in function without body + +ast_passes_equality_in_where = equality constraints are not yet supported in `where` clauses + .label = not supported + .suggestion = if `{$ident}` is an associated type you're trying to set, use the associated type binding syntax + .suggestion_path = if `{$trait_segment}::{$potential_assoc}` is an associated type you're trying to set, use the associated type binding syntax + .note = see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information + +ast_passes_stability_outside_std = stability attributes may not be used outside of the standard library + +ast_passes_feature_on_non_nightly = `#![feature]` may not be used on the {$channel} release channel + .suggestion = remove the attribute + .stable_since = the feature `{$name}` has been stable since `{$since}` and no longer requires an attribute to enable + +ast_passes_incompatbile_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed + .help = remove one of these features + +ast_passes_show_span = {$msg} diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 902b4b1a1..2cc009410 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -13,7 +13,6 @@ use rustc_ast::walk_list; use rustc_ast::*; use rustc_ast_pretty::pprust::{self, State}; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{error_code, fluent, pluralize, struct_span_err, Applicability}; use rustc_macros::Subdiagnostic; use rustc_parse::validate_attr; use rustc_session::lint::builtin::{ @@ -27,11 +26,10 @@ use rustc_span::Span; use rustc_target::spec::abi; use std::mem; use std::ops::{Deref, DerefMut}; +use thin_vec::thin_vec; -use crate::errors::*; - -const MORE_EXTERN: &str = - "for more information, visit https://doc.rust-lang.org/std/keyword.extern.html"; +use crate::errors; +use crate::fluent_generated as fluent; /// Is `self` allowed semantically as the first parameter in an `FnDecl`? enum SelfSemantic { @@ -69,10 +67,6 @@ struct AstValidator<'a> { /// or `Foo::Bar<impl Trait>` is_impl_trait_banned: bool, - /// Used to ban associated type bounds (i.e., `Type<AssocType: Bounds>`) in - /// certain positions. - is_assoc_ty_bound_banned: bool, - /// See [ForbiddenLetReason] forbidden_let_reason: Option<ForbiddenLetReason>, @@ -136,9 +130,9 @@ impl<'a> AstValidator<'a> { fn ban_let_expr(&self, expr: &'a Expr, forbidden_let_reason: ForbiddenLetReason) { let sess = &self.session; if sess.opts.unstable_features.is_nightly_build() { - sess.emit_err(ForbiddenLet { span: expr.span, reason: forbidden_let_reason }); + sess.emit_err(errors::ForbiddenLet { span: expr.span, reason: forbidden_let_reason }); } else { - sess.emit_err(ForbiddenLetStable { span: expr.span }); + sess.emit_err(errors::ForbiddenLetStable { span: expr.span }); } } @@ -178,30 +172,12 @@ impl<'a> AstValidator<'a> { } } - fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) { - let old = mem::replace(&mut self.is_assoc_ty_bound_banned, true); - f(self); - self.is_assoc_ty_bound_banned = old; - } - fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) { let old = mem::replace(&mut self.outer_impl_trait, outer); f(self); self.outer_impl_trait = old; } - fn visit_assoc_constraint_from_generic_args(&mut self, constraint: &'a AssocConstraint) { - match constraint.kind { - AssocConstraintKind::Equality { .. } => {} - AssocConstraintKind::Bound { .. } => { - if self.is_assoc_ty_bound_banned { - self.session.emit_err(ForbiddenAssocConstraint { span: constraint.span }); - } - } - } - self.visit_assoc_constraint(constraint); - } - // Mirrors `visit::walk_ty`, but tracks relevant state. fn walk_ty(&mut self, t: &'a Ty) { match &t.kind { @@ -216,7 +192,7 @@ impl<'a> AstValidator<'a> { // We allow these: // - `Option<impl Trait>` // - `option::Option<impl Trait>` - // - `option::Option<T>::Foo<impl Trait> + // - `option::Option<T>::Foo<impl Trait>` // // But not these: // - `<impl Trait>::Foo` @@ -254,24 +230,24 @@ impl<'a> AstValidator<'a> { fn check_lifetime(&self, ident: Ident) { let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty]; if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() { - self.session.emit_err(KeywordLifetime { span: ident.span }); + self.session.emit_err(errors::KeywordLifetime { span: ident.span }); } } fn check_label(&self, ident: Ident) { if ident.without_first_quote().is_reserved() { - self.session.emit_err(InvalidLabel { span: ident.span, name: ident.name }); + self.session.emit_err(errors::InvalidLabel { span: ident.span, name: ident.name }); } } - fn invalid_visibility(&self, vis: &Visibility, note: Option<InvalidVisibilityNote>) { + fn invalid_visibility(&self, vis: &Visibility, note: Option<errors::InvalidVisibilityNote>) { if let VisibilityKind::Inherited = vis.kind { return; } - self.session.emit_err(InvalidVisibility { + self.session.emit_err(errors::InvalidVisibility { span: vis.span, - implied: if vis.kind.is_pub() { Some(vis.span) } else { None }, + implied: vis.kind.is_pub().then_some(vis.span), note, }); } @@ -290,28 +266,7 @@ impl<'a> AstValidator<'a> { fn check_trait_fn_not_const(&self, constness: Const) { if let Const::Yes(span) = constness { - self.session.emit_err(TraitFnConst { span }); - } - } - - fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) { - // Check only lifetime parameters are present and that the lifetime - // parameters that are present have no bounds. - let non_lt_param_spans: Vec<_> = params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - if !param.bounds.is_empty() { - let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect(); - self.session.emit_err(ForbiddenLifetimeBound { spans }); - } - None - } - _ => Some(param.ident.span), - }) - .collect(); - if !non_lt_param_spans.is_empty() { - self.session.emit_err(ForbiddenNonLifetimeParam { spans: non_lt_param_spans }); + self.session.emit_err(errors::TraitFnConst { span }); } } @@ -328,7 +283,7 @@ impl<'a> AstValidator<'a> { let max_num_args: usize = u16::MAX.into(); if fn_decl.inputs.len() > max_num_args { let Param { span, .. } = fn_decl.inputs[0]; - self.session.emit_fatal(FnParamTooMany { span, max_num_args }); + self.session.emit_fatal(errors::FnParamTooMany { span, max_num_args }); } } @@ -336,13 +291,13 @@ impl<'a> AstValidator<'a> { match &*fn_decl.inputs { [Param { ty, span, .. }] => { if let TyKind::CVarArgs = ty.kind { - self.session.emit_err(FnParamCVarArgsOnly { span: *span }); + self.session.emit_err(errors::FnParamCVarArgsOnly { span: *span }); } } [ps @ .., _] => { for Param { ty, span, .. } in ps { if let TyKind::CVarArgs = ty.kind { - self.session.emit_err(FnParamCVarArgsNotLast { span: *span }); + self.session.emit_err(errors::FnParamCVarArgsNotLast { span: *span }); } } } @@ -369,9 +324,9 @@ impl<'a> AstValidator<'a> { }) .for_each(|attr| { if attr.is_doc_comment() { - self.session.emit_err(FnParamDocComment { span: attr.span }); + self.session.emit_err(errors::FnParamDocComment { span: attr.span }); } else { - self.session.emit_err(FnParamForbiddenAttr { span: attr.span }); + self.session.emit_err(errors::FnParamForbiddenAttr { span: attr.span }); } }); } @@ -379,7 +334,7 @@ impl<'a> AstValidator<'a> { fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) { if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) { if param.is_self() { - self.session.emit_err(FnParamForbiddenSelf { span: param.span }); + self.session.emit_err(errors::FnParamForbiddenSelf { span: param.span }); } } } @@ -387,7 +342,7 @@ impl<'a> AstValidator<'a> { fn check_defaultness(&self, span: Span, defaultness: Defaultness) { if let Defaultness::Default(def_span) = defaultness { let span = self.session.source_map().guess_head_span(span); - self.session.emit_err(ForbiddenDefault { span, def_span }); + self.session.emit_err(errors::ForbiddenDefault { span, def_span }); } } @@ -410,27 +365,17 @@ impl<'a> AstValidator<'a> { [b0] => b0.span(), [b0, .., bl] => b0.span().to(bl.span()), }; - self.err_handler() - .struct_span_err(span, &format!("bounds on `type`s in {} have no effect", ctx)) - .emit(); + self.err_handler().emit_err(errors::BoundInContext { span, ctx }); } fn check_foreign_ty_genericless(&self, generics: &Generics, where_span: Span) { let cannot_have = |span, descr, remove_descr| { - self.err_handler() - .struct_span_err( - span, - &format!("`type`s inside `extern` blocks cannot have {}", descr), - ) - .span_suggestion( - span, - &format!("remove the {}", remove_descr), - "", - Applicability::MaybeIncorrect, - ) - .span_label(self.current_extern_span(), "`extern` block begins here") - .note(MORE_EXTERN) - .emit(); + self.err_handler().emit_err(errors::ExternTypesCannotHave { + span, + descr, + remove_descr, + block_span: self.current_extern_span(), + }); }; if !generics.params.is_empty() { @@ -446,20 +391,12 @@ impl<'a> AstValidator<'a> { let Some(body) = body else { return; }; - self.err_handler() - .struct_span_err(ident.span, &format!("incorrect `{}` inside `extern` block", kind)) - .span_label(ident.span, "cannot have a body") - .span_label(body, "the invalid body") - .span_label( - self.current_extern_span(), - format!( - "`extern` blocks define existing foreign {0}s and {0}s \ - inside of them cannot have a body", - kind - ), - ) - .note(MORE_EXTERN) - .emit(); + self.err_handler().emit_err(errors::BodyInExtern { + span: ident.span, + body, + block: self.current_extern_span(), + kind, + }); } /// An `fn` in `extern { ... }` cannot have a body `{ ... }`. @@ -467,26 +404,11 @@ impl<'a> AstValidator<'a> { let Some(body) = body else { return; }; - self.err_handler() - .struct_span_err(ident.span, "incorrect function inside `extern` block") - .span_label(ident.span, "cannot have a body") - .span_suggestion( - body.span, - "remove the invalid body", - ";", - Applicability::MaybeIncorrect, - ) - .help( - "you might have meant to write a function accessible through FFI, \ - which can be done by writing `extern fn` outside of the `extern` block", - ) - .span_label( - self.current_extern_span(), - "`extern` blocks define existing foreign functions and functions \ - inside of them cannot have a body", - ) - .note(MORE_EXTERN) - .emit(); + self.err_handler().emit_err(errors::FnBodyInExtern { + span: ident.span, + body: body.span, + block: self.current_extern_span(), + }); } fn current_extern_span(&self) -> Span { @@ -496,34 +418,21 @@ impl<'a> AstValidator<'a> { /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`. fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) { if header.has_qualifiers() { - self.err_handler() - .struct_span_err(ident.span, "functions in `extern` blocks cannot have qualifiers") - .span_label(self.current_extern_span(), "in this `extern` block") - .span_suggestion_verbose( - span.until(ident.span.shrink_to_lo()), - "remove the qualifiers", - "fn ", - Applicability::MaybeIncorrect, - ) - .emit(); + self.err_handler().emit_err(errors::FnQualifierInExtern { + span: ident.span, + block: self.current_extern_span(), + sugg_span: span.until(ident.span.shrink_to_lo()), + }); } } /// An item in `extern { ... }` cannot use non-ascii identifier. fn check_foreign_item_ascii_only(&self, ident: Ident) { if !ident.as_str().is_ascii() { - let n = 83942; - self.err_handler() - .struct_span_err( - ident.span, - "items in `extern` blocks cannot use non-ascii identifiers", - ) - .span_label(self.current_extern_span(), "in this `extern` block") - .note(&format!( - "this limitation may be lifted in the future; see issue #{} <https://github.com/rust-lang/rust/issues/{}> for more information", - n, n, - )) - .emit(); + self.err_handler().emit_err(errors::ExternItemAscii { + span: ident.span, + block: self.current_extern_span(), + }); } } @@ -546,12 +455,7 @@ impl<'a> AstValidator<'a> { for Param { ty, span, .. } in &fk.decl().inputs { if let TyKind::CVarArgs = ty.kind { - self.err_handler() - .struct_span_err( - *span, - "only foreign or `unsafe extern \"C\"` functions may be C-variadic", - ) - .emit(); + self.err_handler().emit_err(errors::BadCVariadic { span: *span }); } } } @@ -560,75 +464,32 @@ impl<'a> AstValidator<'a> { if ident.name != kw::Underscore { return; } - self.err_handler() - .struct_span_err(ident.span, &format!("`{}` items in this context need a name", kind)) - .span_label(ident.span, format!("`_` is not a valid name for this `{}` item", kind)) - .emit(); + self.err_handler().emit_err(errors::ItemUnderscore { span: ident.span, kind }); } fn check_nomangle_item_asciionly(&self, ident: Ident, item_span: Span) { if ident.name.as_str().is_ascii() { return; } - let head_span = self.session.source_map().guess_head_span(item_span); - struct_span_err!( - self.session, - head_span, - E0754, - "`#[no_mangle]` requires ASCII identifier" - ) - .emit(); + let span = self.session.source_map().guess_head_span(item_span); + self.session.emit_err(errors::NoMangleAscii { span }); } fn check_mod_file_item_asciionly(&self, ident: Ident) { if ident.name.as_str().is_ascii() { return; } - struct_span_err!( - self.session, - ident.span, - E0754, - "trying to load file for module `{}` with non-ascii identifier name", - ident.name - ) - .help("consider using `#[path]` attribute to specify filesystem path") - .emit(); + self.session.emit_err(errors::ModuleNonAscii { span: ident.span, name: ident.name }); } - fn deny_generic_params(&self, generics: &Generics, ident_span: Span) { + fn deny_generic_params(&self, generics: &Generics, ident: Span) { if !generics.params.is_empty() { - struct_span_err!( - self.session, - generics.span, - E0567, - "auto traits cannot have generic parameters" - ) - .span_label(ident_span, "auto trait cannot have generic parameters") - .span_suggestion( - generics.span, - "remove the parameters", - "", - Applicability::MachineApplicable, - ) - .emit(); + self.session.emit_err(errors::AutoTraitGeneric { span: generics.span, ident }); } } - fn emit_e0568(&self, span: Span, ident_span: Span) { - struct_span_err!( - self.session, - span, - E0568, - "auto traits cannot have super traits or lifetime bounds" - ) - .span_label(ident_span, "auto trait cannot have super traits or lifetime bounds") - .span_suggestion( - span, - "remove the super traits or lifetime bounds", - "", - Applicability::MachineApplicable, - ) - .emit(); + fn emit_e0568(&self, span: Span, ident: Span) { + self.session.emit_err(errors::AutoTraitBounds { span, ident }); } fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) { @@ -644,24 +505,11 @@ impl<'a> AstValidator<'a> { } } - fn deny_items(&self, trait_items: &[P<AssocItem>], ident_span: Span) { + fn deny_items(&self, trait_items: &[P<AssocItem>], ident: Span) { if !trait_items.is_empty() { let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect(); - let total_span = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span); - struct_span_err!( - self.session, - spans, - E0380, - "auto traits cannot have associated items" - ) - .span_suggestion( - total_span, - "remove these associated items", - "", - Applicability::MachineApplicable, - ) - .span_label(ident_span, "auto trait cannot have associated items") - .emit(); + let total = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span); + self.session.emit_err(errors::AutoTraitItems { spans, total, ident }); } } @@ -707,29 +555,17 @@ impl<'a> AstValidator<'a> { let args_len = arg_spans.len(); let constraint_len = constraint_spans.len(); // ...and then error: - self.err_handler() - .struct_span_err( - arg_spans.clone(), - "generic arguments must come before the first constraint", - ) - .span_label(constraint_spans[0], &format!("constraint{}", pluralize!(constraint_len))) - .span_label( - *arg_spans.iter().last().unwrap(), - &format!("generic argument{}", pluralize!(args_len)), - ) - .span_labels(constraint_spans, "") - .span_labels(arg_spans, "") - .span_suggestion_verbose( - data.span, - &format!( - "move the constraint{} after the generic argument{}", - pluralize!(constraint_len), - pluralize!(args_len) - ), - self.correct_generic_order_suggestion(&data), - Applicability::MachineApplicable, - ) - .emit(); + self.err_handler().emit_err(errors::ArgsBeforeConstraint { + arg_spans: arg_spans.clone(), + constraints: constraint_spans[0], + args: *arg_spans.iter().last().unwrap(), + data: data.span, + constraint_spans: errors::EmptyLabelManySpans(constraint_spans), + arg_spans2: errors::EmptyLabelManySpans(arg_spans), + suggestion: self.correct_generic_order_suggestion(&data), + constraint_len, + args_len, + }); } fn visit_ty_common(&mut self, ty: &'a Ty) { @@ -737,15 +573,8 @@ impl<'a> AstValidator<'a> { TyKind::BareFn(bfty) => { self.check_fn_decl(&bfty.decl, SelfSemantic::No); Self::check_decl_no_pat(&bfty.decl, |span, _, _| { - struct_span_err!( - self.session, - span, - E0561, - "patterns aren't allowed in function pointer types" - ) - .emit(); + self.session.emit_err(errors::PatternFnPointer { span }); }); - self.check_late_bound_lifetime_defs(&bfty.generic_params); if let Extern::Implicit(_) = bfty.ext { let sig_span = self.session.source_map().next_point(ty.span.shrink_to_lo()); self.maybe_lint_missing_abi(sig_span, ty.id); @@ -756,13 +585,8 @@ impl<'a> AstValidator<'a> { for bound in bounds { if let GenericBound::Outlives(lifetime) = bound { if any_lifetime_bounds { - struct_span_err!( - self.session, - lifetime.ident.span, - E0226, - "only a single explicit lifetime bound is permitted" - ) - .emit(); + self.session + .emit_err(errors::TraitObjectBound { span: lifetime.ident.span }); break; } any_lifetime_bounds = true; @@ -771,29 +595,19 @@ impl<'a> AstValidator<'a> { } TyKind::ImplTrait(_, bounds) => { if self.is_impl_trait_banned { - struct_span_err!( - self.session, - ty.span, - E0667, - "`impl Trait` is not allowed in path parameters" - ) - .emit(); + self.session.emit_err(errors::ImplTraitPath { span: ty.span }); } if let Some(outer_impl_trait_sp) = self.outer_impl_trait { - struct_span_err!( - self.session, - ty.span, - E0666, - "nested `impl Trait` is not allowed" - ) - .span_label(outer_impl_trait_sp, "outer `impl Trait`") - .span_label(ty.span, "nested `impl Trait` here") - .emit(); + self.session.emit_err(errors::NestedImplTrait { + span: ty.span, + outer: outer_impl_trait_sp, + inner: ty.span, + }); } if !bounds.iter().any(|b| matches!(b, GenericBound::Trait(..))) { - self.err_handler().span_err(ty.span, "at least one trait must be specified"); + self.err_handler().emit_err(errors::AtLeastOneTrait { span: ty.span }); } } _ => {} @@ -814,7 +628,7 @@ impl<'a> AstValidator<'a> { MISSING_ABI, id, span, - "extern declarations without an explicit ABI are deprecated", + fluent::ast_passes_extern_without_abi, BuiltinLintDiagnostics::MissingAbi(span, abi::Abi::FALLBACK), ) } @@ -887,20 +701,13 @@ fn validate_generic_param_order( ordered_params += ">"; for (param_ord, (max_param, spans)) in &out_of_order { - let mut err = handler.struct_span_err( - spans.clone(), - &format!( - "{} parameters must be declared prior to {} parameters", - param_ord, max_param, - ), - ); - err.span_suggestion( - span, - "reorder the parameters: lifetimes, then consts and types", - &ordered_params, - Applicability::MachineApplicable, - ); - err.emit(); + handler.emit_err(errors::OutOfOrderParams { + spans: spans.clone(), + sugg_span: span, + param_ord, + max_param, + ordered_params: &ordered_params, + }); } } } @@ -1014,25 +821,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.with_in_trait_impl(true, Some(*constness), |this| { this.invalid_visibility(&item.vis, None); if let TyKind::Err = self_ty.kind { - this.err_handler() - .struct_span_err( - item.span, - "`impl Trait for .. {}` is an obsolete syntax", - ) - .help("use `auto trait Trait {}` instead") - .emit(); + this.err_handler().emit_err(errors::ObsoleteAuto { span: item.span }); } if let (&Unsafe::Yes(span), &ImplPolarity::Negative(sp)) = (unsafety, polarity) { - struct_span_err!( - this.session, - sp.to(t.path.span), - E0198, - "negative impls cannot be unsafe" - ) - .span_label(sp, "negative because of this") - .span_label(span, "unsafe because of this") - .emit(); + this.session.emit_err(errors::UnsafeNegativeImpl { + span: sp.to(t.path.span), + negative: sp, + r#unsafe: span, + }); } this.visit_vis(&item.vis); @@ -1060,52 +857,54 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self_ty, items: _, }) => { - let error = |annotation_span, annotation| { - let mut err = self.err_handler().struct_span_err( - self_ty.span, - &format!("inherent impls cannot be {}", annotation), - ); - err.span_label(annotation_span, &format!("{} because of this", annotation)); - err.span_label(self_ty.span, "inherent impl for this type"); - err - }; + let error = + |annotation_span, annotation, only_trait: bool| errors::InherentImplCannot { + span: self_ty.span, + annotation_span, + annotation, + self_ty: self_ty.span, + only_trait: only_trait.then_some(()), + }; self.invalid_visibility( &item.vis, - Some(InvalidVisibilityNote::IndividualImplItems), + Some(errors::InvalidVisibilityNote::IndividualImplItems), ); if let &Unsafe::Yes(span) = unsafety { - error(span, "unsafe").code(error_code!(E0197)).emit(); + self.err_handler().emit_err(errors::InherentImplCannotUnsafe { + span: self_ty.span, + annotation_span: span, + annotation: "unsafe", + self_ty: self_ty.span, + }); } if let &ImplPolarity::Negative(span) = polarity { - error(span, "negative").emit(); + self.err_handler().emit_err(error(span, "negative", false)); } if let &Defaultness::Default(def_span) = defaultness { - error(def_span, "`default`") - .note("only trait implementations may be annotated with `default`") - .emit(); + self.err_handler().emit_err(error(def_span, "`default`", true)); } if let &Const::Yes(span) = constness { - error(span, "`const`") - .note("only trait implementations may be annotated with `const`") - .emit(); + self.err_handler().emit_err(error(span, "`const`", true)); } } ItemKind::Fn(box Fn { defaultness, sig, generics, body }) => { self.check_defaultness(item.span, *defaultness); if body.is_none() { - self.session.emit_err(FnWithoutBody { + self.session.emit_err(errors::FnWithoutBody { span: item.span, replace_span: self.ending_semi_or_hi(item.span), extern_block_suggestion: match sig.header.ext { Extern::None => None, - Extern::Implicit(start_span) => Some(ExternBlockSuggestion::Implicit { - start_span, - end_span: item.span.shrink_to_hi(), - }), + Extern::Implicit(start_span) => { + Some(errors::ExternBlockSuggestion::Implicit { + start_span, + end_span: item.span.shrink_to_hi(), + }) + } Extern::Explicit(abi, start_span) => { - Some(ExternBlockSuggestion::Explicit { + Some(errors::ExternBlockSuggestion::Explicit { start_span, end_span: item.span.shrink_to_hi(), abi: abi.symbol_unescaped, @@ -1127,10 +926,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> { let old_item = mem::replace(&mut self.extern_mod, Some(item)); self.invalid_visibility( &item.vis, - Some(InvalidVisibilityNote::IndividualForeignItems), + Some(errors::InvalidVisibilityNote::IndividualForeignItems), ); if let &Unsafe::Yes(span) = unsafety { - self.err_handler().span_err(span, "extern block cannot be declared unsafe"); + self.err_handler().emit_err(errors::UnsafeItem { span, kind: "extern block" }); } if abi.is_none() { self.maybe_lint_missing_abi(item.span, item.id); @@ -1170,7 +969,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } ItemKind::Mod(unsafety, mod_kind) => { if let &Unsafe::Yes(span) = unsafety { - self.err_handler().span_err(span, "module cannot be declared unsafe"); + self.err_handler().emit_err(errors::UnsafeItem { span, kind: "module" }); } // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584). if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _)) @@ -1181,18 +980,18 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } ItemKind::Union(vdata, ..) => { if vdata.fields().is_empty() { - self.err_handler().span_err(item.span, "unions cannot have zero fields"); + self.err_handler().emit_err(errors::FieldlessUnion { span: item.span }); } } ItemKind::Const(def, .., None) => { self.check_defaultness(item.span, *def); - self.session.emit_err(ConstWithoutBody { + self.session.emit_err(errors::ConstWithoutBody { span: item.span, replace_span: self.ending_semi_or_hi(item.span), }); } ItemKind::Static(.., None) => { - self.session.emit_err(StaticWithoutBody { + self.session.emit_err(errors::StaticWithoutBody { span: item.span, replace_span: self.ending_semi_or_hi(item.span), }); @@ -1200,21 +999,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> { ItemKind::TyAlias(box TyAlias { defaultness, where_clauses, bounds, ty, .. }) => { self.check_defaultness(item.span, *defaultness); if ty.is_none() { - self.session.emit_err(TyAliasWithoutBody { + self.session.emit_err(errors::TyAliasWithoutBody { span: item.span, replace_span: self.ending_semi_or_hi(item.span), }); } self.check_type_no_bounds(bounds, "this context"); if where_clauses.1.0 { - let mut err = self.err_handler().struct_span_err( - where_clauses.1.1, - "where clauses are not allowed after the type for type aliases", - ); - err.note( - "see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information", - ); - err.emit(); + self.err_handler() + .emit_err(errors::WhereAfterTypeAlias { span: where_clauses.1.1 }); } } _ => {} @@ -1268,7 +1061,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { // are allowed to contain nested `impl Trait`. AngleBracketedArg::Constraint(constraint) => { self.with_impl_trait(None, |this| { - this.visit_assoc_constraint_from_generic_args(constraint); + this.visit_assoc_constraint(constraint); }); } } @@ -1296,11 +1089,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { if let Some(span) = prev_param_default { - let mut err = self.err_handler().struct_span_err( - span, - "generic parameters with a default must be trailing", - ); - err.emit(); + self.err_handler().emit_err(errors::GenericDefaultTrailing { span }); break; } } @@ -1318,9 +1107,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { for predicate in &generics.where_clause.predicates { match predicate { WherePredicate::BoundPredicate(bound_pred) => { - // A type binding, eg `for<'c> Foo: Send+Clone+'c` - self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params); - // This is slightly complicated. Our representation for poly-trait-refs contains a single // binder and thus we only allow a single level of quantification. However, // the syntax of Rust permits quantification in two places in where clauses, @@ -1331,13 +1117,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { match bound { GenericBound::Trait(t, _) => { if !t.bound_generic_params.is_empty() { - struct_span_err!( - self.err_handler(), - t.span, - E0316, - "nested quantification of lifetimes" - ) - .emit(); + self.err_handler() + .emit_err(errors::NestedLifetimes { span: t.span }); } } GenericBound::Outlives(_) => {} @@ -1362,32 +1143,27 @@ impl<'a> Visitor<'a> for AstValidator<'a> { if let GenericBound::Trait(poly, modify) = bound { match (ctxt, modify) { (BoundKind::SuperTraits, TraitBoundModifier::Maybe) => { - let mut err = self - .err_handler() - .struct_span_err(poly.span, "`?Trait` is not permitted in supertraits"); - let path_str = pprust::path_to_string(&poly.trait_ref.path); - err.note(&format!("traits are `?{}` by default", path_str)); - err.emit(); + self.err_handler().emit_err(errors::OptionalTraitSupertrait { + span: poly.span, + path_str: pprust::path_to_string(&poly.trait_ref.path) + }); } (BoundKind::TraitObject, TraitBoundModifier::Maybe) => { - let mut err = self.err_handler().struct_span_err( - poly.span, - "`?Trait` is not permitted in trait object types", - ); - err.emit(); + self.err_handler().emit_err(errors::OptionalTraitObject {span: poly.span}); } (_, TraitBoundModifier::MaybeConst) if let Some(reason) = &self.disallow_tilde_const => { - let mut err = self.err_handler().struct_span_err(bound.span(), "`~const` is not allowed here"); - match reason { - DisallowTildeConstContext::TraitObject => err.note("trait objects cannot have `~const` trait bounds"), - DisallowTildeConstContext::Fn(FnKind::Closure(..)) => err.note("closures cannot have `~const` trait bounds"), - DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => err.span_note(ident.span, "this function is not `const`, so it cannot have `~const` trait bounds"), + let reason = match reason { + DisallowTildeConstContext::TraitObject => errors::TildeConstReason::TraitObject, + DisallowTildeConstContext::Fn(FnKind::Closure(..)) => errors::TildeConstReason::Closure, + DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => errors::TildeConstReason::Function { ident: ident.span }, }; - err.emit(); + self.err_handler().emit_err(errors::TildeConstDisallowed { + span: bound.span(), + reason + }); } (_, TraitBoundModifier::MaybeConstMaybe) => { - self.err_handler() - .span_err(bound.span(), "`~const` and `?` are mutually exclusive"); + self.err_handler().emit_err(errors::OptionalConstExclusive {span: bound.span()}); } _ => {} } @@ -1396,19 +1172,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { visit::walk_param_bound(self, bound) } - fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef) { - self.check_late_bound_lifetime_defs(&t.bound_generic_params); - visit::walk_poly_trait_ref(self, t); - } - - fn visit_variant_data(&mut self, s: &'a VariantData) { - self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s)) - } - - fn visit_enum_def(&mut self, enum_definition: &'a EnumDef) { - self.with_banned_assoc_ty_bound(|this| visit::walk_enum_def(this, enum_definition)) - } - fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) { // Only associated `fn`s can have `self` parameters. let self_semantic = match fk.ctxt() { @@ -1420,25 +1183,18 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.check_c_variadic_type(fk); // Functions cannot both be `const async` - if let Some(FnHeader { + if let Some(&FnHeader { constness: Const::Yes(cspan), asyncness: Async::Yes { span: aspan, .. }, .. }) = fk.header() { - self.err_handler() - .struct_span_err( - vec![*cspan, *aspan], - "functions cannot be both `const` and `async`", - ) - .span_label(*cspan, "`const` because of this") - .span_label(*aspan, "`async` because of this") - .span_label(span, "") // Point at the fn header. - .emit(); - } - - if let FnKind::Closure(ClosureBinder::For { generic_params, .. }, ..) = fk { - self.check_late_bound_lifetime_defs(generic_params); + self.err_handler().emit_err(errors::ConstAndAsync { + spans: vec![cspan, aspan], + cspan, + aspan, + span, + }); } if let FnKind::Fn( @@ -1456,20 +1212,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> { // Functions without bodies cannot have patterns. if let FnKind::Fn(ctxt, _, sig, _, _, None) = fk { Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| { - let (code, msg, label) = match ctxt { - FnCtxt::Foreign => ( - error_code!(E0130), - "patterns aren't allowed in foreign function declarations", - "pattern not allowed in foreign function", - ), - _ => ( - error_code!(E0642), - "patterns aren't allowed in functions without bodies", - "pattern not allowed in function without body", - ), - }; if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) { if let Some(ident) = ident { + let msg = match ctxt { + FnCtxt::Foreign => fluent::ast_passes_pattern_in_foreign, + _ => fluent::ast_passes_pattern_in_bodiless, + }; let diag = BuiltinLintDiagnostics::PatternsInFnsWithoutBody(span, ident); self.lint_buffer.buffer_lint_with_diagnostic( PATTERNS_IN_FNS_WITHOUT_BODY, @@ -1480,11 +1228,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> { ) } } else { - self.err_handler() - .struct_span_err(span, msg) - .span_label(span, label) - .code(code) - .emit(); + match ctxt { + FnCtxt::Foreign => { + self.err_handler().emit_err(errors::PatternInForeign { span }) + } + _ => self.err_handler().emit_err(errors::PatternInBodiless { span }), + }; } }); } @@ -1511,7 +1260,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { match &item.kind { AssocItemKind::Const(_, _, body) => { if body.is_none() { - self.session.emit_err(AssocConstWithoutBody { + self.session.emit_err(errors::AssocConstWithoutBody { span: item.span, replace_span: self.ending_semi_or_hi(item.span), }); @@ -1519,7 +1268,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } AssocItemKind::Fn(box Fn { body, .. }) => { if body.is_none() { - self.session.emit_err(AssocFnWithoutBody { + self.session.emit_err(errors::AssocFnWithoutBody { span: item.span, replace_span: self.ending_semi_or_hi(item.span), }); @@ -1534,7 +1283,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { .. }) => { if ty.is_none() { - self.session.emit_err(AssocTypeWithoutBody { + self.session.emit_err(errors::AssocTypeWithoutBody { span: item.span, replace_span: self.ending_semi_or_hi(item.span), }); @@ -1606,11 +1355,7 @@ fn deny_equality_constraints( predicate: &WhereEqPredicate, generics: &Generics, ) { - let mut err = this.err_handler().struct_span_err( - predicate.span, - "equality constraints are not yet supported in `where` clauses", - ); - err.span_label(predicate.span, "not supported"); + let mut err = errors::EqualityInWhere { span: predicate.span, assoc: None, assoc2: None }; // Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`. if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind { @@ -1649,25 +1394,17 @@ fn deny_equality_constraints( empty_args => { *empty_args = AngleBracketedArgs { span: ident.span, - args: vec![arg], + args: thin_vec![arg], } .into(); } } - err.span_suggestion_verbose( - predicate.span, - &format!( - "if `{}` is an associated type you're trying to set, \ - use the associated type binding syntax", - ident - ), - format!( - "{}: {}", - param, - pprust::path_to_string(&assoc_path) - ), - Applicability::MaybeIncorrect, - ); + err.assoc = Some(errors::AssociatedSuggestion { + span: predicate.span, + ident: *ident, + param: *param, + path: pprust::path_to_string(&assoc_path), + }) } _ => {} }; @@ -1709,15 +1446,13 @@ fn deny_equality_constraints( trait_segment.span().shrink_to_hi(), ), }; - err.multipart_suggestion( - &format!( - "if `{}::{}` is an associated type you're trying to set, \ - use the associated type binding syntax", - trait_segment.ident, potential_assoc.ident, - ), - vec![(span, args), (predicate.span, String::new())], - Applicability::MaybeIncorrect, - ); + err.assoc2 = Some(errors::AssociatedSuggestion2 { + span, + args, + predicate: predicate.span, + trait_segment: trait_segment.ident, + potential_assoc: potential_assoc.ident, + }); } } } @@ -1725,10 +1460,7 @@ fn deny_equality_constraints( } } } - err.note( - "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information", - ); - err.emit(); + this.err_handler().emit_err(err); } pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool { @@ -1741,7 +1473,6 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> outer_impl_trait: None, disallow_tilde_const: None, is_impl_trait_banned: false, - is_assoc_ty_bound_banned: false, forbidden_let_reason: Some(ForbiddenLetReason::GenericForbidden), lint_buffer: lints, }; @@ -1756,12 +1487,12 @@ pub(crate) enum ForbiddenLetReason { /// `let` is not valid and the source environment is not important GenericForbidden, /// A let chain with the `||` operator - #[note(not_supported_or)] + #[note(ast_passes_not_supported_or)] NotSupportedOr(#[primary_span] Span), /// A let chain with invalid parentheses /// /// For example, `let 1 = 1 && (expr && expr)` is allowed /// but `(let 1 = 1 && (let 1 = 1 && (let 1 = 1))) && let a = 1` is not - #[note(not_supported_parentheses)] + #[note(ast_passes_not_supported_parentheses)] NotSupportedParentheses(#[primary_span] Span), } diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 09e262452..d007097d9 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -1,9 +1,12 @@ //! Errors emitted by ast_passes. +use rustc_ast::ParamKindOrd; +use rustc_errors::AddToDiagnostic; use rustc_macros::{Diagnostic, Subdiagnostic}; -use rustc_span::{Span, Symbol}; +use rustc_span::{symbol::Ident, Span, Symbol}; use crate::ast_validation::ForbiddenLetReason; +use crate::fluent_generated as fluent; #[derive(Diagnostic)] #[diag(ast_passes_forbidden_let)] @@ -24,13 +27,6 @@ pub struct ForbiddenLetStable { } #[derive(Diagnostic)] -#[diag(ast_passes_forbidden_assoc_constraint)] -pub struct ForbiddenAssocConstraint { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] #[diag(ast_passes_keyword_lifetime)] pub struct KeywordLifetime { #[primary_span] @@ -50,7 +46,7 @@ pub struct InvalidLabel { pub struct InvalidVisibility { #[primary_span] pub span: Span, - #[label(implied)] + #[label(ast_passes_implied)] pub implied: Option<Span>, #[subdiagnostic] pub note: Option<InvalidVisibilityNote>, @@ -58,9 +54,9 @@ pub struct InvalidVisibility { #[derive(Subdiagnostic)] pub enum InvalidVisibilityNote { - #[note(individual_impl_items)] + #[note(ast_passes_individual_impl_items)] IndividualImplItems, - #[note(individual_foreign_items)] + #[note(ast_passes_individual_foreign_items)] IndividualForeignItems, } @@ -224,3 +220,474 @@ pub enum ExternBlockSuggestion { abi: Symbol, }, } + +#[derive(Diagnostic)] +#[diag(ast_passes_bound_in_context)] +pub struct BoundInContext<'a> { + #[primary_span] + pub span: Span, + pub ctx: &'a str, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_extern_types_cannot)] +#[note(ast_passes_extern_keyword_link)] +pub struct ExternTypesCannotHave<'a> { + #[primary_span] + #[suggestion(code = "", applicability = "maybe-incorrect")] + pub span: Span, + pub descr: &'a str, + pub remove_descr: &'a str, + #[label] + pub block_span: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_body_in_extern)] +#[note(ast_passes_extern_keyword_link)] +pub struct BodyInExtern<'a> { + #[primary_span] + #[label(ast_passes_cannot_have)] + pub span: Span, + #[label(ast_passes_invalid)] + pub body: Span, + #[label(ast_passes_existing)] + pub block: Span, + pub kind: &'a str, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_fn_body_extern)] +#[help] +#[note(ast_passes_extern_keyword_link)] +pub struct FnBodyInExtern { + #[primary_span] + #[label(ast_passes_cannot_have)] + pub span: Span, + #[suggestion(code = ";", applicability = "maybe-incorrect")] + pub body: Span, + #[label] + pub block: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_extern_fn_qualifiers)] +pub struct FnQualifierInExtern { + #[primary_span] + pub span: Span, + #[label] + pub block: Span, + #[suggestion(code = "fn ", applicability = "maybe-incorrect", style = "verbose")] + pub sugg_span: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_extern_item_ascii)] +#[note] +pub struct ExternItemAscii { + #[primary_span] + pub span: Span, + #[label] + pub block: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_bad_c_variadic)] +pub struct BadCVariadic { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_item_underscore)] +pub struct ItemUnderscore<'a> { + #[primary_span] + #[label] + pub span: Span, + pub kind: &'a str, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_nomangle_ascii, code = "E0754")] +pub struct NoMangleAscii { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_module_nonascii, code = "E0754")] +#[help] +pub struct ModuleNonAscii { + #[primary_span] + pub span: Span, + pub name: Symbol, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_auto_generic, code = "E0567")] +pub struct AutoTraitGeneric { + #[primary_span] + #[suggestion(code = "", applicability = "machine-applicable")] + pub span: Span, + #[label] + pub ident: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_auto_super_lifetime, code = "E0568")] +pub struct AutoTraitBounds { + #[primary_span] + #[suggestion(code = "", applicability = "machine-applicable")] + pub span: Span, + #[label] + pub ident: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_auto_items, code = "E0380")] +pub struct AutoTraitItems { + #[primary_span] + pub spans: Vec<Span>, + #[suggestion(code = "", applicability = "machine-applicable")] + pub total: Span, + #[label] + pub ident: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_generic_before_constraints)] +pub struct ArgsBeforeConstraint { + #[primary_span] + pub arg_spans: Vec<Span>, + #[label(ast_passes_constraints)] + pub constraints: Span, + #[label(ast_passes_args)] + pub args: Span, + #[suggestion(code = "{suggestion}", applicability = "machine-applicable", style = "verbose")] + pub data: Span, + pub suggestion: String, + pub constraint_len: usize, + pub args_len: usize, + #[subdiagnostic] + pub constraint_spans: EmptyLabelManySpans, + #[subdiagnostic] + pub arg_spans2: EmptyLabelManySpans, +} + +pub struct EmptyLabelManySpans(pub Vec<Span>); + +// The derive for `Vec<Span>` does multiple calls to `span_label`, adding commas between each +impl AddToDiagnostic for EmptyLabelManySpans { + fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F) + where + F: Fn( + &mut rustc_errors::Diagnostic, + rustc_errors::SubdiagnosticMessage, + ) -> rustc_errors::SubdiagnosticMessage, + { + diag.span_labels(self.0, ""); + } +} + +#[derive(Diagnostic)] +#[diag(ast_passes_pattern_in_fn_pointer, code = "E0561")] +pub struct PatternFnPointer { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_trait_object_single_bound, code = "E0226")] +pub struct TraitObjectBound { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_impl_trait_path, code = "E0667")] +pub struct ImplTraitPath { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_nested_impl_trait, code = "E0666")] +pub struct NestedImplTrait { + #[primary_span] + pub span: Span, + #[label(ast_passes_outer)] + pub outer: Span, + #[label(ast_passes_inner)] + pub inner: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_at_least_one_trait)] +pub struct AtLeastOneTrait { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_out_of_order_params)] +pub struct OutOfOrderParams<'a> { + #[primary_span] + pub spans: Vec<Span>, + #[suggestion(code = "{ordered_params}", applicability = "machine-applicable")] + pub sugg_span: Span, + pub param_ord: &'a ParamKindOrd, + pub max_param: &'a ParamKindOrd, + pub ordered_params: &'a str, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_obsolete_auto)] +#[help] +pub struct ObsoleteAuto { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_unsafe_negative_impl, code = "E0198")] +pub struct UnsafeNegativeImpl { + #[primary_span] + pub span: Span, + #[label(ast_passes_negative)] + pub negative: Span, + #[label(ast_passes_unsafe)] + pub r#unsafe: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_inherent_cannot_be)] +pub struct InherentImplCannot<'a> { + #[primary_span] + pub span: Span, + #[label(ast_passes_because)] + pub annotation_span: Span, + pub annotation: &'a str, + #[label(ast_passes_type)] + pub self_ty: Span, + #[note(ast_passes_only_trait)] + pub only_trait: Option<()>, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_inherent_cannot_be, code = "E0197")] +pub struct InherentImplCannotUnsafe<'a> { + #[primary_span] + pub span: Span, + #[label(ast_passes_because)] + pub annotation_span: Span, + pub annotation: &'a str, + #[label(ast_passes_type)] + pub self_ty: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_unsafe_item)] +pub struct UnsafeItem { + #[primary_span] + pub span: Span, + pub kind: &'static str, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_fieldless_union)] +pub struct FieldlessUnion { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_where_after_type_alias)] +#[note] +pub struct WhereAfterTypeAlias { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_generic_default_trailing)] +pub struct GenericDefaultTrailing { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_nested_lifetimes, code = "E0316")] +pub struct NestedLifetimes { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_optional_trait_supertrait)] +#[note] +pub struct OptionalTraitSupertrait { + #[primary_span] + pub span: Span, + pub path_str: String, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_optional_trait_object)] +pub struct OptionalTraitObject { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_tilde_const_disallowed)] +pub struct TildeConstDisallowed { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub reason: TildeConstReason, +} + +#[derive(Subdiagnostic)] +pub enum TildeConstReason { + #[note(ast_passes_trait)] + TraitObject, + #[note(ast_passes_closure)] + Closure, + #[note(ast_passes_function)] + Function { + #[primary_span] + ident: Span, + }, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_optional_const_exclusive)] +pub struct OptionalConstExclusive { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_const_and_async)] +pub struct ConstAndAsync { + #[primary_span] + pub spans: Vec<Span>, + #[label(ast_passes_const)] + pub cspan: Span, + #[label(ast_passes_async)] + pub aspan: Span, + #[label] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_pattern_in_foreign, code = "E0130")] +pub struct PatternInForeign { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_pattern_in_bodiless, code = "E0642")] +pub struct PatternInBodiless { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_equality_in_where)] +#[note] +pub struct EqualityInWhere { + #[primary_span] + #[label] + pub span: Span, + #[subdiagnostic] + pub assoc: Option<AssociatedSuggestion>, + #[subdiagnostic] + pub assoc2: Option<AssociatedSuggestion2>, +} + +#[derive(Subdiagnostic)] +#[suggestion( + ast_passes_suggestion, + code = "{param}: {path}", + style = "verbose", + applicability = "maybe-incorrect" +)] +pub struct AssociatedSuggestion { + #[primary_span] + pub span: Span, + pub ident: Ident, + pub param: Ident, + pub path: String, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(ast_passes_suggestion_path, applicability = "maybe-incorrect")] +pub struct AssociatedSuggestion2 { + #[suggestion_part(code = "{args}")] + pub span: Span, + pub args: String, + #[suggestion_part(code = "")] + pub predicate: Span, + pub trait_segment: Ident, + pub potential_assoc: Ident, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_stability_outside_std, code = "E0734")] +pub struct StabilityOutsideStd { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_feature_on_non_nightly, code = "E0554")] +pub struct FeatureOnNonNightly { + #[primary_span] + pub span: Span, + pub channel: &'static str, + #[subdiagnostic] + pub stable_features: Vec<StableFeature>, + #[suggestion(code = "", applicability = "machine-applicable")] + pub sugg: Option<Span>, +} + +pub struct StableFeature { + pub name: Symbol, + pub since: Symbol, +} + +impl AddToDiagnostic for StableFeature { + fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F) + where + F: Fn( + &mut rustc_errors::Diagnostic, + rustc_errors::SubdiagnosticMessage, + ) -> rustc_errors::SubdiagnosticMessage, + { + diag.set_arg("name", self.name); + diag.set_arg("since", self.since); + diag.help(fluent::ast_passes_stable_since); + } +} + +#[derive(Diagnostic)] +#[diag(ast_passes_incompatbile_features)] +#[help] +pub struct IncompatibleFeatures { + #[primary_span] + pub spans: Vec<Span>, + pub f1: Symbol, + pub f2: Symbol, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_show_span)] +pub struct ShowSpan { + #[primary_span] + pub span: Span, + pub msg: &'static str, +} diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 89ba6f936..96042ea30 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -2,7 +2,7 @@ use rustc_ast as ast; use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; use rustc_ast::{AssocConstraint, AssocConstraintKind, NodeId}; use rustc_ast::{PatKind, RangeEnd}; -use rustc_errors::{struct_span_err, Applicability, StashKey}; +use rustc_errors::{Applicability, StashKey}; use rustc_feature::{AttributeGate, BuiltinAttribute, Features, GateIssue, BUILTIN_ATTRIBUTE_MAP}; use rustc_session::parse::{feature_err, feature_err_issue, feature_warn}; use rustc_session::Session; @@ -10,6 +10,10 @@ use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; use rustc_span::Span; use rustc_target::spec::abi; +use thin_vec::ThinVec; +use tracing::debug; + +use crate::errors; macro_rules! gate_feature_fn { ($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $help: expr) => {{ @@ -136,6 +140,34 @@ impl<'a> PostExpansionVisitor<'a> { } ImplTraitVisitor { vis: self }.visit_ty(ty); } + + fn check_late_bound_lifetime_defs(&self, params: &[ast::GenericParam]) { + // Check only lifetime parameters are present and that the lifetime + // parameters that are present have no bounds. + let non_lt_param_spans: Vec<_> = params + .iter() + .filter_map(|param| match param.kind { + ast::GenericParamKind::Lifetime { .. } => None, + _ => Some(param.ident.span), + }) + .collect(); + // FIXME: gate_feature_post doesn't really handle multispans... + if !non_lt_param_spans.is_empty() && !self.features.non_lifetime_binders { + feature_err( + &self.sess.parse_sess, + sym::non_lifetime_binders, + non_lt_param_spans, + crate::fluent_generated::ast_passes_forbidden_non_lifetime_param, + ) + .emit(); + } + for param in params { + if !param.bounds.is_empty() { + let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect(); + self.sess.emit_err(errors::ForbiddenLifetimeBound { spans }); + } + } + } } impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { @@ -147,7 +179,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { .. }) = attr_info { - gate_feature_fn!(self, has_feature, attr.span, *name, descr); + gate_feature_fn!(self, has_feature, attr.span, *name, *descr); } // Check unstable flavors of the `#[doc]` attribute. if attr.has_name(sym::doc) { @@ -186,13 +218,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { || attr.has_name(sym::rustc_const_stable) || attr.has_name(sym::rustc_default_body_unstable) { - struct_span_err!( - self.sess, - attr.span, - E0734, - "stability attributes may not be used outside of the standard library", - ) - .emit(); + self.sess.emit_err(errors::StabilityOutsideStd { span: attr.span }); } } } @@ -220,7 +246,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ast::ItemKind::Struct(..) => { for attr in self.sess.filter_by_name(&i.attrs, sym::repr) { - for item in attr.meta_item_list().unwrap_or_else(Vec::new) { + for item in attr.meta_item_list().unwrap_or_else(ThinVec::new) { if item.has_name(sym::simd) { gate_feature_post!( &self, @@ -306,6 +332,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ast::TyKind::BareFn(bare_fn_ty) => { // Function pointers cannot be `const` self.check_extern(bare_fn_ty.ext, ast::Const::No); + self.check_late_bound_lifetime_defs(&bare_fn_ty.generic_params); } ast::TyKind::Never => { gate_feature_post!(&self, never_type, ty.span, "the `!` type is experimental"); @@ -318,6 +345,19 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { visit::walk_ty(self, ty) } + fn visit_generics(&mut self, g: &'a ast::Generics) { + for predicate in &g.where_clause.predicates { + match predicate { + ast::WherePredicate::BoundPredicate(bound_pred) => { + // A type binding, eg `for<'c> Foo: Send+Clone+'c` + self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params); + } + _ => {} + } + } + visit::walk_generics(self, g); + } + fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FnRetTy) { if let ast::FnRetTy::Ty(output_ty) = ret_ty { if let ast::TyKind::Never = output_ty.kind { @@ -346,7 +386,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ).span_suggestion_verbose( lhs.span.shrink_to_lo(), "you might have meant to introduce a new binding", - "let ".to_string(), + "let ", Applicability::MachineApplicable, ).emit(); } @@ -437,12 +477,21 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { visit::walk_pat(self, pattern) } + fn visit_poly_trait_ref(&mut self, t: &'a ast::PolyTraitRef) { + self.check_late_bound_lifetime_defs(&t.bound_generic_params); + visit::walk_poly_trait_ref(self, t); + } + fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) { if let Some(header) = fn_kind.header() { // Stability of const fn methods are covered in `visit_assoc_item` below. self.check_extern(header.ext, header.constness); } + if let FnKind::Closure(ast::ClosureBinder::For { generic_params, .. }, ..) = fn_kind { + self.check_late_bound_lifetime_defs(generic_params); + } + if fn_kind.ctxt() != Some(FnCtxt::Foreign) && fn_kind.decl().c_variadic() { gate_feature_post!(&self, c_variadic, span, "C-variadic functions are unstable"); } @@ -580,13 +629,13 @@ fn maybe_stage_features(sess: &Session, krate: &ast::Crate) { return; } for attr in krate.attrs.iter().filter(|attr| attr.has_name(sym::feature)) { - let mut err = struct_span_err!( - sess.parse_sess.span_diagnostic, - attr.span, - E0554, - "`#![feature]` may not be used on the {} release channel", - option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)") - ); + let mut err = errors::FeatureOnNonNightly { + span: attr.span, + channel: option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"), + stable_features: vec![], + sugg: None, + }; + let mut all_stable = true; for ident in attr.meta_item_list().into_iter().flatten().flat_map(|nested| nested.ident()) @@ -597,24 +646,15 @@ fn maybe_stage_features(sess: &Session, krate: &ast::Crate) { .flat_map(|&(feature, _, since)| if feature == name { since } else { None }) .next(); if let Some(since) = stable_since { - err.help(&format!( - "the feature `{}` has been stable since {} and no longer requires \ - an attribute to enable", - name, since - )); + err.stable_features.push(errors::StableFeature { name, since }); } else { all_stable = false; } } if all_stable { - err.span_suggestion( - attr.span, - "remove the attribute", - "", - Applicability::MachineApplicable, - ); + err.sugg = Some(attr.span); } - err.emit(); + sess.parse_sess.span_diagnostic.emit_err(err); } } } @@ -637,16 +677,7 @@ fn check_incompatible_features(sess: &Session) { if let Some((f2_name, f2_span)) = declared_features.clone().find(|(name, _)| name == f2) { let spans = vec![f1_span, f2_span]; - sess.struct_span_err( - spans, - &format!( - "features `{}` and `{}` are incompatible, using them at the same time \ - is not allowed", - f1_name, f2_name - ), - ) - .help("remove one of these features") - .emit(); + sess.emit_err(errors::IncompatibleFeatures { spans, f1: f1_name, f2: f2_name }); } } } diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs index f58fffc91..b9dcaee23 100644 --- a/compiler/rustc_ast_passes/src/lib.rs +++ b/compiler/rustc_ast_passes/src/lib.rs @@ -10,12 +10,16 @@ #![feature(iter_is_partitioned)] #![feature(let_chains)] #![recursion_limit = "256"] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] -#[macro_use] -extern crate tracing; +use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; +use rustc_macros::fluent_messages; pub mod ast_validation; mod errors; pub mod feature_gate; pub mod node_count; pub mod show_span; + +fluent_messages! { "../locales/en-US.ftl" } diff --git a/compiler/rustc_ast_passes/src/show_span.rs b/compiler/rustc_ast_passes/src/show_span.rs index 27637e311..280cf3284 100644 --- a/compiler/rustc_ast_passes/src/show_span.rs +++ b/compiler/rustc_ast_passes/src/show_span.rs @@ -9,6 +9,8 @@ use rustc_ast as ast; use rustc_ast::visit; use rustc_ast::visit::Visitor; +use crate::errors; + enum Mode { Expression, Pattern, @@ -36,21 +38,21 @@ struct ShowSpanVisitor<'a> { impl<'a> Visitor<'a> for ShowSpanVisitor<'a> { fn visit_expr(&mut self, e: &'a ast::Expr) { if let Mode::Expression = self.mode { - self.span_diagnostic.span_warn(e.span, "expression"); + self.span_diagnostic.emit_warning(errors::ShowSpan { span: e.span, msg: "expression" }); } visit::walk_expr(self, e); } fn visit_pat(&mut self, p: &'a ast::Pat) { if let Mode::Pattern = self.mode { - self.span_diagnostic.span_warn(p.span, "pattern"); + self.span_diagnostic.emit_warning(errors::ShowSpan { span: p.span, msg: "pattern" }); } visit::walk_pat(self, p); } fn visit_ty(&mut self, t: &'a ast::Ty) { if let Mode::Type = self.mode { - self.span_diagnostic.span_warn(t.span, "type"); + self.span_diagnostic.emit_warning(errors::ShowSpan { span: t.span, msg: "type" }); } visit::walk_ty(self, t); } diff --git a/compiler/rustc_ast_pretty/Cargo.toml b/compiler/rustc_ast_pretty/Cargo.toml index a3e3e823b..980a8fa93 100644 --- a/compiler/rustc_ast_pretty/Cargo.toml +++ b/compiler/rustc_ast_pretty/Cargo.toml @@ -6,5 +6,6 @@ edition = "2021" [lib] [dependencies] -rustc_span = { path = "../rustc_span" } rustc_ast = { path = "../rustc_ast" } +rustc_span = { path = "../rustc_span" } +thin-vec = "0.2.12" diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 6a8064b0e..694d688bf 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -4,7 +4,7 @@ mod item; use crate::pp::Breaks::{Consistent, Inconsistent}; use crate::pp::{self, Breaks}; - +use rustc_ast::attr::AttrIdGenerator; use rustc_ast::ptr::P; use rustc_ast::token::{self, BinOpToken, CommentKind, Delimiter, Nonterminal, Token, TokenKind}; use rustc_ast::tokenstream::{TokenStream, TokenTree}; @@ -20,9 +20,8 @@ use rustc_span::edition::Edition; use rustc_span::source_map::{SourceMap, Spanned}; use rustc_span::symbol::{kw, sym, Ident, IdentPrinter, Symbol}; use rustc_span::{BytePos, FileName, Span, DUMMY_SP}; - -use rustc_ast::attr::AttrIdGenerator; use std::borrow::Cow; +use thin_vec::ThinVec; pub use self::delimited::IterDelimited; @@ -131,7 +130,7 @@ pub fn print_crate<'a>( // Currently, in Rust 2018 we don't have `extern crate std;` at the crate // root, so this is not needed, and actually breaks things. - if edition == Edition::Edition2015 { + if edition.is_rust_2015() { // `#![no_std]` let fake_attr = attr::mk_attr_word(g, ast::AttrStyle::Inner, sym::no_std, DUMMY_SP); s.print_attribute(&fake_attr); @@ -1567,8 +1566,18 @@ impl<'a> State<'a> { match bound { GenericBound::Trait(tref, modifier) => { - if modifier == &TraitBoundModifier::Maybe { - self.word("?"); + match modifier { + TraitBoundModifier::None => {} + TraitBoundModifier::Maybe => { + self.word("?"); + } + TraitBoundModifier::MaybeConst => { + self.word_space("~const"); + } + TraitBoundModifier::MaybeConstMaybe => { + self.word_space("~const"); + self.word("?"); + } } self.print_poly_trait_ref(tref); } @@ -1712,10 +1721,10 @@ impl<'a> State<'a> { self.ibox(INDENT_UNIT); self.print_formal_generic_params(generic_params); let generics = ast::Generics { - params: Vec::new(), + params: ThinVec::new(), where_clause: ast::WhereClause { has_where_token: false, - predicates: Vec::new(), + predicates: ThinVec::new(), span: DUMMY_SP, }, span: DUMMY_SP, diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 2a18e5164..cacfe9eb2 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -6,6 +6,11 @@ use rustc_ast::token; use rustc_ast::util::literal::escape_byte_str_symbol; use rustc_ast::util::parser::{self, AssocOp, Fixity}; use rustc_ast::{self as ast, BlockCheckMode}; +use rustc_ast::{ + FormatAlignment, FormatArgPosition, FormatArgsPiece, FormatCount, FormatDebugHex, FormatSign, + FormatTrait, +}; +use std::fmt::Write; impl<'a> State<'a> { fn print_else(&mut self, els: Option<&ast::Expr>) { @@ -527,9 +532,23 @@ impl<'a> State<'a> { } } ast::ExprKind::InlineAsm(a) => { + // FIXME: This should have its own syntax, distinct from a macro invocation. self.word("asm!"); self.print_inline_asm(a); } + ast::ExprKind::FormatArgs(fmt) => { + // FIXME: This should have its own syntax, distinct from a macro invocation. + self.word("format_args!"); + self.popen(); + self.rbox(0, Inconsistent); + self.word(reconstruct_format_args_template_string(&fmt.template)); + for arg in fmt.arguments.all_args() { + self.word_space(","); + self.print_expr(&arg.expr); + } + self.end(); + self.pclose(); + } ast::ExprKind::MacCall(m) => self.print_mac(m), ast::ExprKind::Paren(e) => { self.popen(); @@ -629,3 +648,88 @@ impl<'a> State<'a> { } } } + +pub fn reconstruct_format_args_template_string(pieces: &[FormatArgsPiece]) -> String { + let mut template = "\"".to_string(); + for piece in pieces { + match piece { + FormatArgsPiece::Literal(s) => { + for c in s.as_str().escape_debug() { + template.push(c); + if let '{' | '}' = c { + template.push(c); + } + } + } + FormatArgsPiece::Placeholder(p) => { + template.push('{'); + let (Ok(n) | Err(n)) = p.argument.index; + write!(template, "{n}").unwrap(); + if p.format_options != Default::default() || p.format_trait != FormatTrait::Display + { + template.push_str(":"); + } + if let Some(fill) = p.format_options.fill { + template.push(fill); + } + match p.format_options.alignment { + Some(FormatAlignment::Left) => template.push_str("<"), + Some(FormatAlignment::Right) => template.push_str(">"), + Some(FormatAlignment::Center) => template.push_str("^"), + None => {} + } + match p.format_options.sign { + Some(FormatSign::Plus) => template.push('+'), + Some(FormatSign::Minus) => template.push('-'), + None => {} + } + if p.format_options.alternate { + template.push('#'); + } + if p.format_options.zero_pad { + template.push('0'); + } + if let Some(width) = &p.format_options.width { + match width { + FormatCount::Literal(n) => write!(template, "{n}").unwrap(), + FormatCount::Argument(FormatArgPosition { + index: Ok(n) | Err(n), .. + }) => { + write!(template, "{n}$").unwrap(); + } + } + } + if let Some(precision) = &p.format_options.precision { + template.push('.'); + match precision { + FormatCount::Literal(n) => write!(template, "{n}").unwrap(), + FormatCount::Argument(FormatArgPosition { + index: Ok(n) | Err(n), .. + }) => { + write!(template, "{n}$").unwrap(); + } + } + } + match p.format_options.debug_hex { + Some(FormatDebugHex::Lower) => template.push('x'), + Some(FormatDebugHex::Upper) => template.push('X'), + None => {} + } + template.push_str(match p.format_trait { + FormatTrait::Display => "", + FormatTrait::Debug => "?", + FormatTrait::LowerExp => "e", + FormatTrait::UpperExp => "E", + FormatTrait::Octal => "o", + FormatTrait::Pointer => "p", + FormatTrait::Binary => "b", + FormatTrait::LowerHex => "x", + FormatTrait::UpperHex => "X", + }); + template.push('}'); + } + } + } + template.push('"'); + template +} diff --git a/compiler/rustc_ast_pretty/src/pprust/tests.rs b/compiler/rustc_ast_pretty/src/pprust/tests.rs index 6c8d42f33..3b2b60a86 100644 --- a/compiler/rustc_ast_pretty/src/pprust/tests.rs +++ b/compiler/rustc_ast_pretty/src/pprust/tests.rs @@ -3,6 +3,7 @@ use super::*; use rustc_ast as ast; use rustc_span::create_default_session_globals_then; use rustc_span::symbol::Ident; +use thin_vec::ThinVec; fn fun_to_string( decl: &ast::FnDecl, @@ -27,8 +28,10 @@ fn test_fun_to_string() { create_default_session_globals_then(|| { let abba_ident = Ident::from_str("abba"); - let decl = - ast::FnDecl { inputs: Vec::new(), output: ast::FnRetTy::Default(rustc_span::DUMMY_SP) }; + let decl = ast::FnDecl { + inputs: ThinVec::new(), + output: ast::FnRetTy::Default(rustc_span::DUMMY_SP), + }; let generics = ast::Generics::default(); assert_eq!( fun_to_string(&decl, ast::FnHeader::default(), abba_ident, &generics), |