diff options
Diffstat (limited to 'compiler')
538 files changed, 8906 insertions, 7863 deletions
diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 716bb716cdb..c2405553756 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -1,3 +1,4 @@ +use std::collections::BTreeSet; use std::fmt::{self, Write}; use std::ops::{Bound, Deref}; use std::{cmp, iter}; @@ -5,7 +6,7 @@ use std::{cmp, iter}; use rustc_hashes::Hash64; use rustc_index::Idx; use rustc_index::bit_set::BitMatrix; -use tracing::debug; +use tracing::{debug, trace}; use crate::{ AbiAlign, Align, BackendRepr, FieldsShape, HasDataLayout, IndexSlice, IndexVec, Integer, @@ -766,30 +767,63 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { let niche_filling_layout = calculate_niche_filling_layout(); - let (mut min, mut max) = (i128::MAX, i128::MIN); let discr_type = repr.discr_type(); - let bits = Integer::from_attr(dl, discr_type).size().bits(); - for (i, mut val) in discriminants { - if !repr.c() && variants[i].iter().any(|f| f.is_uninhabited()) { - continue; - } - if discr_type.is_signed() { - // sign extend the raw representation to be an i128 - val = (val << (128 - bits)) >> (128 - bits); - } - if val < min { - min = val; - } - if val > max { - max = val; - } - } - // We might have no inhabited variants, so pretend there's at least one. - if (min, max) == (i128::MAX, i128::MIN) { - min = 0; - max = 0; - } - assert!(min <= max, "discriminant range is {min}...{max}"); + let discr_int = Integer::from_attr(dl, discr_type); + // Because we can only represent one range of valid values, we'll look for the + // largest range of invalid values and pick everything else as the range of valid + // values. + + // First we need to sort the possible discriminant values so that we can look for the largest gap: + let valid_discriminants: BTreeSet<i128> = discriminants + .filter(|&(i, _)| repr.c() || variants[i].iter().all(|f| !f.is_uninhabited())) + .map(|(_, val)| { + if discr_type.is_signed() { + // sign extend the raw representation to be an i128 + // FIXME: do this at the discriminant iterator creation sites + discr_int.size().sign_extend(val as u128) + } else { + val + } + }) + .collect(); + trace!(?valid_discriminants); + let discriminants = valid_discriminants.iter().copied(); + //let next_discriminants = discriminants.clone().cycle().skip(1); + let next_discriminants = + discriminants.clone().chain(valid_discriminants.first().copied()).skip(1); + // Iterate over pairs of each discriminant together with the next one. + // Since they were sorted, we can now compute the niche sizes and pick the largest. + let discriminants = discriminants.zip(next_discriminants); + let largest_niche = discriminants.max_by_key(|&(start, end)| { + trace!(?start, ?end); + // If this is a wraparound range, the niche size is `MAX - abs(diff)`, as the diff between + // the two end points is actually the size of the valid discriminants. + let dist = if start > end { + // Overflow can happen for 128 bit discriminants if `end` is negative. + // But in that case casting to `u128` still gets us the right value, + // as the distance must be positive if the lhs of the subtraction is larger than the rhs. + let dist = start.wrapping_sub(end); + if discr_type.is_signed() { + discr_int.signed_max().wrapping_sub(dist) as u128 + } else { + discr_int.size().unsigned_int_max() - dist as u128 + } + } else { + // Overflow can happen for 128 bit discriminants if `start` is negative. + // But in that case casting to `u128` still gets us the right value, + // as the distance must be positive if the lhs of the subtraction is larger than the rhs. + end.wrapping_sub(start) as u128 + }; + trace!(?dist); + dist + }); + trace!(?largest_niche); + + // `max` is the last valid discriminant before the largest niche + // `min` is the first valid discriminant after the largest niche + let (max, min) = largest_niche + // We might have no inhabited variants, so pretend there's at least one. + .unwrap_or((0, 0)); let (min_ity, signed) = discr_range_of_repr(min, max); //Integer::repr_discr(tcx, ty, &repr, min, max); let mut align = dl.aggregate_align; diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 8e346706877..14e256b8045 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1205,6 +1205,19 @@ impl Integer { } } + /// Returns the smallest signed value that can be represented by this Integer. + #[inline] + pub fn signed_min(self) -> i128 { + use Integer::*; + match self { + I8 => i8::MIN as i128, + I16 => i16::MIN as i128, + I32 => i32::MIN as i128, + I64 => i64::MIN as i128, + I128 => i128::MIN, + } + } + /// Finds the smallest Integer type which can represent the signed value. #[inline] pub fn fit_signed(x: i128) -> Integer { diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 984b280e81b..8160ed3cc46 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -23,7 +23,7 @@ use std::{cmp, fmt}; pub use GenericArgs::*; pub use UnsafeSource::*; -pub use rustc_ast_ir::{Movability, Mutability, Pinnedness}; +pub use rustc_ast_ir::{FloatTy, IntTy, Movability, Mutability, Pinnedness, UintTy}; use rustc_data_structures::packed::Pu128; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -35,7 +35,6 @@ use rustc_span::{ByteSymbol, DUMMY_SP, ErrorGuaranteed, Ident, Span, Symbol, kw, use thin_vec::{ThinVec, thin_vec}; pub use crate::format::*; -use crate::ptr::P; use crate::token::{self, CommentKind, Delimiter}; use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, TokenStream}; use crate::util::parser::{ExprPrecedence, Fixity}; @@ -225,7 +224,7 @@ pub struct PathSegment { /// `Some` means that parameter list is supplied (`Path<X, Y>`) /// but it can be empty (`Path<>`). /// `P` is used as a size optimization for the common case with no parameters. - pub args: Option<P<GenericArgs>>, + pub args: Option<Box<GenericArgs>>, } // Succeeds if the path segment is arg-free and matches the given symbol. @@ -286,7 +285,7 @@ pub enum GenericArg { /// `'a` in `Foo<'a>`. Lifetime(#[visitable(extra = LifetimeCtxt::GenericArg)] Lifetime), /// `Bar` in `Foo<Bar>`. - Type(P<Ty>), + Type(Box<Ty>), /// `1` in `Foo<1>`. Const(AnonConst), } @@ -328,15 +327,15 @@ impl AngleBracketedArg { } } -impl From<AngleBracketedArgs> for P<GenericArgs> { +impl From<AngleBracketedArgs> for Box<GenericArgs> { fn from(val: AngleBracketedArgs) -> Self { - P(GenericArgs::AngleBracketed(val)) + Box::new(GenericArgs::AngleBracketed(val)) } } -impl From<ParenthesizedArgs> for P<GenericArgs> { +impl From<ParenthesizedArgs> for Box<GenericArgs> { fn from(val: ParenthesizedArgs) -> Self { - P(GenericArgs::Parenthesized(val)) + Box::new(GenericArgs::Parenthesized(val)) } } @@ -350,7 +349,7 @@ pub struct ParenthesizedArgs { pub span: Span, /// `(A, B)` - pub inputs: ThinVec<P<Ty>>, + pub inputs: ThinVec<Box<Ty>>, /// ```text /// Foo(A, B) -> C @@ -435,10 +434,10 @@ pub enum GenericParamKind { /// A lifetime definition (e.g., `'a: 'b + 'c + 'd`). Lifetime, Type { - default: Option<P<Ty>>, + default: Option<Box<Ty>>, }, Const { - ty: P<Ty>, + ty: Box<Ty>, /// Span of the whole parameter definition, including default. span: Span, /// Optional default value for the const generic param. @@ -526,7 +525,7 @@ pub struct WhereBoundPredicate { /// Any generics from a `for` binding. pub bound_generic_params: ThinVec<GenericParam>, /// The type being bounded. - pub bounded_ty: P<Ty>, + pub bounded_ty: Box<Ty>, /// Trait and lifetime bounds (`Clone + Send + 'static`). #[visitable(extra = BoundKind::Bound)] pub bounds: GenericBounds, @@ -548,8 +547,8 @@ pub struct WhereRegionPredicate { /// E.g., `T = int`. #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub struct WhereEqPredicate { - pub lhs_ty: P<Ty>, - pub rhs_ty: P<Ty>, + pub lhs_ty: Box<Ty>, + pub rhs_ty: Box<Ty>, } #[derive(Clone, Encodable, Decodable, Debug, Walkable)] @@ -558,7 +557,7 @@ pub struct Crate { /// expansion placeholders or an unassigned value (`DUMMY_NODE_ID`) before that. pub id: NodeId, pub attrs: AttrVec, - pub items: ThinVec<P<Item>>, + pub items: ThinVec<Box<Item>>, pub spans: ModSpans, pub is_placeholder: bool, } @@ -638,7 +637,7 @@ pub struct Pat { impl Pat { /// Attempt reparsing the pattern as a type. /// This is intended for use by diagnostics. - pub fn to_ty(&self) -> Option<P<Ty>> { + pub fn to_ty(&self) -> Option<Box<Ty>> { let kind = match &self.kind { PatKind::Missing => unreachable!(), // In a type expression `_` is an inference variable. @@ -671,7 +670,7 @@ impl Pat { _ => return None, }; - Some(P(Ty { kind, id: self.id, span: self.span, tokens: None })) + Some(Box::new(Ty { kind, id: self.id, span: self.span, tokens: None })) } /// Walk top-down and call `it` in each place where a pattern occurs @@ -764,8 +763,8 @@ impl Pat { } } -impl From<P<Pat>> for Pat { - fn from(value: P<Pat>) -> Self { +impl From<Box<Pat>> for Pat { + fn from(value: Box<Pat>) -> Self { *value } } @@ -780,7 +779,7 @@ pub struct PatField { /// The identifier for the field. pub ident: Ident, /// The pattern the field is destructured to. - pub pat: P<Pat>, + pub pat: Box<Pat>, pub is_shorthand: bool, pub attrs: AttrVec, pub id: NodeId, @@ -865,44 +864,44 @@ pub enum PatKind { /// or a unit struct/variant pattern, or a const pattern (in the last two cases the third /// field must be `None`). Disambiguation cannot be done with parser alone, so it happens /// during name resolution. - Ident(BindingMode, Ident, Option<P<Pat>>), + Ident(BindingMode, Ident, Option<Box<Pat>>), /// A struct or struct variant pattern (e.g., `Variant {x, y, ..}`). - Struct(Option<P<QSelf>>, Path, ThinVec<PatField>, PatFieldsRest), + Struct(Option<Box<QSelf>>, Path, ThinVec<PatField>, PatFieldsRest), /// A tuple struct/variant pattern (`Variant(x, y, .., z)`). - TupleStruct(Option<P<QSelf>>, Path, ThinVec<P<Pat>>), + TupleStruct(Option<Box<QSelf>>, Path, ThinVec<Box<Pat>>), /// An or-pattern `A | B | C`. /// Invariant: `pats.len() >= 2`. - Or(ThinVec<P<Pat>>), + Or(ThinVec<Box<Pat>>), /// A possibly qualified path pattern. /// Unqualified path patterns `A::B::C` can legally refer to variants, structs, constants /// or associated constants. Qualified path patterns `<A>::B::C`/`<A as Trait>::B::C` can /// only legally refer to associated constants. - Path(Option<P<QSelf>>, Path), + Path(Option<Box<QSelf>>, Path), /// A tuple pattern (`(a, b)`). - Tuple(ThinVec<P<Pat>>), + Tuple(ThinVec<Box<Pat>>), /// A `box` pattern. - Box(P<Pat>), + Box(Box<Pat>), /// A `deref` pattern (currently `deref!()` macro-based syntax). - Deref(P<Pat>), + Deref(Box<Pat>), /// A reference pattern (e.g., `&mut (a, b)`). - Ref(P<Pat>, Mutability), + Ref(Box<Pat>, Mutability), /// A literal, const block or path. - Expr(P<Expr>), + Expr(Box<Expr>), /// A range pattern (e.g., `1...2`, `1..2`, `1..`, `..2`, `1..=2`, `..=2`). - Range(Option<P<Expr>>, Option<P<Expr>>, Spanned<RangeEnd>), + Range(Option<Box<Expr>>, Option<Box<Expr>>, Spanned<RangeEnd>), /// A slice pattern `[a, b, c]`. - Slice(ThinVec<P<Pat>>), + Slice(ThinVec<Box<Pat>>), /// A rest pattern `..`. /// @@ -922,13 +921,13 @@ pub enum PatKind { Never, /// A guard pattern (e.g., `x if guard(x)`). - Guard(P<Pat>, P<Expr>), + Guard(Box<Pat>, Box<Expr>), /// Parentheses in patterns used for grouping (i.e., `(PAT)`). - Paren(P<Pat>), + Paren(Box<Pat>), /// A macro pattern; pre-expansion. - MacCall(P<MacCall>), + MacCall(Box<MacCall>), /// Placeholder for a pattern that wasn't syntactically well formed in some way. Err(ErrorGuaranteed), @@ -1223,22 +1222,22 @@ impl Stmt { #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub enum StmtKind { /// A local (let) binding. - Let(P<Local>), + Let(Box<Local>), /// An item definition. - Item(P<Item>), + Item(Box<Item>), /// Expr without trailing semi-colon. - Expr(P<Expr>), + Expr(Box<Expr>), /// Expr with a trailing semi-colon. - Semi(P<Expr>), + Semi(Box<Expr>), /// Just a trailing semi-colon. Empty, /// Macro. - MacCall(P<MacCallStmt>), + MacCall(Box<MacCallStmt>), } #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub struct MacCallStmt { - pub mac: P<MacCall>, + pub mac: Box<MacCall>, pub style: MacStmtStyle, pub attrs: AttrVec, pub tokens: Option<LazyAttrTokenStream>, @@ -1262,8 +1261,8 @@ pub enum MacStmtStyle { pub struct Local { pub id: NodeId, pub super_: Option<Span>, - pub pat: P<Pat>, - pub ty: Option<P<Ty>>, + pub pat: Box<Pat>, + pub ty: Option<Box<Ty>>, pub kind: LocalKind, pub span: Span, pub colon_sp: Option<Span>, @@ -1278,10 +1277,10 @@ pub enum LocalKind { Decl, /// Local declaration with an initializer. /// Example: `let x = y;` - Init(P<Expr>), + Init(Box<Expr>), /// Local declaration with an initializer and an `else` clause. /// Example: `let Some(x) = y else { return };` - InitElse(P<Expr>, P<Block>), + InitElse(Box<Expr>, Box<Block>), } impl LocalKind { @@ -1315,11 +1314,11 @@ impl LocalKind { pub struct Arm { pub attrs: AttrVec, /// Match arm pattern, e.g. `10` in `match foo { 10 => {}, _ => {} }`. - pub pat: P<Pat>, + pub pat: Box<Pat>, /// Match arm guard, e.g. `n > 10` in `match foo { n if n > 10 => {}, _ => {} }`. - pub guard: Option<P<Expr>>, + pub guard: Option<Box<Expr>>, /// Match arm body. Omitted if the pattern is a never pattern. - pub body: Option<P<Expr>>, + pub body: Option<Box<Expr>>, pub span: Span, pub id: NodeId, pub is_placeholder: bool, @@ -1332,7 +1331,7 @@ pub struct ExprField { pub id: NodeId, pub span: Span, pub ident: Ident, - pub expr: P<Expr>, + pub expr: Box<Expr>, pub is_shorthand: bool, pub is_placeholder: bool, } @@ -1357,7 +1356,7 @@ pub enum UnsafeSource { #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub struct AnonConst { pub id: NodeId, - pub value: P<Expr>, + pub value: Box<Expr>, } /// An expression. @@ -1469,7 +1468,7 @@ impl Expr { } /// Attempts to reparse as `Ty` (for diagnostic purposes). - pub fn to_ty(&self) -> Option<P<Ty>> { + pub fn to_ty(&self) -> Option<Box<Ty>> { let kind = match &self.kind { // Trivial conversions. ExprKind::Path(qself, path) => TyKind::Path(qself.clone(), path.clone()), @@ -1511,7 +1510,7 @@ impl Expr { _ => return None, }; - Some(P(Ty { kind, id: self.id, span: self.span, tokens: None })) + Some(Box::new(Ty { kind, id: self.id, span: self.span, tokens: None })) } pub fn precedence(&self) -> ExprPrecedence { @@ -1632,8 +1631,8 @@ impl Expr { } } -impl From<P<Expr>> for Expr { - fn from(value: P<Expr>) -> Self { +impl From<Box<Expr>> for Expr { + fn from(value: Box<Expr>) -> Self { *value } } @@ -1645,8 +1644,8 @@ pub struct Closure { pub constness: Const, pub coroutine_kind: Option<CoroutineKind>, pub movability: Movability, - pub fn_decl: P<FnDecl>, - pub body: P<Expr>, + pub fn_decl: Box<FnDecl>, + pub body: Box<Expr>, /// The span of the declaration block: 'move |...| -> ...' pub fn_decl_span: Span, /// The span of the argument block `|...|` @@ -1677,9 +1676,9 @@ pub struct MethodCall { /// The method name and its generic arguments, e.g. `foo::<Bar, Baz>`. pub seg: PathSegment, /// The receiver, e.g. `x`. - pub receiver: P<Expr>, + pub receiver: Box<Expr>, /// The arguments, e.g. `a, b, c`. - pub args: ThinVec<P<Expr>>, + pub args: ThinVec<Box<Expr>>, /// The span of the function, without the dot and receiver e.g. `foo::<Bar, /// Baz>(a, b, c)`. pub span: Span, @@ -1688,7 +1687,7 @@ pub struct MethodCall { #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub enum StructRest { /// `..x`. - Base(P<Expr>), + Base(Box<Expr>), /// `..`. Rest(Span), /// No trailing `..` or expression. @@ -1697,7 +1696,7 @@ pub enum StructRest { #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub struct StructExpr { - pub qself: Option<P<QSelf>>, + pub qself: Option<Box<QSelf>>, pub path: Path, pub fields: ThinVec<ExprField>, pub rest: StructRest, @@ -1707,7 +1706,7 @@ pub struct StructExpr { #[derive(Clone, Encodable, Decodable, Debug)] pub enum ExprKind { /// An array (e.g, `[a, b, c, d]`). - Array(ThinVec<P<Expr>>), + Array(ThinVec<Box<Expr>>), /// Allow anonymous constants from an inline `const` block. ConstBlock(AnonConst), /// A function call. @@ -1716,90 +1715,90 @@ 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>, ThinVec<P<Expr>>), + Call(Box<Expr>, ThinVec<Box<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(ThinVec<P<Expr>>), + Tup(ThinVec<Box<Expr>>), /// A binary operation (e.g., `a + b`, `a * b`). - Binary(BinOp, P<Expr>, P<Expr>), + Binary(BinOp, Box<Expr>, Box<Expr>), /// A unary operation (e.g., `!x`, `*x`). - Unary(UnOp, P<Expr>), + Unary(UnOp, Box<Expr>), /// A literal (e.g., `1`, `"foo"`). Lit(token::Lit), /// A cast (e.g., `foo as f64`). - Cast(P<Expr>, P<Ty>), + Cast(Box<Expr>, Box<Ty>), /// A type ascription (e.g., `builtin # type_ascribe(42, usize)`). /// /// Usually not written directly in user code but /// indirectly via the macro `type_ascribe!(...)`. - Type(P<Expr>, P<Ty>), + Type(Box<Expr>, Box<Ty>), /// A `let pat = expr` expression that is only semantically allowed in the condition /// of `if` / `while` expressions. (e.g., `if let 0 = x { .. }`). /// /// `Span` represents the whole `let pat = expr` statement. - Let(P<Pat>, P<Expr>, Span, Recovered), + Let(Box<Pat>, Box<Expr>, Span, Recovered), /// An `if` block, with an optional `else` block. /// /// `if expr { block } else { expr }` /// /// If present, the "else" expr is always `ExprKind::Block` (for `else`) or /// `ExprKind::If` (for `else if`). - If(P<Expr>, P<Block>, Option<P<Expr>>), + If(Box<Expr>, Box<Block>, Option<Box<Expr>>), /// A while loop, with an optional label. /// /// `'label: while expr { block }` - While(P<Expr>, P<Block>, Option<Label>), + While(Box<Expr>, Box<Block>, Option<Label>), /// A `for` loop, with an optional label. /// /// `'label: for await? pat in iter { block }` /// /// This is desugared to a combination of `loop` and `match` expressions. ForLoop { - pat: P<Pat>, - iter: P<Expr>, - body: P<Block>, + pat: Box<Pat>, + iter: Box<Expr>, + body: Box<Block>, label: Option<Label>, kind: ForLoopKind, }, /// Conditionless loop (can be exited with `break`, `continue`, or `return`). /// /// `'label: loop { block }` - Loop(P<Block>, Option<Label>, Span), + Loop(Box<Block>, Option<Label>, Span), /// A `match` block. - Match(P<Expr>, ThinVec<Arm>, MatchKind), + Match(Box<Expr>, ThinVec<Arm>, MatchKind), /// A closure (e.g., `move |a, b, c| a + b + c`). Closure(Box<Closure>), /// A block (`'label: { ... }`). - Block(P<Block>, Option<Label>), + Block(Box<Block>, Option<Label>), /// An `async` block (`async move { ... }`), /// or a `gen` block (`gen move { ... }`). /// /// The span is the "decl", which is the header before the body `{ }` /// including the `asyng`/`gen` keywords and possibly `move`. - Gen(CaptureBy, P<Block>, GenBlockKind, Span), + Gen(CaptureBy, Box<Block>, GenBlockKind, Span), /// An await expression (`my_future.await`). Span is of await keyword. - Await(P<Expr>, Span), + Await(Box<Expr>, Span), /// A use expression (`x.use`). Span is of use keyword. - Use(P<Expr>, Span), + Use(Box<Expr>, Span), /// A try block (`try { ... }`). - TryBlock(P<Block>), + TryBlock(Box<Block>), /// An assignment (`a = foo()`). /// The `Span` argument is the span of the `=` token. - Assign(P<Expr>, P<Expr>, Span), + Assign(Box<Expr>, Box<Expr>, Span), /// An assignment with an operator. /// /// E.g., `a += 1`. - AssignOp(AssignOp, P<Expr>, P<Expr>), + AssignOp(AssignOp, Box<Expr>, Box<Expr>), /// Access of a named (e.g., `obj.foo`) or unnamed (e.g., `obj.0`) struct field. - Field(P<Expr>, Ident), + Field(Box<Expr>, Ident), /// An indexing operation (e.g., `foo[2]`). /// The span represents the span of the `[2]`, including brackets. - Index(P<Expr>, P<Expr>, Span), + Index(Box<Expr>, Box<Expr>, Span), /// A range (e.g., `1..2`, `1..`, `..2`, `1..=2`, `..=2`; and `..` in destructuring assignment). - Range(Option<P<Expr>>, Option<P<Expr>>, RangeLimits), + Range(Option<Box<Expr>>, Option<Box<Expr>>, RangeLimits), /// An underscore, used in destructuring assignment to ignore a value. Underscore, @@ -1807,57 +1806,57 @@ pub enum ExprKind { /// parameters (e.g., `foo::bar::<baz>`). /// /// Optionally "qualified" (e.g., `<Vec<T> as SomeTrait>::SomeType`). - Path(Option<P<QSelf>>, Path), + Path(Option<Box<QSelf>>, Path), /// A referencing operation (`&a`, `&mut a`, `&raw const a` or `&raw mut a`). - AddrOf(BorrowKind, Mutability, P<Expr>), + AddrOf(BorrowKind, Mutability, Box<Expr>), /// A `break`, with an optional label to break, and an optional expression. - Break(Option<Label>, Option<P<Expr>>), + Break(Option<Label>, Option<Box<Expr>>), /// A `continue`, with an optional label. Continue(Option<Label>), /// A `return`, with an optional value to be returned. - Ret(Option<P<Expr>>), + Ret(Option<Box<Expr>>), /// Output of the `asm!()` macro. - InlineAsm(P<InlineAsm>), + InlineAsm(Box<InlineAsm>), /// An `offset_of` expression (e.g., `builtin # offset_of(Struct, field)`). /// /// Usually not written directly in user code but /// indirectly via the macro `core::mem::offset_of!(...)`. - OffsetOf(P<Ty>, Vec<Ident>), + OffsetOf(Box<Ty>, Vec<Ident>), /// A macro invocation; pre-expansion. - MacCall(P<MacCall>), + MacCall(Box<MacCall>), /// A struct literal expression. /// /// E.g., `Foo {x: 1, y: 2}`, or `Foo {x: 1, .. rest}`. - Struct(P<StructExpr>), + Struct(Box<StructExpr>), /// An array literal constructed from one repeated element. /// /// E.g., `[1; 5]`. The expression is the element to be /// repeated; the constant is the number of times to repeat it. - Repeat(P<Expr>, AnonConst), + Repeat(Box<Expr>, AnonConst), /// No-op: used solely so we can pretty-print faithfully. - Paren(P<Expr>), + Paren(Box<Expr>), /// A try expression (`expr?`). - Try(P<Expr>), + Try(Box<Expr>), /// A `yield`, with an optional value to be yielded. Yield(YieldKind), /// A `do yeet` (aka `throw`/`fail`/`bail`/`raise`/whatever), /// with an optional value to be returned. - Yeet(Option<P<Expr>>), + Yeet(Option<Box<Expr>>), /// A tail call return, with the value to be returned. /// /// While `.0` must be a function call, we check this later, after parsing. - Become(P<Expr>), + Become(Box<Expr>), /// Bytes included via `include_bytes!` /// @@ -1873,9 +1872,9 @@ pub enum ExprKind { IncludedBytes(ByteSymbol), /// A `format_args!()` expression. - FormatArgs(P<FormatArgs>), + FormatArgs(Box<FormatArgs>), - UnsafeBinderCast(UnsafeBinderCastKind, P<Expr>, Option<P<Ty>>), + UnsafeBinderCast(UnsafeBinderCastKind, Box<Expr>, Option<Box<Ty>>), /// Placeholder for an expression that wasn't syntactically well formed in some way. Err(ErrorGuaranteed), @@ -1941,7 +1940,7 @@ pub enum UnsafeBinderCastKind { /// ``` #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub struct QSelf { - pub ty: P<Ty>, + pub ty: Box<Ty>, /// The span of `a::b::Trait` in a path like `<Vec<T> as /// a::b::Trait>::AssociatedItem`; in the case where `position == @@ -2001,7 +2000,7 @@ pub enum ClosureBinder { #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub struct MacCall { pub path: Path, - pub args: P<DelimArgs>, + pub args: Box<DelimArgs>, } impl MacCall { @@ -2021,7 +2020,7 @@ pub enum AttrArgs { Eq { /// Span of the `=` token. eq_span: Span, - expr: P<Expr>, + expr: Box<Expr>, }, } @@ -2064,7 +2063,7 @@ impl DelimArgs { /// Represents a macro definition. #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic, Walkable)] pub struct MacroDef { - pub body: P<DelimArgs>, + pub body: Box<DelimArgs>, /// `true` if macro was defined with `macro_rules`. pub macro_rules: bool, } @@ -2093,16 +2092,16 @@ pub enum MatchKind { #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub enum YieldKind { /// yield expr { ... } - Prefix(Option<P<Expr>>), + Prefix(Option<Box<Expr>>), /// expr.yield { ... } - Postfix(P<Expr>), + Postfix(Box<Expr>), } impl YieldKind { /// Returns the expression inside the yield expression, if any. /// /// For postfix yields, this is guaranteed to be `Some`. - pub const fn expr(&self) -> Option<&P<Expr>> { + pub const fn expr(&self) -> Option<&Box<Expr>> { match self { YieldKind::Prefix(expr) => expr.as_ref(), YieldKind::Postfix(expr) => Some(expr), @@ -2110,7 +2109,7 @@ impl YieldKind { } /// Returns a mutable reference to the expression being yielded, if any. - pub const fn expr_mut(&mut self) -> Option<&mut P<Expr>> { + pub const fn expr_mut(&mut self) -> Option<&mut Box<Expr>> { match self { YieldKind::Prefix(expr) => expr.as_mut(), YieldKind::Postfix(expr) => Some(expr), @@ -2272,7 +2271,7 @@ impl LitKind { // type structure in `middle/ty.rs` as well. #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub struct MutTy { - pub ty: P<Ty>, + pub ty: Box<Ty>, pub mutbl: Mutability, } @@ -2281,109 +2280,10 @@ pub struct MutTy { #[derive(Clone, Encodable, Decodable, Debug)] pub struct FnSig { pub header: FnHeader, - pub decl: P<FnDecl>, + pub decl: Box<FnDecl>, pub span: Span, } -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[derive(Encodable, Decodable, HashStable_Generic)] -pub enum FloatTy { - F16, - F32, - F64, - F128, -} - -impl FloatTy { - pub fn name_str(self) -> &'static str { - match self { - FloatTy::F16 => "f16", - FloatTy::F32 => "f32", - FloatTy::F64 => "f64", - FloatTy::F128 => "f128", - } - } - - pub fn name(self) -> Symbol { - match self { - FloatTy::F16 => sym::f16, - FloatTy::F32 => sym::f32, - FloatTy::F64 => sym::f64, - FloatTy::F128 => sym::f128, - } - } -} - -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[derive(Encodable, Decodable, HashStable_Generic)] -pub enum IntTy { - Isize, - I8, - I16, - I32, - I64, - I128, -} - -impl IntTy { - pub fn name_str(&self) -> &'static str { - match *self { - IntTy::Isize => "isize", - IntTy::I8 => "i8", - IntTy::I16 => "i16", - IntTy::I32 => "i32", - IntTy::I64 => "i64", - IntTy::I128 => "i128", - } - } - - pub fn name(&self) -> Symbol { - match *self { - IntTy::Isize => sym::isize, - IntTy::I8 => sym::i8, - IntTy::I16 => sym::i16, - IntTy::I32 => sym::i32, - IntTy::I64 => sym::i64, - IntTy::I128 => sym::i128, - } - } -} - -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Debug)] -#[derive(Encodable, Decodable, HashStable_Generic)] -pub enum UintTy { - Usize, - U8, - U16, - U32, - U64, - U128, -} - -impl UintTy { - pub fn name_str(&self) -> &'static str { - match *self { - UintTy::Usize => "usize", - UintTy::U8 => "u8", - UintTy::U16 => "u16", - UintTy::U32 => "u32", - UintTy::U64 => "u64", - UintTy::U128 => "u128", - } - } - - pub fn name(&self) -> Symbol { - match *self { - UintTy::Usize => sym::usize, - UintTy::U8 => sym::u8, - UintTy::U16 => sym::u16, - UintTy::U32 => sym::u32, - UintTy::U64 => sym::u64, - UintTy::U128 => sym::u128, - } - } -} - /// A constraint on an associated item. /// /// ### Examples @@ -2405,12 +2305,12 @@ pub struct AssocItemConstraint { #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub enum Term { - Ty(P<Ty>), + Ty(Box<Ty>), Const(AnonConst), } -impl From<P<Ty>> for Term { - fn from(v: P<Ty>) -> Self { +impl From<Box<Ty>> for Term { + fn from(v: Box<Ty>) -> Self { Term::Ty(v) } } @@ -2457,8 +2357,8 @@ impl Clone for Ty { } } -impl From<P<Ty>> for Ty { - fn from(value: P<Ty>) -> Self { +impl From<Box<Ty>> for Ty { + fn from(value: Box<Ty>) -> Self { *value } } @@ -2487,7 +2387,7 @@ pub struct FnPtrTy { pub safety: Safety, pub ext: Extern, pub generic_params: ThinVec<GenericParam>, - pub decl: P<FnDecl>, + pub decl: Box<FnDecl>, /// Span of the `[unsafe] [extern] fn(...) -> ...` part, i.e. everything /// after the generic params (if there are any, e.g. `for<'a>`). pub decl_span: Span, @@ -2496,7 +2396,7 @@ pub struct FnPtrTy { #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub struct UnsafeBinderTy { pub generic_params: ThinVec<GenericParam>, - pub inner_ty: P<Ty>, + pub inner_ty: Box<Ty>, } /// The various kinds of type recognized by the compiler. @@ -2505,9 +2405,9 @@ pub struct UnsafeBinderTy { #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub enum TyKind { /// A variable-length slice (`[T]`). - Slice(P<Ty>), + Slice(Box<Ty>), /// A fixed length array (`[T; n]`). - Array(P<Ty>, AnonConst), + Array(Box<Ty>, AnonConst), /// A raw pointer (`*const T` or `*mut T`). Ptr(MutTy), /// A reference (`&'a T` or `&'a mut T`). @@ -2517,18 +2417,18 @@ pub enum TyKind { /// Desugars into `Pin<&'a T>` or `Pin<&'a mut T>`. PinnedRef(#[visitable(extra = LifetimeCtxt::Ref)] Option<Lifetime>, MutTy), /// A function pointer type (e.g., `fn(usize) -> bool`). - FnPtr(P<FnPtrTy>), + FnPtr(Box<FnPtrTy>), /// An unsafe existential lifetime binder (e.g., `unsafe<'a> &'a ()`). - UnsafeBinder(P<UnsafeBinderTy>), + UnsafeBinder(Box<UnsafeBinderTy>), /// The never type (`!`). Never, /// A tuple (`(A, B, C, D,...)`). - Tup(ThinVec<P<Ty>>), + Tup(ThinVec<Box<Ty>>), /// A path (`module::module::...::Type`), optionally /// "qualified", e.g., `<Vec<T> as SomeTrait>::SomeType`. /// /// Type parameters are stored in the `Path` itself. - Path(Option<P<QSelf>>, Path), + Path(Option<Box<QSelf>>, Path), /// A trait object type `Bound1 + Bound2 + Bound3` /// where `Bound` is a trait or a lifetime. TraitObject(#[visitable(extra = BoundKind::TraitObject)] GenericBounds, TraitObjectSyntax), @@ -2540,7 +2440,7 @@ pub enum TyKind { /// the generation of opaque `type Foo = impl Trait` items significantly. ImplTrait(NodeId, #[visitable(extra = BoundKind::Impl)] GenericBounds), /// No-op; kept solely so that we can pretty-print faithfully. - Paren(P<Ty>), + Paren(Box<Ty>), /// Unused for now. Typeof(AnonConst), /// This means the type should be inferred instead of it having been @@ -2549,12 +2449,12 @@ pub enum TyKind { /// Inferred type of a `self` or `&self` argument in a method. ImplicitSelf, /// A macro in the type position. - MacCall(P<MacCall>), + MacCall(Box<MacCall>), /// Placeholder for a `va_list`. CVarArgs, /// Pattern types like `pattern_type!(u32 is 1..=)`, which is the same as `NonZero<u32>`, /// just as part of the type system. - Pat(P<Ty>, P<TyPat>), + Pat(Box<Ty>, Box<TyPat>), /// Sometimes we need a dummy value when no error has occurred. Dummy, /// Placeholder for a kind that has failed to be defined. @@ -2630,9 +2530,9 @@ pub struct TyPat { #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub enum TyPatKind { /// A range pattern (e.g., `1...2`, `1..2`, `1..`, `..2`, `1..=2`, `..=2`). - Range(Option<P<AnonConst>>, Option<P<AnonConst>>, Spanned<RangeEnd>), + Range(Option<Box<AnonConst>>, Option<Box<AnonConst>>, Spanned<RangeEnd>), - Or(ThinVec<P<TyPat>>), + Or(ThinVec<Box<TyPat>>), /// Placeholder for a pattern that wasn't syntactically well formed in some way. Err(ErrorGuaranteed), @@ -2797,7 +2697,7 @@ impl InlineAsmTemplatePiece { #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub struct InlineAsmSym { pub id: NodeId, - pub qself: Option<P<QSelf>>, + pub qself: Option<Box<QSelf>>, pub path: Path, } @@ -2808,23 +2708,23 @@ pub struct InlineAsmSym { pub enum InlineAsmOperand { In { reg: InlineAsmRegOrRegClass, - expr: P<Expr>, + expr: Box<Expr>, }, Out { reg: InlineAsmRegOrRegClass, late: bool, - expr: Option<P<Expr>>, + expr: Option<Box<Expr>>, }, InOut { reg: InlineAsmRegOrRegClass, late: bool, - expr: P<Expr>, + expr: Box<Expr>, }, SplitInOut { reg: InlineAsmRegOrRegClass, late: bool, - in_expr: P<Expr>, - out_expr: Option<P<Expr>>, + in_expr: Box<Expr>, + out_expr: Option<Box<Expr>>, }, Const { anon_const: AnonConst, @@ -2833,7 +2733,7 @@ pub enum InlineAsmOperand { sym: InlineAsmSym, }, Label { - block: P<Block>, + block: Box<Block>, }, } @@ -2906,8 +2806,8 @@ pub struct InlineAsm { #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub struct Param { pub attrs: AttrVec, - pub ty: P<Ty>, - pub pat: P<Pat>, + pub ty: Box<Ty>, + pub pat: Box<Pat>, pub id: NodeId, pub span: Span, pub is_placeholder: bool, @@ -2925,7 +2825,7 @@ pub enum SelfKind { /// `&'lt pin const self`, `&'lt pin mut self` Pinned(Option<Lifetime>, Mutability), /// `self: TYPE`, `mut self: TYPE` - Explicit(P<Ty>, Mutability), + Explicit(Box<Ty>, Mutability), } impl SelfKind { @@ -2981,7 +2881,7 @@ impl Param { /// Builds a `Param` object from `ExplicitSelf`. pub fn from_self(attrs: AttrVec, eself: ExplicitSelf, eself_ident: Ident) -> Param { let span = eself.span.to(eself_ident.span); - let infer_ty = P(Ty { + let infer_ty = Box::new(Ty { id: DUMMY_NODE_ID, kind: TyKind::ImplicitSelf, span: eself_ident.span, @@ -2992,7 +2892,7 @@ impl Param { SelfKind::Value(mutbl) => (mutbl, infer_ty), SelfKind::Region(lt, mutbl) => ( Mutability::Not, - P(Ty { + Box::new(Ty { id: DUMMY_NODE_ID, kind: TyKind::Ref(lt, MutTy { ty: infer_ty, mutbl }), span, @@ -3001,7 +2901,7 @@ impl Param { ), SelfKind::Pinned(lt, mutbl) => ( mutbl, - P(Ty { + Box::new(Ty { id: DUMMY_NODE_ID, kind: TyKind::PinnedRef(lt, MutTy { ty: infer_ty, mutbl }), span, @@ -3011,7 +2911,7 @@ impl Param { }; Param { attrs, - pat: P(Pat { + pat: Box::new(Pat { id: DUMMY_NODE_ID, kind: PatKind::Ident(BindingMode(ByRef::No, mutbl), eself_ident, None), span, @@ -3222,7 +3122,7 @@ pub enum FnRetTy { /// Span points to where return type would be inserted. Default(Span), /// Everything else. - Ty(P<Ty>), + Ty(Box<Ty>), } impl FnRetTy { @@ -3247,7 +3147,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(ThinVec<P<Item>>, Inline, ModSpans, Result<(), ErrorGuaranteed>), + Loaded(ThinVec<Box<Item>>, Inline, ModSpans, Result<(), ErrorGuaranteed>), /// Module with definition outlined to a separate file `mod foo;` but not yet loaded from it. Unloaded, } @@ -3271,7 +3171,7 @@ pub struct ForeignMod { /// semantically by Rust. pub safety: Safety, pub abi: Option<StrLit>, - pub items: ThinVec<P<ForeignItem>>, + pub items: ThinVec<Box<ForeignItem>>, } #[derive(Clone, Encodable, Decodable, Debug, Walkable)] @@ -3366,7 +3266,7 @@ pub struct Attribute { #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub enum AttrKind { /// A normal attribute. - Normal(P<NormalAttr>), + Normal(Box<NormalAttr>), /// A doc comment (e.g. `/// ...`, `//! ...`, `/** ... */`, `/*! ... */`). /// Doc attributes (e.g. `#[doc="..."]`) are represented with the `Normal` @@ -3480,7 +3380,7 @@ pub struct Visibility { #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub enum VisibilityKind { Public, - Restricted { path: P<Path>, id: NodeId, shorthand: bool }, + Restricted { path: Box<Path>, id: NodeId, shorthand: bool }, Inherited, } @@ -3502,7 +3402,7 @@ pub struct FieldDef { pub safety: Safety, pub ident: Option<Ident>, - pub ty: P<Ty>, + pub ty: Box<Ty>, pub default: Option<AnonConst>, pub is_placeholder: bool, } @@ -3708,7 +3608,7 @@ pub struct Trait { #[visitable(extra = BoundKind::SuperTraits)] pub bounds: GenericBounds, #[visitable(extra = AssocCtxt::Trait)] - pub items: ThinVec<P<AssocItem>>, + pub items: ThinVec<Box<AssocItem>>, } /// The location of a where clause on a `TyAlias` (`Span`) and whether there was @@ -3756,7 +3656,7 @@ pub struct TyAlias { pub where_clauses: TyAliasWhereClauses, #[visitable(extra = BoundKind::Bound)] pub bounds: GenericBounds, - pub ty: Option<P<Ty>>, + pub ty: Option<Box<Ty>>, } #[derive(Clone, Encodable, Decodable, Debug)] @@ -3768,14 +3668,14 @@ pub struct Impl { pub polarity: ImplPolarity, /// The trait being implemented, if any. pub of_trait: Option<TraitRef>, - pub self_ty: P<Ty>, - pub items: ThinVec<P<AssocItem>>, + pub self_ty: Box<Ty>, + pub items: ThinVec<Box<AssocItem>>, } #[derive(Clone, Encodable, Decodable, Debug, Default, Walkable)] pub struct FnContract { - pub requires: Option<P<Expr>>, - pub ensures: Option<P<Expr>>, + pub requires: Option<Box<Expr>>, + pub ensures: Option<Box<Expr>>, } #[derive(Clone, Encodable, Decodable, Debug)] @@ -3784,40 +3684,40 @@ pub struct Fn { pub ident: Ident, pub generics: Generics, pub sig: FnSig, - pub contract: Option<P<FnContract>>, + pub contract: Option<Box<FnContract>>, pub define_opaque: Option<ThinVec<(NodeId, Path)>>, - pub body: Option<P<Block>>, + pub body: Option<Box<Block>>, } #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub struct Delegation { /// Path resolution id. pub id: NodeId, - pub qself: Option<P<QSelf>>, + pub qself: Option<Box<QSelf>>, pub path: Path, pub ident: Ident, pub rename: Option<Ident>, - pub body: Option<P<Block>>, + pub body: Option<Box<Block>>, /// The item was expanded from a glob delegation item. pub from_glob: bool, } #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub struct DelegationMac { - pub qself: Option<P<QSelf>>, + pub qself: Option<Box<QSelf>>, pub prefix: Path, // Some for list delegation, and None for glob delegation. pub suffixes: Option<ThinVec<(Ident, Option<Ident>)>>, - pub body: Option<P<Block>>, + pub body: Option<Box<Block>>, } #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub struct StaticItem { pub ident: Ident, - pub ty: P<Ty>, + pub ty: Box<Ty>, pub safety: Safety, pub mutability: Mutability, - pub expr: Option<P<Expr>>, + pub expr: Option<Box<Expr>>, pub define_opaque: Option<ThinVec<(NodeId, Path)>>, } @@ -3826,8 +3726,8 @@ pub struct ConstItem { pub defaultness: Defaultness, pub ident: Ident, pub generics: Generics, - pub ty: P<Ty>, - pub expr: Option<P<Expr>>, + pub ty: Box<Ty>, + pub expr: Option<Box<Expr>>, pub define_opaque: Option<ThinVec<(NodeId, Path)>>, } @@ -3897,7 +3797,7 @@ pub enum ItemKind { /// A macro invocation. /// /// E.g., `foo!(..)`. - MacCall(P<MacCall>), + MacCall(Box<MacCall>), /// A macro definition. MacroDef(Ident, MacroDef), /// A single delegation item (`reuse`). @@ -4007,7 +3907,7 @@ pub enum AssocItemKind { /// An associated type. Type(Box<TyAlias>), /// A macro expanding to associated items. - MacCall(P<MacCall>), + MacCall(Box<MacCall>), /// An associated delegation item. Delegation(Box<Delegation>), /// An associated list or glob delegation item. @@ -4077,7 +3977,7 @@ pub enum ForeignItemKind { /// A foreign type. TyAlias(Box<TyAlias>), /// A macro expanding to foreign items. - MacCall(P<MacCall>), + MacCall(Box<MacCall>), } impl ForeignItemKind { diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs index 9d91f41d6c7..3d2477e5f03 100644 --- a/compiler/rustc_ast/src/ast_traits.rs +++ b/compiler/rustc_ast/src/ast_traits.rs @@ -5,7 +5,6 @@ use std::fmt; use std::marker::PhantomData; -use crate::ptr::P; use crate::tokenstream::LazyAttrTokenStream; use crate::{ Arm, AssocItem, AttrItem, AttrKind, AttrVec, Attribute, Block, Crate, Expr, ExprField, @@ -53,7 +52,7 @@ impl_has_node_id!( WherePredicate, ); -impl<T: HasNodeId> HasNodeId for P<T> { +impl<T: HasNodeId> HasNodeId for Box<T> { fn node_id(&self) -> NodeId { (**self).node_id() } @@ -119,7 +118,7 @@ impl<T: HasTokens> HasTokens for Option<T> { } } -impl<T: HasTokens> HasTokens for P<T> { +impl<T: HasTokens> HasTokens for Box<T> { fn tokens(&self) -> Option<&LazyAttrTokenStream> { (**self).tokens() } @@ -245,7 +244,7 @@ impl_has_attrs!( ); impl_has_attrs_none!(Attribute, AttrItem, Block, Pat, Path, Ty, Visibility); -impl<T: HasAttrs> HasAttrs for P<T> { +impl<T: HasAttrs> HasAttrs for Box<T> { const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::SUPPORTS_CUSTOM_INNER_ATTRS; fn attrs(&self) -> &[Attribute] { (**self).attrs() @@ -322,8 +321,8 @@ impl<Wrapped, Tag> AstNodeWrapper<Wrapped, Tag> { } // FIXME: remove after `stmt_expr_attributes` is stabilized. -impl<T, Tag> From<AstNodeWrapper<P<T>, Tag>> for AstNodeWrapper<T, Tag> { - fn from(value: AstNodeWrapper<P<T>, Tag>) -> Self { +impl<T, Tag> From<AstNodeWrapper<Box<T>, Tag>> for AstNodeWrapper<T, Tag> { + fn from(value: AstNodeWrapper<Box<T>, Tag>) -> Self { AstNodeWrapper { wrapped: *value.wrapped, tag: value.tag } } } diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 4348a4bb120..6ada93b4c89 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -13,7 +13,6 @@ use crate::ast::{ Expr, ExprKind, LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NormalAttr, Path, PathSegment, Safety, }; -use crate::ptr::P; use crate::token::{self, CommentKind, Delimiter, InvisibleOrigin, MetaVarKind, Token}; use crate::tokenstream::{ DelimSpan, LazyAttrTokenStream, Spacing, TokenStream, TokenStreamIter, TokenTree, @@ -660,7 +659,7 @@ pub fn mk_attr_from_item( span: Span, ) -> Attribute { Attribute { - kind: AttrKind::Normal(P(NormalAttr { item, tokens })), + kind: AttrKind::Normal(Box::new(NormalAttr { item, tokens })), id: g.mk_attr_id(), style, span, @@ -710,7 +709,7 @@ pub fn mk_attr_name_value_str( span: Span, ) -> Attribute { let lit = token::Lit::new(token::Str, escape_string_symbol(val), None); - let expr = P(Expr { + let expr = Box::new(Expr { id: DUMMY_NODE_ID, kind: ExprKind::Lit(lit), span, diff --git a/compiler/rustc_ast/src/expand/autodiff_attrs.rs b/compiler/rustc_ast/src/expand/autodiff_attrs.rs index 2f918faaf75..33451f99748 100644 --- a/compiler/rustc_ast/src/expand/autodiff_attrs.rs +++ b/compiler/rustc_ast/src/expand/autodiff_attrs.rs @@ -7,7 +7,6 @@ use std::fmt::{self, Display, Formatter}; use std::str::FromStr; use crate::expand::{Decodable, Encodable, HashStable_Generic}; -use crate::ptr::P; use crate::{Ty, TyKind}; /// Forward and Reverse Mode are well known names for automatic differentiation implementations. @@ -162,7 +161,7 @@ pub fn valid_ret_activity(mode: DiffMode, activity: DiffActivity) -> bool { /// since Duplicated expects a mutable ref/ptr and we would thus end up with a shadow value /// who is an indirect type, which doesn't match the primal scalar type. We can't prevent /// users here from marking scalars as Duplicated, due to type aliases. -pub fn valid_ty_for_activity(ty: &P<Ty>, activity: DiffActivity) -> bool { +pub fn valid_ty_for_activity(ty: &Box<Ty>, activity: DiffActivity) -> bool { use DiffActivity::*; // It's always allowed to mark something as Const, since we won't compute derivatives wrt. it. // Dual variants also support all types. diff --git a/compiler/rustc_ast/src/format.rs b/compiler/rustc_ast/src/format.rs index c2a1de60a98..cadebb2254d 100644 --- a/compiler/rustc_ast/src/format.rs +++ b/compiler/rustc_ast/src/format.rs @@ -3,7 +3,6 @@ use rustc_macros::{Decodable, Encodable, Walkable}; use rustc_span::{Ident, Span, Symbol}; use crate::Expr; -use crate::ptr::P; use crate::token::LitKind; // Definitions: @@ -147,7 +146,7 @@ impl FormatArguments { #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub struct FormatArgument { pub kind: FormatArgumentKind, - pub expr: P<Expr>, + pub expr: Box<Expr>, } #[derive(Clone, Encodable, Decodable, Debug, Walkable)] diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 896d1e1148a..f1951049b47 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -37,7 +37,6 @@ pub mod expand; pub mod format; pub mod mut_visit; pub mod node_id; -pub mod ptr; pub mod token; pub mod tokenstream; pub mod visit; diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 06708e2e703..be8e1d22c9d 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -17,7 +17,6 @@ use smallvec::{SmallVec, smallvec}; use thin_vec::ThinVec; use crate::ast::*; -use crate::ptr::P; use crate::tokenstream::*; use crate::visit::{AssocCtxt, BoundKind, FnCtxt, LifetimeCtxt, VisitorResult, try_visit}; @@ -41,7 +40,7 @@ pub(crate) trait MutVisitable<V: MutVisitor> { fn visit_mut(&mut self, visitor: &mut V, extra: Self::Extra); } -impl<V: MutVisitor, T: ?Sized> MutVisitable<V> for P<T> +impl<V: MutVisitor, T: ?Sized> MutVisitable<V> for Box<T> where T: MutVisitable<V>, { @@ -293,15 +292,15 @@ macro_rules! generate_flat_map_visitor_fns { } generate_flat_map_visitor_fns! { - visit_items, P<Item>, flat_map_item; - visit_foreign_items, P<ForeignItem>, flat_map_foreign_item; + visit_items, Box<Item>, flat_map_item; + visit_foreign_items, Box<ForeignItem>, flat_map_foreign_item; visit_generic_params, GenericParam, flat_map_generic_param; visit_stmts, Stmt, flat_map_stmt; - visit_exprs, P<Expr>, filter_map_expr; + visit_exprs, Box<Expr>, filter_map_expr; visit_expr_fields, ExprField, flat_map_expr_field; visit_pat_fields, PatField, flat_map_pat_field; visit_variants, Variant, flat_map_variant; - visit_assoc_items, P<AssocItem>, flat_map_assoc_item, ctxt: AssocCtxt; + visit_assoc_items, Box<AssocItem>, flat_map_assoc_item, ctxt: AssocCtxt; visit_where_predicates, WherePredicate, flat_map_where_predicate; visit_params, Param, flat_map_param; visit_field_defs, FieldDef, flat_map_field_def; @@ -333,12 +332,12 @@ generate_walk_flat_map_fns! { walk_flat_map_where_predicate(WherePredicate) => visit_where_predicate; walk_flat_map_field_def(FieldDef) => visit_field_def; walk_flat_map_expr_field(ExprField) => visit_expr_field; - walk_flat_map_item(P<Item>) => visit_item; - walk_flat_map_foreign_item(P<ForeignItem>) => visit_foreign_item; - walk_flat_map_assoc_item(P<AssocItem>, ctxt: AssocCtxt) => visit_assoc_item; + walk_flat_map_item(Box<Item>) => visit_item; + walk_flat_map_foreign_item(Box<ForeignItem>) => visit_foreign_item; + walk_flat_map_assoc_item(Box<AssocItem>, ctxt: AssocCtxt) => visit_assoc_item; } -pub fn walk_filter_map_expr<T: MutVisitor>(vis: &mut T, mut e: P<Expr>) -> Option<P<Expr>> { +pub fn walk_filter_map_expr<T: MutVisitor>(vis: &mut T, mut e: Box<Expr>) -> Option<Box<Expr>> { vis.visit_expr(&mut e); Some(e) } diff --git a/compiler/rustc_ast/src/ptr.rs b/compiler/rustc_ast/src/ptr.rs deleted file mode 100644 index fffeab8bbca..00000000000 --- a/compiler/rustc_ast/src/ptr.rs +++ /dev/null @@ -1,11 +0,0 @@ -/// A pointer type that uniquely owns a heap allocation of type T. -/// -/// This used to be its own type, but now it's just a typedef for `Box` and we are planning to -/// remove it soon. -pub type P<T> = Box<T>; - -/// Construct a `P<T>` from a `T` value. -#[allow(non_snake_case)] -pub fn P<T>(value: T) -> P<T> { - Box::new(value) -} diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index 2dfd695d880..e9cf3cf0737 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -190,15 +190,15 @@ impl fmt::Display for LitKind { LitKind::Int(n, ty) => { write!(f, "{n}")?; match ty { - ast::LitIntType::Unsigned(ty) => write!(f, "{}", ty.name())?, - ast::LitIntType::Signed(ty) => write!(f, "{}", ty.name())?, + ast::LitIntType::Unsigned(ty) => write!(f, "{}", ty.name_str())?, + ast::LitIntType::Signed(ty) => write!(f, "{}", ty.name_str())?, ast::LitIntType::Unsuffixed => {} } } LitKind::Float(symbol, ty) => { write!(f, "{symbol}")?; match ty { - ast::LitFloatType::Suffixed(ty) => write!(f, "{}", ty.name())?, + ast::LitFloatType::Suffixed(ty) => write!(f, "{}", ty.name_str())?, ast::LitFloatType::Unsuffixed => {} } } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index ab15cb28fa1..5fdce27db53 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -20,7 +20,6 @@ use rustc_span::{Ident, Span, Symbol}; use thin_vec::ThinVec; use crate::ast::*; -use crate::ptr::P; use crate::tokenstream::DelimSpan; #[derive(Copy, Clone, Debug, PartialEq)] @@ -82,7 +81,7 @@ pub(crate) trait Visitable<'a, V: Visitor<'a>> { fn visit(&'a self, visitor: &mut V, extra: Self::Extra) -> V::Result; } -impl<'a, V: Visitor<'a>, T: ?Sized> Visitable<'a, V> for P<T> +impl<'a, V: Visitor<'a>, T: ?Sized> Visitable<'a, V> for Box<T> where T: Visitable<'a, V>, { @@ -322,7 +321,7 @@ macro_rules! common_visitor_and_walkers { Fn(FnCtxt, &'a $($mut)? Visibility, &'a $($mut)? Fn), /// E.g., `|x, y| body`. - Closure(&'a $($mut)? ClosureBinder, &'a $($mut)? Option<CoroutineKind>, &'a $($mut)? P<FnDecl>, &'a $($mut)? P<Expr>), + Closure(&'a $($mut)? ClosureBinder, &'a $($mut)? Option<CoroutineKind>, &'a $($mut)? Box<FnDecl>, &'a $($mut)? Box<Expr>), } impl<'a> FnKind<'a> { @@ -390,9 +389,9 @@ macro_rules! common_visitor_and_walkers { ThinVec<(NodeId, Path)>, ThinVec<PathSegment>, ThinVec<PreciseCapturingArg>, - ThinVec<P<Pat>>, - ThinVec<P<Ty>>, - ThinVec<P<TyPat>>, + ThinVec<Box<Pat>>, + ThinVec<Box<Ty>>, + ThinVec<Box<TyPat>>, ); // This macro generates `impl Visitable` and `impl MutVisitable` that forward to `Walkable` @@ -676,11 +675,11 @@ macro_rules! common_visitor_and_walkers { // Do nothing. } - fn flat_map_foreign_item(&mut self, ni: P<ForeignItem>) -> SmallVec<[P<ForeignItem>; 1]> { + fn flat_map_foreign_item(&mut self, ni: Box<ForeignItem>) -> SmallVec<[Box<ForeignItem>; 1]> { walk_flat_map_foreign_item(self, ni) } - fn flat_map_item(&mut self, i: P<Item>) -> SmallVec<[P<Item>; 1]> { + fn flat_map_item(&mut self, i: Box<Item>) -> SmallVec<[Box<Item>; 1]> { walk_flat_map_item(self, i) } @@ -690,9 +689,9 @@ macro_rules! common_visitor_and_walkers { fn flat_map_assoc_item( &mut self, - i: P<AssocItem>, + i: Box<AssocItem>, ctxt: AssocCtxt, - ) -> SmallVec<[P<AssocItem>; 1]> { + ) -> SmallVec<[Box<AssocItem>; 1]> { walk_flat_map_assoc_item(self, i, ctxt) } @@ -704,7 +703,7 @@ macro_rules! common_visitor_and_walkers { walk_flat_map_arm(self, arm) } - fn filter_map_expr(&mut self, e: P<Expr>) -> Option<P<Expr>> { + fn filter_map_expr(&mut self, e: Box<Expr>) -> Option<Box<Expr>> { walk_filter_map_expr(self, e) } @@ -1144,15 +1143,15 @@ macro_rules! generate_list_visit_fns { } generate_list_visit_fns! { - visit_items, P<Item>, visit_item; - visit_foreign_items, P<ForeignItem>, visit_foreign_item; + visit_items, Box<Item>, visit_item; + visit_foreign_items, Box<ForeignItem>, visit_foreign_item; visit_generic_params, GenericParam, visit_generic_param; visit_stmts, Stmt, visit_stmt; - visit_exprs, P<Expr>, visit_expr; + visit_exprs, Box<Expr>, visit_expr; visit_expr_fields, ExprField, visit_expr_field; visit_pat_fields, PatField, visit_pat_field; visit_variants, Variant, visit_variant; - visit_assoc_items, P<AssocItem>, visit_assoc_item, ctxt: AssocCtxt; + visit_assoc_items, Box<AssocItem>, visit_assoc_item, ctxt: AssocCtxt; visit_where_predicates, WherePredicate, visit_where_predicate; visit_params, Param, visit_param; visit_field_defs, FieldDef, visit_field_def; diff --git a/compiler/rustc_ast_ir/Cargo.toml b/compiler/rustc_ast_ir/Cargo.toml index 76bdd9f7eb6..1d21a07dc44 100644 --- a/compiler/rustc_ast_ir/Cargo.toml +++ b/compiler/rustc_ast_ir/Cargo.toml @@ -8,12 +8,16 @@ edition = "2024" rustc_data_structures = { path = "../rustc_data_structures", optional = true } rustc_macros = { path = "../rustc_macros", optional = true } rustc_serialize = { path = "../rustc_serialize", optional = true } +rustc_span = { path = "../rustc_span", optional = true } # tidy-alphabetical-end [features] +# tidy-alphabetical-start default = ["nightly"] nightly = [ - "dep:rustc_serialize", "dep:rustc_data_structures", "dep:rustc_macros", + "dep:rustc_serialize", + "dep:rustc_span", ] +# tidy-alphabetical-end diff --git a/compiler/rustc_ast_ir/src/lib.rs b/compiler/rustc_ast_ir/src/lib.rs index 0898433a74c..8f2a37c1210 100644 --- a/compiler/rustc_ast_ir/src/lib.rs +++ b/compiler/rustc_ast_ir/src/lib.rs @@ -11,11 +11,221 @@ #![cfg_attr(feature = "nightly", feature(rustc_attrs))] // tidy-alphabetical-end +use std::fmt; + #[cfg(feature = "nightly")] use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; +#[cfg(feature = "nightly")] +use rustc_span::{Symbol, sym}; pub mod visit; +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] +pub enum IntTy { + Isize, + I8, + I16, + I32, + I64, + I128, +} + +impl IntTy { + pub fn name_str(&self) -> &'static str { + match *self { + IntTy::Isize => "isize", + IntTy::I8 => "i8", + IntTy::I16 => "i16", + IntTy::I32 => "i32", + IntTy::I64 => "i64", + IntTy::I128 => "i128", + } + } + + #[cfg(feature = "nightly")] + pub fn name(self) -> Symbol { + match self { + IntTy::Isize => sym::isize, + IntTy::I8 => sym::i8, + IntTy::I16 => sym::i16, + IntTy::I32 => sym::i32, + IntTy::I64 => sym::i64, + IntTy::I128 => sym::i128, + } + } + + pub fn bit_width(&self) -> Option<u64> { + Some(match *self { + IntTy::Isize => return None, + IntTy::I8 => 8, + IntTy::I16 => 16, + IntTy::I32 => 32, + IntTy::I64 => 64, + IntTy::I128 => 128, + }) + } + + pub fn normalize(&self, target_width: u32) -> Self { + match self { + IntTy::Isize => match target_width { + 16 => IntTy::I16, + 32 => IntTy::I32, + 64 => IntTy::I64, + _ => unreachable!(), + }, + _ => *self, + } + } + + pub fn to_unsigned(self) -> UintTy { + match self { + IntTy::Isize => UintTy::Usize, + IntTy::I8 => UintTy::U8, + IntTy::I16 => UintTy::U16, + IntTy::I32 => UintTy::U32, + IntTy::I64 => UintTy::U64, + IntTy::I128 => UintTy::U128, + } + } +} + +impl fmt::Debug for IntTy { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.name_str()) + } +} + +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] +pub enum UintTy { + Usize, + U8, + U16, + U32, + U64, + U128, +} + +impl UintTy { + pub fn name_str(&self) -> &'static str { + match *self { + UintTy::Usize => "usize", + UintTy::U8 => "u8", + UintTy::U16 => "u16", + UintTy::U32 => "u32", + UintTy::U64 => "u64", + UintTy::U128 => "u128", + } + } + + #[cfg(feature = "nightly")] + pub fn name(self) -> Symbol { + match self { + UintTy::Usize => sym::usize, + UintTy::U8 => sym::u8, + UintTy::U16 => sym::u16, + UintTy::U32 => sym::u32, + UintTy::U64 => sym::u64, + UintTy::U128 => sym::u128, + } + } + + pub fn bit_width(&self) -> Option<u64> { + Some(match *self { + UintTy::Usize => return None, + UintTy::U8 => 8, + UintTy::U16 => 16, + UintTy::U32 => 32, + UintTy::U64 => 64, + UintTy::U128 => 128, + }) + } + + pub fn normalize(&self, target_width: u32) -> Self { + match self { + UintTy::Usize => match target_width { + 16 => UintTy::U16, + 32 => UintTy::U32, + 64 => UintTy::U64, + _ => unreachable!(), + }, + _ => *self, + } + } + + pub fn to_signed(self) -> IntTy { + match self { + UintTy::Usize => IntTy::Isize, + UintTy::U8 => IntTy::I8, + UintTy::U16 => IntTy::I16, + UintTy::U32 => IntTy::I32, + UintTy::U64 => IntTy::I64, + UintTy::U128 => IntTy::I128, + } + } +} + +impl fmt::Debug for UintTy { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.name_str()) + } +} + +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] +pub enum FloatTy { + F16, + F32, + F64, + F128, +} + +impl FloatTy { + pub fn name_str(self) -> &'static str { + match self { + FloatTy::F16 => "f16", + FloatTy::F32 => "f32", + FloatTy::F64 => "f64", + FloatTy::F128 => "f128", + } + } + + #[cfg(feature = "nightly")] + pub fn name(self) -> Symbol { + match self { + FloatTy::F16 => sym::f16, + FloatTy::F32 => sym::f32, + FloatTy::F64 => sym::f64, + FloatTy::F128 => sym::f128, + } + } + + pub fn bit_width(self) -> u64 { + match self { + FloatTy::F16 => 16, + FloatTy::F32 => 32, + FloatTy::F64 => 64, + FloatTy::F128 => 128, + } + } +} + +impl fmt::Debug for FloatTy { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.name_str()) + } +} + /// The movability of a coroutine / closure literal: /// whether a coroutine contains self-references, causing it to be `!Unpin`. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Copy)] diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml index dc571f5c367..6ac258155fe 100644 --- a/compiler/rustc_ast_lowering/Cargo.toml +++ b/compiler/rustc_ast_lowering/Cargo.toml @@ -11,7 +11,6 @@ doctest = false rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } -rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index c3222b79e55..2cc07694afb 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -95,7 +95,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_local(&mut self, l: &Local) -> &'hir hir::LetStmt<'hir> { // Let statements are allowed to have impl trait in bindings. - let super_ = l.super_; + let super_ = l.super_.map(|span| self.lower_span(span)); let ty = l.ty.as_ref().map(|t| { self.lower_ty(t, self.impl_trait_in_bindings_ctxt(ImplTraitPosition::Variable)) }); diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 15e736261d5..2ddbf083a09 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1,14 +1,13 @@ use std::ops::ControlFlow; use std::sync::Arc; -use rustc_ast::ptr::P as AstP; use rustc_ast::*; use rustc_ast_pretty::pprust::expr_to_string; -use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; -use rustc_hir::HirId; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{DefKind, Res}; +use rustc_hir::{HirId, find_attr}; use rustc_middle::span_bug; use rustc_middle::ty::TyCtxt; use rustc_session::errors::report_lit_error; @@ -53,7 +52,7 @@ impl<'v> rustc_ast::visit::Visitor<'v> for WillCreateDefIdsVisitor { } impl<'hir> LoweringContext<'_, 'hir> { - fn lower_exprs(&mut self, exprs: &[AstP<Expr>]) -> &'hir [hir::Expr<'hir>] { + fn lower_exprs(&mut self, exprs: &[Box<Expr>]) -> &'hir [hir::Expr<'hir>] { self.arena.alloc_from_iter(exprs.iter().map(|x| self.lower_expr_mut(x))) } @@ -98,7 +97,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } let expr_hir_id = self.lower_node_id(e.id); - self.lower_attrs(expr_hir_id, &e.attrs, e.span); + let attrs = self.lower_attrs(expr_hir_id, &e.attrs, e.span); let kind = match &e.kind { ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), @@ -232,10 +231,10 @@ impl<'hir> LoweringContext<'_, 'hir> { *fn_arg_span, ), None => self.lower_expr_closure( + attrs, binder, *capture_clause, e.id, - expr_hir_id, *constness, *movability, fn_decl, @@ -282,9 +281,11 @@ impl<'hir> LoweringContext<'_, 'hir> { ExprKind::Field(el, ident) => { hir::ExprKind::Field(self.lower_expr(el), self.lower_ident(*ident)) } - ExprKind::Index(el, er, brackets_span) => { - hir::ExprKind::Index(self.lower_expr(el), self.lower_expr(er), *brackets_span) - } + ExprKind::Index(el, er, brackets_span) => hir::ExprKind::Index( + self.lower_expr(el), + self.lower_expr(er), + self.lower_span(*brackets_span), + ), ExprKind::Range(e1, e2, lims) => { self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), *lims) } @@ -334,7 +335,9 @@ impl<'hir> LoweringContext<'_, 'hir> { ExprKind::Struct(se) => { let rest = match &se.rest { StructRest::Base(e) => hir::StructTailExpr::Base(self.lower_expr(e)), - StructRest::Rest(sp) => hir::StructTailExpr::DefaultFields(*sp), + StructRest::Rest(sp) => { + hir::StructTailExpr::DefaultFields(self.lower_span(*sp)) + } StructRest::None => hir::StructTailExpr::None, }; hir::ExprKind::Struct( @@ -451,7 +454,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_legacy_const_generics( &mut self, mut f: Expr, - args: ThinVec<AstP<Expr>>, + args: ThinVec<Box<Expr>>, legacy_args_idx: &[usize], ) -> hir::ExprKind<'hir> { let ExprKind::Path(None, path) = &mut f.kind else { @@ -491,7 +494,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.create_def(node_id, None, DefKind::AnonConst, f.span); let mut visitor = WillCreateDefIdsVisitor {}; let const_value = if let ControlFlow::Break(span) = visitor.visit_expr(&arg) { - AstP(Expr { + Box::new(Expr { id: self.next_node_id(), kind: ExprKind::Err(invalid_expr_error(self.tcx, span)), span: f.span, @@ -512,7 +515,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // Add generic args to the last element of the path. let last_segment = path.segments.last_mut().unwrap(); assert!(last_segment.args.is_none()); - last_segment.args = Some(AstP(GenericArgs::AngleBracketed(AngleBracketedArgs { + last_segment.args = Some(Box::new(GenericArgs::AngleBracketed(AngleBracketedArgs { span: DUMMY_SP, args: generic_args, }))); @@ -678,6 +681,14 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::Arm { hir_id, pat, guard, body, span } } + fn lower_capture_clause(&mut self, capture_clause: CaptureBy) -> CaptureBy { + match capture_clause { + CaptureBy::Ref => CaptureBy::Ref, + CaptureBy::Use { use_kw } => CaptureBy::Use { use_kw: self.lower_span(use_kw) }, + CaptureBy::Value { move_kw } => CaptureBy::Value { move_kw: self.lower_span(move_kw) }, + } + } + /// Lower/desugar a coroutine construct. /// /// In particular, this creates the correct async resume argument and `_task_context`. @@ -769,7 +780,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ExprKind::Closure(self.arena.alloc(hir::Closure { def_id: closure_def_id, binder: hir::ClosureBinder::Default, - capture_clause, + capture_clause: self.lower_capture_clause(capture_clause), bound_generic_params: &[], fn_decl, body, @@ -800,7 +811,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_attrs( inner_hir_id, &[Attribute { - kind: AttrKind::Normal(ptr::P(NormalAttr::from_ident(Ident::new( + kind: AttrKind::Normal(Box::new(NormalAttr::from_ident(Ident::new( sym::track_caller, span, )))), @@ -1035,15 +1046,15 @@ impl<'hir> LoweringContext<'_, 'hir> { } fn lower_expr_use(&mut self, use_kw_span: Span, expr: &Expr) -> hir::ExprKind<'hir> { - hir::ExprKind::Use(self.lower_expr(expr), use_kw_span) + hir::ExprKind::Use(self.lower_expr(expr), self.lower_span(use_kw_span)) } fn lower_expr_closure( &mut self, + attrs: &[rustc_hir::Attribute], binder: &ClosureBinder, capture_clause: CaptureBy, closure_id: NodeId, - closure_hir_id: hir::HirId, constness: Const, movability: Movability, decl: &FnDecl, @@ -1055,15 +1066,9 @@ impl<'hir> LoweringContext<'_, 'hir> { let (binder_clause, generic_params) = self.lower_closure_binder(binder); let (body_id, closure_kind) = self.with_new_scopes(fn_decl_span, move |this| { - let mut coroutine_kind = if this - .attrs - .get(&closure_hir_id.local_id) - .is_some_and(|attrs| attrs.iter().any(|attr| attr.has_name(sym::coroutine))) - { - Some(hir::CoroutineKind::Coroutine(Movability::Movable)) - } else { - None - }; + + let mut coroutine_kind = find_attr!(attrs, AttributeKind::Coroutine(_) => hir::CoroutineKind::Coroutine(Movability::Movable)); + // FIXME(contracts): Support contracts on closures? let body_id = this.lower_fn_body(decl, None, |this| { this.coroutine_kind = coroutine_kind; @@ -1083,7 +1088,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let c = self.arena.alloc(hir::Closure { def_id: closure_def_id, binder: binder_clause, - capture_clause, + capture_clause: self.lower_capture_clause(capture_clause), bound_generic_params, fn_decl, body: body_id, @@ -1197,7 +1202,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let c = self.arena.alloc(hir::Closure { def_id: closure_def_id, binder: binder_clause, - capture_clause, + capture_clause: self.lower_capture_clause(capture_clause), bound_generic_params, fn_decl, body, @@ -1279,7 +1284,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn extract_tuple_struct_path<'a>( &mut self, expr: &'a Expr, - ) -> Option<(&'a Option<AstP<QSelf>>, &'a Path)> { + ) -> Option<(&'a Option<Box<QSelf>>, &'a Path)> { if let ExprKind::Path(qself, path) = &expr.kind { // Does the path resolve to something disallowed in a tuple struct/variant pattern? if let Some(partial_res) = self.resolver.get_partial_res(expr.id) { @@ -1301,7 +1306,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn extract_unit_struct_path<'a>( &mut self, expr: &'a Expr, - ) -> Option<(&'a Option<AstP<QSelf>>, &'a Path)> { + ) -> Option<(&'a Option<Box<QSelf>>, &'a Path)> { if let ExprKind::Path(qself, path) = &expr.kind { // Does the path resolve to something disallowed in a unit struct/variant pattern? if let Some(partial_res) = self.resolver.get_partial_res(expr.id) { @@ -1472,7 +1477,7 @@ impl<'hir> LoweringContext<'_, 'hir> { /// Each sub-assignment is recorded in `assignments`. fn destructure_sequence( &mut self, - elements: &[AstP<Expr>], + elements: &[Box<Expr>], ctx: &str, eq_sign_span: Span, assignments: &mut Vec<hir::Stmt<'hir>>, @@ -2101,7 +2106,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn expr_uint(&mut self, sp: Span, ty: ast::UintTy, value: u128) -> hir::Expr<'hir> { let lit = hir::Lit { - span: sp, + span: self.lower_span(sp), node: ast::LitKind::Int(value.into(), ast::LitIntType::Unsigned(ty)), }; self.expr(sp, hir::ExprKind::Lit(lit)) @@ -2120,7 +2125,10 @@ impl<'hir> LoweringContext<'_, 'hir> { } pub(super) fn expr_str(&mut self, sp: Span, value: Symbol) -> hir::Expr<'hir> { - let lit = hir::Lit { span: sp, node: ast::LitKind::Str(value, ast::StrStyle::Cooked) }; + let lit = hir::Lit { + span: self.lower_span(sp), + node: ast::LitKind::Str(value, ast::StrStyle::Cooked), + }; self.expr(sp, hir::ExprKind::Lit(lit)) } @@ -2206,7 +2214,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.arena.alloc(hir::Path { span: self.lower_span(span), res, - segments: arena_vec![self; hir::PathSegment::new(ident, hir_id, res)], + segments: arena_vec![self; hir::PathSegment::new(self.lower_ident(ident), hir_id, res)], }), )); diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index 5b1dcab87b9..ec9d26eb33f 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -402,6 +402,8 @@ fn expand_format_args<'hir>( fmt: &FormatArgs, allow_const: bool, ) -> hir::ExprKind<'hir> { + let macsp = ctx.lower_span(macsp); + let mut incomplete_lit = String::new(); let lit_pieces = ctx.arena.alloc_from_iter(fmt.template.iter().enumerate().filter_map(|(i, piece)| { diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index 5b63206d7d6..5f8933aa2be 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -311,7 +311,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { ); self.with_parent(const_arg.hir_id, |this| { - intravisit::walk_ambig_const_arg(this, const_arg); + intravisit::walk_const_arg(this, const_arg); }); } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index ddf01b69e7f..ac6fac4c08e 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1,12 +1,11 @@ use rustc_abi::ExternAbi; -use rustc_ast::ptr::P; use rustc_ast::visit::AssocCtxt; use rustc_ast::*; -use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err}; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{DefKind, PerNS, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; -use rustc_hir::{self as hir, HirId, LifetimeSource, PredicateOrigin}; +use rustc_hir::{self as hir, HirId, LifetimeSource, PredicateOrigin, find_attr}; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::span_bug; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; @@ -102,7 +101,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { impl<'hir> LoweringContext<'_, 'hir> { pub(super) fn lower_mod( &mut self, - items: &[P<Item>], + items: &[Box<Item>], spans: &ModSpans, ) -> &'hir hir::Mod<'hir> { self.arena.alloc(hir::Mod { @@ -462,7 +461,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } ItemKind::MacroDef(ident, MacroDef { body, macro_rules }) => { let ident = self.lower_ident(*ident); - let body = P(self.lower_delim_args(body)); + let body = Box::new(self.lower_delim_args(body)); let def_id = self.local_def_id(id); let def_kind = self.tcx.def_kind(def_id); let DefKind::Macro(macro_kind) = def_kind else { @@ -627,6 +626,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } else { // For non-empty lists we can just drop all the data, the prefix is already // present in HIR as a part of nested imports. + let span = self.lower_span(span); self.arena.alloc(hir::UsePath { res: PerNS::default(), segments: &[], span }) }; hir::ItemKind::Use(path, hir::UseKind::ListStem) @@ -1567,7 +1567,7 @@ impl<'hir> LoweringContext<'_, 'hir> { attrs: &[hir::Attribute], ) -> hir::FnHeader { let asyncness = if let Some(CoroutineKind::Async { span, .. }) = h.coroutine_kind { - hir::IsAsync::Async(span) + hir::IsAsync::Async(self.lower_span(span)) } else { hir::IsAsync::NotAsync }; @@ -1804,7 +1804,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let res = Res::Def(DefKind::TyParam, def_id); let ident = self.lower_ident(ident); let ty_path = self.arena.alloc(hir::Path { - span: param_span, + span: self.lower_span(param_span), res, segments: self .arena diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 9aef189a29d..64c1b53f633 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -675,7 +675,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let bodies = SortedMap::from_presorted_elements(bodies); // Don't hash unless necessary, because it's expensive. - let (opt_hash_including_bodies, attrs_hash, delayed_lints_hash) = + let rustc_middle::hir::Hashes { opt_hash_including_bodies, attrs_hash, delayed_lints_hash } = self.tcx.hash_owner_nodes(node, &bodies, &attrs, &delayed_lints, define_opaque); let num_nodes = self.item_local_id_counter.as_usize(); let (nodes, parenting) = index::index_hir(self.tcx, node, &bodies, num_nodes); @@ -1217,7 +1217,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_path_ty( &mut self, t: &Ty, - qself: &Option<ptr::P<QSelf>>, + qself: &Option<Box<QSelf>>, path: &Path, param_mode: ParamMode, itctx: ImplTraitContext, @@ -2368,7 +2368,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, modifiers: TraitBoundModifiers, ) -> hir::TraitBoundModifiers { - hir::TraitBoundModifiers { constness: modifiers.constness, polarity: modifiers.polarity } + let constness = match modifiers.constness { + BoundConstness::Never => BoundConstness::Never, + BoundConstness::Always(span) => BoundConstness::Always(self.lower_span(span)), + BoundConstness::Maybe(span) => BoundConstness::Maybe(self.lower_span(span)), + }; + let polarity = match modifiers.polarity { + BoundPolarity::Positive => BoundPolarity::Positive, + BoundPolarity::Negative(span) => BoundPolarity::Negative(self.lower_span(span)), + BoundPolarity::Maybe(span) => BoundPolarity::Maybe(self.lower_span(span)), + }; + hir::TraitBoundModifiers { constness, polarity } } // Helper methods for building HIR. @@ -2414,6 +2424,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { init: Option<&'hir hir::Expr<'hir>>, ) -> hir::Stmt<'hir> { let hir_id = self.next_id(); + let span = self.lower_span(span); let local = hir::LetStmt { super_: Some(span), hir_id, @@ -2421,7 +2432,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { pat, els: None, source: hir::LocalSource::Normal, - span: self.lower_span(span), + span, ty: None, }; self.stmt(span, hir::StmtKind::Let(self.arena.alloc(local))) diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index e4440621048..b6533060a76 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -1,6 +1,5 @@ use std::sync::Arc; -use rustc_ast::ptr::P; use rustc_ast::*; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::def::{DefKind, Res}; @@ -154,7 +153,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_pat_tuple( &mut self, - pats: &[P<Pat>], + pats: &[Box<Pat>], ctx: &str, ) -> (&'hir [hir::Pat<'hir>], hir::DotDotPos) { let mut elems = Vec::with_capacity(pats.len()); @@ -209,7 +208,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// When encountering `($binding_mode $ident @)? ..` (`slice`), /// this is interpreted as a sub-slice pattern semantically. /// Patterns that follow, which are not like `slice` -- or an error occurs, are in `after`. - fn lower_pat_slice(&mut self, pats: &[P<Pat>]) -> hir::PatKind<'hir> { + fn lower_pat_slice(&mut self, pats: &[Box<Pat>]) -> hir::PatKind<'hir> { let mut before = Vec::new(); let mut after = Vec::new(); let mut slice = None; diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index c80ef275c80..3322e0fb66b 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -24,7 +24,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { pub(crate) fn lower_qpath( &mut self, id: NodeId, - qself: &Option<ptr::P<QSelf>>, + qself: &Option<Box<QSelf>>, p: &Path, param_mode: ParamMode, allow_return_type_notation: AllowReturnTypeNotation, diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index af93d55c898..53e64439afc 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -40,7 +40,7 @@ ast_passes_auto_generic = auto traits cannot have generic parameters ast_passes_auto_items = auto traits cannot have associated items .label = {ast_passes_auto_items} - .suggestion = remove these associated items + .suggestion = remove the associated items ast_passes_auto_super_lifetime = auto traits cannot have super traits or lifetime bounds .label = {ast_passes_auto_super_lifetime} @@ -241,6 +241,10 @@ ast_passes_tilde_const_disallowed = `[const]` is not allowed here .trait_assoc_ty = associated types in non-`const` traits cannot have `[const]` trait bounds .trait_impl_assoc_ty = associated types in non-const impls cannot have `[const]` trait bounds .inherent_assoc_ty = inherent associated types cannot have `[const]` trait bounds + .struct = structs cannot have `[const]` trait bounds + .enum = enums cannot have `[const]` trait bounds + .union = unions cannot have `[const]` trait bounds + .anon_const = anonymous constants cannot have `[const]` trait bounds .object = trait objects cannot have `[const]` trait bounds .item = this item cannot have `[const]` trait bounds diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 895a457ec1d..9d3b0969ef3 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -22,7 +22,6 @@ use std::str::FromStr; use itertools::{Either, Itertools}; use rustc_abi::{CanonAbi, ExternAbi, InterruptKind}; -use rustc_ast::ptr::P; use rustc_ast::visit::{AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor, walk_list}; use rustc_ast::*; use rustc_ast_pretty::pprust::{self, State}; @@ -699,23 +698,27 @@ impl<'a> AstValidator<'a> { } } - fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) { + fn deny_super_traits(&self, bounds: &GenericBounds, ident: Span) { if let [.., last] = &bounds[..] { - let span = ident_span.shrink_to_hi().to(last.span()); - self.dcx().emit_err(errors::AutoTraitBounds { span, ident: ident_span }); + let span = bounds.iter().map(|b| b.span()).collect(); + let removal = ident.shrink_to_hi().to(last.span()); + self.dcx().emit_err(errors::AutoTraitBounds { span, removal, ident }); } } - fn deny_where_clause(&self, where_clause: &WhereClause, ident_span: Span) { + fn deny_where_clause(&self, where_clause: &WhereClause, ident: Span) { if !where_clause.predicates.is_empty() { // FIXME: The current diagnostic is misleading since it only talks about // super trait and lifetime bounds while we should just say “bounds”. - self.dcx() - .emit_err(errors::AutoTraitBounds { span: where_clause.span, ident: ident_span }); + self.dcx().emit_err(errors::AutoTraitBounds { + span: vec![where_clause.span], + removal: where_clause.span, + ident, + }); } } - fn deny_items(&self, trait_items: &[P<AssocItem>], ident_span: Span) { + fn deny_items(&self, trait_items: &[Box<AssocItem>], ident_span: Span) { if !trait_items.is_empty() { let spans: Vec<_> = trait_items.iter().map(|i| i.kind.ident().unwrap().span).collect(); let total = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span); @@ -1124,7 +1127,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { ); } } - visit::walk_item(self, item) + self.with_tilde_const(Some(TildeConstReason::Enum { span: item.span }), |this| { + visit::walk_item(this, item) + }); } ItemKind::Trait(box Trait { constness, @@ -1175,26 +1180,32 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } visit::walk_item(self, item) } - ItemKind::Struct(ident, generics, vdata) => match vdata { - VariantData::Struct { fields, .. } => { - self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident); - self.visit_generics(generics); - walk_list!(self, visit_field_def, fields); - } - _ => visit::walk_item(self, item), - }, + ItemKind::Struct(ident, generics, vdata) => { + self.with_tilde_const(Some(TildeConstReason::Struct { span: item.span }), |this| { + match vdata { + VariantData::Struct { fields, .. } => { + this.visit_attrs_vis_ident(&item.attrs, &item.vis, ident); + this.visit_generics(generics); + walk_list!(this, visit_field_def, fields); + } + _ => visit::walk_item(this, item), + } + }) + } ItemKind::Union(ident, generics, vdata) => { if vdata.fields().is_empty() { self.dcx().emit_err(errors::FieldlessUnion { span: item.span }); } - match vdata { - VariantData::Struct { fields, .. } => { - self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident); - self.visit_generics(generics); - walk_list!(self, visit_field_def, fields); + self.with_tilde_const(Some(TildeConstReason::Union { span: item.span }), |this| { + match vdata { + VariantData::Struct { fields, .. } => { + this.visit_attrs_vis_ident(&item.attrs, &item.vis, ident); + this.visit_generics(generics); + walk_list!(this, visit_field_def, fields); + } + _ => visit::walk_item(this, item), } - _ => visit::walk_item(self, item), - } + }); } ItemKind::Const(box ConstItem { defaultness, expr, .. }) => { self.check_defaultness(item.span, *defaultness); @@ -1623,6 +1634,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> { _ => self.with_in_trait_impl(None, |this| visit::walk_assoc_item(this, item, ctxt)), } } + + fn visit_anon_const(&mut self, anon_const: &'a AnonConst) { + self.with_tilde_const( + Some(TildeConstReason::AnonConst { span: anon_const.value.span }), + |this| visit::walk_anon_const(this, anon_const), + ) + } } /// When encountering an equality constraint in a `where` clause, emit an error. If the code seems diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index fd4b2528541..60f47490f12 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -344,7 +344,7 @@ pub(crate) struct ModuleNonAscii { #[diag(ast_passes_auto_generic, code = E0567)] pub(crate) struct AutoTraitGeneric { #[primary_span] - #[suggestion(code = "", applicability = "machine-applicable")] + #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")] pub span: Span, #[label] pub ident: Span, @@ -354,8 +354,9 @@ pub(crate) struct AutoTraitGeneric { #[diag(ast_passes_auto_super_lifetime, code = E0568)] pub(crate) struct AutoTraitBounds { #[primary_span] - #[suggestion(code = "", applicability = "machine-applicable")] - pub span: Span, + pub span: Vec<Span>, + #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")] + pub removal: Span, #[label] pub ident: Span, } @@ -365,7 +366,7 @@ pub(crate) struct AutoTraitBounds { pub(crate) struct AutoTraitItems { #[primary_span] pub spans: Vec<Span>, - #[suggestion(code = "", applicability = "machine-applicable")] + #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")] pub total: Span, #[label] pub ident: Span, @@ -623,6 +624,26 @@ pub(crate) enum TildeConstReason { #[primary_span] span: Span, }, + #[note(ast_passes_struct)] + Struct { + #[primary_span] + span: Span, + }, + #[note(ast_passes_enum)] + Enum { + #[primary_span] + span: Span, + }, + #[note(ast_passes_union)] + Union { + #[primary_span] + span: Span, + }, + #[note(ast_passes_anon_const)] + AnonConst { + #[primary_span] + span: Span, + }, #[note(ast_passes_object)] TraitObject, #[note(ast_passes_item)] diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index f0cf0c1487f..85f76036df7 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -10,7 +10,6 @@ use std::borrow::Cow; use std::sync::Arc; use rustc_ast::attr::AttrIdGenerator; -use rustc_ast::ptr::P; use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Token, TokenKind}; use rustc_ast::tokenstream::{Spacing, TokenStream, TokenTree}; use rustc_ast::util::classify; @@ -1178,7 +1177,7 @@ impl<'a> State<'a> { self.end(rb); } - fn commasep_exprs(&mut self, b: Breaks, exprs: &[P<ast::Expr>]) { + fn commasep_exprs(&mut self, b: Breaks, exprs: &[Box<ast::Expr>]) { self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e, FixupContext::default()), |e| e.span) } diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 8a2cb64b2a0..bdf73ac32f0 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -2,7 +2,6 @@ use std::fmt::Write; use ast::{ForLoopKind, MatchKind}; use itertools::{Itertools, Position}; -use rustc_ast::ptr::P; use rustc_ast::util::classify; use rustc_ast::util::literal::escape_byte_str_symbol; use rustc_ast::util::parser::{self, ExprPrecedence, Fixity}; @@ -54,7 +53,7 @@ impl<'a> State<'a> { self.print_else(elseopt) } - fn print_call_post(&mut self, args: &[P<ast::Expr>]) { + fn print_call_post(&mut self, args: &[Box<ast::Expr>]) { self.popen(); self.commasep_exprs(Inconsistent, args); self.pclose() @@ -111,7 +110,7 @@ impl<'a> State<'a> { } } - fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>]) { + fn print_expr_vec(&mut self, exprs: &[Box<ast::Expr>]) { let ib = self.ibox(INDENT_UNIT); self.word("["); self.commasep_exprs(Inconsistent, exprs); @@ -149,7 +148,7 @@ impl<'a> State<'a> { fn print_expr_struct( &mut self, - qself: &Option<P<ast::QSelf>>, + qself: &Option<Box<ast::QSelf>>, path: &ast::Path, fields: &[ast::ExprField], rest: &ast::StructRest, @@ -204,7 +203,7 @@ impl<'a> State<'a> { self.word("}"); } - fn print_expr_tup(&mut self, exprs: &[P<ast::Expr>]) { + fn print_expr_tup(&mut self, exprs: &[Box<ast::Expr>]) { self.popen(); self.commasep_exprs(Inconsistent, exprs); if exprs.len() == 1 { @@ -213,7 +212,7 @@ impl<'a> State<'a> { self.pclose() } - fn print_expr_call(&mut self, func: &ast::Expr, args: &[P<ast::Expr>], fixup: FixupContext) { + fn print_expr_call(&mut self, func: &ast::Expr, args: &[Box<ast::Expr>], fixup: FixupContext) { // Independent of parenthesization related to precedence, we must // parenthesize `func` if this is a statement context in which without // parentheses, a statement boundary would occur inside `func` or @@ -247,7 +246,7 @@ impl<'a> State<'a> { &mut self, segment: &ast::PathSegment, receiver: &ast::Expr, - base_args: &[P<ast::Expr>], + base_args: &[Box<ast::Expr>], fixup: FixupContext, ) { // The fixup here is different than in `print_expr_call` because diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 11c97a552c6..6e34d1b61db 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -2,7 +2,6 @@ use ast::StaticItem; use itertools::{Itertools, Position}; use rustc_ast as ast; use rustc_ast::ModKind; -use rustc_ast::ptr::P; use rustc_span::Ident; use crate::pp::BoxMarker; @@ -628,10 +627,10 @@ impl<'a> State<'a> { &mut self, attrs: &[ast::Attribute], vis: &ast::Visibility, - qself: &Option<P<ast::QSelf>>, + qself: &Option<Box<ast::QSelf>>, path: &ast::Path, kind: DelegationKind<'_>, - body: &Option<P<ast::Block>>, + body: &Option<Box<ast::Block>>, ) { let body_cb_ib = body.as_ref().map(|body| (body, self.head(""))); self.print_visibility(vis); diff --git a/compiler/rustc_attr_data_structures/Cargo.toml b/compiler/rustc_attr_data_structures/Cargo.toml deleted file mode 100644 index b18923c337f..00000000000 --- a/compiler/rustc_attr_data_structures/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "rustc_attr_data_structures" -version = "0.0.0" -edition = "2024" - -[dependencies] -# tidy-alphabetical-start -rustc_abi = {path = "../rustc_abi"} -rustc_ast = {path = "../rustc_ast"} -rustc_ast_pretty = {path = "../rustc_ast_pretty"} -rustc_data_structures = {path = "../rustc_data_structures"} -rustc_macros = {path = "../rustc_macros"} -rustc_serialize = {path = "../rustc_serialize"} -rustc_span = {path = "../rustc_span"} -thin-vec = "0.2.12" -# tidy-alphabetical-end diff --git a/compiler/rustc_attr_data_structures/src/lints.rs b/compiler/rustc_attr_data_structures/src/lints.rs deleted file mode 100644 index 60ca4d43ce9..00000000000 --- a/compiler/rustc_attr_data_structures/src/lints.rs +++ /dev/null @@ -1,16 +0,0 @@ -use rustc_macros::HashStable_Generic; -use rustc_span::Span; - -#[derive(Clone, Debug, HashStable_Generic)] -pub struct AttributeLint<Id> { - pub id: Id, - pub span: Span, - pub kind: AttributeLintKind, -} - -#[derive(Clone, Debug, HashStable_Generic)] -pub enum AttributeLintKind { - UnusedDuplicate { this: Span, other: Span, warning: bool }, - IllFormedAttributeInput { suggestions: Vec<String> }, - EmptyAttribute { first_span: Span }, -} diff --git a/compiler/rustc_attr_parsing/Cargo.toml b/compiler/rustc_attr_parsing/Cargo.toml index 32029137268..cec9d62e656 100644 --- a/compiler/rustc_attr_parsing/Cargo.toml +++ b/compiler/rustc_attr_parsing/Cargo.toml @@ -8,7 +8,6 @@ edition = "2024" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } -rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index a6bd2306ec5..95104b896ac 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -1,7 +1,7 @@ use std::iter; -use rustc_attr_data_structures::AttributeKind; use rustc_feature::{AttributeTemplate, template}; +use rustc_hir::attrs::AttributeKind; use rustc_span::{Span, Symbol, sym}; use super::{CombineAttributeParser, ConvertFn}; diff --git a/compiler/rustc_attr_parsing/src/attributes/body.rs b/compiler/rustc_attr_parsing/src/attributes/body.rs new file mode 100644 index 00000000000..ab9330216f6 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/body.rs @@ -0,0 +1,15 @@ +//! Attributes that can be found in function body. + +use rustc_hir::attrs::AttributeKind; +use rustc_span::{Symbol, sym}; + +use super::{NoArgsAttributeParser, OnDuplicate}; +use crate::context::Stage; + +pub(crate) struct CoroutineParser; + +impl<S: Stage> NoArgsAttributeParser<S> for CoroutineParser { + const PATH: &[Symbol] = &[sym::coroutine]; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const CREATE: fn(rustc_span::Span) -> AttributeKind = |span| AttributeKind::Coroutine(span); +} diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index 6373cf6e08a..947be28bc95 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -1,6 +1,7 @@ use rustc_ast::{LitKind, NodeId}; -use rustc_attr_data_structures::{CfgEntry, RustcVersion}; use rustc_feature::{AttributeTemplate, Features, template}; +use rustc_hir::RustcVersion; +use rustc_hir::attrs::CfgEntry; use rustc_session::Session; use rustc_session::config::ExpectedValues; use rustc_session::lint::BuiltinLintDiag; diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs b/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs index c5025a8b6ea..3257d898ecc 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs @@ -1,7 +1,7 @@ use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NodeId}; use rustc_ast_pretty::pprust; -use rustc_attr_data_structures::RustcVersion; use rustc_feature::{Features, GatedCfg, find_gated_cfg}; +use rustc_hir::RustcVersion; use rustc_session::Session; use rustc_session::config::ExpectedValues; use rustc_session::lint::builtin::UNEXPECTED_CFGS; diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index bb28121c2c5..c5fb11dbf6a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -1,5 +1,5 @@ -use rustc_attr_data_structures::{AttributeKind, CoverageStatus, OptimizeAttr, UsedBy}; use rustc_feature::{AttributeTemplate, template}; +use rustc_hir::attrs::{AttributeKind, CoverageAttrKind, OptimizeAttr, UsedBy}; use rustc_session::parse::feature_err; use rustc_span::{Span, Symbol, sym}; @@ -78,16 +78,16 @@ impl<S: Stage> SingleAttributeParser<S> for CoverageParser { return None; }; - let status = match arg.path().word_sym() { - Some(sym::off) => CoverageStatus::Off, - Some(sym::on) => CoverageStatus::On, + let kind = match arg.path().word_sym() { + Some(sym::off) => CoverageAttrKind::Off, + Some(sym::on) => CoverageAttrKind::On, None | Some(_) => { fail_incorrect_argument(arg.span()); return None; } }; - Some(AttributeKind::Coverage(cx.attr_span, status)) + Some(AttributeKind::Coverage(cx.attr_span, kind)) } } @@ -374,11 +374,3 @@ impl<S: Stage> CombineAttributeParser<S> for TargetFeatureParser { features } } - -pub(crate) struct OmitGdbPrettyPrinterSectionParser; - -impl<S: Stage> NoArgsAttributeParser<S> for OmitGdbPrettyPrinterSectionParser { - const PATH: &[Symbol] = &[sym::omit_gdb_pretty_printer_section]; - const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; - const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::OmitGdbPrettyPrinterSection; -} diff --git a/compiler/rustc_attr_parsing/src/attributes/confusables.rs b/compiler/rustc_attr_parsing/src/attributes/confusables.rs index c911908dfb3..7d24c89a6e8 100644 --- a/compiler/rustc_attr_parsing/src/attributes/confusables.rs +++ b/compiler/rustc_attr_parsing/src/attributes/confusables.rs @@ -1,5 +1,5 @@ -use rustc_attr_data_structures::AttributeKind; use rustc_feature::template; +use rustc_hir::attrs::AttributeKind; use rustc_span::{Span, Symbol, sym}; use thin_vec::ThinVec; diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index 08cf1ab5d19..38ec4bd5645 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -1,5 +1,5 @@ -use rustc_attr_data_structures::{AttributeKind, DeprecatedSince, Deprecation}; use rustc_feature::{AttributeTemplate, template}; +use rustc_hir::attrs::{AttributeKind, DeprecatedSince, Deprecation}; use rustc_span::{Span, Symbol, sym}; use super::util::parse_version; diff --git a/compiler/rustc_attr_parsing/src/attributes/dummy.rs b/compiler/rustc_attr_parsing/src/attributes/dummy.rs index e5e1c3bb6b6..bbcd9ab530c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/dummy.rs +++ b/compiler/rustc_attr_parsing/src/attributes/dummy.rs @@ -1,5 +1,5 @@ -use rustc_attr_data_structures::AttributeKind; use rustc_feature::{AttributeTemplate, template}; +use rustc_hir::attrs::AttributeKind; use rustc_span::{Symbol, sym}; use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index fe812175218..8437713206e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -2,9 +2,9 @@ // note: need to model better how duplicate attr errors work when not using // SingleAttributeParser which is what we have two of here. -use rustc_attr_data_structures::lints::AttributeLintKind; -use rustc_attr_data_structures::{AttributeKind, InlineAttr}; use rustc_feature::{AttributeTemplate, template}; +use rustc_hir::attrs::{AttributeKind, InlineAttr}; +use rustc_hir::lints::AttributeLintKind; use rustc_span::{Symbol, sym}; use super::{AcceptContext, AttributeOrder, OnDuplicate}; diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index 960cebd8925..7eab3090870 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -1,6 +1,6 @@ -use rustc_attr_data_structures::AttributeKind; -use rustc_attr_data_structures::AttributeKind::{LinkName, LinkOrdinal, LinkSection}; use rustc_feature::{AttributeTemplate, template}; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::attrs::AttributeKind::{LinkName, LinkOrdinal, LinkSection}; use rustc_span::{Span, Symbol, sym}; use crate::attributes::{ diff --git a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs index 0eceff53e8b..9530fec07d6 100644 --- a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs +++ b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs @@ -1,4 +1,4 @@ -use rustc_attr_data_structures::AttributeKind; +use rustc_hir::attrs::AttributeKind; use rustc_span::{Span, Symbol, sym}; use crate::attributes::{NoArgsAttributeParser, OnDuplicate}; diff --git a/compiler/rustc_attr_parsing/src/attributes/loop_match.rs b/compiler/rustc_attr_parsing/src/attributes/loop_match.rs index 80808b90dc6..868c113a6d1 100644 --- a/compiler/rustc_attr_parsing/src/attributes/loop_match.rs +++ b/compiler/rustc_attr_parsing/src/attributes/loop_match.rs @@ -1,4 +1,4 @@ -use rustc_attr_data_structures::AttributeKind; +use rustc_hir::attrs::AttributeKind; use rustc_span::{Span, Symbol, sym}; use crate::attributes::{NoArgsAttributeParser, OnDuplicate}; diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs index eade49180ac..886f7a889d3 100644 --- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs @@ -1,6 +1,6 @@ -use rustc_attr_data_structures::{AttributeKind, MacroUseArgs}; use rustc_errors::DiagArgValue; use rustc_feature::{AttributeTemplate, template}; +use rustc_hir::attrs::{AttributeKind, MacroUseArgs}; use rustc_span::{Span, Symbol, sym}; use thin_vec::ThinVec; diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 0c10517d044..f7946ade6d2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -16,8 +16,8 @@ use std::marker::PhantomData; -use rustc_attr_data_structures::AttributeKind; use rustc_feature::{AttributeTemplate, template}; +use rustc_hir::attrs::AttributeKind; use rustc_span::{Span, Symbol}; use thin_vec::ThinVec; @@ -26,6 +26,7 @@ use crate::parser::ArgParser; use crate::session_diagnostics::UnusedMultiple; pub(crate) mod allow_unstable; +pub(crate) mod body; pub(crate) mod cfg; pub(crate) mod cfg_old; pub(crate) mod codegen_attrs; diff --git a/compiler/rustc_attr_parsing/src/attributes/must_use.rs b/compiler/rustc_attr_parsing/src/attributes/must_use.rs index 42af3ed0bfa..d767abbc250 100644 --- a/compiler/rustc_attr_parsing/src/attributes/must_use.rs +++ b/compiler/rustc_attr_parsing/src/attributes/must_use.rs @@ -1,6 +1,6 @@ -use rustc_attr_data_structures::AttributeKind; use rustc_errors::DiagArgValue; use rustc_feature::{AttributeTemplate, template}; +use rustc_hir::attrs::AttributeKind; use rustc_span::{Symbol, sym}; use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; diff --git a/compiler/rustc_attr_parsing/src/attributes/no_implicit_prelude.rs b/compiler/rustc_attr_parsing/src/attributes/no_implicit_prelude.rs index 47cc925f7f6..40f8d00685e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/no_implicit_prelude.rs +++ b/compiler/rustc_attr_parsing/src/attributes/no_implicit_prelude.rs @@ -1,4 +1,4 @@ -use rustc_attr_data_structures::AttributeKind; +use rustc_hir::attrs::AttributeKind; use rustc_span::{Span, sym}; use crate::attributes::{NoArgsAttributeParser, OnDuplicate}; diff --git a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs index 94f6a65c74e..361ac8e959d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs +++ b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs @@ -1,4 +1,4 @@ -use rustc_attr_data_structures::AttributeKind; +use rustc_hir::attrs::AttributeKind; use rustc_span::{Span, Symbol, sym}; use crate::attributes::{NoArgsAttributeParser, OnDuplicate}; diff --git a/compiler/rustc_attr_parsing/src/attributes/path.rs b/compiler/rustc_attr_parsing/src/attributes/path.rs index febb1b45a18..5700d780d71 100644 --- a/compiler/rustc_attr_parsing/src/attributes/path.rs +++ b/compiler/rustc_attr_parsing/src/attributes/path.rs @@ -1,5 +1,5 @@ -use rustc_attr_data_structures::AttributeKind; use rustc_feature::{AttributeTemplate, template}; +use rustc_hir::attrs::AttributeKind; use rustc_span::{Symbol, sym}; use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; diff --git a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs index 4de77dc268e..b156a7c5845 100644 --- a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs @@ -1,5 +1,5 @@ -use rustc_attr_data_structures::AttributeKind; use rustc_feature::{AttributeTemplate, template}; +use rustc_hir::attrs::AttributeKind; use rustc_span::{Span, Symbol, sym}; use thin_vec::ThinVec; diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 521acbb607c..6087afe6ded 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -1,7 +1,7 @@ use rustc_abi::Align; use rustc_ast::{IntTy, LitIntType, LitKind, UintTy}; -use rustc_attr_data_structures::{AttributeKind, IntType, ReprAttr}; use rustc_feature::{AttributeTemplate, template}; +use rustc_hir::attrs::{AttributeKind, IntType, ReprAttr}; use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use super::{AcceptMapping, AttributeParser, CombineAttributeParser, ConvertFn, FinalizeContext}; diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index 7ca951dc0bb..b465d2e62ff 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -1,5 +1,5 @@ -use rustc_attr_data_structures::AttributeKind; use rustc_feature::{AttributeTemplate, template}; +use rustc_hir::attrs::AttributeKind; use rustc_span::{Symbol, sym}; use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; diff --git a/compiler/rustc_attr_parsing/src/attributes/semantics.rs b/compiler/rustc_attr_parsing/src/attributes/semantics.rs index 74fdff5d2e1..70a8a002099 100644 --- a/compiler/rustc_attr_parsing/src/attributes/semantics.rs +++ b/compiler/rustc_attr_parsing/src/attributes/semantics.rs @@ -1,4 +1,4 @@ -use rustc_attr_data_structures::AttributeKind; +use rustc_hir::attrs::AttributeKind; use rustc_span::{Span, Symbol, sym}; use crate::attributes::{NoArgsAttributeParser, OnDuplicate}; diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index c54fc6b41f8..3c4ec133d51 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -1,11 +1,12 @@ use std::num::NonZero; -use rustc_attr_data_structures::{ - AttributeKind, DefaultBodyStability, PartialConstStability, Stability, StabilityLevel, - StableSince, UnstableReason, VERSION_PLACEHOLDER, -}; use rustc_errors::ErrorGuaranteed; use rustc_feature::template; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::{ + DefaultBodyStability, PartialConstStability, Stability, StabilityLevel, StableSince, + UnstableReason, VERSION_PLACEHOLDER, +}; use rustc_span::{Ident, Span, Symbol, sym}; use super::util::parse_version; diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs index ee81f64860f..77b494328c7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs @@ -1,6 +1,6 @@ -use rustc_attr_data_structures::AttributeKind; -use rustc_attr_data_structures::lints::AttributeLintKind; use rustc_feature::{AttributeTemplate, template}; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::lints::AttributeLintKind; use rustc_span::{Symbol, sym}; use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; @@ -44,3 +44,55 @@ impl<S: Stage> SingleAttributeParser<S> for IgnoreParser { }) } } + +pub(crate) struct ShouldPanicParser; + +impl<S: Stage> SingleAttributeParser<S> for ShouldPanicParser { + const PATH: &[Symbol] = &[sym::should_panic]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError; + const TEMPLATE: AttributeTemplate = + template!(Word, List: r#"expected = "reason""#, NameValueStr: "reason"); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { + Some(AttributeKind::ShouldPanic { + span: cx.attr_span, + reason: match args { + ArgParser::NoArgs => None, + ArgParser::NameValue(name_value) => { + let Some(str_value) = name_value.value_as_str() else { + cx.expected_string_literal( + name_value.value_span, + Some(name_value.value_as_lit()), + ); + return None; + }; + Some(str_value) + } + ArgParser::List(list) => { + let Some(single) = list.single() else { + cx.expected_single_argument(list.span); + return None; + }; + let Some(single) = single.meta_item() else { + cx.expected_name_value(single.span(), Some(sym::expected)); + return None; + }; + if !single.path().word_is(sym::expected) { + cx.expected_specific_argument_strings(list.span, vec!["expected"]); + return None; + } + let Some(nv) = single.args().name_value() else { + cx.expected_name_value(single.span(), Some(sym::expected)); + return None; + }; + let Some(expected) = nv.value_as_str() else { + cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit())); + return None; + }; + Some(expected) + } + }, + }) + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs index e69a533699b..a954617ca57 100644 --- a/compiler/rustc_attr_parsing/src/attributes/traits.rs +++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs @@ -1,7 +1,7 @@ use core::mem; -use rustc_attr_data_structures::AttributeKind; use rustc_feature::{AttributeTemplate, template}; +use rustc_hir::attrs::AttributeKind; use rustc_span::{Span, Symbol, sym}; use crate::attributes::{ diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs index c9fdc57cc06..1c57dc1ebe2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs +++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs @@ -1,5 +1,5 @@ -use rustc_attr_data_structures::AttributeKind; use rustc_feature::{AttributeTemplate, template}; +use rustc_hir::attrs::AttributeKind; use rustc_span::hygiene::Transparency; use rustc_span::{Symbol, sym}; diff --git a/compiler/rustc_attr_parsing/src/attributes/util.rs b/compiler/rustc_attr_parsing/src/attributes/util.rs index 503d2f1fae1..10134915b27 100644 --- a/compiler/rustc_attr_parsing/src/attributes/util.rs +++ b/compiler/rustc_attr_parsing/src/attributes/util.rs @@ -1,6 +1,6 @@ use rustc_ast::attr::{AttributeExt, first_attr_value_str_by_name}; -use rustc_attr_data_structures::RustcVersion; use rustc_feature::is_builtin_attr_name; +use rustc_hir::RustcVersion; use rustc_span::{Symbol, sym}; /// Parse a rustc version number written inside string literal in an attribute, diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 9b86d101840..80dfdffdb55 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -5,10 +5,10 @@ use std::sync::LazyLock; use private::Sealed; use rustc_ast::{self as ast, LitKind, MetaItemLit, NodeId}; -use rustc_attr_data_structures::AttributeKind; -use rustc_attr_data_structures::lints::{AttributeLint, AttributeLintKind}; use rustc_errors::{DiagCtxtHandle, Diagnostic}; use rustc_feature::{AttributeTemplate, Features}; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::lints::{AttributeLint, AttributeLintKind}; use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirId}; use rustc_session::Session; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; @@ -16,10 +16,10 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; use crate::attributes::allow_unstable::{ AllowConstFnUnstableParser, AllowInternalUnstableParser, UnstableFeatureBoundParser, }; +use crate::attributes::body::CoroutineParser; use crate::attributes::codegen_attrs::{ - ColdParser, CoverageParser, ExportNameParser, NakedParser, NoMangleParser, - OmitGdbPrettyPrinterSectionParser, OptimizeParser, TargetFeatureParser, TrackCallerParser, - UsedParser, + ColdParser, CoverageParser, ExportNameParser, NakedParser, NoMangleParser, OptimizeParser, + TargetFeatureParser, TrackCallerParser, UsedParser, }; use crate::attributes::confusables::ConfusablesParser; use crate::attributes::deprecation::DeprecationParser; @@ -50,7 +50,7 @@ use crate::attributes::semantics::MayDangleParser; use crate::attributes::stability::{ BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser, }; -use crate::attributes::test_attrs::IgnoreParser; +use crate::attributes::test_attrs::{IgnoreParser, ShouldPanicParser}; use crate::attributes::traits::{ AllowIncoherentImplParser, CoherenceIsCoreParser, CoinductiveParser, ConstTraitParser, DenyExplicitImplParser, DoNotImplementViaObjectParser, FundamentalParser, MarkerParser, @@ -62,15 +62,23 @@ use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs}; use crate::parser::{ArgParser, MetaItemParser, PathParser}; use crate::session_diagnostics::{AttributeParseError, AttributeParseErrorReason, UnknownMetaItem}; -macro_rules! group_type { - ($stage: ty) => { - LazyLock<( - BTreeMap<&'static [Symbol], Vec<(AttributeTemplate, Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, $stage>, &ArgParser<'a>) + Send + Sync>)>>, - Vec<Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, $stage>) -> Option<AttributeKind>>> - )> - }; +type GroupType<S> = LazyLock<GroupTypeInner<S>>; + +struct GroupTypeInner<S: Stage> { + accepters: BTreeMap<&'static [Symbol], Vec<GroupTypeInnerAccept<S>>>, + finalizers: Vec<FinalizeFn<S>>, +} + +struct GroupTypeInnerAccept<S: Stage> { + template: AttributeTemplate, + accept_fn: AcceptFn<S>, } +type AcceptFn<S> = + Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, S>, &ArgParser<'a>) + Send + Sync>; +type FinalizeFn<S> = + Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, S>) -> Option<AttributeKind>>; + macro_rules! attribute_parsers { ( pub(crate) static $name: ident = [$($names: ty),* $(,)?]; @@ -93,11 +101,11 @@ macro_rules! attribute_parsers { } }; ( - @[$ty: ty] pub(crate) static $name: ident = [$($names: ty),* $(,)?]; + @[$stage: ty] pub(crate) static $name: ident = [$($names: ty),* $(,)?]; ) => { - pub(crate) static $name: group_type!($ty) = LazyLock::new(|| { - let mut accepts = BTreeMap::<_, Vec<(AttributeTemplate, Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, $ty>, &ArgParser<'a>) + Send + Sync>)>>::new(); - let mut finalizes = Vec::<Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, $ty>) -> Option<AttributeKind>>>::new(); + pub(crate) static $name: GroupType<$stage> = LazyLock::new(|| { + let mut accepts = BTreeMap::<_, Vec<GroupTypeInnerAccept<$stage>>>::new(); + let mut finalizes = Vec::<FinalizeFn<$stage>>::new(); $( { thread_local! { @@ -105,11 +113,14 @@ macro_rules! attribute_parsers { }; for (path, template, accept_fn) in <$names>::ATTRIBUTES { - accepts.entry(*path).or_default().push((*template, Box::new(|cx, args| { - STATE_OBJECT.with_borrow_mut(|s| { - accept_fn(s, cx, args) + accepts.entry(*path).or_default().push(GroupTypeInnerAccept { + template: *template, + accept_fn: Box::new(|cx, args| { + STATE_OBJECT.with_borrow_mut(|s| { + accept_fn(s, cx, args) + }) }) - }))); + }); } finalizes.push(Box::new(|cx| { @@ -119,7 +130,7 @@ macro_rules! attribute_parsers { } )* - (accepts, finalizes) + GroupTypeInner { accepters:accepts, finalizers:finalizes } }); }; } @@ -163,6 +174,7 @@ attribute_parsers!( Single<RustcLayoutScalarValidRangeEnd>, Single<RustcLayoutScalarValidRangeStart>, Single<RustcObjectLifetimeDefaultParser>, + Single<ShouldPanicParser>, Single<SkipDuringMethodDispatchParser>, Single<TransparencyParser>, Single<WithoutArgs<AllowIncoherentImplParser>>, @@ -174,6 +186,7 @@ attribute_parsers!( Single<WithoutArgs<ConstContinueParser>>, Single<WithoutArgs<ConstStabilityIndirectParser>>, Single<WithoutArgs<ConstTraitParser>>, + Single<WithoutArgs<CoroutineParser>>, Single<WithoutArgs<DenyExplicitImplParser>>, Single<WithoutArgs<DoNotImplementViaObjectParser>>, Single<WithoutArgs<ExportStableParser>>, @@ -187,7 +200,6 @@ attribute_parsers!( Single<WithoutArgs<NoImplicitPreludeParser>>, Single<WithoutArgs<NoMangleParser>>, Single<WithoutArgs<NonExhaustiveParser>>, - Single<WithoutArgs<OmitGdbPrettyPrinterSectionParser>>, Single<WithoutArgs<ParenSugarParser>>, Single<WithoutArgs<PassByValueParser>>, Single<WithoutArgs<PointeeParser>>, @@ -213,24 +225,24 @@ mod private { #[allow(private_interfaces)] pub trait Stage: Sized + 'static + Sealed { type Id: Copy; - const SHOULD_EMIT_LINTS: bool; - fn parsers() -> &'static group_type!(Self); + fn parsers() -> &'static GroupType<Self>; fn emit_err<'sess>( &self, sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>, ) -> ErrorGuaranteed; + + fn should_emit(&self) -> ShouldEmit; } // allow because it's a sealed trait #[allow(private_interfaces)] impl Stage for Early { type Id = NodeId; - const SHOULD_EMIT_LINTS: bool = false; - fn parsers() -> &'static group_type!(Self) { + fn parsers() -> &'static GroupType<Self> { &early::ATTRIBUTE_PARSERS } fn emit_err<'sess>( @@ -244,15 +256,18 @@ impl Stage for Early { sess.dcx().create_err(diag).delay_as_bug() } } + + fn should_emit(&self) -> ShouldEmit { + self.emit_errors + } } // allow because it's a sealed trait #[allow(private_interfaces)] impl Stage for Late { type Id = HirId; - const SHOULD_EMIT_LINTS: bool = true; - fn parsers() -> &'static group_type!(Self) { + fn parsers() -> &'static GroupType<Self> { &late::ATTRIBUTE_PARSERS } fn emit_err<'sess>( @@ -262,6 +277,10 @@ impl Stage for Late { ) -> ErrorGuaranteed { tcx.dcx().emit_err(diag) } + + fn should_emit(&self) -> ShouldEmit { + ShouldEmit::ErrorsAndLints + } } /// used when parsing attributes for miscellaneous things *before* ast lowering @@ -300,7 +319,7 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> { /// must be delayed until after HIR is built. This method will take care of the details of /// that. pub(crate) fn emit_lint(&mut self, lint: AttributeLintKind, span: Span) { - if !S::SHOULD_EMIT_LINTS { + if !self.stage.should_emit().should_emit() { return; } let id = self.target_id; @@ -811,8 +830,8 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { let args = parser.args(); let parts = path.segments().map(|i| i.name).collect::<Vec<_>>(); - if let Some(accepts) = S::parsers().0.get(parts.as_slice()) { - for (template, accept) in accepts { + if let Some(accepts) = S::parsers().accepters.get(parts.as_slice()) { + for accept in accepts { let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext { shared: SharedContext { cx: self, @@ -821,11 +840,11 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { emit_lint: &mut emit_lint, }, attr_span: lower_span(attr.span), - template, + template: &accept.template, attr_path: path.get_attribute_path(), }; - accept(&mut cx, args) + (accept.accept_fn)(&mut cx, args) } } else { // If we're here, we must be compiling a tool attribute... Or someone @@ -856,7 +875,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { } let mut parsed_attributes = Vec::new(); - for f in &S::parsers().1 { + for f in &S::parsers().finalizers { if let Some(attr) = f(&mut FinalizeContext { shared: SharedContext { cx: self, @@ -877,7 +896,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { /// Returns whether there is a parser for an attribute with this name pub fn is_parsed_attribute(path: &[Symbol]) -> bool { - Late::parsers().0.contains_key(path) + Late::parsers().accepters.contains_key(path) } fn lower_attr_args(&self, args: &ast::AttrArgs, lower_span: impl Fn(Span) -> Span) -> AttrArgs { diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index dc54cb6b840..fc1377e5314 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -1,13 +1,13 @@ //! Centralized logic for parsing and attributes. //! //! ## Architecture -//! This crate is part of a series of crates that handle attribute processing. -//! - [rustc_attr_data_structures](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_data_structures/index.html): Defines the data structures that store parsed attributes +//! This crate is part of a series of crates and modules that handle attribute processing. +//! - [rustc_hir::attrs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/index.html): Defines the data structures that store parsed attributes //! - [rustc_attr_parsing](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_parsing/index.html): This crate, handles the parsing of attributes -//! - (planned) rustc_attr_validation: Will handle attribute validation +//! - (planned) rustc_attr_validation: Will handle attribute validation, logic currently handled in `rustc_passes` //! //! The separation between data structures and parsing follows the principle of separation of concerns. -//! Data structures (`rustc_attr_data_structures`) define what attributes look like after parsing. +//! Data structures (`rustc_hir::attrs`) define what attributes look like after parsing. //! This crate (`rustc_attr_parsing`) handles how to convert raw tokens into those structures. //! This split allows other parts of the compiler to use the data structures without needing //! the parsing logic, making the codebase more modular and maintainable. @@ -62,7 +62,7 @@ //! a "stability" of an item. So, the stability attribute has an //! [`AttributeParser`](attributes::AttributeParser) that recognizes both the `#[stable()]` //! and `#[unstable()]` syntactic attributes, and at the end produce a single -//! [`AttributeKind::Stability`](rustc_attr_data_structures::AttributeKind::Stability). +//! [`AttributeKind::Stability`](rustc_hir::attrs::AttributeKind::Stability). //! //! When multiple instances of the same attribute are allowed, they're combined into a single //! semantic attribute. For example: diff --git a/compiler/rustc_attr_parsing/src/lints.rs b/compiler/rustc_attr_parsing/src/lints.rs index e648ca4fdf8..22f5531bc80 100644 --- a/compiler/rustc_attr_parsing/src/lints.rs +++ b/compiler/rustc_attr_parsing/src/lints.rs @@ -1,6 +1,6 @@ -use rustc_attr_data_structures::lints::{AttributeLint, AttributeLintKind}; use rustc_errors::{DiagArgValue, LintEmitter}; use rustc_hir::HirId; +use rustc_hir::lints::{AttributeLint, AttributeLintKind}; use crate::session_diagnostics; diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 0de4bd67f0c..76da9dc8832 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -3,7 +3,7 @@ use std::rc::Rc; use rustc_errors::Diag; use rustc_hir::def_id::LocalDefId; -use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData}; +use rustc_infer::infer::region_constraints::{Constraint, ConstraintKind, RegionConstraintData}; use rustc_infer::infer::{ InferCtxt, RegionResolutionError, RegionVariableOrigin, SubregionOrigin, TyCtxtInferExt as _, }; @@ -277,7 +277,7 @@ where // `QueryNormalizeExt::query_normalize` used in the query and `normalize` called below: // the former fails to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` // test. Check after #85499 lands to see if its fixes have erased this difference. - let (param_env, value) = key.into_parts(); + let ty::ParamEnvAnd { param_env, value } = key; let _ = ocx.normalize(&cause, param_env, value.value); let diag = try_extract_error_from_fulfill_cx( @@ -324,7 +324,7 @@ where mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query); let ocx = ObligationCtxt::new(&infcx); - let (param_env, value) = key.into_parts(); + let ty::ParamEnvAnd { param_env, value } = key; let _ = ocx.deeply_normalize(&cause, param_env, value.value); let diag = try_extract_error_from_fulfill_cx( @@ -454,25 +454,24 @@ fn try_extract_error_from_region_constraints<'a, 'tcx>( (RePlaceholder(a_p), RePlaceholder(b_p)) => a_p.bound == b_p.bound, _ => a_region == b_region, }; - let mut check = - |constraint: &Constraint<'tcx>, cause: &SubregionOrigin<'tcx>, exact| match *constraint { - Constraint::RegSubReg(sub, sup) - if ((exact && sup == placeholder_region) - || (!exact && regions_the_same(sup, placeholder_region))) - && sup != sub => - { - Some((sub, cause.clone())) - } - Constraint::VarSubReg(vid, sup) - if (exact - && sup == placeholder_region - && !universe_of_region(vid).can_name(placeholder_universe)) - || (!exact && regions_the_same(sup, placeholder_region)) => - { - Some((ty::Region::new_var(infcx.tcx, vid), cause.clone())) - } - _ => None, - }; + let mut check = |c: &Constraint<'tcx>, cause: &SubregionOrigin<'tcx>, exact| match c.kind { + ConstraintKind::RegSubReg + if ((exact && c.sup == placeholder_region) + || (!exact && regions_the_same(c.sup, placeholder_region))) + && c.sup != c.sub => + { + Some((c.sub, cause.clone())) + } + ConstraintKind::VarSubReg + if (exact + && c.sup == placeholder_region + && !universe_of_region(c.sub.as_var()).can_name(placeholder_universe)) + || (!exact && regions_the_same(c.sup, placeholder_region)) => + { + Some((c.sub, cause.clone())) + } + _ => None, + }; let mut find_culprit = |exact_match: bool| { region_constraints diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index a10da08ddf3..fdca6b56540 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -341,7 +341,7 @@ impl<'tcx> BorrowExplanation<'tcx> { } } } else if let LocalInfo::BlockTailTemp(info) = local_decl.local_info() { - let sp = info.span.find_oldest_ancestor_in_same_ctxt(); + let sp = info.span.find_ancestor_not_from_macro().unwrap_or(info.span); if info.tail_result_is_ignored { // #85581: If the first mutable borrow's scope contains // the second borrow, this suggestion isn't helpful. diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 56fdaf1c724..b67dba3af96 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -51,7 +51,7 @@ mod conflict_errors; mod explain_borrow; mod move_errors; mod mutability_errors; -mod opaque_suggestions; +mod opaque_types; mod region_errors; pub(crate) use bound_region_errors::{ToUniverseInfo, UniverseInfo}; @@ -613,7 +613,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { /// Return the name of the provided `Ty` (that must be a reference) with a synthesized lifetime /// name where required. pub(super) fn get_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String { - let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, Namespace::TypeNS); + let mut p = ty::print::FmtPrinter::new(self.infcx.tcx, Namespace::TypeNS); // We need to add synthesized lifetimes where appropriate. We do // this by hooking into the pretty printer and telling it to label the @@ -624,19 +624,19 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { | ty::RePlaceholder(ty::PlaceholderRegion { bound: ty::BoundRegion { kind: br, .. }, .. - }) => printer.region_highlight_mode.highlighting_bound_region(br, counter), + }) => p.region_highlight_mode.highlighting_bound_region(br, counter), _ => {} } } - ty.print(&mut printer).unwrap(); - printer.into_buffer() + ty.print(&mut p).unwrap(); + p.into_buffer() } /// Returns the name of the provided `Ty` (that must be a reference)'s region with a /// synthesized lifetime name where required. pub(super) fn get_region_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String { - let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, Namespace::TypeNS); + let mut p = ty::print::FmtPrinter::new(self.infcx.tcx, Namespace::TypeNS); let region = if let ty::Ref(region, ..) = ty.kind() { match region.kind() { @@ -644,7 +644,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { | ty::RePlaceholder(ty::PlaceholderRegion { bound: ty::BoundRegion { kind: br, .. }, .. - }) => printer.region_highlight_mode.highlighting_bound_region(br, counter), + }) => p.region_highlight_mode.highlighting_bound_region(br, counter), _ => {} } region @@ -652,8 +652,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { bug!("ty for annotation of borrow region is not a reference"); }; - region.print(&mut printer).unwrap(); - printer.into_buffer() + region.print(&mut p).unwrap(); + p.into_buffer() } /// Add a note to region errors and borrow explanations when higher-ranked regions in predicates diff --git a/compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs b/compiler/rustc_borrowck/src/diagnostics/opaque_types.rs index 7192a889adc..83fe4a9f98f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs +++ b/compiler/rustc_borrowck/src/diagnostics/opaque_types.rs @@ -18,9 +18,28 @@ use rustc_trait_selection::errors::impl_trait_overcapture_suggestion; use crate::MirBorrowckCtxt; use crate::borrow_set::BorrowData; use crate::consumers::RegionInferenceContext; +use crate::region_infer::opaque_types::DeferredOpaqueTypeError; use crate::type_check::Locations; impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { + pub(crate) fn report_opaque_type_errors(&mut self, errors: Vec<DeferredOpaqueTypeError<'tcx>>) { + if errors.is_empty() { + return; + } + let mut guar = None; + for error in errors { + guar = Some(match error { + DeferredOpaqueTypeError::InvalidOpaqueTypeArgs(err) => err.report(self.infcx), + DeferredOpaqueTypeError::LifetimeMismatchOpaqueParam(err) => { + self.infcx.dcx().emit_err(err) + } + }); + } + let guar = guar.unwrap(); + self.root_cx.set_tainted_by_errors(guar); + self.infcx.set_tainted_by_errors(guar); + } + /// Try to note when an opaque is involved in a borrowck error and that /// opaque captures lifetimes due to edition 2024. // FIXME: This code is otherwise somewhat general, and could easily be adapted diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index b130cf8ed27..2b74f1a48f7 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -92,9 +92,6 @@ impl<'tcx> RegionErrors<'tcx> { ) -> impl Iterator<Item = (RegionErrorKind<'tcx>, ErrorGuaranteed)> { self.0.into_iter() } - pub(crate) fn has_errors(&self) -> Option<ErrorGuaranteed> { - self.0.get(0).map(|x| x.1) - } } impl std::fmt::Debug for RegionErrors<'_> { diff --git a/compiler/rustc_borrowck/src/handle_placeholders.rs b/compiler/rustc_borrowck/src/handle_placeholders.rs index aaaf2f45c86..e168b819a8d 100644 --- a/compiler/rustc_borrowck/src/handle_placeholders.rs +++ b/compiler/rustc_borrowck/src/handle_placeholders.rs @@ -157,7 +157,7 @@ fn region_definitions<'tcx>( for info in var_infos.iter() { let origin = match info.origin { RegionVariableOrigin::Nll(origin) => origin, - _ => NllRegionVariableOrigin::Existential { from_forall: false }, + _ => NllRegionVariableOrigin::Existential { from_forall: false, name: None }, }; let definition = RegionDefinition { origin, universe: info.universe, external_name: None }; @@ -216,22 +216,11 @@ pub(crate) fn compute_sccs_applying_placeholder_outlives_constraints<'tcx>( placeholder_index_to_region: _, liveness_constraints, mut outlives_constraints, - mut member_constraints, + member_constraints, universe_causes, type_tests, } = constraints; - if let Some(guar) = universal_regions.tainted_by_errors() { - debug!("Universal regions tainted by errors; removing constraints!"); - // Suppress unhelpful extra errors in `infer_opaque_types` by clearing out all - // outlives bounds that we may end up checking. - outlives_constraints = Default::default(); - member_constraints = Default::default(); - - // Also taint the entire scope. - infcx.set_tainted_by_errors(guar); - } - let fr_static = universal_regions.fr_static; let compute_sccs = |constraints: &OutlivesConstraintSet<'tcx>, diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 321b18c9b78..d76d6a04e6e 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -19,6 +19,7 @@ use std::borrow::Cow; use std::cell::{OnceCell, RefCell}; use std::marker::PhantomData; use std::ops::{ControlFlow, Deref}; +use std::rc::Rc; use borrow_set::LocalsStateAtExit; use root_cx::BorrowCheckRootCtxt; @@ -44,6 +45,7 @@ use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces} use rustc_mir_dataflow::move_paths::{ InitIndex, InitLocation, LookupResult, MoveData, MovePathIndex, }; +use rustc_mir_dataflow::points::DenseLocationMap; use rustc_mir_dataflow::{Analysis, Results, ResultsVisitor, visit_results}; use rustc_session::lint::builtin::{TAIL_EXPR_DROP_ORDER, UNUSED_MUT}; use rustc_span::{ErrorGuaranteed, Span, Symbol}; @@ -60,11 +62,14 @@ use crate::path_utils::*; use crate::place_ext::PlaceExt; use crate::places_conflict::{PlaceConflictBias, places_conflict}; use crate::polonius::PoloniusDiagnosticsContext; -use crate::polonius::legacy::{PoloniusLocationTable, PoloniusOutput}; +use crate::polonius::legacy::{ + PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput, +}; use crate::prefixes::PrefixSet; use crate::region_infer::RegionInferenceContext; use crate::renumber::RegionCtxt; use crate::session_diagnostics::VarNeedNotMut; +use crate::type_check::MirTypeckResults; mod borrow_set; mod borrowck_errors; @@ -321,7 +326,34 @@ fn do_mir_borrowck<'tcx>( let locals_are_invalidated_at_exit = tcx.hir_body_owner_kind(def).is_fn_or_closure(); let borrow_set = BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &move_data); - // Compute non-lexical lifetimes. + let location_map = Rc::new(DenseLocationMap::new(body)); + + let polonius_input = root_cx.consumer.as_ref().map_or(false, |c| c.polonius_input()) + || infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled(); + let mut polonius_facts = + (polonius_input || PoloniusFacts::enabled(infcx.tcx)).then_some(PoloniusFacts::default()); + + // Run the MIR type-checker. + let MirTypeckResults { + constraints, + universal_region_relations, + opaque_type_values, + polonius_context, + } = type_check::type_check( + root_cx, + &infcx, + body, + &promoted, + universal_regions, + &location_table, + &borrow_set, + &mut polonius_facts, + &move_data, + Rc::clone(&location_map), + ); + + // Compute non-lexical lifetimes using the constraints computed + // by typechecking the MIR body. let nll::NllOutput { regioncx, polonius_input, @@ -332,14 +364,19 @@ fn do_mir_borrowck<'tcx>( } = nll::compute_regions( root_cx, &infcx, - universal_regions, body, - &promoted, &location_table, &move_data, &borrow_set, + location_map, + universal_region_relations, + constraints, + polonius_facts, + polonius_context, ); + let opaque_type_errors = regioncx.infer_opaque_types(root_cx, &infcx, opaque_type_values); + // Dump MIR results into a file, if that is enabled. This lets us // write unit-tests, as well as helping with debugging. nll::dump_nll_mir(&infcx, body, ®ioncx, &opt_closure_req, &borrow_set); @@ -434,7 +471,11 @@ fn do_mir_borrowck<'tcx>( }; // Compute and report region errors, if any. - mbcx.report_region_errors(nll_errors); + if nll_errors.is_empty() { + mbcx.report_opaque_type_errors(opaque_type_errors); + } else { + mbcx.report_region_errors(nll_errors); + } let (mut flow_analysis, flow_entry_states) = get_flow_results(tcx, body, &move_data, &borrow_set, ®ioncx); diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 41f67e78930..8608a8a3a66 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -5,7 +5,8 @@ use std::path::PathBuf; use std::rc::Rc; use std::str::FromStr; -use polonius_engine::{Algorithm, Output}; +use polonius_engine::{Algorithm, AllFacts, Output}; +use rustc_data_structures::frozen::Frozen; use rustc_index::IndexSlice; use rustc_middle::mir::pretty::{PrettyPrintMirOptions, dump_mir_with_options}; use rustc_middle::mir::{Body, PassWhere, Promoted, create_dump_file, dump_enabled, dump_mir}; @@ -18,14 +19,16 @@ use rustc_span::sym; use tracing::{debug, instrument}; use crate::borrow_set::BorrowSet; +use crate::consumers::RustcFacts; use crate::diagnostics::RegionErrors; use crate::handle_placeholders::compute_sccs_applying_placeholder_outlives_constraints; -use crate::polonius::PoloniusDiagnosticsContext; use crate::polonius::legacy::{ PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput, }; +use crate::polonius::{PoloniusContext, PoloniusDiagnosticsContext}; use crate::region_infer::RegionInferenceContext; -use crate::type_check::{self, MirTypeckResults}; +use crate::type_check::MirTypeckRegionConstraints; +use crate::type_check::free_region_relations::UniversalRegionRelations; use crate::universal_regions::UniversalRegions; use crate::{ BorrowCheckRootCtxt, BorrowckInferCtxt, ClosureOutlivesSubject, ClosureRegionRequirements, @@ -76,41 +79,18 @@ pub(crate) fn replace_regions_in_mir<'tcx>( pub(crate) fn compute_regions<'tcx>( root_cx: &mut BorrowCheckRootCtxt<'tcx>, infcx: &BorrowckInferCtxt<'tcx>, - universal_regions: UniversalRegions<'tcx>, body: &Body<'tcx>, - promoted: &IndexSlice<Promoted, Body<'tcx>>, location_table: &PoloniusLocationTable, move_data: &MoveData<'tcx>, borrow_set: &BorrowSet<'tcx>, + location_map: Rc<DenseLocationMap>, + universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>, + constraints: MirTypeckRegionConstraints<'tcx>, + mut polonius_facts: Option<AllFacts<RustcFacts>>, + polonius_context: Option<PoloniusContext>, ) -> NllOutput<'tcx> { - let is_polonius_legacy_enabled = infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled(); - let polonius_input = root_cx.consumer.as_ref().map_or(false, |c| c.polonius_input()) - || is_polonius_legacy_enabled; let polonius_output = root_cx.consumer.as_ref().map_or(false, |c| c.polonius_output()) - || is_polonius_legacy_enabled; - let mut polonius_facts = - (polonius_input || PoloniusFacts::enabled(infcx.tcx)).then_some(PoloniusFacts::default()); - - let location_map = Rc::new(DenseLocationMap::new(body)); - - // Run the MIR type-checker. - let MirTypeckResults { - constraints, - universal_region_relations, - opaque_type_values, - polonius_context, - } = type_check::type_check( - root_cx, - infcx, - body, - promoted, - universal_regions, - location_table, - borrow_set, - &mut polonius_facts, - move_data, - Rc::clone(&location_map), - ); + || infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled(); let lowered_constraints = compute_sccs_applying_placeholder_outlives_constraints( constraints, @@ -168,13 +148,6 @@ pub(crate) fn compute_regions<'tcx>( let (closure_region_requirements, nll_errors) = regioncx.solve(infcx, body, polonius_output.clone()); - if let Some(guar) = nll_errors.has_errors() { - // Suppress unhelpful extra errors in `infer_opaque_types`. - infcx.set_tainted_by_errors(guar); - } - - regioncx.infer_opaque_types(root_cx, infcx, opaque_type_values); - NllOutput { regioncx, polonius_input: polonius_facts.map(Box::new), diff --git a/compiler/rustc_borrowck/src/region_infer/graphviz.rs b/compiler/rustc_borrowck/src/region_infer/graphviz.rs index a3e29982e90..b2f67c43125 100644 --- a/compiler/rustc_borrowck/src/region_infer/graphviz.rs +++ b/compiler/rustc_borrowck/src/region_infer/graphviz.rs @@ -41,7 +41,22 @@ fn render_region_vid<'tcx>( "".to_string() }; - format!("{:?}{universe_str}{external_name_str}", rvid) + let extra_info = match regioncx.region_definition(rvid).origin { + NllRegionVariableOrigin::FreeRegion => "".to_string(), + NllRegionVariableOrigin::Placeholder(p) => match p.bound.kind { + ty::BoundRegionKind::Named(def_id) => { + format!(" (for<{}>)", tcx.item_name(def_id)) + } + ty::BoundRegionKind::ClosureEnv | ty::BoundRegionKind::Anon => " (for<'_>)".to_string(), + ty::BoundRegionKind::NamedAnon(_) => { + bug!("only used for pretty printing") + } + }, + NllRegionVariableOrigin::Existential { name: Some(name), .. } => format!(" (ex<{name}>)"), + NllRegionVariableOrigin::Existential { .. } => format!(" (ex<'_>)"), + }; + + format!("{:?}{universe_str}{external_name_str}{extra_info}", rvid) } impl<'tcx> RegionInferenceContext<'tcx> { diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 68f1637e07e..dbd245214a2 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -44,7 +44,7 @@ use crate::{ mod dump_mir; mod graphviz; -mod opaque_types; +pub(crate) mod opaque_types; mod reverse_sccs; pub(crate) mod values; @@ -417,7 +417,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// minimum values. /// /// For example: - /// ``` + /// ```ignore (illustrative) /// fn foo<'a, 'b>( /* ... */ ) where 'a: 'b { /* ... */ } /// ``` /// would initialize two variables like so: @@ -1940,9 +1940,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { // and here we prefer to blame the source (the y = x statement). let blame_source = match from_region_origin { NllRegionVariableOrigin::FreeRegion - | NllRegionVariableOrigin::Existential { from_forall: false } => true, + | NllRegionVariableOrigin::Existential { from_forall: false, name: _ } => true, NllRegionVariableOrigin::Placeholder(_) - | NllRegionVariableOrigin::Existential { from_forall: true } => false, + | NllRegionVariableOrigin::Existential { from_forall: true, name: _ } => false, }; // To pick a constraint to blame, we organize constraints by how interesting we expect them diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 6270e6d9a60..23c4554aa15 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -6,7 +6,9 @@ use rustc_middle::ty::{ TypeVisitableExt, fold_regions, }; use rustc_span::Span; -use rustc_trait_selection::opaque_types::check_opaque_type_parameter_valid; +use rustc_trait_selection::opaque_types::{ + InvalidOpaqueTypeArgs, check_opaque_type_parameter_valid, +}; use tracing::{debug, instrument}; use super::RegionInferenceContext; @@ -14,6 +16,11 @@ use crate::BorrowCheckRootCtxt; use crate::session_diagnostics::LifetimeMismatchOpaqueParam; use crate::universal_regions::RegionClassification; +pub(crate) enum DeferredOpaqueTypeError<'tcx> { + InvalidOpaqueTypeArgs(InvalidOpaqueTypeArgs<'tcx>), + LifetimeMismatchOpaqueParam(LifetimeMismatchOpaqueParam<'tcx>), +} + impl<'tcx> RegionInferenceContext<'tcx> { /// Resolve any opaque types that were encountered while borrow checking /// this item. This is then used to get the type in the `type_of` query. @@ -58,13 +65,14 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// /// [rustc-dev-guide chapter]: /// https://rustc-dev-guide.rust-lang.org/opaque-types-region-infer-restrictions.html - #[instrument(level = "debug", skip(self, root_cx, infcx), ret)] + #[instrument(level = "debug", skip(self, root_cx, infcx))] pub(crate) fn infer_opaque_types( &self, root_cx: &mut BorrowCheckRootCtxt<'tcx>, infcx: &InferCtxt<'tcx>, opaque_ty_decls: FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>, - ) { + ) -> Vec<DeferredOpaqueTypeError<'tcx>> { + let mut errors = Vec::new(); let mut decls_modulo_regions: FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueTypeKey<'tcx>, Span)> = FxIndexMap::default(); @@ -124,8 +132,15 @@ impl<'tcx> RegionInferenceContext<'tcx> { }); debug!(?concrete_type); - let ty = - infcx.infer_opaque_definition_from_instantiation(opaque_type_key, concrete_type); + let ty = match infcx + .infer_opaque_definition_from_instantiation(opaque_type_key, concrete_type) + { + Ok(ty) => ty, + Err(err) => { + errors.push(DeferredOpaqueTypeError::InvalidOpaqueTypeArgs(err)); + continue; + } + }; // Sometimes, when the hidden type is an inference variable, it can happen that // the hidden type becomes the opaque type itself. In this case, this was an opaque @@ -149,25 +164,27 @@ impl<'tcx> RegionInferenceContext<'tcx> { // non-region parameters. This is necessary because within the new solver we perform // various query operations modulo regions, and thus could unsoundly select some impls // that don't hold. - if !ty.references_error() - && let Some((prev_decl_key, prev_span)) = decls_modulo_regions.insert( - infcx.tcx.erase_regions(opaque_type_key), - (opaque_type_key, concrete_type.span), - ) - && let Some((arg1, arg2)) = std::iter::zip( - prev_decl_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg), - opaque_type_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg), - ) - .find(|(arg1, arg2)| arg1 != arg2) + if let Some((prev_decl_key, prev_span)) = decls_modulo_regions.insert( + infcx.tcx.erase_regions(opaque_type_key), + (opaque_type_key, concrete_type.span), + ) && let Some((arg1, arg2)) = std::iter::zip( + prev_decl_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg), + opaque_type_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg), + ) + .find(|(arg1, arg2)| arg1 != arg2) { - infcx.dcx().emit_err(LifetimeMismatchOpaqueParam { - arg: arg1, - prev: arg2, - span: prev_span, - prev_span: concrete_type.span, - }); + errors.push(DeferredOpaqueTypeError::LifetimeMismatchOpaqueParam( + LifetimeMismatchOpaqueParam { + arg: arg1, + prev: arg2, + span: prev_span, + prev_span: concrete_type.span, + }, + )); } } + + errors } /// Map the regions in the type to named regions. This is similar to what @@ -260,19 +277,13 @@ impl<'tcx> InferCtxt<'tcx> { &self, opaque_type_key: OpaqueTypeKey<'tcx>, instantiated_ty: OpaqueHiddenType<'tcx>, - ) -> Ty<'tcx> { - if let Some(e) = self.tainted_by_errors() { - return Ty::new_error(self.tcx, e); - } - - if let Err(err) = check_opaque_type_parameter_valid( + ) -> Result<Ty<'tcx>, InvalidOpaqueTypeArgs<'tcx>> { + check_opaque_type_parameter_valid( self, opaque_type_key, instantiated_ty.span, DefiningScopeKind::MirBorrowck, - ) { - return Ty::new_error(self.tcx, err.report(self)); - } + )?; let definition_ty = instantiated_ty .remap_generic_params_to_declaration_params( @@ -282,10 +293,7 @@ impl<'tcx> InferCtxt<'tcx> { ) .ty; - if let Err(e) = definition_ty.error_reported() { - return Ty::new_error(self.tcx, e); - } - - definition_ty + definition_ty.error_reported()?; + Ok(definition_ty) } } diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs index ff92b4168a8..100d30704b9 100644 --- a/compiler/rustc_borrowck/src/renumber.rs +++ b/compiler/rustc_borrowck/src/renumber.rs @@ -66,7 +66,7 @@ impl<'a, 'tcx> RegionRenumberer<'a, 'tcx> { T: TypeFoldable<TyCtxt<'tcx>>, F: Fn() -> RegionCtxt, { - let origin = NllRegionVariableOrigin::Existential { from_forall: false }; + let origin = NllRegionVariableOrigin::Existential { from_forall: false, name: None }; fold_regions(self.infcx.tcx, value, |_region, _depth| { self.infcx.next_nll_region_var(origin, || region_ctxt_fn()) }) diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index 99392ea1915..eb31b5de05d 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -86,7 +86,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // them with fresh ty vars. resume_ty: next_ty_var(), yield_ty: next_ty_var(), - witness: next_ty_var(), }, ) .args, diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index f5fedbf95c1..c3aa205d5aa 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -182,6 +182,17 @@ pub(crate) fn type_check<'tcx>( ) }); + // In case type check encountered an error region, we suppress unhelpful extra + // errors in by clearing out all outlives bounds that we may end up checking. + if let Some(guar) = universal_region_relations.universal_regions.encountered_re_error() { + debug!("encountered an error region; removing constraints!"); + constraints.outlives_constraints = Default::default(); + constraints.member_constraints = Default::default(); + constraints.type_tests = Default::default(); + root_cx.set_tainted_by_errors(guar); + infcx.set_tainted_by_errors(guar); + } + MirTypeckResults { constraints, universal_region_relations, @@ -769,9 +780,13 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } TerminatorKind::Call { func, args, .. } | TerminatorKind::TailCall { func, args, .. } => { - let call_source = match term.kind { - TerminatorKind::Call { call_source, .. } => call_source, - TerminatorKind::TailCall { .. } => CallSource::Normal, + let (call_source, destination, is_diverging) = match term.kind { + TerminatorKind::Call { call_source, destination, target, .. } => { + (call_source, destination, target.is_none()) + } + TerminatorKind::TailCall { .. } => { + (CallSource::Normal, RETURN_PLACE.into(), false) + } _ => unreachable!(), }; @@ -845,9 +860,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ); } - if let TerminatorKind::Call { destination, target, .. } = term.kind { - self.check_call_dest(term, &sig, destination, target, term_location); - } + self.check_call_dest(term, &sig, destination, is_diverging, term_location); // The ordinary liveness rules will ensure that all // regions in the type of the callee are live here. We @@ -1874,65 +1887,61 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { term: &Terminator<'tcx>, sig: &ty::FnSig<'tcx>, destination: Place<'tcx>, - target: Option<BasicBlock>, + is_diverging: bool, term_location: Location, ) { let tcx = self.tcx(); - match target { - Some(_) => { - let dest_ty = destination.ty(self.body, tcx).ty; - let dest_ty = self.normalize(dest_ty, term_location); - let category = match destination.as_local() { - Some(RETURN_PLACE) => { - if let DefiningTy::Const(def_id, _) | DefiningTy::InlineConst(def_id, _) = - self.universal_regions.defining_ty - { - if tcx.is_static(def_id) { - ConstraintCategory::UseAsStatic - } else { - ConstraintCategory::UseAsConst - } + if is_diverging { + // The signature in this call can reference region variables, + // so erase them before calling a query. + let output_ty = self.tcx().erase_regions(sig.output()); + if !output_ty + .is_privately_uninhabited(self.tcx(), self.infcx.typing_env(self.infcx.param_env)) + { + span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig); + } + } else { + let dest_ty = destination.ty(self.body, tcx).ty; + let dest_ty = self.normalize(dest_ty, term_location); + let category = match destination.as_local() { + Some(RETURN_PLACE) => { + if let DefiningTy::Const(def_id, _) | DefiningTy::InlineConst(def_id, _) = + self.universal_regions.defining_ty + { + if tcx.is_static(def_id) { + ConstraintCategory::UseAsStatic } else { - ConstraintCategory::Return(ReturnConstraint::Normal) + ConstraintCategory::UseAsConst } + } else { + ConstraintCategory::Return(ReturnConstraint::Normal) } - Some(l) if !self.body.local_decls[l].is_user_variable() => { - ConstraintCategory::Boring - } - // The return type of a call is interesting for diagnostics. - _ => ConstraintCategory::Assignment, - }; - - let locations = term_location.to_locations(); - - if let Err(terr) = self.sub_types(sig.output(), dest_ty, locations, category) { - span_mirbug!( - self, - term, - "call dest mismatch ({:?} <- {:?}): {:?}", - dest_ty, - sig.output(), - terr - ); } - - // When `unsized_fn_params` is not enabled, - // this check is done at `check_local`. - if self.unsized_feature_enabled() { - let span = term.source_info.span; - self.ensure_place_sized(dest_ty, span); + Some(l) if !self.body.local_decls[l].is_user_variable() => { + ConstraintCategory::Boring } + // The return type of a call is interesting for diagnostics. + _ => ConstraintCategory::Assignment, + }; + + let locations = term_location.to_locations(); + + if let Err(terr) = self.sub_types(sig.output(), dest_ty, locations, category) { + span_mirbug!( + self, + term, + "call dest mismatch ({:?} <- {:?}): {:?}", + dest_ty, + sig.output(), + terr + ); } - None => { - // The signature in this call can reference region variables, - // so erase them before calling a query. - let output_ty = self.tcx().erase_regions(sig.output()); - if !output_ty.is_privately_uninhabited( - self.tcx(), - self.infcx.typing_env(self.infcx.param_env), - ) { - span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig); - } + + // When `unsized_fn_params` is not enabled, + // this check is done at `check_local`. + if self.unsized_feature_enabled() { + let span = term.source_info.span; + self.ensure_place_sized(dest_ty, span); } } } diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index e023300f1c2..393adafea0b 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -187,7 +187,7 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> { types: &mut |_bound_ty: ty::BoundTy| { unreachable!("we only replace regions in nll_relate, not types") }, - consts: &mut |_bound_var: ty::BoundVar| { + consts: &mut |_bound_const: ty::BoundConst| { unreachable!("we only replace regions in nll_relate, not consts") }, }; @@ -226,7 +226,7 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> { types: &mut |_bound_ty: ty::BoundTy| { unreachable!("we only replace regions in nll_relate, not types") }, - consts: &mut |_bound_var: ty::BoundVar| { + consts: &mut |_bound_const: ty::BoundConst| { unreachable!("we only replace regions in nll_relate, not consts") }, }; @@ -249,7 +249,7 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> { from_forall: bool, name: Option<Symbol>, ) -> ty::Region<'tcx> { - let origin = NllRegionVariableOrigin::Existential { from_forall }; + let origin = NllRegionVariableOrigin::Existential { name, from_forall }; let reg_var = self.type_checker.infcx.next_nll_region_var(origin, || RegionCtxt::Existential(name)); diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index f138f265320..296a2735533 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -217,7 +217,7 @@ struct UniversalRegionIndices<'tcx> { /// Whether we've encountered an error region. If we have, cancel all /// outlives errors, as they are likely bogus. - pub tainted_by_errors: Cell<Option<ErrorGuaranteed>>, + pub encountered_re_error: Cell<Option<ErrorGuaranteed>>, } #[derive(Debug, PartialEq)] @@ -442,8 +442,8 @@ impl<'tcx> UniversalRegions<'tcx> { self.fr_fn_body } - pub(crate) fn tainted_by_errors(&self) -> Option<ErrorGuaranteed> { - self.indices.tainted_by_errors.get() + pub(crate) fn encountered_re_error(&self) -> Option<ErrorGuaranteed> { + self.indices.encountered_re_error.get() } } @@ -706,7 +706,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { UniversalRegionIndices { indices: global_mapping.chain(arg_mapping).collect(), fr_static, - tainted_by_errors: Cell::new(None), + encountered_re_error: Cell::new(None), } } @@ -916,7 +916,7 @@ impl<'tcx> UniversalRegionIndices<'tcx> { match r.kind() { ty::ReVar(..) => r.as_var(), ty::ReError(guar) => { - self.tainted_by_errors.set(Some(guar)); + self.encountered_re_error.set(Some(guar)); // We use the `'static` `RegionVid` because `ReError` doesn't actually exist in the // `UniversalRegionIndices`. This is fine because 1) it is a fallback only used if // errors are being emitted and 2) it leaves the happy path unaffected. @@ -969,13 +969,28 @@ fn for_each_late_bound_region_in_item<'tcx>( mir_def_id: LocalDefId, mut f: impl FnMut(ty::Region<'tcx>), ) { - if !tcx.def_kind(mir_def_id).is_fn_like() { - return; - } + let bound_vars = match tcx.def_kind(mir_def_id) { + DefKind::Fn | DefKind::AssocFn => { + tcx.late_bound_vars(tcx.local_def_id_to_hir_id(mir_def_id)) + } + // We extract the bound vars from the deduced closure signature, since we may have + // only deduced that a param in the closure signature is late-bound from a constraint + // that we discover during typeck. + DefKind::Closure => { + let ty = tcx.type_of(mir_def_id).instantiate_identity(); + match *ty.kind() { + ty::Closure(_, args) => args.as_closure().sig().bound_vars(), + ty::CoroutineClosure(_, args) => { + args.as_coroutine_closure().coroutine_closure_sig().bound_vars() + } + ty::Coroutine(_, _) | ty::Error(_) => return, + _ => unreachable!("unexpected type for closure: {ty}"), + } + } + _ => return, + }; - for (idx, bound_var) in - tcx.late_bound_vars(tcx.local_def_id_to_hir_id(mir_def_id)).iter().enumerate() - { + for (idx, bound_var) in bound_vars.iter().enumerate() { if let ty::BoundVariableKind::Region(kind) = bound_var { let kind = ty::LateParamRegionKind::from_bound(ty::BoundVar::from_usize(idx), kind); let liberated_region = ty::Region::new_late_param(tcx, mir_def_id.to_def_id(), kind); diff --git a/compiler/rustc_builtin_macros/Cargo.toml b/compiler/rustc_builtin_macros/Cargo.toml index 4c1264c6f1c..e56b9e641a1 100644 --- a/compiler/rustc_builtin_macros/Cargo.toml +++ b/compiler/rustc_builtin_macros/Cargo.toml @@ -10,7 +10,6 @@ doctest = false # tidy-alphabetical-start rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } -rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs index e75bc944d7e..35ef6be095e 100644 --- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs +++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs @@ -1,4 +1,3 @@ -use rustc_ast::ptr::P; use rustc_ast::{ self as ast, Fn, FnHeader, FnSig, Generics, ItemKind, Safety, Stmt, StmtKind, TyKind, }; @@ -46,7 +45,7 @@ pub(crate) fn expand( let const_body = ecx.expr_block(ecx.block(span, stmts)); let const_item = ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body); let const_item = if is_stmt { - Annotatable::Stmt(P(ecx.stmt_item(span, const_item))) + Annotatable::Stmt(Box::new(ecx.stmt_item(span, const_item))) } else { Annotatable::Item(const_item) }; diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 1fb99817222..86b8e1ff8db 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -1,5 +1,4 @@ use lint::BuiltinLintDiag; -use rustc_ast::ptr::P; use rustc_ast::tokenstream::TokenStream; use rustc_ast::{AsmMacro, token}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; @@ -19,7 +18,7 @@ use crate::{errors, fluent_generated as fluent}; /// Validated assembly arguments, ready for macro expansion. struct ValidatedAsmArgs { - pub templates: Vec<P<ast::Expr>>, + pub templates: Vec<Box<ast::Expr>>, pub operands: Vec<(ast::InlineAsmOperand, Span)>, named_args: FxIndexMap<Symbol, usize>, reg_args: GrowableBitSet<usize>, @@ -600,9 +599,9 @@ pub(super) fn expand_asm<'cx>( return ExpandResult::Retry(()); }; let expr = match mac { - Ok(inline_asm) => P(ast::Expr { + Ok(inline_asm) => Box::new(ast::Expr { id: ast::DUMMY_NODE_ID, - kind: ast::ExprKind::InlineAsm(P(inline_asm)), + kind: ast::ExprKind::InlineAsm(Box::new(inline_asm)), span: sp, attrs: ast::AttrVec::new(), tokens: None, @@ -630,9 +629,9 @@ pub(super) fn expand_naked_asm<'cx>( return ExpandResult::Retry(()); }; let expr = match mac { - Ok(inline_asm) => P(ast::Expr { + Ok(inline_asm) => Box::new(ast::Expr { id: ast::DUMMY_NODE_ID, - kind: ast::ExprKind::InlineAsm(P(inline_asm)), + kind: ast::ExprKind::InlineAsm(Box::new(inline_asm)), span: sp, attrs: ast::AttrVec::new(), tokens: None, @@ -660,7 +659,7 @@ pub(super) fn expand_global_asm<'cx>( return ExpandResult::Retry(()); }; match mac { - Ok(inline_asm) => MacEager::items(smallvec![P(ast::Item { + Ok(inline_asm) => MacEager::items(smallvec![Box::new(ast::Item { attrs: ast::AttrVec::new(), id: ast::DUMMY_NODE_ID, kind: ast::ItemKind::GlobalAsm(Box::new(inline_asm)), diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs index c659b1cff59..855da5caa31 100644 --- a/compiler/rustc_builtin_macros/src/assert.rs +++ b/compiler/rustc_builtin_macros/src/assert.rs @@ -1,6 +1,5 @@ mod context; -use rustc_ast::ptr::P; use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::{DelimSpan, TokenStream}; use rustc_ast::{DelimArgs, Expr, ExprKind, MacCall, Path, PathSegment, UnOp, token}; @@ -55,9 +54,9 @@ pub(crate) fn expand_assert<'cx>( let expr = if let Some(tokens) = custom_message { let then = cx.expr( call_site_span, - ExprKind::MacCall(P(MacCall { + ExprKind::MacCall(Box::new(MacCall { path: panic_path(), - args: P(DelimArgs { + args: Box::new(DelimArgs { dspan: DelimSpan::from_single(call_site_span), delim: Delimiter::Parenthesis, tokens, @@ -96,7 +95,7 @@ pub(crate) fn expand_assert<'cx>( } struct Assert { - cond_expr: P<Expr>, + cond_expr: Box<Expr>, custom_message: Option<TokenStream>, } @@ -104,10 +103,10 @@ struct Assert { fn expr_if_not( cx: &ExtCtxt<'_>, span: Span, - cond: P<Expr>, - then: P<Expr>, - els: Option<P<Expr>>, -) -> P<Expr> { + cond: Box<Expr>, + then: Box<Expr>, + els: Option<Box<Expr>>, +) -> Box<Expr> { cx.expr_if(span, cx.expr(span, ExprKind::Unary(UnOp::Not, cond)), then, els) } diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index ea7248ca539..31855cbd4e6 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -1,4 +1,3 @@ -use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, IdentIsRaw}; use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree}; use rustc_ast::{ @@ -70,7 +69,7 @@ impl<'cx, 'a> Context<'cx, 'a> { /// } /// } /// ``` - pub(super) fn build(mut self, mut cond_expr: P<Expr>, panic_path: Path) -> P<Expr> { + pub(super) fn build(mut self, mut cond_expr: Box<Expr>, panic_path: Path) -> Box<Expr> { let expr_str = pprust::expr_to_string(&cond_expr); self.manage_cond_expr(&mut cond_expr); let initial_imports = self.build_initial_imports(); @@ -129,7 +128,7 @@ impl<'cx, 'a> Context<'cx, 'a> { } /// Takes the conditional expression of `assert!` and then wraps it inside `unlikely` - fn build_unlikely(&self, cond_expr: P<Expr>) -> P<Expr> { + fn build_unlikely(&self, cond_expr: Box<Expr>) -> Box<Expr> { let unlikely_path = self.cx.std_path(&[sym::intrinsics, sym::unlikely]); self.cx.expr_call( self.span, @@ -145,7 +144,7 @@ impl<'cx, 'a> Context<'cx, 'a> { /// __capture0, /// ... /// ); - fn build_panic(&self, expr_str: &str, panic_path: Path) -> P<Expr> { + fn build_panic(&self, expr_str: &str, panic_path: Path) -> Box<Expr> { let escaped_expr_str = escape_to_fmt(expr_str); let initial = [ TokenTree::token_joint( @@ -176,9 +175,9 @@ impl<'cx, 'a> Context<'cx, 'a> { }); self.cx.expr( self.span, - ExprKind::MacCall(P(MacCall { + ExprKind::MacCall(Box::new(MacCall { path: panic_path, - args: P(DelimArgs { + args: Box::new(DelimArgs { dspan: DelimSpan::from_single(self.span), delim: Delimiter::Parenthesis, tokens: initial.into_iter().chain(captures).collect::<TokenStream>(), @@ -190,7 +189,7 @@ impl<'cx, 'a> Context<'cx, 'a> { /// Recursive function called until `cond_expr` and `fmt_str` are fully modified. /// /// See [Self::manage_initial_capture] and [Self::manage_try_capture] - fn manage_cond_expr(&mut self, expr: &mut P<Expr>) { + fn manage_cond_expr(&mut self, expr: &mut Box<Expr>) { match &mut expr.kind { ExprKind::AddrOf(_, mutability, local_expr) => { self.with_is_consumed_management(matches!(mutability, Mutability::Mut), |this| { @@ -331,7 +330,7 @@ impl<'cx, 'a> Context<'cx, 'a> { /// /// `fmt_str`, the formatting string used for debugging, is constructed to show possible /// captured variables. - fn manage_initial_capture(&mut self, expr: &mut P<Expr>, path_ident: Ident) { + fn manage_initial_capture(&mut self, expr: &mut Box<Expr>, path_ident: Ident) { if self.paths.contains(&path_ident) { return; } else { @@ -360,7 +359,12 @@ impl<'cx, 'a> Context<'cx, 'a> { /// (&Wrapper(__local_bindN)).try_capture(&mut __captureN); /// __local_bindN /// } - fn manage_try_capture(&mut self, capture: Ident, curr_capture_idx: usize, expr: &mut P<Expr>) { + fn manage_try_capture( + &mut self, + capture: Ident, + curr_capture_idx: usize, + expr: &mut Box<Expr>, + ) { let local_bind_string = format!("__local_bind{curr_capture_idx}"); let local_bind = Ident::new(Symbol::intern(&local_bind_string), self.span); self.local_bind_decls.push(self.cx.stmt_let( @@ -441,20 +445,20 @@ fn escape_to_fmt(s: &str) -> String { rslt } -fn expr_addr_of_mut(cx: &ExtCtxt<'_>, sp: Span, e: P<Expr>) -> P<Expr> { +fn expr_addr_of_mut(cx: &ExtCtxt<'_>, sp: Span, e: Box<Expr>) -> Box<Expr> { cx.expr(sp, ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, e)) } fn expr_method_call( cx: &ExtCtxt<'_>, seg: PathSegment, - receiver: P<Expr>, - args: ThinVec<P<Expr>>, + receiver: Box<Expr>, + args: ThinVec<Box<Expr>>, span: Span, -) -> P<Expr> { +) -> Box<Expr> { cx.expr(span, ExprKind::MethodCall(Box::new(MethodCall { seg, receiver, args, span }))) } -fn expr_paren(cx: &ExtCtxt<'_>, sp: Span, e: P<Expr>) -> P<Expr> { +fn expr_paren(cx: &ExtCtxt<'_>, sp: Span, e: Box<Expr>) -> Box<Expr> { cx.expr(sp, ExprKind::Paren(e)) } diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index c7844778332..a662840eda5 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -11,7 +11,6 @@ mod llvm_enzyme { AutoDiffAttrs, DiffActivity, DiffMode, valid_input_activity, valid_ret_activity, valid_ty_for_activity, }; - use rustc_ast::ptr::P; use rustc_ast::token::{Lit, LitKind, Token, TokenKind}; use rustc_ast::tokenstream::*; use rustc_ast::visit::AssocCtxt::*; @@ -27,7 +26,7 @@ mod llvm_enzyme { use crate::errors; pub(crate) fn outer_normal_attr( - kind: &P<rustc_ast::NormalAttr>, + kind: &Box<rustc_ast::NormalAttr>, id: rustc_ast::AttrId, span: Span, ) -> rustc_ast::Attribute { @@ -73,7 +72,7 @@ mod llvm_enzyme { } // Get information about the function the macro is applied to - fn extract_item_info(iitem: &P<ast::Item>) -> Option<(Visibility, FnSig, Ident, Generics)> { + fn extract_item_info(iitem: &Box<ast::Item>) -> Option<(Visibility, FnSig, Ident, Generics)> { match &iitem.kind { ItemKind::Fn(box ast::Fn { sig, ident, generics, .. }) => { Some((iitem.vis.clone(), sig.clone(), ident.clone(), generics.clone())) @@ -346,7 +345,7 @@ mod llvm_enzyme { define_opaque: None, }); let mut rustc_ad_attr = - P(ast::NormalAttr::from_ident(Ident::with_dummy_span(sym::rustc_autodiff))); + Box::new(ast::NormalAttr::from_ident(Ident::with_dummy_span(sym::rustc_autodiff))); let ts2: Vec<TokenTree> = vec![TokenTree::Token( Token::new(TokenKind::Ident(sym::never, false.into()), span), @@ -363,7 +362,7 @@ mod llvm_enzyme { args: ast::AttrArgs::Delimited(never_arg), tokens: None, }; - let inline_never_attr = P(ast::NormalAttr { item: inline_item, tokens: None }); + let inline_never_attr = Box::new(ast::NormalAttr { item: inline_item, tokens: None }); let new_id = ecx.sess.psess.attr_id_generator.mk_attr_id(); let attr = outer_normal_attr(&rustc_ad_attr, new_id, span); let new_id = ecx.sess.psess.attr_id_generator.mk_attr_id(); @@ -433,7 +432,7 @@ mod llvm_enzyme { let d_annotatable = match &item { Annotatable::AssocItem(_, _) => { let assoc_item: AssocItemKind = ast::AssocItemKind::Fn(asdf); - let d_fn = P(ast::AssocItem { + let d_fn = Box::new(ast::AssocItem { attrs: thin_vec![d_attr, inline_never], id: ast::DUMMY_NODE_ID, span, @@ -453,7 +452,7 @@ mod llvm_enzyme { let mut d_fn = ecx.item(span, thin_vec![d_attr, inline_never], ItemKind::Fn(asdf)); d_fn.vis = vis; - Annotatable::Stmt(P(ast::Stmt { + Annotatable::Stmt(Box::new(ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Item(d_fn), span, @@ -506,7 +505,7 @@ mod llvm_enzyme { idents: &[Ident], errored: bool, generics: &Generics, - ) -> (P<ast::Block>, P<ast::Expr>, P<ast::Expr>, P<ast::Expr>) { + ) -> (Box<ast::Block>, Box<ast::Expr>, Box<ast::Expr>, Box<ast::Expr>) { let blackbox_path = ecx.std_path(&[sym::hint, sym::black_box]); let noop = ast::InlineAsm { asm_macro: ast::AsmMacro::Asm, @@ -517,7 +516,7 @@ mod llvm_enzyme { options: ast::InlineAsmOptions::PURE | ast::InlineAsmOptions::NOMEM, line_spans: vec![], }; - let noop_expr = ecx.expr_asm(span, P(noop)); + let noop_expr = ecx.expr_asm(span, Box::new(noop)); let unsf = ast::BlockCheckMode::Unsafe(ast::UnsafeSource::CompilerGenerated); let unsf_block = ast::Block { stmts: thin_vec![ecx.stmt_semi(noop_expr)], @@ -526,7 +525,7 @@ mod llvm_enzyme { rules: unsf, span, }; - let unsf_expr = ecx.expr_block(P(unsf_block)); + let unsf_expr = ecx.expr_block(Box::new(unsf_block)); let blackbox_call_expr = ecx.expr_path(ecx.path(span, blackbox_path)); let primal_call = gen_primal_call(ecx, span, primal, idents, generics); let black_box_primal_call = ecx.expr_call( @@ -578,7 +577,7 @@ mod llvm_enzyme { idents: Vec<Ident>, errored: bool, generics: &Generics, - ) -> P<ast::Block> { + ) -> Box<ast::Block> { let new_decl_span = d_sig.span; // Just adding some default inline-asm and black_box usages to prevent early inlining @@ -634,7 +633,7 @@ mod llvm_enzyme { return body; } - let mut exprs: P<ast::Expr> = primal_call; + let mut exprs: Box<ast::Expr> = primal_call; let d_ret_ty = match d_sig.decl.output { FnRetTy::Ty(ref ty) => ty.clone(), FnRetTy::Default(span) => { @@ -653,7 +652,7 @@ mod llvm_enzyme { } else { let q = QSelf { ty: d_ret_ty, path_span: span, position: 0 }; let y = ExprKind::Path( - Some(P(q)), + Some(Box::new(q)), ecx.path_ident(span, Ident::with_dummy_span(kw::Default)), ); let default_call_expr = ecx.expr(span, y); @@ -703,7 +702,7 @@ mod llvm_enzyme { primal: Ident, idents: &[Ident], generics: &Generics, - ) -> P<ast::Expr> { + ) -> Box<ast::Expr> { let has_self = idents.len() > 0 && idents[0].name == kw::SelfLower; if has_self { @@ -740,7 +739,7 @@ mod llvm_enzyme { }, ); - ast::AngleBracketedArg::Arg(ast::GenericArg::Type(P(ast::Ty { + ast::AngleBracketedArg::Arg(ast::GenericArg::Type(Box::new(ast::Ty { id: type_param.id, span, kind: generic_param, @@ -750,7 +749,7 @@ mod llvm_enzyme { .collect(); function_path.args = - Some(P(ast::GenericArgs::AngleBracketed(ast::AngleBracketedArgs { + Some(Box::new(ast::GenericArgs::AngleBracketed(ast::AngleBracketedArgs { span, args: generated_generic_types, }))); @@ -856,7 +855,7 @@ mod llvm_enzyme { for i in 0..x.width { let mut shadow_arg = arg.clone(); // We += into the shadow in reverse mode. - shadow_arg.ty = P(assure_mut_ref(&arg.ty)); + shadow_arg.ty = Box::new(assure_mut_ref(&arg.ty)); let old_name = if let PatKind::Ident(_, ident, _) = arg.pat.kind { ident.name } else { @@ -866,7 +865,7 @@ mod llvm_enzyme { let name: String = format!("d{}_{}", old_name, i); new_inputs.push(name.clone()); let ident = Ident::from_str_and_span(&name, shadow_arg.pat.span); - shadow_arg.pat = P(ast::Pat { + shadow_arg.pat = Box::new(ast::Pat { id: ast::DUMMY_NODE_ID, kind: PatKind::Ident(BindingMode::NONE, ident, None), span: shadow_arg.pat.span, @@ -898,7 +897,7 @@ mod llvm_enzyme { let name: String = format!("b{}_{}", old_name, i); new_inputs.push(name.clone()); let ident = Ident::from_str_and_span(&name, shadow_arg.pat.span); - shadow_arg.pat = P(ast::Pat { + shadow_arg.pat = Box::new(ast::Pat { id: ast::DUMMY_NODE_ID, kind: PatKind::Ident(BindingMode::NONE, ident, None), span: shadow_arg.pat.span, @@ -942,7 +941,7 @@ mod llvm_enzyme { let shadow_arg = ast::Param { attrs: ThinVec::new(), ty: ty.clone(), - pat: P(ast::Pat { + pat: Box::new(ast::Pat { id: ast::DUMMY_NODE_ID, kind: PatKind::Ident(BindingMode::NONE, ident, None), span: ty.span, @@ -966,7 +965,12 @@ mod llvm_enzyme { FnRetTy::Default(span) => { // We want to return std::hint::black_box(()). let kind = TyKind::Tup(ThinVec::new()); - let ty = P(rustc_ast::Ty { kind, id: ast::DUMMY_NODE_ID, span, tokens: None }); + let ty = Box::new(rustc_ast::Ty { + kind, + id: ast::DUMMY_NODE_ID, + span, + tokens: None, + }); d_decl.output = FnRetTy::Ty(ty.clone()); assert!(matches!(x.ret_activity, DiffActivity::None)); // this won't be used below, so any type would be fine. @@ -987,7 +991,7 @@ mod llvm_enzyme { }; TyKind::Array(ty.clone(), anon_const) }; - let ty = P(rustc_ast::Ty { kind, id: ty.id, span: ty.span, tokens: None }); + let ty = Box::new(rustc_ast::Ty { kind, id: ty.id, span: ty.span, tokens: None }); d_decl.output = FnRetTy::Ty(ty); } if matches!(x.ret_activity, DiffActivity::DualOnly | DiffActivity::DualvOnly) { @@ -1000,7 +1004,8 @@ mod llvm_enzyme { value: ecx.expr_usize(span, x.width as usize), }; let kind = TyKind::Array(ty.clone(), anon_const); - let ty = P(rustc_ast::Ty { kind, id: ty.id, span: ty.span, tokens: None }); + let ty = + Box::new(rustc_ast::Ty { kind, id: ty.id, span: ty.span, tokens: None }); d_decl.output = FnRetTy::Ty(ty); } } @@ -1022,14 +1027,14 @@ mod llvm_enzyme { act_ret.insert(0, ty.clone()); } let kind = TyKind::Tup(act_ret); - P(rustc_ast::Ty { kind, id: ty.id, span: ty.span, tokens: None }) + Box::new(rustc_ast::Ty { kind, id: ty.id, span: ty.span, tokens: None }) } FnRetTy::Default(span) => { if act_ret.len() == 1 { act_ret[0].clone() } else { let kind = TyKind::Tup(act_ret.iter().map(|arg| arg.clone()).collect()); - P(rustc_ast::Ty { kind, id: ast::DUMMY_NODE_ID, span, tokens: None }) + Box::new(rustc_ast::Ty { kind, id: ast::DUMMY_NODE_ID, span, tokens: None }) } } }; diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index ec3b87467a9..dd770fe5f1a 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -2,7 +2,6 @@ use core::ops::ControlFlow; use rustc_ast as ast; use rustc_ast::mut_visit::MutVisitor; -use rustc_ast::ptr::P; use rustc_ast::visit::{AssocCtxt, Visitor}; use rustc_ast::{Attribute, HasAttrs, HasTokens, NodeId, mut_visit, visit}; use rustc_errors::PResult; @@ -132,7 +131,7 @@ impl CfgEval<'_> { let stmt = parser .parse_stmt_without_recovery(false, ForceCollect::Yes, false)? .unwrap(); - Annotatable::Stmt(P(self.flat_map_stmt(stmt).pop().unwrap())) + Annotatable::Stmt(Box::new(self.flat_map_stmt(stmt).pop().unwrap())) } Annotatable::Expr(_) => { let mut expr = parser.parse_expr_force_collect()?; @@ -166,7 +165,7 @@ impl MutVisitor for CfgEval<'_> { mut_visit::walk_expr(self, expr); } - fn filter_map_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> { + fn filter_map_expr(&mut self, expr: Box<ast::Expr>) -> Option<Box<ast::Expr>> { let mut expr = configure!(self, expr); mut_visit::walk_expr(self, &mut expr); Some(expr) @@ -185,24 +184,24 @@ impl MutVisitor for CfgEval<'_> { mut_visit::walk_flat_map_stmt(self, stmt) } - fn flat_map_item(&mut self, item: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> { + fn flat_map_item(&mut self, item: Box<ast::Item>) -> SmallVec<[Box<ast::Item>; 1]> { let item = configure!(self, item); mut_visit::walk_flat_map_item(self, item) } fn flat_map_assoc_item( &mut self, - item: P<ast::AssocItem>, + item: Box<ast::AssocItem>, ctxt: AssocCtxt, - ) -> SmallVec<[P<ast::AssocItem>; 1]> { + ) -> SmallVec<[Box<ast::AssocItem>; 1]> { let item = configure!(self, item); mut_visit::walk_flat_map_assoc_item(self, item, ctxt) } fn flat_map_foreign_item( &mut self, - foreign_item: P<ast::ForeignItem>, - ) -> SmallVec<[P<ast::ForeignItem>; 1]> { + foreign_item: Box<ast::ForeignItem>, + ) -> SmallVec<[Box<ast::ForeignItem>; 1]> { let foreign_item = configure!(self, foreign_item); mut_visit::walk_flat_map_foreign_item(self, foreign_item) } diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs index fd2d740c020..8885017b930 100644 --- a/compiler/rustc_builtin_macros/src/concat_bytes.rs +++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs @@ -1,4 +1,3 @@ -use rustc_ast::ptr::P; use rustc_ast::tokenstream::TokenStream; use rustc_ast::{ExprKind, LitIntType, LitKind, StrStyle, UintTy, token}; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; @@ -90,7 +89,7 @@ fn handle_array_element( cx: &ExtCtxt<'_>, guar: &mut Option<ErrorGuaranteed>, missing_literals: &mut Vec<rustc_span::Span>, - expr: &P<rustc_ast::Expr>, + expr: &Box<rustc_ast::Expr>, ) -> Option<u8> { let dcx = cx.dcx(); diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs index 990835fa277..a0f71a1868b 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -1,4 +1,3 @@ -use rustc_ast::ptr::P; use rustc_ast::{BinOpKind, BorrowKind, Expr, ExprKind, MetaItem, Mutability}; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::{Span, sym}; @@ -119,7 +118,7 @@ fn get_substructure_equality_expr( cx: &ExtCtxt<'_>, span: Span, substructure: &Substructure<'_>, -) -> P<Expr> { +) -> Box<Expr> { use SubstructureFields::*; match substructure.fields { @@ -180,7 +179,7 @@ fn get_substructure_equality_expr( /// /// Panics if there are not exactly two arguments to compare (should be `self` /// and `other`). -fn get_field_equality_expr(cx: &ExtCtxt<'_>, field: &FieldInfo) -> P<Expr> { +fn get_field_equality_expr(cx: &ExtCtxt<'_>, field: &FieldInfo) -> Box<Expr> { let [rhs] = &field.other_selflike_exprs[..] else { cx.dcx().span_bug(field.span, "not exactly 2 arguments in `derive(PartialEq)`"); }; @@ -198,7 +197,7 @@ fn get_field_equality_expr(cx: &ExtCtxt<'_>, field: &FieldInfo) -> P<Expr> { /// This is used to strip away any number of leading `&` from an expression /// (e.g., `&&&T` becomes `T`). Only removes immutable references; mutable /// references are preserved. -fn peel_refs(mut expr: &P<Expr>) -> P<Expr> { +fn peel_refs(mut expr: &Box<Expr>) -> Box<Expr> { while let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = &expr.kind { expr = &inner; } @@ -210,7 +209,7 @@ fn peel_refs(mut expr: &P<Expr>) -> P<Expr> { /// /// If the given expression is a block, it is wrapped in parentheses; otherwise, /// it is returned unchanged. -fn wrap_block_expr(cx: &ExtCtxt<'_>, expr: P<Expr>) -> P<Expr> { +fn wrap_block_expr(cx: &ExtCtxt<'_>, expr: Box<Expr>) -> Box<Expr> { if matches!(&expr.kind, ExprKind::Block(..)) { return cx.expr_paren(expr.span, expr); } diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index 1d63ce7d5fd..597af0e09c0 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -94,7 +94,7 @@ fn show_substructure(cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> field: &FieldInfo, index: usize, len: usize, - ) -> ast::ptr::P<ast::Expr> { + ) -> Box<ast::Expr> { if index < len - 1 { field.self_expr.clone() } else { diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index b4e2d27fed3..2462114ec24 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -56,7 +56,7 @@ pub(crate) fn expand_deriving_default( trait_def.expand(cx, mitem, item, push) } -fn default_call(cx: &ExtCtxt<'_>, span: Span) -> ast::ptr::P<ast::Expr> { +fn default_call(cx: &ExtCtxt<'_>, span: Span) -> Box<ast::Expr> { // Note that `kw::Default` is "default" and `sym::Default` is "Default"! let default_ident = cx.std_path(&[kw::Default, sym::Default, kw::Default]); cx.expr_call_global(span, default_ident, ThinVec::new()) diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index b24e5563761..3f4b47152c4 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -180,17 +180,16 @@ use std::{iter, vec}; pub(crate) use StaticFields::*; pub(crate) use SubstructureFields::*; -use rustc_ast::ptr::P; use rustc_ast::token::{IdentIsRaw, LitKind, Token, TokenKind}; use rustc_ast::tokenstream::{DelimSpan, Spacing, TokenTree}; use rustc_ast::{ self as ast, AnonConst, AttrArgs, BindingMode, ByRef, DelimArgs, EnumDef, Expr, GenericArg, GenericParamKind, Generics, Mutability, PatKind, Safety, VariantData, }; -use rustc_attr_data_structures::{AttributeKind, ReprPacked}; use rustc_attr_parsing::AttributeParser; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_hir::Attribute; +use rustc_hir::attrs::{AttributeKind, ReprPacked}; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; use thin_vec::{ThinVec, thin_vec}; use ty::{Bounds, Path, Ref, Self_, Ty}; @@ -272,7 +271,7 @@ pub(crate) struct Substructure<'a> { pub type_ident: Ident, /// Verbatim access to any non-selflike arguments, i.e. arguments that /// don't have type `&Self`. - pub nonselflike_args: &'a [P<Expr>], + pub nonselflike_args: &'a [Box<Expr>], pub fields: &'a SubstructureFields<'a>, } @@ -284,10 +283,10 @@ pub(crate) struct FieldInfo { pub name: Option<Ident>, /// The expression corresponding to this field of `self` /// (specifically, a reference to it). - pub self_expr: P<Expr>, + pub self_expr: Box<Expr>, /// The expressions corresponding to references to this field in /// the other selflike arguments. - pub other_selflike_exprs: Vec<P<Expr>>, + pub other_selflike_exprs: Vec<Box<Expr>>, pub maybe_scalar: bool, } @@ -323,7 +322,7 @@ pub(crate) enum SubstructureFields<'a> { /// The discriminant of an enum. The first field is a `FieldInfo` for the discriminants, as /// if they were fields. The second field is the expression to combine the /// discriminant expression with; it will be `None` if no match is necessary. - EnumDiscr(FieldInfo, Option<P<Expr>>), + EnumDiscr(FieldInfo, Option<Box<Expr>>), /// A static method where `Self` is a struct. StaticStruct(&'a ast::VariantData, StaticFields), @@ -345,7 +344,7 @@ pub(crate) fn combine_substructure( struct TypeParameter { bound_generic_params: ThinVec<ast::GenericParam>, - ty: P<ast::Ty>, + ty: Box<ast::Ty>, } /// The code snippets built up for derived code are sometimes used as blocks @@ -354,23 +353,23 @@ struct TypeParameter { /// avoiding the insertion of any unnecessary blocks. /// /// The statements come before the expression. -pub(crate) struct BlockOrExpr(ThinVec<ast::Stmt>, Option<P<Expr>>); +pub(crate) struct BlockOrExpr(ThinVec<ast::Stmt>, Option<Box<Expr>>); impl BlockOrExpr { pub(crate) fn new_stmts(stmts: ThinVec<ast::Stmt>) -> BlockOrExpr { BlockOrExpr(stmts, None) } - pub(crate) fn new_expr(expr: P<Expr>) -> BlockOrExpr { + pub(crate) fn new_expr(expr: Box<Expr>) -> BlockOrExpr { BlockOrExpr(ThinVec::new(), Some(expr)) } - pub(crate) fn new_mixed(stmts: ThinVec<ast::Stmt>, expr: Option<P<Expr>>) -> BlockOrExpr { + pub(crate) fn new_mixed(stmts: ThinVec<ast::Stmt>, expr: Option<Box<Expr>>) -> BlockOrExpr { BlockOrExpr(stmts, expr) } // Converts it into a block. - fn into_block(mut self, cx: &ExtCtxt<'_>, span: Span) -> P<ast::Block> { + fn into_block(mut self, cx: &ExtCtxt<'_>, span: Span) -> Box<ast::Block> { if let Some(expr) = self.1 { self.0.push(cx.stmt_expr(expr)); } @@ -378,7 +377,7 @@ impl BlockOrExpr { } // Converts it into an expression. - fn into_expr(self, cx: &ExtCtxt<'_>, span: Span) -> P<Expr> { + fn into_expr(self, cx: &ExtCtxt<'_>, span: Span) -> Box<Expr> { if self.0.is_empty() { match self.1 { None => cx.expr_block(cx.block(span, ThinVec::new())), @@ -432,7 +431,7 @@ fn find_type_parameters( { self.type_params.push(TypeParameter { bound_generic_params: self.bound_generic_params_stack.clone(), - ty: P(ty.clone()), + ty: Box::new(ty.clone()), }); } @@ -544,7 +543,7 @@ impl<'a> TraitDef<'a> { }) .cloned(), ); - push(Annotatable::Item(P(ast::Item { attrs, ..(*newitem).clone() }))) + push(Annotatable::Item(Box::new(ast::Item { attrs, ..(*newitem).clone() }))) } _ => unreachable!(), } @@ -590,15 +589,15 @@ impl<'a> TraitDef<'a> { cx: &ExtCtxt<'_>, type_ident: Ident, generics: &Generics, - field_tys: Vec<P<ast::Ty>>, - methods: Vec<P<ast::AssocItem>>, + field_tys: Vec<Box<ast::Ty>>, + methods: Vec<Box<ast::AssocItem>>, is_packed: bool, - ) -> P<ast::Item> { + ) -> Box<ast::Item> { let trait_path = self.path.to_path(cx, self.span, type_ident, generics); // Transform associated types from `deriving::ty::Ty` into `ast::AssocItem` let associated_types = self.associated_types.iter().map(|&(ident, ref type_def)| { - P(ast::AssocItem { + Box::new(ast::AssocItem { id: ast::DUMMY_NODE_ID, span: self.span, vis: ast::Visibility { @@ -853,8 +852,8 @@ impl<'a> TraitDef<'a> { generics: &Generics, from_scratch: bool, is_packed: bool, - ) -> P<ast::Item> { - let field_tys: Vec<P<ast::Ty>> = + ) -> Box<ast::Item> { + let field_tys: Vec<Box<ast::Ty>> = struct_def.fields().iter().map(|field| field.ty.clone()).collect(); let methods = self @@ -906,7 +905,7 @@ impl<'a> TraitDef<'a> { type_ident: Ident, generics: &Generics, from_scratch: bool, - ) -> P<ast::Item> { + ) -> Box<ast::Item> { let mut field_tys = Vec::new(); for variant in &enum_def.variants { @@ -962,7 +961,7 @@ impl<'a> MethodDef<'a> { cx: &ExtCtxt<'_>, trait_: &TraitDef<'_>, type_ident: Ident, - nonselflike_args: &[P<Expr>], + nonselflike_args: &[Box<Expr>], fields: &SubstructureFields<'_>, ) -> BlockOrExpr { let span = trait_.span; @@ -978,7 +977,7 @@ impl<'a> MethodDef<'a> { trait_: &TraitDef<'_>, generics: &Generics, type_ident: Ident, - ) -> P<ast::Ty> { + ) -> Box<ast::Ty> { self.ret_ty.to_ty(cx, trait_.span, type_ident, generics) } @@ -999,7 +998,8 @@ impl<'a> MethodDef<'a> { trait_: &TraitDef<'_>, type_ident: Ident, generics: &Generics, - ) -> (Option<ast::ExplicitSelf>, ThinVec<P<Expr>>, Vec<P<Expr>>, Vec<(Ident, P<ast::Ty>)>) { + ) -> (Option<ast::ExplicitSelf>, ThinVec<Box<Expr>>, Vec<Box<Expr>>, Vec<(Ident, Box<ast::Ty>)>) + { let mut selflike_args = ThinVec::new(); let mut nonselflike_args = Vec::new(); let mut nonself_arg_tys = Vec::new(); @@ -1036,9 +1036,9 @@ impl<'a> MethodDef<'a> { type_ident: Ident, generics: &Generics, explicit_self: Option<ast::ExplicitSelf>, - nonself_arg_tys: Vec<(Ident, P<ast::Ty>)>, + nonself_arg_tys: Vec<(Ident, Box<ast::Ty>)>, body: BlockOrExpr, - ) -> P<ast::AssocItem> { + ) -> Box<ast::AssocItem> { let span = trait_.span; // Create the generics that aren't for `Self`. let fn_generics = self.generics.to_generics(cx, span, type_ident, generics); @@ -1065,7 +1065,7 @@ impl<'a> MethodDef<'a> { let defaultness = ast::Defaultness::Final; // Create the method. - P(ast::AssocItem { + Box::new(ast::AssocItem { id: ast::DUMMY_NODE_ID, attrs: self.attributes.clone(), span, @@ -1128,8 +1128,8 @@ impl<'a> MethodDef<'a> { trait_: &TraitDef<'b>, struct_def: &'b VariantData, type_ident: Ident, - selflike_args: &[P<Expr>], - nonselflike_args: &[P<Expr>], + selflike_args: &[Box<Expr>], + nonselflike_args: &[Box<Expr>], is_packed: bool, ) -> BlockOrExpr { assert!(selflike_args.len() == 1 || selflike_args.len() == 2); @@ -1151,7 +1151,7 @@ impl<'a> MethodDef<'a> { trait_: &TraitDef<'_>, struct_def: &VariantData, type_ident: Ident, - nonselflike_args: &[P<Expr>], + nonselflike_args: &[Box<Expr>], ) -> BlockOrExpr { let summary = trait_.summarise_struct(cx, struct_def); @@ -1205,8 +1205,8 @@ impl<'a> MethodDef<'a> { trait_: &TraitDef<'b>, enum_def: &'b EnumDef, type_ident: Ident, - mut selflike_args: ThinVec<P<Expr>>, - nonselflike_args: &[P<Expr>], + mut selflike_args: ThinVec<Box<Expr>>, + nonselflike_args: &[Box<Expr>], ) -> BlockOrExpr { assert!( !selflike_args.is_empty(), @@ -1418,7 +1418,7 @@ impl<'a> MethodDef<'a> { // ... // _ => ::core::intrinsics::unreachable(), // } - let get_match_expr = |mut selflike_args: ThinVec<P<Expr>>| { + let get_match_expr = |mut selflike_args: ThinVec<Box<Expr>>| { let match_arg = if selflike_args.len() == 1 { selflike_args.pop().unwrap() } else { @@ -1454,7 +1454,7 @@ impl<'a> MethodDef<'a> { trait_: &TraitDef<'_>, enum_def: &EnumDef, type_ident: Ident, - nonselflike_args: &[P<Expr>], + nonselflike_args: &[Box<Expr>], ) -> BlockOrExpr { self.call_substructure_method( cx, @@ -1503,7 +1503,7 @@ impl<'a> TraitDef<'a> { struct_def: &'a VariantData, prefixes: &[String], by_ref: ByRef, - ) -> ThinVec<P<ast::Pat>> { + ) -> ThinVec<Box<ast::Pat>> { prefixes .iter() .map(|prefix| { @@ -1558,7 +1558,7 @@ impl<'a> TraitDef<'a> { fn create_fields<F>(&self, struct_def: &'a VariantData, mk_exprs: F) -> Vec<FieldInfo> where - F: Fn(usize, &ast::FieldDef, Span) -> Vec<P<ast::Expr>>, + F: Fn(usize, &ast::FieldDef, Span) -> Vec<Box<ast::Expr>>, { struct_def .fields() @@ -1606,7 +1606,7 @@ impl<'a> TraitDef<'a> { fn create_struct_field_access_fields( &self, cx: &ExtCtxt<'_>, - selflike_args: &[P<Expr>], + selflike_args: &[Box<Expr>], struct_def: &'a VariantData, is_packed: bool, ) -> Vec<FieldInfo> { @@ -1651,7 +1651,7 @@ pub(crate) enum CsFold<'a> { /// The combination of two field expressions. E.g. for `PartialEq::eq` this /// is something like `<field1 equality> && <field2 equality>`. - Combine(Span, P<Expr>, P<Expr>), + Combine(Span, Box<Expr>, Box<Expr>), // The fallback case for a struct or enum variant with no fields. Fieldless, @@ -1665,9 +1665,9 @@ pub(crate) fn cs_fold<F>( trait_span: Span, substructure: &Substructure<'_>, mut f: F, -) -> P<Expr> +) -> Box<Expr> where - F: FnMut(&ExtCtxt<'_>, CsFold<'_>) -> P<Expr>, + F: FnMut(&ExtCtxt<'_>, CsFold<'_>) -> Box<Expr>, { match substructure.fields { EnumMatching(.., all_fields) | Struct(_, all_fields) => { diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs index f34a6ae1d98..00e70b21cf4 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs @@ -2,7 +2,6 @@ //! when specifying impls to be derived. pub(crate) use Ty::*; -use rustc_ast::ptr::P; use rustc_ast::{self as ast, Expr, GenericArg, GenericParamKind, Generics, SelfKind}; use rustc_expand::base::ExtCtxt; use rustc_span::source_map::respan; @@ -41,7 +40,7 @@ impl Path { span: Span, self_ty: Ident, self_generics: &Generics, - ) -> P<ast::Ty> { + ) -> Box<ast::Ty> { cx.ty_path(self.to_path(cx, span, self_ty, self_generics)) } pub(crate) fn to_path( @@ -90,7 +89,7 @@ impl Ty { span: Span, self_ty: Ident, self_generics: &Generics, - ) -> P<ast::Ty> { + ) -> Box<ast::Ty> { match self { Ref(ty, mutbl) => { let raw_ty = ty.to_ty(cx, span, self_ty, self_generics); @@ -192,7 +191,7 @@ impl Bounds { } } -pub(crate) fn get_explicit_self(cx: &ExtCtxt<'_>, span: Span) -> (P<Expr>, ast::ExplicitSelf) { +pub(crate) fn get_explicit_self(cx: &ExtCtxt<'_>, span: Span) -> (Box<Expr>, ast::ExplicitSelf) { // This constructs a fresh `self` path. let self_path = cx.expr_self(span); let self_ty = respan(span, SelfKind::Region(None, ast::Mutability::Not)); diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index e45d09b5796..1edc2965def 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -1,7 +1,6 @@ //! The compiler code necessary to implement the `#[derive]` extensions. use rustc_ast as ast; -use rustc_ast::ptr::P; use rustc_ast::{GenericArg, MetaItem}; use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier}; use rustc_span::{Span, Symbol, sym}; @@ -66,7 +65,7 @@ impl MultiItemModifier for BuiltinDerive { &mut |a| { // Cannot use 'ecx.stmt_item' here, because we need to pass 'ecx' // to the function - items.push(Annotatable::Stmt(P(ast::Stmt { + items.push(Annotatable::Stmt(Box::new(ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Item(a.expect_item()), span, @@ -91,20 +90,20 @@ fn call_intrinsic( cx: &ExtCtxt<'_>, span: Span, intrinsic: Symbol, - args: ThinVec<P<ast::Expr>>, -) -> P<ast::Expr> { + args: ThinVec<Box<ast::Expr>>, +) -> Box<ast::Expr> { let span = cx.with_def_site_ctxt(span); let path = cx.std_path(&[sym::intrinsics, intrinsic]); cx.expr_call_global(span, path, args) } /// Constructs an expression that calls the `unreachable` intrinsic. -fn call_unreachable(cx: &ExtCtxt<'_>, span: Span) -> P<ast::Expr> { +fn call_unreachable(cx: &ExtCtxt<'_>, span: Span) -> Box<ast::Expr> { let span = cx.with_def_site_ctxt(span); let path = cx.std_path(&[sym::intrinsics, sym::unreachable]); let call = cx.expr_call_global(span, path, ThinVec::new()); - cx.expr_block(P(ast::Block { + cx.expr_block(Box::new(ast::Block { stmts: thin_vec![cx.stmt_expr(call)], id: ast::DUMMY_NODE_ID, rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated), @@ -116,7 +115,7 @@ fn call_unreachable(cx: &ExtCtxt<'_>, span: Span) -> P<ast::Expr> { fn assert_ty_bounds( cx: &ExtCtxt<'_>, stmts: &mut ThinVec<ast::Stmt>, - ty: P<ast::Ty>, + ty: Box<ast::Ty>, span: Span, assert_path: &[Symbol], ) { diff --git a/compiler/rustc_builtin_macros/src/edition_panic.rs b/compiler/rustc_builtin_macros/src/edition_panic.rs index ccfcc3079eb..08f555b9e52 100644 --- a/compiler/rustc_builtin_macros/src/edition_panic.rs +++ b/compiler/rustc_builtin_macros/src/edition_panic.rs @@ -1,4 +1,3 @@ -use rustc_ast::ptr::P; use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::{DelimSpan, TokenStream}; use rustc_ast::*; @@ -48,7 +47,7 @@ fn expand<'cx>( ExpandResult::Ready(MacEager::expr( cx.expr( sp, - ExprKind::MacCall(P(MacCall { + ExprKind::MacCall(Box::new(MacCall { path: Path { span: sp, segments: cx @@ -58,7 +57,7 @@ fn expand<'cx>( .collect(), tokens: None, }, - args: P(DelimArgs { + args: Box::new(DelimArgs { dspan: DelimSpan::from_single(sp), delim: Delimiter::Parenthesis, tokens: tts, diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 6785cb6aef5..ec613b7b710 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -1,7 +1,6 @@ use std::ops::Range; use parse::Position::ArgumentNamed; -use rustc_ast::ptr::P; use rustc_ast::tokenstream::TokenStream; use rustc_ast::{ Expr, ExprKind, FormatAlignment, FormatArgPosition, FormatArgPositionKind, FormatArgs, @@ -45,7 +44,7 @@ use PositionUsedAs::*; #[derive(Debug)] struct MacroInput { - fmtstr: P<Expr>, + fmtstr: Box<Expr>, args: FormatArguments, /// Whether the first argument was a string literal or a result from eager macro expansion. /// If it's not a string literal, we disallow implicit argument capturing. @@ -1018,7 +1017,7 @@ fn expand_format_args_impl<'cx>( }; match mac { Ok(format_args) => { - MacEager::expr(ecx.expr(sp, ExprKind::FormatArgs(P(format_args)))) + MacEager::expr(ecx.expr(sp, ExprKind::FormatArgs(Box::new(format_args)))) } Err(guar) => MacEager::expr(DummyResult::raw_expr(sp, Some(guar))), } diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs index 13d5b42942a..3e5a26c0556 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign.rs @@ -346,18 +346,18 @@ pub(crate) mod printf { // ```regex // (?x) // ^ % - // (?: (?P<parameter> \d+) \$ )? - // (?P<flags> [-+ 0\#']* ) - // (?P<width> \d+ | \* (?: (?P<widtha> \d+) \$ )? )? - // (?: \. (?P<precision> \d+ | \* (?: (?P<precisiona> \d+) \$ )? ) )? - // (?P<length> + // (?: (?Box<parameter> \d+) \$ )? + // (?Box<flags> [-+ 0\#']* ) + // (?Box<width> \d+ | \* (?: (?Box<widtha> \d+) \$ )? )? + // (?: \. (?Box<precision> \d+ | \* (?: (?Box<precisiona> \d+) \$ )? ) )? + // (?Box<length> // # Standard // hh | h | ll | l | L | z | j | t // // # Other // | I32 | I64 | I | q // )? - // (?P<type> . ) + // (?Box<type> . ) // ``` // Used to establish the full span at the end. diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs index 4b1958bce32..f14b1920722 100644 --- a/compiler/rustc_builtin_macros/src/global_allocator.rs +++ b/compiler/rustc_builtin_macros/src/global_allocator.rs @@ -1,7 +1,6 @@ use rustc_ast::expand::allocator::{ ALLOCATOR_METHODS, AllocatorMethod, AllocatorMethodInput, AllocatorTy, global_fn_name, }; -use rustc_ast::ptr::P; use rustc_ast::{ self as ast, AttrVec, Expr, Fn, FnHeader, FnSig, Generics, ItemKind, Mutability, Param, Safety, Stmt, StmtKind, Ty, TyKind, @@ -51,7 +50,7 @@ pub(crate) fn expand( let const_body = ecx.expr_block(ecx.block(span, stmts)); let const_item = ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body); let const_item = if is_stmt { - Annotatable::Stmt(P(ecx.stmt_item(span, const_item))) + Annotatable::Stmt(Box::new(ecx.stmt_item(span, const_item))) } else { Annotatable::Item(const_item) }; @@ -90,7 +89,7 @@ impl AllocFnFactory<'_, '_> { self.cx.stmt_item(self.ty_span, item) } - fn call_allocator(&self, method: Symbol, mut args: ThinVec<P<Expr>>) -> P<Expr> { + fn call_allocator(&self, method: Symbol, mut args: ThinVec<Box<Expr>>) -> Box<Expr> { let method = self.cx.std_path(&[sym::alloc, sym::GlobalAlloc, method]); let method = self.cx.expr_path(self.cx.path(self.ty_span, method)); let allocator = self.cx.path_ident(self.ty_span, self.global); @@ -105,7 +104,7 @@ impl AllocFnFactory<'_, '_> { thin_vec![self.cx.attr_word(sym::rustc_std_internal_symbol, self.span)] } - fn arg_ty(&self, input: &AllocatorMethodInput, args: &mut ThinVec<Param>) -> P<Expr> { + fn arg_ty(&self, input: &AllocatorMethodInput, args: &mut ThinVec<Param>) -> Box<Expr> { match input.ty { AllocatorTy::Layout => { // If an allocator method is ever introduced having multiple @@ -148,7 +147,7 @@ impl AllocFnFactory<'_, '_> { } } - fn ret_ty(&self, ty: &AllocatorTy) -> P<Ty> { + fn ret_ty(&self, ty: &AllocatorTy) -> Box<Ty> { match *ty { AllocatorTy::ResultPtr => self.ptr_u8(), @@ -160,12 +159,12 @@ impl AllocFnFactory<'_, '_> { } } - fn usize(&self) -> P<Ty> { + fn usize(&self) -> Box<Ty> { let usize = self.cx.path_ident(self.span, Ident::new(sym::usize, self.span)); self.cx.ty_path(usize) } - fn ptr_u8(&self) -> P<Ty> { + fn ptr_u8(&self) -> Box<Ty> { let u8 = self.cx.path_ident(self.span, Ident::new(sym::u8, self.span)); let ty_u8 = self.cx.ty_path(u8); self.cx.ty_ptr(self.span, ty_u8, Mutability::Mut) diff --git a/compiler/rustc_builtin_macros/src/iter.rs b/compiler/rustc_builtin_macros/src/iter.rs index 7ad83903a1b..e9f340ef119 100644 --- a/compiler/rustc_builtin_macros/src/iter.rs +++ b/compiler/rustc_builtin_macros/src/iter.rs @@ -1,4 +1,3 @@ -use rustc_ast::ptr::P; use rustc_ast::tokenstream::TokenStream; use rustc_ast::{CoroutineKind, DUMMY_NODE_ID, Expr, ast, token}; use rustc_errors::PResult; @@ -24,7 +23,7 @@ fn parse_closure<'a>( cx: &mut ExtCtxt<'a>, span: Span, stream: TokenStream, -) -> PResult<'a, P<Expr>> { +) -> PResult<'a, Box<Expr>> { let mut closure_parser = cx.new_parser_from_tts(stream); let coroutine_kind = Some(CoroutineKind::Gen { diff --git a/compiler/rustc_builtin_macros/src/pattern_type.rs b/compiler/rustc_builtin_macros/src/pattern_type.rs index b61af0b0aaa..34faafdc07c 100644 --- a/compiler/rustc_builtin_macros/src/pattern_type.rs +++ b/compiler/rustc_builtin_macros/src/pattern_type.rs @@ -1,4 +1,3 @@ -use rustc_ast::ptr::P; use rustc_ast::tokenstream::TokenStream; use rustc_ast::{AnonConst, DUMMY_NODE_ID, Ty, TyPat, TyPatKind, ast, token}; use rustc_errors::PResult; @@ -22,7 +21,10 @@ pub(crate) fn expand<'cx>( ExpandResult::Ready(base::MacEager::ty(cx.ty(sp, ast::TyKind::Pat(ty, pat)))) } -fn parse_pat_ty<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P<Ty>, P<TyPat>)> { +fn parse_pat_ty<'a>( + cx: &mut ExtCtxt<'a>, + stream: TokenStream, +) -> PResult<'a, (Box<Ty>, Box<TyPat>)> { let mut parser = cx.new_parser_from_tts(stream); let ty = parser.parse_ty()?; @@ -45,15 +47,15 @@ fn parse_pat_ty<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P Ok((ty, pat)) } -fn ty_pat(kind: TyPatKind, span: Span) -> P<TyPat> { - P(TyPat { id: DUMMY_NODE_ID, kind, span, tokens: None }) +fn ty_pat(kind: TyPatKind, span: Span) -> Box<TyPat> { + Box::new(TyPat { id: DUMMY_NODE_ID, kind, span, tokens: None }) } -fn pat_to_ty_pat(cx: &mut ExtCtxt<'_>, pat: ast::Pat) -> P<TyPat> { +fn pat_to_ty_pat(cx: &mut ExtCtxt<'_>, pat: ast::Pat) -> Box<TyPat> { let kind = match pat.kind { ast::PatKind::Range(start, end, include_end) => TyPatKind::Range( - start.map(|value| P(AnonConst { id: DUMMY_NODE_ID, value })), - end.map(|value| P(AnonConst { id: DUMMY_NODE_ID, value })), + start.map(|value| Box::new(AnonConst { id: DUMMY_NODE_ID, value })), + end.map(|value| Box::new(AnonConst { id: DUMMY_NODE_ID, value })), include_end, ), ast::PatKind::Or(variants) => { diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index 09f5e6f6efc..f440adf6cf0 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -1,15 +1,14 @@ use std::{mem, slice}; -use rustc_ast::ptr::P; use rustc_ast::visit::{self, Visitor}; use rustc_ast::{self as ast, HasNodeId, NodeId, attr}; use rustc_ast_pretty::pprust; -use rustc_attr_data_structures::AttributeKind; use rustc_attr_parsing::AttributeParser; use rustc_errors::DiagCtxtHandle; use rustc_expand::base::{ExtCtxt, ResolverExpand}; use rustc_expand::expand::{AstFragment, ExpansionConfig}; use rustc_feature::Features; +use rustc_hir::attrs::AttributeKind; use rustc_session::Session; use rustc_span::hygiene::AstPass; use rustc_span::source_map::SourceMap; @@ -286,7 +285,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { // // ... // ]; // } -fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P<ast::Item> { +fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> Box<ast::Item> { let expn_id = cx.resolver.expansion_for_ast_pass( DUMMY_SP, AstPass::ProcMacroHarness, diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index ecfd46a84ec..37bab5be542 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -3,7 +3,6 @@ use std::rc::Rc; use std::sync::Arc; use rustc_ast as ast; -use rustc_ast::ptr::P; use rustc_ast::tokenstream::TokenStream; use rustc_ast::{join_path_idents, token}; use rustc_ast_pretty::pprust; @@ -144,7 +143,7 @@ pub(crate) fn expand_include<'cx>( node_id: ast::NodeId, } impl<'a> MacResult for ExpandInclude<'a> { - fn make_expr(mut self: Box<ExpandInclude<'a>>) -> Option<P<ast::Expr>> { + fn make_expr(mut self: Box<ExpandInclude<'a>>) -> Option<Box<ast::Expr>> { let expr = parse_expr(&mut self.p).ok()?; if self.p.token != token::Eof { self.p.psess.buffer_lint( @@ -157,7 +156,7 @@ pub(crate) fn expand_include<'cx>( Some(expr) } - fn make_items(mut self: Box<ExpandInclude<'a>>) -> Option<SmallVec<[P<ast::Item>; 1]>> { + fn make_items(mut self: Box<ExpandInclude<'a>>) -> Option<SmallVec<[Box<ast::Item>; 1]>> { let mut ret = SmallVec::new(); loop { match self.p.parse_item(ForceCollect::No) { diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs index 682e7c9b17a..2068b5ca54d 100644 --- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs +++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs @@ -47,8 +47,6 @@ pub fn inject( ast::ItemKind::ExternCrate(None, Ident::new(name, ident_span)), ); - krate.items.insert(0, item); - let root = (edition == Edition2015).then_some(kw::PathRoot); let import_path = root @@ -75,6 +73,6 @@ pub fn inject( }), ); - krate.items.insert(0, use_item); + krate.items.splice(0..0, [item, use_item]); krate.items.len() - orig_num_items } diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index ba3d8368b2a..7a189ee1f4d 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -4,11 +4,13 @@ use std::assert_matches::assert_matches; use std::iter; -use rustc_ast::ptr::P; -use rustc_ast::{self as ast, GenericParamKind, attr, join_path_idents}; +use rustc_ast::{self as ast, GenericParamKind, HasNodeId, attr, join_path_idents}; use rustc_ast_pretty::pprust; +use rustc_attr_parsing::AttributeParser; use rustc_errors::{Applicability, Diag, Level}; use rustc_expand::base::*; +use rustc_hir::Attribute; +use rustc_hir::attrs::AttributeKind; use rustc_span::{ErrorGuaranteed, FileNameDisplayPreference, Ident, Span, Symbol, sym}; use thin_vec::{ThinVec, thin_vec}; use tracing::debug; @@ -75,7 +77,7 @@ pub(crate) fn expand_test_case( } let ret = if is_stmt { - Annotatable::Stmt(P(ecx.stmt_item(item.span, item))) + Annotatable::Stmt(Box::new(ecx.stmt_item(item.span, item))) } else { Annotatable::Item(item) }; @@ -128,7 +130,7 @@ pub(crate) fn expand_test_or_bench( let ast::ItemKind::Fn(fn_) = &item.kind else { not_testable_error(cx, attr_sp, Some(&item)); return if is_stmt { - vec![Annotatable::Stmt(P(cx.stmt_item(item.span, item)))] + vec![Annotatable::Stmt(Box::new(cx.stmt_item(item.span, item)))] } else { vec![Annotatable::Item(item)] }; @@ -152,7 +154,7 @@ pub(crate) fn expand_test_or_bench( }; if check_result.is_err() { return if is_stmt { - vec![Annotatable::Stmt(P(cx.stmt_item(item.span, item)))] + vec![Annotatable::Stmt(Box::new(cx.stmt_item(item.span, item)))] } else { vec![Annotatable::Item(item)] }; @@ -198,7 +200,7 @@ pub(crate) fn expand_test_or_bench( // `-Cinstrument-coverage` builds. // This requires `#[allow_internal_unstable(coverage_attribute)]` on the // corresponding macro declaration in `core::macros`. - let coverage_off = |mut expr: P<ast::Expr>| { + let coverage_off = |mut expr: Box<ast::Expr>| { assert_matches!(expr.kind, ast::ExprKind::Closure(_)); expr.attrs.push(cx.attr_nested_word(sym::coverage, sym::off, sp)); expr @@ -385,11 +387,11 @@ pub(crate) fn expand_test_or_bench( if is_stmt { vec![ // Access to libtest under a hygienic name - Annotatable::Stmt(P(cx.stmt_item(sp, test_extern))), + Annotatable::Stmt(Box::new(cx.stmt_item(sp, test_extern))), // The generated test case - Annotatable::Stmt(P(cx.stmt_item(sp, test_const))), + Annotatable::Stmt(Box::new(cx.stmt_item(sp, test_const))), // The original item - Annotatable::Stmt(P(cx.stmt_item(sp, item))), + Annotatable::Stmt(Box::new(cx.stmt_item(sp, item))), ] } else { vec![ @@ -473,39 +475,19 @@ fn should_ignore_message(i: &ast::Item) -> Option<Symbol> { } fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic { - match attr::find_by_name(&i.attrs, sym::should_panic) { - Some(attr) => { - match attr.meta_item_list() { - // Handle #[should_panic(expected = "foo")] - Some(list) => { - let msg = list - .iter() - .find(|mi| mi.has_name(sym::expected)) - .and_then(|mi| mi.meta_item()) - .and_then(|mi| mi.value_str()); - if list.len() != 1 || msg.is_none() { - cx.dcx() - .struct_span_warn( - attr.span, - "argument must be of the form: \ - `expected = \"error message\"`", - ) - .with_note( - "errors in this attribute were erroneously \ - allowed and will become a hard error in a \ - future release", - ) - .emit(); - ShouldPanic::Yes(None) - } else { - ShouldPanic::Yes(msg) - } - } - // Handle #[should_panic] and #[should_panic = "expected"] - None => ShouldPanic::Yes(attr.value_str()), - } - } - None => ShouldPanic::No, + if let Some(Attribute::Parsed(AttributeKind::ShouldPanic { reason, .. })) = + AttributeParser::parse_limited( + cx.sess, + &i.attrs, + sym::should_panic, + i.span, + i.node_id(), + None, + ) + { + ShouldPanic::Yes(reason) + } else { + ShouldPanic::No } } diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 111c85d49eb..e803f3be82b 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -5,7 +5,6 @@ use std::mem; use rustc_ast as ast; use rustc_ast::entry::EntryPointType; use rustc_ast::mut_visit::*; -use rustc_ast::ptr::P; use rustc_ast::visit::Visitor; use rustc_ast::{ModKind, attr}; use rustc_errors::DiagCtxtHandle; @@ -284,7 +283,7 @@ fn generate_test_harness( /// [`TestCtxt::reexport_test_harness_main`] provides a different name for the `main` /// function and [`TestCtxt::test_runner`] provides a path that replaces /// `test::test_main_static`. -fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> { +fn mk_main(cx: &mut TestCtxt<'_>) -> Box<ast::Item> { let sp = cx.def_site; let ecx = &cx.ext_cx; let test_ident = Ident::new(sym::test, sp); @@ -348,7 +347,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> { define_opaque: None, })); - let main = P(ast::Item { + let main = Box::new(ast::Item { attrs: thin_vec![main_attr, coverage_attr, doc_hidden_attr], id: ast::DUMMY_NODE_ID, kind: main, @@ -364,7 +363,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> { /// Creates a slice containing every test like so: /// &[&test1, &test2] -fn mk_tests_slice(cx: &TestCtxt<'_>, sp: Span) -> P<ast::Expr> { +fn mk_tests_slice(cx: &TestCtxt<'_>, sp: Span) -> Box<ast::Expr> { debug!("building test vector from {} tests", cx.test_cases.len()); let ecx = &cx.ext_cx; diff --git a/compiler/rustc_builtin_macros/src/util.rs b/compiler/rustc_builtin_macros/src/util.rs index 38fec2bff14..f00c170e485 100644 --- a/compiler/rustc_builtin_macros/src/util.rs +++ b/compiler/rustc_builtin_macros/src/util.rs @@ -1,4 +1,3 @@ -use rustc_ast::ptr::P; use rustc_ast::tokenstream::TokenStream; use rustc_ast::{self as ast, AttrStyle, Attribute, MetaItem, attr, token}; use rustc_errors::{Applicability, Diag, ErrorGuaranteed}; @@ -83,7 +82,7 @@ type UnexpectedExprKind<'a> = Result<(Diag<'a>, bool /* has_suggestions */), Err #[allow(rustc::untranslatable_diagnostic)] pub(crate) fn expr_to_spanned_string<'a>( cx: &'a mut ExtCtxt<'_>, - expr: P<ast::Expr>, + expr: Box<ast::Expr>, err_msg: &'static str, ) -> ExpandResult<ExprToSpannedStringResult<'a>, ()> { if !cx.force_mode @@ -135,7 +134,7 @@ pub(crate) fn expr_to_spanned_string<'a>( /// compilation on error, merely emits a non-fatal error and returns `Err`. pub(crate) fn expr_to_string( cx: &mut ExtCtxt<'_>, - expr: P<ast::Expr>, + expr: Box<ast::Expr>, err_msg: &'static str, ) -> ExpandResult<Result<(Symbol, ast::StrStyle), ErrorGuaranteed>, ()> { expr_to_spanned_string(cx, expr, err_msg).map(|res| { @@ -158,7 +157,7 @@ pub(crate) fn check_zero_tts(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream, nam } /// Parse an expression. On error, emit it, advancing to `Eof`, and return `Err`. -pub(crate) fn parse_expr(p: &mut parser::Parser<'_>) -> Result<P<ast::Expr>, ErrorGuaranteed> { +pub(crate) fn parse_expr(p: &mut parser::Parser<'_>) -> Result<Box<ast::Expr>, ErrorGuaranteed> { let guar = match p.parse_expr() { Ok(expr) => return Ok(expr), Err(err) => err.emit(), @@ -209,7 +208,7 @@ pub(crate) fn get_single_expr_from_tts( span: Span, tts: TokenStream, name: &str, -) -> ExpandResult<Result<P<ast::Expr>, ErrorGuaranteed>, ()> { +) -> ExpandResult<Result<Box<ast::Expr>, ErrorGuaranteed>, ()> { let mut p = cx.new_parser_from_tts(tts); if p.token == token::Eof { let guar = cx.dcx().emit_err(errors::OnlyOneArgument { span, name }); @@ -232,7 +231,7 @@ pub(crate) fn get_single_expr_from_tts( pub(crate) fn get_exprs_from_tts( cx: &mut ExtCtxt<'_>, tts: TokenStream, -) -> ExpandResult<Result<Vec<P<ast::Expr>>, ErrorGuaranteed>, ()> { +) -> ExpandResult<Result<Vec<Box<ast::Expr>>, ErrorGuaranteed>, ()> { let mut p = cx.new_parser_from_tts(tts); let mut es = Vec::new(); while p.token != token::Eof { diff --git a/compiler/rustc_codegen_cranelift/patches/0027-sysroot_tests-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/patches/0027-sysroot_tests-128bit-atomic-operations.patch index f6e6bbc2387..f3d1d5c43ea 100644 --- a/compiler/rustc_codegen_cranelift/patches/0027-sysroot_tests-128bit-atomic-operations.patch +++ b/compiler/rustc_codegen_cranelift/patches/0027-sysroot_tests-128bit-atomic-operations.patch @@ -19,7 +19,7 @@ index 1e336bf..35e6f54 100644 -#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))] #![cfg_attr(test, feature(cfg_select))] #![feature(alloc_layout_extra)] - #![feature(array_chunks)] + #![feature(array_ptr_get)] diff --git a/coretests/tests/atomic.rs b/coretests/tests/atomic.rs index b735957..ea728b6 100644 --- a/coretests/tests/atomic.rs diff --git a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh index 532702bb1a4..492f4dc4452 100644 --- a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh +++ b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh @@ -33,6 +33,7 @@ rustc = "$(pwd)/../dist/bin/rustc-clif" cargo = "$(rustup which cargo)" full-bootstrap = true local-rebuild = true +compiletest-allow-stage0 = true [rust] download-rustc = false diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh index 7e356b4b462..52e02c857c7 100755 --- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh +++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh @@ -166,5 +166,5 @@ index 073116933bd..c3e4578204d 100644 EOF echo "[TEST] rustc test suite" -COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0 --test-args=--no-capture tests/{codegen-units,run-make,ui,incremental} +./x.py test --stage 0 --test-args=--no-capture tests/{codegen-units,run-make,ui,incremental} popd diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index a04cfa27237..bec546badc9 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -310,7 +310,10 @@ fn data_id_for_static( // `extern_with_linkage_foo` will instead be initialized to // zero. - let ref_name = format!("_rust_extern_with_linkage_{}", symbol_name); + let ref_name = format!( + "_rust_extern_with_linkage_{:016x}_{symbol_name}", + tcx.stable_crate_id(LOCAL_CRATE) + ); let ref_data_id = module.declare_data(&ref_name, Linkage::Local, false, false).unwrap(); let mut data = DataDescription::new(); data.set_align(align); diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 4ff5773a06c..ed40901ac9b 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -969,7 +969,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let layout = amount.layout(); match layout.ty.kind() { - ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} + ty::Uint(_) | ty::Int(_) => {} _ => { report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty); return Ok(()); @@ -982,7 +982,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Add, ptr, amount); - let old = CValue::by_val(old, layout); + let old = CValue::by_val(old, ret.layout()); ret.write_cvalue(fx, old); } sym::atomic_xsub => { @@ -991,7 +991,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let layout = amount.layout(); match layout.ty.kind() { - ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} + ty::Uint(_) | ty::Int(_) => {} _ => { report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty); return Ok(()); @@ -1004,7 +1004,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Sub, ptr, amount); - let old = CValue::by_val(old, layout); + let old = CValue::by_val(old, ret.layout()); ret.write_cvalue(fx, old); } sym::atomic_and => { @@ -1013,7 +1013,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let layout = src.layout(); match layout.ty.kind() { - ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} + ty::Uint(_) | ty::Int(_) => {} _ => { report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty); return Ok(()); @@ -1025,7 +1025,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::And, ptr, src); - let old = CValue::by_val(old, layout); + let old = CValue::by_val(old, ret.layout()); ret.write_cvalue(fx, old); } sym::atomic_or => { @@ -1034,7 +1034,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let layout = src.layout(); match layout.ty.kind() { - ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} + ty::Uint(_) | ty::Int(_) => {} _ => { report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty); return Ok(()); @@ -1046,7 +1046,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Or, ptr, src); - let old = CValue::by_val(old, layout); + let old = CValue::by_val(old, ret.layout()); ret.write_cvalue(fx, old); } sym::atomic_xor => { @@ -1055,7 +1055,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let layout = src.layout(); match layout.ty.kind() { - ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} + ty::Uint(_) | ty::Int(_) => {} _ => { report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty); return Ok(()); @@ -1067,7 +1067,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Xor, ptr, src); - let old = CValue::by_val(old, layout); + let old = CValue::by_val(old, ret.layout()); ret.write_cvalue(fx, old); } sym::atomic_nand => { @@ -1076,7 +1076,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let layout = src.layout(); match layout.ty.kind() { - ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} + ty::Uint(_) | ty::Int(_) => {} _ => { report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty); return Ok(()); @@ -1088,7 +1088,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Nand, ptr, src); - let old = CValue::by_val(old, layout); + let old = CValue::by_val(old, ret.layout()); ret.write_cvalue(fx, old); } sym::atomic_max => { diff --git a/compiler/rustc_codegen_gcc/build_system/src/abi_test.rs b/compiler/rustc_codegen_gcc/build_system/src/abi_test.rs index 3c1531be27a..a85886d87f3 100644 --- a/compiler/rustc_codegen_gcc/build_system/src/abi_test.rs +++ b/compiler/rustc_codegen_gcc/build_system/src/abi_test.rs @@ -31,7 +31,7 @@ pub fn run() -> Result<(), String> { Some("clones/abi-cafe".as_ref()), true, ) - .map_err(|err| (format!("Git clone failed with message: {err:?}!")))?; + .map_err(|err| format!("Git clone failed with message: {err:?}!"))?; // Configure abi-cafe to use the exact same rustc version we use - this is crucial. // Otherwise, the concept of ABI compatibility becomes meanignless. std::fs::copy("rust-toolchain", "clones/abi-cafe/rust-toolchain") diff --git a/compiler/rustc_codegen_gcc/build_system/src/fuzz.rs b/compiler/rustc_codegen_gcc/build_system/src/fuzz.rs index 453211366b3..9714ce29af9 100644 --- a/compiler/rustc_codegen_gcc/build_system/src/fuzz.rs +++ b/compiler/rustc_codegen_gcc/build_system/src/fuzz.rs @@ -43,18 +43,18 @@ pub fn run() -> Result<(), String> { "--start" => { start = str::parse(&args.next().ok_or_else(|| "Fuzz start not provided!".to_string())?) - .map_err(|err| (format!("Fuzz start not a number {err:?}!")))?; + .map_err(|err| format!("Fuzz start not a number {err:?}!"))?; } "--count" => { count = str::parse(&args.next().ok_or_else(|| "Fuzz count not provided!".to_string())?) - .map_err(|err| (format!("Fuzz count not a number {err:?}!")))?; + .map_err(|err| format!("Fuzz count not a number {err:?}!"))?; } "-j" | "--jobs" => { threads = str::parse( &args.next().ok_or_else(|| "Fuzz thread count not provided!".to_string())?, ) - .map_err(|err| (format!("Fuzz thread count not a number {err:?}!")))?; + .map_err(|err| format!("Fuzz thread count not a number {err:?}!"))?; } _ => return Err(format!("Unknown option {arg}")), } @@ -66,7 +66,7 @@ pub fn run() -> Result<(), String> { Some("clones/rustlantis".as_ref()), true, ) - .map_err(|err| (format!("Git clone failed with message: {err:?}!")))?; + .map_err(|err| format!("Git clone failed with message: {err:?}!"))?; // Ensure that we are on the newest rustlantis commit. let cmd: &[&dyn AsRef<OsStr>] = &[&"git", &"pull", &"origin"]; diff --git a/compiler/rustc_codegen_gcc/build_system/src/test.rs b/compiler/rustc_codegen_gcc/build_system/src/test.rs index bc0fdd40b6e..2c8271c36a9 100644 --- a/compiler/rustc_codegen_gcc/build_system/src/test.rs +++ b/compiler/rustc_codegen_gcc/build_system/src/test.rs @@ -561,8 +561,6 @@ fn asm_tests(env: &Env, args: &TestArg) -> Result<(), String> { // FIXME: create a function "display_if_not_quiet" or something along the line. println!("[TEST] rustc asm test suite"); - env.insert("COMPILETEST_FORCE_STAGE0".to_string(), "1".to_string()); - let codegen_backend_path = format!( "{pwd}/target/{channel}/librustc_codegen_gcc.{dylib_ext}", pwd = std::env::current_dir() @@ -588,6 +586,8 @@ fn asm_tests(env: &Env, args: &TestArg) -> Result<(), String> { &"always", &"--stage", &"0", + &"--set", + &"build.compiletest-allow-stage0=true", &"tests/assembly-llvm/asm", &"--compiletest-rustc-args", &rustc_args, @@ -1047,7 +1047,6 @@ where // FIXME: create a function "display_if_not_quiet" or something along the line. println!("[TEST] rustc {test_type} test suite"); - env.insert("COMPILETEST_FORCE_STAGE0".to_string(), "1".to_string()); let extra = if args.is_using_gcc_master_branch() { "" } else { " -Csymbol-mangling-version=v0" }; @@ -1070,6 +1069,8 @@ where &"always", &"--stage", &"0", + &"--set", + &"build.compiletest-allow-stage0=true", &format!("tests/{test_type}"), &"--compiletest-rustc-args", &rustc_args, diff --git a/compiler/rustc_codegen_gcc/messages.ftl b/compiler/rustc_codegen_gcc/messages.ftl index a70ac08f01a..b9b77b7d18c 100644 --- a/compiler/rustc_codegen_gcc/messages.ftl +++ b/compiler/rustc_codegen_gcc/messages.ftl @@ -4,3 +4,5 @@ codegen_gcc_unwinding_inline_asm = codegen_gcc_copy_bitcode = failed to copy bitcode to object file: {$err} codegen_gcc_lto_bitcode_from_rlib = failed to get bitcode from object file for LTO ({$gcc_err}) + +codegen_gcc_explicit_tail_calls_unsupported = explicit tail calls with the 'become' keyword are not implemented in the GCC backend diff --git a/compiler/rustc_codegen_gcc/patches/0001-Add-stdarch-Cargo.toml-for-testing.patch b/compiler/rustc_codegen_gcc/patches/0001-Add-stdarch-Cargo.toml-for-testing.patch index 9cc377850b9..3a8c37a8b8d 100644 --- a/compiler/rustc_codegen_gcc/patches/0001-Add-stdarch-Cargo.toml-for-testing.patch +++ b/compiler/rustc_codegen_gcc/patches/0001-Add-stdarch-Cargo.toml-for-testing.patch @@ -1,29 +1,28 @@ -From b8f3eed3053c9333b5dfbeaeb2a6a65a4b3156df Mon Sep 17 00:00:00 2001 -From: Antoni Boucher <bouanto@zoho.com> -Date: Tue, 29 Aug 2023 13:06:34 -0400 +From 190e26c9274b3c93a9ee3516b395590e6bd9213b Mon Sep 17 00:00:00 2001 +From: None <none@example.com> +Date: Sun, 3 Aug 2025 19:54:56 -0400 Subject: [PATCH] Patch 0001-Add-stdarch-Cargo.toml-for-testing.patch --- - library/stdarch/Cargo.toml | 23 +++++++++++++++++++++++ - 1 file changed, 23 insertions(+) + library/stdarch/Cargo.toml | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) create mode 100644 library/stdarch/Cargo.toml diff --git a/library/stdarch/Cargo.toml b/library/stdarch/Cargo.toml new file mode 100644 -index 0000000..4c63700 +index 0000000..bd6725c --- /dev/null +++ b/library/stdarch/Cargo.toml -@@ -0,0 +1,21 @@ +@@ -0,0 +1,20 @@ +[workspace] +resolver = "1" +members = [ -+ "crates/core_arch", -+ "crates/std_detect", -+ "crates/stdarch-gen-arm", ++ "crates/*", + #"examples/" +] +exclude = [ -+ "crates/wasm-assert-instr-tests" ++ "crates/wasm-assert-instr-tests", ++ "rust_programs", +] + +[profile.release] @@ -36,5 +35,5 @@ index 0000000..4c63700 +opt-level = 3 +incremental = true -- -2.42.0 +2.50.1 diff --git a/compiler/rustc_codegen_gcc/rust-toolchain b/compiler/rustc_codegen_gcc/rust-toolchain index 2fe8ec4647f..058e734be5c 100644 --- a/compiler/rustc_codegen_gcc/rust-toolchain +++ b/compiler/rustc_codegen_gcc/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2025-07-04" +channel = "nightly-2025-08-03" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] diff --git a/compiler/rustc_codegen_gcc/src/allocator.rs b/compiler/rustc_codegen_gcc/src/allocator.rs index 0d8dc93274f..2a95a7368aa 100644 --- a/compiler/rustc_codegen_gcc/src/allocator.rs +++ b/compiler/rustc_codegen_gcc/src/allocator.rs @@ -99,11 +99,15 @@ fn create_const_value_function( let func = context.new_function(None, FunctionType::Exported, output, &[], name, false); #[cfg(feature = "master")] - func.add_attribute(FnAttribute::Visibility(symbol_visibility_to_gcc( - tcx.sess.default_visibility(), - ))); - - func.add_attribute(FnAttribute::AlwaysInline); + { + func.add_attribute(FnAttribute::Visibility(symbol_visibility_to_gcc( + tcx.sess.default_visibility(), + ))); + + // FIXME(antoyo): cg_llvm sets AlwaysInline, but AlwaysInline is different in GCC and using + // it here will causes linking errors when using LTO. + func.add_attribute(FnAttribute::Inline); + } if tcx.sess.must_emit_unwind_tables() { // TODO(antoyo): emit unwind tables. diff --git a/compiler/rustc_codegen_gcc/src/attributes.rs b/compiler/rustc_codegen_gcc/src/attributes.rs index 7a1ae6ca9c8..04b43bb8bb7 100644 --- a/compiler/rustc_codegen_gcc/src/attributes.rs +++ b/compiler/rustc_codegen_gcc/src/attributes.rs @@ -2,8 +2,8 @@ use gccjit::FnAttribute; use gccjit::Function; #[cfg(feature = "master")] -use rustc_attr_data_structures::InlineAttr; -use rustc_attr_data_structures::InstructionSetAttr; +use rustc_hir::attrs::InlineAttr; +use rustc_hir::attrs::InstructionSetAttr; #[cfg(feature = "master")] use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; #[cfg(feature = "master")] diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index a4ec4bf8dea..f7a7a3f8c7e 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -34,6 +34,7 @@ use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, Target, X86Abi}; use crate::common::{SignType, TypeReflection, type_is_pointer}; use crate::context::CodegenCx; +use crate::errors; use crate::intrinsic::llvm; use crate::type_of::LayoutGccExt; @@ -539,9 +540,15 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn ret(&mut self, mut value: RValue<'gcc>) { let expected_return_type = self.current_func().get_return_type(); - if !expected_return_type.is_compatible_with(value.get_type()) { - // NOTE: due to opaque pointers now being used, we need to cast here. - value = self.context.new_cast(self.location, value, expected_return_type); + let value_type = value.get_type(); + if !expected_return_type.is_compatible_with(value_type) { + // NOTE: due to opaque pointers now being used, we need to (bit)cast here. + if self.is_native_int_type(value_type) && self.is_native_int_type(expected_return_type) + { + value = self.context.new_cast(self.location, value, expected_return_type); + } else { + value = self.context.new_bitcast(self.location, value, expected_return_type); + } } self.llbb().end_with_return(self.location, value); } @@ -1278,11 +1285,19 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn intcast( &mut self, - value: RValue<'gcc>, + mut value: RValue<'gcc>, dest_typ: Type<'gcc>, - _is_signed: bool, + is_signed: bool, ) -> RValue<'gcc> { - // NOTE: is_signed is for value, not dest_typ. + let value_type = value.get_type(); + if is_signed && !value_type.is_signed(self.cx) { + let signed_type = value_type.to_signed(self.cx); + value = self.gcc_int_cast(value, signed_type); + } else if !is_signed && value_type.is_signed(self.cx) { + let unsigned_type = value_type.to_unsigned(self.cx); + value = self.gcc_int_cast(value, unsigned_type); + } + self.gcc_int_cast(value, dest_typ) } @@ -1656,6 +1671,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { dst: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering, + ret_ptr: bool, ) -> RValue<'gcc> { let size = get_maybe_pointer_size(src); let name = match op { @@ -1683,6 +1699,9 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let atomic_function = self.context.get_builtin_function(name); let order = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc()); + // FIXME: If `ret_ptr` is true and `src` is an integer, we should really tell GCC + // that this is a pointer operation that needs to preserve provenance -- but like LLVM, + // GCC does not currently seems to support that. let void_ptr_type = self.context.new_type::<*mut ()>(); let volatile_void_ptr_type = void_ptr_type.make_volatile(); let dst = self.context.new_cast(self.location, dst, volatile_void_ptr_type); @@ -1690,7 +1709,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let new_src_type = atomic_function.get_param(1).to_rvalue().get_type(); let src = self.context.new_bitcast(self.location, src, new_src_type); let res = self.context.new_call(self.location, atomic_function, &[dst, src, order]); - self.context.new_cast(self.location, res, src.get_type()) + let res_type = if ret_ptr { void_ptr_type } else { src.get_type() }; + self.context.new_cast(self.location, res, res_type) } fn atomic_fence(&mut self, order: AtomicOrdering, scope: SynchronizationScope) { @@ -1742,6 +1762,20 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { call } + fn tail_call( + &mut self, + _llty: Self::Type, + _fn_attrs: Option<&CodegenFnAttrs>, + _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + _llfn: Self::Value, + _args: &[Self::Value], + _funclet: Option<&Self::Funclet>, + _instance: Option<Instance<'tcx>>, + ) { + // FIXME: implement support for explicit tail calls like rustc_codegen_llvm. + self.tcx.dcx().emit_fatal(errors::ExplicitTailCallsUnsupported); + } + fn zext(&mut self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> { // FIXME(antoyo): this does not zero-extend. self.gcc_int_cast(value, dest_typ) diff --git a/compiler/rustc_codegen_gcc/src/callee.rs b/compiler/rustc_codegen_gcc/src/callee.rs index e7ca95af594..8487a85bd03 100644 --- a/compiler/rustc_codegen_gcc/src/callee.rs +++ b/compiler/rustc_codegen_gcc/src/callee.rs @@ -106,7 +106,7 @@ pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>) // This is a monomorphization of a generic function. if !(cx.tcx.sess.opts.share_generics() || tcx.codegen_instance_attrs(instance.def).inline - == rustc_attr_data_structures::InlineAttr::Never) + == rustc_hir::attrs::InlineAttr::Never) { // When not sharing generics, all instances are in the same // crate and have hidden visibility. diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs index c04c75e1b11..873f1f1951c 100644 --- a/compiler/rustc_codegen_gcc/src/consts.rs +++ b/compiler/rustc_codegen_gcc/src/consts.rs @@ -6,6 +6,7 @@ use rustc_codegen_ssa::traits::{ BaseTypeCodegenMethods, ConstCodegenMethods, StaticCodegenMethods, }; use rustc_hir::def::DefKind; +use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::interpret::{ self, ConstAllocation, ErrorHandled, Scalar as InterpScalar, read_target_uint, @@ -384,8 +385,8 @@ fn check_and_apply_linkage<'gcc, 'tcx>( // linkage and there are no definitions), then // `extern_with_linkage_foo` will instead be initialized to // zero. - let mut real_name = "_rust_extern_with_linkage_".to_string(); - real_name.push_str(sym); + let real_name = + format!("_rust_extern_with_linkage_{:016x}_{sym}", cx.tcx.stable_crate_id(LOCAL_CRATE)); let global2 = cx.define_global(&real_name, gcc_type, is_tls, attrs.link_section); // TODO(antoyo): set linkage. let value = cx.const_ptrcast(global1.get_address(None), gcc_type); diff --git a/compiler/rustc_codegen_gcc/src/errors.rs b/compiler/rustc_codegen_gcc/src/errors.rs index 0aa16bd88b4..b252c39c0c0 100644 --- a/compiler/rustc_codegen_gcc/src/errors.rs +++ b/compiler/rustc_codegen_gcc/src/errors.rs @@ -19,3 +19,7 @@ pub(crate) struct CopyBitcode { pub(crate) struct LtoBitcodeFromRlib { pub gcc_err: String, } + +#[derive(Diagnostic)] +#[diag(codegen_gcc_explicit_tail_calls_unsupported)] +pub(crate) struct ExplicitTailCallsUnsupported; diff --git a/compiler/rustc_codegen_gcc/src/int.rs b/compiler/rustc_codegen_gcc/src/int.rs index 6f21ce9352b..9fb7f6bad68 100644 --- a/compiler/rustc_codegen_gcc/src/int.rs +++ b/compiler/rustc_codegen_gcc/src/int.rs @@ -4,12 +4,15 @@ // cSpell:words cmpti divti modti mulodi muloti udivti umodti -use gccjit::{BinaryOp, ComparisonOp, FunctionType, Location, RValue, ToRValue, Type, UnaryOp}; +use gccjit::{ + BinaryOp, CType, ComparisonOp, FunctionType, Location, RValue, ToRValue, Type, UnaryOp, +}; use rustc_abi::{CanonAbi, Endian, ExternAbi}; use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeCodegenMethods, BuilderMethods, OverflowOp}; use rustc_middle::ty::{self, Ty}; use rustc_target::callconv::{ArgAbi, ArgAttributes, FnAbi, PassMode}; +use rustc_type_ir::{Interner, TyKind}; use crate::builder::{Builder, ToGccComp}; use crate::common::{SignType, TypeReflection}; @@ -167,9 +170,9 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { if a_type.is_vector() { // Vector types need to be bitcast. // TODO(antoyo): perhaps use __builtin_convertvector for vector casting. - b = self.context.new_bitcast(self.location, b, a.get_type()); + b = self.context.new_bitcast(self.location, b, a_type); } else { - b = self.context.new_cast(self.location, b, a.get_type()); + b = self.context.new_cast(self.location, b, a_type); } } self.context.new_binary_op(self.location, operation, a_type, a, b) @@ -216,13 +219,22 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { operation_name: &str, signed: bool, a: RValue<'gcc>, - b: RValue<'gcc>, + mut b: RValue<'gcc>, ) -> RValue<'gcc> { let a_type = a.get_type(); let b_type = b.get_type(); if (self.is_native_int_type_or_bool(a_type) && self.is_native_int_type_or_bool(b_type)) || (a_type.is_vector() && b_type.is_vector()) { + if !a_type.is_compatible_with(b_type) { + if a_type.is_vector() { + // Vector types need to be bitcast. + // TODO(antoyo): perhaps use __builtin_convertvector for vector casting. + b = self.context.new_bitcast(self.location, b, a_type); + } else { + b = self.context.new_cast(self.location, b, a_type); + } + } self.context.new_binary_op(self.location, operation, a_type, a, b) } else { debug_assert!(a_type.dyncast_array().is_some()); @@ -351,6 +363,11 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // TODO(antoyo): is it correct to use rhs type instead of the parameter typ? .new_local(self.location, rhs.get_type(), "binopResult") .get_address(self.location); + let new_type = type_kind_to_gcc_type(new_kind); + let new_type = self.context.new_c_type(new_type); + let lhs = self.context.new_cast(self.location, lhs, new_type); + let rhs = self.context.new_cast(self.location, rhs, new_type); + let res = self.context.new_cast(self.location, res, new_type.make_pointer()); let overflow = self.overflow_call(intrinsic, &[lhs, rhs, res], None); (res.dereference(self.location).to_rvalue(), overflow) } @@ -477,11 +494,27 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let lhs_low = self.context.new_cast(self.location, self.low(lhs), unsigned_type); let rhs_low = self.context.new_cast(self.location, self.low(rhs), unsigned_type); + let mut lhs_high = self.high(lhs); + let mut rhs_high = self.high(rhs); + + match op { + IntPredicate::IntUGT + | IntPredicate::IntUGE + | IntPredicate::IntULT + | IntPredicate::IntULE => { + lhs_high = self.context.new_cast(self.location, lhs_high, unsigned_type); + rhs_high = self.context.new_cast(self.location, rhs_high, unsigned_type); + } + // TODO(antoyo): we probably need to handle signed comparison for unsigned + // integers. + _ => (), + } + let condition = self.context.new_comparison( self.location, ComparisonOp::LessThan, - self.high(lhs), - self.high(rhs), + lhs_high, + rhs_high, ); self.llbb().end_with_conditional(self.location, condition, block1, block2); @@ -495,8 +528,8 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let condition = self.context.new_comparison( self.location, ComparisonOp::GreaterThan, - self.high(lhs), - self.high(rhs), + lhs_high, + rhs_high, ); block2.end_with_conditional(self.location, condition, block3, block4); @@ -620,7 +653,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { } } - pub fn gcc_xor(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + pub fn gcc_xor(&self, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> { let a_type = a.get_type(); let b_type = b.get_type(); if a_type.is_vector() && b_type.is_vector() { @@ -628,6 +661,9 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { a ^ b } else if self.is_native_int_type_or_bool(a_type) && self.is_native_int_type_or_bool(b_type) { + if !a_type.is_compatible_with(b_type) { + b = self.context.new_cast(self.location, b, a_type); + } a ^ b } else { self.concat_low_high_rvalues( @@ -1042,3 +1078,25 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { self.context.new_array_constructor(None, typ, &values) } } + +fn type_kind_to_gcc_type<I: Interner>(kind: TyKind<I>) -> CType { + use rustc_middle::ty::IntTy::*; + use rustc_middle::ty::UintTy::*; + use rustc_middle::ty::{Int, Uint}; + + match kind { + Int(I8) => CType::Int8t, + Int(I16) => CType::Int16t, + Int(I32) => CType::Int32t, + Int(I64) => CType::Int64t, + Int(I128) => CType::Int128t, + + Uint(U8) => CType::UInt8t, + Uint(U16) => CType::UInt16t, + Uint(U32) => CType::UInt32t, + Uint(U64) => CType::UInt64t, + Uint(U128) => CType::UInt128t, + + _ => unimplemented!("Kind: {:?}", kind), + } +} diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/archs.rs b/compiler/rustc_codegen_gcc/src/intrinsic/archs.rs index 915ed875e32..d1b2a93243d 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/archs.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/archs.rs @@ -95,8 +95,11 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { "cubema" => "__builtin_amdgcn_cubema", "cubesc" => "__builtin_amdgcn_cubesc", "cubetc" => "__builtin_amdgcn_cubetc", + "cvt.f16.bf8" => "__builtin_amdgcn_cvt_f16_bf8", + "cvt.f16.fp8" => "__builtin_amdgcn_cvt_f16_fp8", "cvt.f32.bf8" => "__builtin_amdgcn_cvt_f32_bf8", "cvt.f32.fp8" => "__builtin_amdgcn_cvt_f32_fp8", + "cvt.f32.fp8.e5m3" => "__builtin_amdgcn_cvt_f32_fp8_e5m3", "cvt.off.f32.i4" => "__builtin_amdgcn_cvt_off_f32_i4", "cvt.pk.bf8.f32" => "__builtin_amdgcn_cvt_pk_bf8_f32", "cvt.pk.f16.bf8" => "__builtin_amdgcn_cvt_pk_f16_bf8", @@ -181,6 +184,12 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { "dot4.f32.fp8.bf8" => "__builtin_amdgcn_dot4_f32_fp8_bf8", "dot4.f32.fp8.fp8" => "__builtin_amdgcn_dot4_f32_fp8_fp8", "ds.add.gs.reg.rtn" => "__builtin_amdgcn_ds_add_gs_reg_rtn", + "ds.atomic.async.barrier.arrive.b64" => { + "__builtin_amdgcn_ds_atomic_async_barrier_arrive_b64" + } + "ds.atomic.barrier.arrive.rtn.b64" => { + "__builtin_amdgcn_ds_atomic_barrier_arrive_rtn_b64" + } "ds.bpermute" => "__builtin_amdgcn_ds_bpermute", "ds.bpermute.fi.b32" => "__builtin_amdgcn_ds_bpermute_fi_b32", "ds.gws.barrier" => "__builtin_amdgcn_ds_gws_barrier", @@ -198,8 +207,32 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { "fdot2.f16.f16" => "__builtin_amdgcn_fdot2_f16_f16", "fdot2.f32.bf16" => "__builtin_amdgcn_fdot2_f32_bf16", "fdot2c.f32.bf16" => "__builtin_amdgcn_fdot2c_f32_bf16", + "flat.prefetch" => "__builtin_amdgcn_flat_prefetch", "fmul.legacy" => "__builtin_amdgcn_fmul_legacy", + "global.load.async.to.lds.b128" => { + "__builtin_amdgcn_global_load_async_to_lds_b128" + } + "global.load.async.to.lds.b32" => { + "__builtin_amdgcn_global_load_async_to_lds_b32" + } + "global.load.async.to.lds.b64" => { + "__builtin_amdgcn_global_load_async_to_lds_b64" + } + "global.load.async.to.lds.b8" => "__builtin_amdgcn_global_load_async_to_lds_b8", "global.load.lds" => "__builtin_amdgcn_global_load_lds", + "global.prefetch" => "__builtin_amdgcn_global_prefetch", + "global.store.async.from.lds.b128" => { + "__builtin_amdgcn_global_store_async_from_lds_b128" + } + "global.store.async.from.lds.b32" => { + "__builtin_amdgcn_global_store_async_from_lds_b32" + } + "global.store.async.from.lds.b64" => { + "__builtin_amdgcn_global_store_async_from_lds_b64" + } + "global.store.async.from.lds.b8" => { + "__builtin_amdgcn_global_store_async_from_lds_b8" + } "groupstaticsize" => "__builtin_amdgcn_groupstaticsize", "iglp.opt" => "__builtin_amdgcn_iglp_opt", "implicit.buffer.ptr" => "__builtin_amdgcn_implicit_buffer_ptr", @@ -291,6 +324,7 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { "s.incperflevel" => "__builtin_amdgcn_s_incperflevel", "s.memrealtime" => "__builtin_amdgcn_s_memrealtime", "s.memtime" => "__builtin_amdgcn_s_memtime", + "s.monitor.sleep" => "__builtin_amdgcn_s_monitor_sleep", "s.sendmsg" => "__builtin_amdgcn_s_sendmsg", "s.sendmsghalt" => "__builtin_amdgcn_s_sendmsghalt", "s.setprio" => "__builtin_amdgcn_s_setprio", @@ -300,11 +334,15 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { "s.sleep.var" => "__builtin_amdgcn_s_sleep_var", "s.ttracedata" => "__builtin_amdgcn_s_ttracedata", "s.ttracedata.imm" => "__builtin_amdgcn_s_ttracedata_imm", + "s.wait.asynccnt" => "__builtin_amdgcn_s_wait_asynccnt", "s.wait.event.export.ready" => "__builtin_amdgcn_s_wait_event_export_ready", + "s.wait.tensorcnt" => "__builtin_amdgcn_s_wait_tensorcnt", "s.waitcnt" => "__builtin_amdgcn_s_waitcnt", "sad.hi.u8" => "__builtin_amdgcn_sad_hi_u8", "sad.u16" => "__builtin_amdgcn_sad_u16", "sad.u8" => "__builtin_amdgcn_sad_u8", + "sat.pk4.i4.i8" => "__builtin_amdgcn_sat_pk4_i4_i8", + "sat.pk4.u4.u8" => "__builtin_amdgcn_sat_pk4_u4_u8", "sched.barrier" => "__builtin_amdgcn_sched_barrier", "sched.group.barrier" => "__builtin_amdgcn_sched_group_barrier", "sdot2" => "__builtin_amdgcn_sdot2", @@ -346,8 +384,13 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { "smfmac.i32.16x16x64.i8" => "__builtin_amdgcn_smfmac_i32_16x16x64_i8", "smfmac.i32.32x32x32.i8" => "__builtin_amdgcn_smfmac_i32_32x32x32_i8", "smfmac.i32.32x32x64.i8" => "__builtin_amdgcn_smfmac_i32_32x32x64_i8", + "struct.ptr.buffer.load.lds" => "__builtin_amdgcn_struct_ptr_buffer_load_lds", "sudot4" => "__builtin_amdgcn_sudot4", "sudot8" => "__builtin_amdgcn_sudot8", + "tensor.load.to.lds" => "__builtin_amdgcn_tensor_load_to_lds", + "tensor.load.to.lds.d2" => "__builtin_amdgcn_tensor_load_to_lds_d2", + "tensor.store.from.lds" => "__builtin_amdgcn_tensor_store_from_lds", + "tensor.store.from.lds.d2" => "__builtin_amdgcn_tensor_store_from_lds_d2", "udot2" => "__builtin_amdgcn_udot2", "udot4" => "__builtin_amdgcn_udot4", "udot8" => "__builtin_amdgcn_udot8", @@ -6326,6 +6369,23 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { } s390(name, full_name) } + "spv" => { + #[allow(non_snake_case)] + fn spv(name: &str, full_name: &str) -> &'static str { + match name { + // spv + "num.subgroups" => "__builtin_spirv_num_subgroups", + "subgroup.id" => "__builtin_spirv_subgroup_id", + "subgroup.local.invocation.id" => { + "__builtin_spirv_subgroup_local_invocation_id" + } + "subgroup.max.size" => "__builtin_spirv_subgroup_max_size", + "subgroup.size" => "__builtin_spirv_subgroup_size", + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), + } + } + spv(name, full_name) + } "ve" => { #[allow(non_snake_case)] fn ve(name: &str, full_name: &str) -> &'static str { diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 0753ac1aeb8..eb0a5336a1f 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -925,10 +925,17 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // TODO(antoyo): use width? let arg_type = arg.get_type(); let result_type = self.u32_type; + let arg = if arg_type.is_signed(self.cx) { + let new_type = arg_type.to_unsigned(self.cx); + self.gcc_int_cast(arg, new_type) + } else { + arg + }; + let arg_type = arg.get_type(); let count_leading_zeroes = // TODO(antoyo): write a new function Type::is_compatible_with(&Type) and use it here // instead of using is_uint(). - if arg_type.is_uint(self.cx) { + if arg_type.is_uchar(self.cx) || arg_type.is_ushort(self.cx) || arg_type.is_uint(self.cx) { "__builtin_clz" } else if arg_type.is_ulong(self.cx) { diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs index 350915a277e..fdc15d580ef 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs @@ -206,6 +206,28 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( ); } + #[cfg(feature = "master")] + if name == sym::simd_funnel_shl { + return Ok(simd_funnel_shift( + bx, + args[0].immediate(), + args[1].immediate(), + args[2].immediate(), + true, + )); + } + + #[cfg(feature = "master")] + if name == sym::simd_funnel_shr { + return Ok(simd_funnel_shift( + bx, + args[0].immediate(), + args[1].immediate(), + args[2].immediate(), + false, + )); + } + if name == sym::simd_bswap { return Ok(simd_bswap(bx, args[0].immediate())); } @@ -1434,3 +1456,62 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( unimplemented!("simd {}", name); } + +#[cfg(feature = "master")] +fn simd_funnel_shift<'a, 'gcc, 'tcx>( + bx: &mut Builder<'a, 'gcc, 'tcx>, + a: RValue<'gcc>, + b: RValue<'gcc>, + shift: RValue<'gcc>, + shift_left: bool, +) -> RValue<'gcc> { + use crate::common::SignType; + + let a_type = a.get_type(); + let vector_type = a_type.unqualified().dyncast_vector().expect("vector type"); + let num_units = vector_type.get_num_units(); + let elem_type = vector_type.get_element_type(); + + let (new_int_type, int_shift_val, int_mask) = if elem_type.is_compatible_with(bx.u8_type) + || elem_type.is_compatible_with(bx.i8_type) + { + (bx.u16_type, 8, u8::MAX as u64) + } else if elem_type.is_compatible_with(bx.u16_type) || elem_type.is_compatible_with(bx.i16_type) + { + (bx.u32_type, 16, u16::MAX as u64) + } else if elem_type.is_compatible_with(bx.u32_type) || elem_type.is_compatible_with(bx.i32_type) + { + (bx.u64_type, 32, u32::MAX as u64) + } else if elem_type.is_compatible_with(bx.u64_type) || elem_type.is_compatible_with(bx.i64_type) + { + (bx.u128_type, 64, u64::MAX) + } else { + unimplemented!("funnel shift on {:?}", elem_type); + }; + + let int_mask = bx.context.new_rvalue_from_long(new_int_type, int_mask as i64); + let int_shift_val = bx.context.new_rvalue_from_int(new_int_type, int_shift_val); + let mut elements = vec![]; + let unsigned_type = elem_type.to_unsigned(bx); + for i in 0..num_units { + let index = bx.context.new_rvalue_from_int(bx.int_type, i as i32); + let a_val = bx.context.new_vector_access(None, a, index).to_rvalue(); + let a_val = bx.context.new_bitcast(None, a_val, unsigned_type); + // TODO: we probably need to use gcc_int_cast instead. + let a_val = bx.gcc_int_cast(a_val, new_int_type); + let b_val = bx.context.new_vector_access(None, b, index).to_rvalue(); + let b_val = bx.context.new_bitcast(None, b_val, unsigned_type); + let b_val = bx.gcc_int_cast(b_val, new_int_type); + let shift_val = bx.context.new_vector_access(None, shift, index).to_rvalue(); + let shift_val = bx.gcc_int_cast(shift_val, new_int_type); + let mut val = a_val << int_shift_val | b_val; + if shift_left { + val = (val << shift_val) >> int_shift_val; + } else { + val = (val >> shift_val) & int_mask; + } + let val = bx.gcc_int_cast(val, elem_type); + elements.push(val); + } + bx.context.new_rvalue_from_vector(None, a_type, &elements) +} diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index a3120682500..b11f11d38e3 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -35,7 +35,6 @@ extern crate tracing; extern crate rustc_abi; extern crate rustc_apfloat; extern crate rustc_ast; -extern crate rustc_attr_data_structures; extern crate rustc_codegen_ssa; extern crate rustc_data_structures; extern crate rustc_errors; @@ -51,6 +50,7 @@ extern crate rustc_session; extern crate rustc_span; extern crate rustc_symbol_mangling; extern crate rustc_target; +extern crate rustc_type_ir; // This prevents duplicating functions and statics that are already part of the host rustc process. #[allow(unused_extern_crates)] @@ -363,9 +363,9 @@ impl WriteBackendMethods for GccCodegenBackend { _exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], modules: Vec<FatLtoInput<Self>>, - diff_fncs: Vec<AutoDiffItem>, + diff_functions: Vec<AutoDiffItem>, ) -> Result<ModuleCodegen<Self::Module>, FatalError> { - if !diff_fncs.is_empty() { + if !diff_functions.is_empty() { unimplemented!(); } diff --git a/compiler/rustc_codegen_gcc/tests/failing-lto-tests.txt b/compiler/rustc_codegen_gcc/tests/failing-lto-tests.txt index b9126fb73a7..bf0633f7320 100644 --- a/compiler/rustc_codegen_gcc/tests/failing-lto-tests.txt +++ b/compiler/rustc_codegen_gcc/tests/failing-lto-tests.txt @@ -28,6 +28,6 @@ tests/ui/macros/macro-comma-behavior-rpass.rs tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs tests/ui/macros/stringify.rs -tests/ui/reexport-test-harness-main.rs tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-in-test.rs tests/ui/binding/fn-arg-incomplete-pattern-drop-order.rs +tests/ui/lto/debuginfo-lto-alloc.rs diff --git a/compiler/rustc_codegen_gcc/tests/failing-run-make-tests.txt b/compiler/rustc_codegen_gcc/tests/failing-run-make-tests.txt index 842533cd3c6..29032b321fa 100644 --- a/compiler/rustc_codegen_gcc/tests/failing-run-make-tests.txt +++ b/compiler/rustc_codegen_gcc/tests/failing-run-make-tests.txt @@ -6,7 +6,6 @@ tests/run-make/doctests-keep-binaries/ tests/run-make/doctests-runtool/ tests/run-make/emit-shared-files/ tests/run-make/exit-code/ -tests/run-make/issue-22131/ tests/run-make/issue-64153/ tests/run-make/llvm-ident/ tests/run-make/native-link-modifier-bundle/ diff --git a/compiler/rustc_codegen_gcc/tests/failing-ui-tests.txt b/compiler/rustc_codegen_gcc/tests/failing-ui-tests.txt index 6979c04d534..41fb4729c07 100644 --- a/compiler/rustc_codegen_gcc/tests/failing-ui-tests.txt +++ b/compiler/rustc_codegen_gcc/tests/failing-ui-tests.txt @@ -10,11 +10,10 @@ tests/ui/iterators/iter-sum-overflow-overflow-checks.rs tests/ui/mir/mir_drop_order.rs tests/ui/mir/mir_let_chains_drop_order.rs tests/ui/mir/mir_match_guard_let_chains_drop_order.rs -tests/ui/oom_unwind.rs +tests/ui/panics/oom-panic-unwind.rs tests/ui/panic-runtime/abort-link-to-unwinding-crates.rs tests/ui/panic-runtime/abort.rs tests/ui/panic-runtime/link-to-abort.rs -tests/ui/unwind-no-uwtable.rs tests/ui/parser/unclosed-delimiter-in-dep.rs tests/ui/consts/missing_span_in_backtrace.rs tests/ui/drop/dynamic-drop.rs @@ -82,3 +81,8 @@ tests/ui/coroutine/panic-drops.rs tests/ui/coroutine/panic-safe.rs tests/ui/process/nofile-limit.rs tests/ui/simd/intrinsic/generic-arithmetic-pass.rs +tests/ui/linking/no-gc-encapsulation-symbols.rs +tests/ui/panics/unwind-force-no-unwind-tables.rs +tests/ui/attributes/fn-align-dyn.rs +tests/ui/linkage-attr/raw-dylib/elf/glibc-x86_64.rs +tests/ui/explicit-tail-calls/recursion-etc.rs diff --git a/compiler/rustc_codegen_gcc/tools/cspell_dicts/rustc_codegen_gcc.txt b/compiler/rustc_codegen_gcc/tools/cspell_dicts/rustc_codegen_gcc.txt index 31023e50ffa..4fb018b3ecd 100644 --- a/compiler/rustc_codegen_gcc/tools/cspell_dicts/rustc_codegen_gcc.txt +++ b/compiler/rustc_codegen_gcc/tools/cspell_dicts/rustc_codegen_gcc.txt @@ -8,6 +8,7 @@ clzll cmse codegened csky +ctfe ctlz ctpop cttz @@ -25,6 +26,7 @@ fwrapv gimple hrtb immediates +interner liblto llbb llcx @@ -47,6 +49,7 @@ mavx mcmodel minimumf minnumf +miri monomorphization monomorphizations monomorphized diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index 5ab22f8fc4d..2d11628250c 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -19,7 +19,6 @@ object = { version = "0.37.0", default-features = false, features = ["std", "rea rustc-demangle = "0.1.21" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } -rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_codegen_ssa = { path = "../rustc_codegen_ssa" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } @@ -38,11 +37,14 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_symbol_mangling = { path = "../rustc_symbol_mangling" } rustc_target = { path = "../rustc_target" } -serde = { version = "1", features = [ "derive" ]} +serde = { version = "1", features = ["derive"] } serde_json = "1" smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" # tidy-alphabetical-end [features] +# tidy-alphabetical-start check_only = ["rustc_llvm/check_only"] +# tidy-alphabetical-end + diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index c32f11b27f3..c548f467583 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -1,6 +1,6 @@ //! Set and unset common attributes on LLVM values. -use rustc_attr_data_structures::{InlineAttr, InstructionSetAttr, OptimizeAttr}; use rustc_codegen_ssa::traits::*; +use rustc_hir::attrs::{InlineAttr, InstructionSetAttr, OptimizeAttr}; use rustc_hir::def_id::DefId; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, PatchableFunctionEntry}; use rustc_middle::ty::{self, TyCtxt}; diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index f712b3b83fa..32cdef075e7 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -15,6 +15,7 @@ use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::*; use rustc_data_structures::small_c_str::SmallCStr; use rustc_hir::def_id::DefId; +use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::ty::layout::{ FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTypingEnv, LayoutError, LayoutOfHelpers, @@ -24,7 +25,7 @@ use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_sanitizers::{cfi, kcfi}; use rustc_session::config::OptLevel; use rustc_span::Span; -use rustc_target::callconv::FnAbi; +use rustc_target::callconv::{FnAbi, PassMode}; use rustc_target::spec::{HasTargetSpec, SanitizerSet, Target}; use smallvec::SmallVec; use tracing::{debug, instrument}; @@ -1326,15 +1327,13 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { &mut self, op: rustc_codegen_ssa::common::AtomicRmwBinOp, dst: &'ll Value, - mut src: &'ll Value, + src: &'ll Value, order: rustc_middle::ty::AtomicOrdering, + ret_ptr: bool, ) -> &'ll Value { - // The only RMW operation that LLVM supports on pointers is compare-exchange. - let requires_cast_to_int = self.val_ty(src) == self.type_ptr() - && op != rustc_codegen_ssa::common::AtomicRmwBinOp::AtomicXchg; - if requires_cast_to_int { - src = self.ptrtoint(src, self.type_isize()); - } + // FIXME: If `ret_ptr` is true and `src` is not a pointer, we *should* tell LLVM that the + // LHS is a pointer and the operation should be provenance-preserving, but LLVM does not + // currently support that (https://github.com/llvm/llvm-project/issues/120837). let mut res = unsafe { llvm::LLVMBuildAtomicRMW( self.llbuilder, @@ -1345,7 +1344,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { llvm::False, // SingleThreaded ) }; - if requires_cast_to_int { + if ret_ptr && self.val_ty(res) != self.type_ptr() { res = self.inttoptr(res, self.type_ptr()); } res @@ -1431,6 +1430,28 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { call } + fn tail_call( + &mut self, + llty: Self::Type, + fn_attrs: Option<&CodegenFnAttrs>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + llfn: Self::Value, + args: &[Self::Value], + funclet: Option<&Self::Funclet>, + instance: Option<Instance<'tcx>>, + ) { + let call = self.call(llty, fn_attrs, Some(fn_abi), llfn, args, funclet, instance); + llvm::LLVMRustSetTailCallKind(call, llvm::TailCallKind::MustTail); + + match &fn_abi.ret.mode { + PassMode::Ignore | PassMode::Indirect { .. } => self.ret_void(), + PassMode::Direct(_) | PassMode::Pair { .. } => self.ret(call), + mode @ PassMode::Cast { .. } => { + bug!("Encountered `PassMode::{mode:?}` during codegen") + } + } + } + fn zext(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { unsafe { llvm::LLVMBuildZExt(self.llbuilder, val, dest_ty, UNNAMED) } } @@ -1863,48 +1884,4 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { ) { self.call_intrinsic("llvm.instrprof.increment", &[], &[fn_name, hash, num_counters, index]); } - - /// Emits a call to `llvm.instrprof.mcdc.parameters`. - /// - /// This doesn't produce any code directly, but is used as input by - /// the LLVM pass that handles coverage instrumentation. - /// - /// (See clang's [`CodeGenPGO::emitMCDCParameters`] for comparison.) - /// - /// [`CodeGenPGO::emitMCDCParameters`]: - /// https://github.com/rust-lang/llvm-project/blob/5399a24/clang/lib/CodeGen/CodeGenPGO.cpp#L1124 - #[instrument(level = "debug", skip(self))] - pub(crate) fn mcdc_parameters( - &mut self, - fn_name: &'ll Value, - hash: &'ll Value, - bitmap_bits: &'ll Value, - ) { - self.call_intrinsic("llvm.instrprof.mcdc.parameters", &[], &[fn_name, hash, bitmap_bits]); - } - - #[instrument(level = "debug", skip(self))] - pub(crate) fn mcdc_tvbitmap_update( - &mut self, - fn_name: &'ll Value, - hash: &'ll Value, - bitmap_index: &'ll Value, - mcdc_temp: &'ll Value, - ) { - let args = &[fn_name, hash, bitmap_index, mcdc_temp]; - self.call_intrinsic("llvm.instrprof.mcdc.tvbitmap.update", &[], args); - } - - #[instrument(level = "debug", skip(self))] - pub(crate) fn mcdc_condbitmap_reset(&mut self, mcdc_temp: &'ll Value) { - self.store(self.const_i32(0), mcdc_temp, self.tcx.data_layout.i32_align.abi); - } - - #[instrument(level = "debug", skip(self))] - pub(crate) fn mcdc_condbitmap_update(&mut self, cond_index: &'ll Value, mcdc_temp: &'ll Value) { - let align = self.tcx.data_layout.i32_align.abi; - let current_tv_index = self.load(self.cx.type_i32(), mcdc_temp, align); - let new_tv_index = self.add(current_tv_index, cond_index); - self.store(new_tv_index, mcdc_temp, align); - } } diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs index 5a3dd90ab24..791a71d73ae 100644 --- a/compiler/rustc_codegen_llvm/src/callee.rs +++ b/compiler/rustc_codegen_llvm/src/callee.rs @@ -103,7 +103,7 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t // This is a monomorphization of a generic function. if !(cx.tcx.sess.opts.share_generics() || tcx.codegen_instance_attrs(instance.def).inline - == rustc_attr_data_structures::InlineAttr::Never) + == rustc_hir::attrs::InlineAttr::Never) { // When not sharing generics, all instances are in the same // crate and have hidden visibility. diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 0b96b63bc85..6b06daf3477 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -5,7 +5,7 @@ use rustc_codegen_ssa::common; use rustc_codegen_ssa::traits::*; use rustc_hir::LangItem; use rustc_hir::def::DefKind; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::interpret::{ Allocation, ConstAllocation, ErrorHandled, InitChunk, Pointer, Scalar as InterpScalar, @@ -191,8 +191,8 @@ fn check_and_apply_linkage<'ll, 'tcx>( // linkage and there are no definitions), then // `extern_with_linkage_foo` will instead be initialized to // zero. - let mut real_name = "_rust_extern_with_linkage_".to_string(); - real_name.push_str(sym); + let real_name = + format!("_rust_extern_with_linkage_{:016x}_{sym}", cx.tcx.stable_crate_id(LOCAL_CRATE)); let g2 = cx.define_global(&real_name, llty).unwrap_or_else(|| { cx.sess().dcx().emit_fatal(SymbolAlreadyDefined { span: cx.tcx.def_span(def_id), diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs index f6000e72840..a4b60d420f3 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs @@ -73,48 +73,6 @@ pub(crate) struct CounterExpression { pub(crate) rhs: Counter, } -pub(crate) mod mcdc { - use rustc_middle::mir::coverage::{ConditionId, ConditionInfo, DecisionInfo}; - - /// Must match the layout of `LLVMRustMCDCDecisionParameters`. - #[repr(C)] - #[derive(Clone, Copy, Debug, Default)] - pub(crate) struct DecisionParameters { - bitmap_idx: u32, - num_conditions: u16, - } - - type LLVMConditionId = i16; - - /// Must match the layout of `LLVMRustMCDCBranchParameters`. - #[repr(C)] - #[derive(Clone, Copy, Debug, Default)] - pub(crate) struct BranchParameters { - condition_id: LLVMConditionId, - condition_ids: [LLVMConditionId; 2], - } - - impl From<ConditionInfo> for BranchParameters { - fn from(value: ConditionInfo) -> Self { - let to_llvm_cond_id = |cond_id: Option<ConditionId>| { - cond_id.and_then(|id| LLVMConditionId::try_from(id.as_usize()).ok()).unwrap_or(-1) - }; - let ConditionInfo { condition_id, true_next_id, false_next_id } = value; - Self { - condition_id: to_llvm_cond_id(Some(condition_id)), - condition_ids: [to_llvm_cond_id(false_next_id), to_llvm_cond_id(true_next_id)], - } - } - } - - impl From<DecisionInfo> for DecisionParameters { - fn from(info: DecisionInfo) -> Self { - let DecisionInfo { bitmap_idx, num_conditions } = info; - Self { bitmap_idx, num_conditions } - } - } -} - /// A span of source code coordinates to be embedded in coverage metadata. /// /// Must match the layout of `LLVMRustCoverageSpan`. @@ -148,26 +106,14 @@ pub(crate) struct Regions { pub(crate) code_regions: Vec<CodeRegion>, pub(crate) expansion_regions: Vec<ExpansionRegion>, pub(crate) branch_regions: Vec<BranchRegion>, - pub(crate) mcdc_branch_regions: Vec<MCDCBranchRegion>, - pub(crate) mcdc_decision_regions: Vec<MCDCDecisionRegion>, } impl Regions { /// Returns true if none of this structure's tables contain any regions. pub(crate) fn has_no_regions(&self) -> bool { - let Self { - code_regions, - expansion_regions, - branch_regions, - mcdc_branch_regions, - mcdc_decision_regions, - } = self; - - code_regions.is_empty() - && expansion_regions.is_empty() - && branch_regions.is_empty() - && mcdc_branch_regions.is_empty() - && mcdc_decision_regions.is_empty() + let Self { code_regions, expansion_regions, branch_regions } = self; + + code_regions.is_empty() && expansion_regions.is_empty() && branch_regions.is_empty() } } @@ -195,21 +141,3 @@ pub(crate) struct BranchRegion { pub(crate) true_counter: Counter, pub(crate) false_counter: Counter, } - -/// Must match the layout of `LLVMRustCoverageMCDCBranchRegion`. -#[derive(Clone, Debug)] -#[repr(C)] -pub(crate) struct MCDCBranchRegion { - pub(crate) cov_span: CoverageSpan, - pub(crate) true_counter: Counter, - pub(crate) false_counter: Counter, - pub(crate) mcdc_branch_params: mcdc::BranchParameters, -} - -/// Must match the layout of `LLVMRustCoverageMCDCDecisionRegion`. -#[derive(Clone, Debug)] -#[repr(C)] -pub(crate) struct MCDCDecisionRegion { - pub(crate) cov_span: CoverageSpan, - pub(crate) mcdc_decision_params: mcdc::DecisionParameters, -} diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs index 907d6d41a1f..bc4f6bb6a82 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs @@ -63,13 +63,7 @@ pub(crate) fn write_function_mappings_to_buffer( expressions: &[ffi::CounterExpression], regions: &ffi::Regions, ) -> Vec<u8> { - let ffi::Regions { - code_regions, - expansion_regions, - branch_regions, - mcdc_branch_regions, - mcdc_decision_regions, - } = regions; + let ffi::Regions { code_regions, expansion_regions, branch_regions } = regions; // SAFETY: // - All types are FFI-compatible and have matching representations in Rust/C++. @@ -87,10 +81,6 @@ pub(crate) fn write_function_mappings_to_buffer( expansion_regions.len(), branch_regions.as_ptr(), branch_regions.len(), - mcdc_branch_regions.as_ptr(), - mcdc_branch_regions.len(), - mcdc_decision_regions.as_ptr(), - mcdc_decision_regions.len(), buffer, ) }) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 8c9dfcfd18c..d1cb95507d9 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -1,3 +1,4 @@ +use std::assert_matches::assert_matches; use std::sync::Arc; use itertools::Itertools; @@ -5,6 +6,7 @@ use rustc_abi::Align; use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, ConstCodegenMethods}; use rustc_data_structures::fx::FxIndexMap; use rustc_index::IndexVec; +use rustc_macros::TryFromU32; use rustc_middle::ty::TyCtxt; use rustc_session::RemapFileNameExt; use rustc_session::config::RemapPathScopeComponents; @@ -20,6 +22,23 @@ mod covfun; mod spans; mod unused; +/// Version number that will be included the `__llvm_covmap` section header. +/// Corresponds to LLVM's `llvm::coverage::CovMapVersion` (in `CoverageMapping.h`), +/// or at least the subset that we know and care about. +/// +/// Note that version `n` is encoded as `(n-1)`. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, TryFromU32)] +enum CovmapVersion { + /// Used by LLVM 18 onwards. + Version7 = 6, +} + +impl CovmapVersion { + fn to_u32(self) -> u32 { + self as u32 + } +} + /// Generates and exports the coverage map, which is embedded in special /// linker sections in the final binary. /// @@ -29,19 +48,13 @@ pub(crate) fn finalize(cx: &mut CodegenCx<'_, '_>) { let tcx = cx.tcx; // Ensure that LLVM is using a version of the coverage mapping format that - // agrees with our Rust-side code. Expected versions (encoded as n-1) are: - // - `CovMapVersion::Version7` (6) used by LLVM 18-19 - let covmap_version = { - let llvm_covmap_version = llvm_cov::mapping_version(); - let expected_versions = 6..=6; - assert!( - expected_versions.contains(&llvm_covmap_version), - "Coverage mapping version exposed by `llvm-wrapper` is out of sync; \ - expected {expected_versions:?} but was {llvm_covmap_version}" - ); - // This is the version number that we will embed in the covmap section: - llvm_covmap_version - }; + // agrees with our Rust-side code. Expected versions are: + // - `Version7` (6) used by LLVM 18 onwards. + let covmap_version = + CovmapVersion::try_from(llvm_cov::mapping_version()).unwrap_or_else(|raw_version: u32| { + panic!("unknown coverage mapping version reported by `llvm-wrapper`: {raw_version}") + }); + assert_matches!(covmap_version, CovmapVersion::Version7); debug!("Generating coverage map for CodegenUnit: `{}`", cx.codegen_unit.name()); @@ -201,7 +214,11 @@ impl VirtualFileMapping { /// Generates the contents of the covmap record for this CGU, which mostly /// consists of a header and a list of filenames. The record is then stored /// as a global variable in the `__llvm_covmap` section. -fn generate_covmap_record<'ll>(cx: &mut CodegenCx<'ll, '_>, version: u32, filenames_buffer: &[u8]) { +fn generate_covmap_record<'ll>( + cx: &mut CodegenCx<'ll, '_>, + version: CovmapVersion, + filenames_buffer: &[u8], +) { // A covmap record consists of four target-endian u32 values, followed by // the encoded filenames table. Two of the header fields are unused in // modern versions of the LLVM coverage mapping format, and are always 0. @@ -212,7 +229,7 @@ fn generate_covmap_record<'ll>(cx: &mut CodegenCx<'ll, '_>, version: u32, filena cx.const_u32(0), // (unused) cx.const_u32(filenames_buffer.len() as u32), cx.const_u32(0), // (unused) - cx.const_u32(version), + cx.const_u32(version.to_u32()), ], /* packed */ false, ); diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs index b704cf2b1cd..e0da8d36876 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs @@ -27,6 +27,9 @@ use crate::llvm; /// the final record that will be embedded in the `__llvm_covfun` section. #[derive(Debug)] pub(crate) struct CovfunRecord<'tcx> { + /// Not used directly, but helpful in debug messages. + _instance: Instance<'tcx>, + mangled_function_name: &'tcx str, source_hash: u64, is_used: bool, @@ -55,6 +58,7 @@ pub(crate) fn prepare_covfun_record<'tcx>( let expressions = prepare_expressions(ids_info); let mut covfun = CovfunRecord { + _instance: instance, mangled_function_name: tcx.symbol_name(instance).name, source_hash: if is_used { fn_cov_info.function_source_hash } else { 0 }, is_used, @@ -102,11 +106,21 @@ fn fill_region_tables<'tcx>( ids_info: &'tcx CoverageIdsInfo, covfun: &mut CovfunRecord<'tcx>, ) { + // If this function is unused, replace all counters with zero. + let counter_for_bcb = |bcb: BasicCoverageBlock| -> ffi::Counter { + let term = if covfun.is_used { + ids_info.term_for_bcb[bcb].expect("every BCB in a mapping was given a term") + } else { + CovTerm::Zero + }; + ffi::Counter::from_term(term) + }; + // Currently a function's mappings must all be in the same file, so use the // first mapping's span to determine the file. let source_map = tcx.sess.source_map(); let Some(first_span) = (try { fn_cov_info.mappings.first()?.span }) else { - debug_assert!(false, "function has no mappings: {:?}", covfun.mangled_function_name); + debug_assert!(false, "function has no mappings: {covfun:?}"); return; }; let source_file = source_map.lookup_source_file(first_span.lo()); @@ -117,7 +131,7 @@ fn fill_region_tables<'tcx>( // codegen needs to handle that gracefully to avoid #133606. // It's hard for tests to trigger this organically, so instead we set // `-Zcoverage-options=discard-all-spans-in-codegen` to force it to occur. - let discard_all = tcx.sess.coverage_discard_all_spans_in_codegen(); + let discard_all = tcx.sess.coverage_options().discard_all_spans_in_codegen; let make_coords = |span: Span| { if discard_all { None } else { spans::make_coords(source_map, &source_file, span) } }; @@ -126,23 +140,11 @@ fn fill_region_tables<'tcx>( code_regions, expansion_regions: _, // FIXME(Zalathar): Fill out support for expansion regions branch_regions, - mcdc_branch_regions, - mcdc_decision_regions, } = &mut covfun.regions; // For each counter/region pair in this function+file, convert it to a // form suitable for FFI. for &Mapping { ref kind, span } in &fn_cov_info.mappings { - // If this function is unused, replace all counters with zero. - let counter_for_bcb = |bcb: BasicCoverageBlock| -> ffi::Counter { - let term = if covfun.is_used { - ids_info.term_for_bcb[bcb].expect("every BCB in a mapping was given a term") - } else { - CovTerm::Zero - }; - ffi::Counter::from_term(term) - }; - let Some(coords) = make_coords(span) else { continue }; let cov_span = coords.make_coverage_span(local_file_id); @@ -157,20 +159,6 @@ fn fill_region_tables<'tcx>( false_counter: counter_for_bcb(false_bcb), }); } - MappingKind::MCDCBranch { true_bcb, false_bcb, mcdc_params } => { - mcdc_branch_regions.push(ffi::MCDCBranchRegion { - cov_span, - true_counter: counter_for_bcb(true_bcb), - false_counter: counter_for_bcb(false_bcb), - mcdc_branch_params: ffi::mcdc::BranchParameters::from(mcdc_params), - }); - } - MappingKind::MCDCDecision(mcdc_decision_params) => { - mcdc_decision_regions.push(ffi::MCDCDecisionRegion { - cov_span, - mcdc_decision_params: ffi::mcdc::DecisionParameters::from(mcdc_decision_params), - }); - } } } } @@ -184,6 +172,7 @@ pub(crate) fn generate_covfun_record<'tcx>( covfun: &CovfunRecord<'tcx>, ) { let &CovfunRecord { + _instance, mangled_function_name, source_hash, is_used, diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs index 39a59560c9d..574463be7ff 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs @@ -39,7 +39,10 @@ impl Coords { /// or other expansions), and if it does happen then skipping a span or function is /// better than an ICE or `llvm-cov` failure that the user might have no way to avoid. pub(crate) fn make_coords(source_map: &SourceMap, file: &SourceFile, span: Span) -> Option<Coords> { - let span = ensure_non_empty_span(source_map, span)?; + if span.is_empty() { + debug_assert!(false, "can't make coords from empty span: {span:?}"); + return None; + } let lo = span.lo(); let hi = span.hi(); @@ -70,29 +73,6 @@ pub(crate) fn make_coords(source_map: &SourceMap, file: &SourceFile, span: Span) }) } -fn ensure_non_empty_span(source_map: &SourceMap, span: Span) -> Option<Span> { - if !span.is_empty() { - return Some(span); - } - - // The span is empty, so try to enlarge it to cover an adjacent '{' or '}'. - source_map - .span_to_source(span, |src, start, end| try { - // Adjusting span endpoints by `BytePos(1)` is normally a bug, - // but in this case we have specifically checked that the character - // we're skipping over is one of two specific ASCII characters, so - // adjusting by exactly 1 byte is correct. - if src.as_bytes().get(end).copied() == Some(b'{') { - Some(span.with_hi(span.hi() + BytePos(1))) - } else if start > 0 && src.as_bytes()[start - 1] == b'}' { - Some(span.with_lo(span.lo() - BytePos(1))) - } else { - None - } - }) - .ok()? -} - /// If `llvm-cov` sees a source region that is improperly ordered (end < start), /// it will immediately exit with a fatal error. To prevent that from happening, /// discard regions that are improperly ordered, or might be interpreted in a diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs index 119237abd6b..6a58f495c9d 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs @@ -1,11 +1,10 @@ use std::cell::{OnceCell, RefCell}; use std::ffi::{CStr, CString}; -use rustc_abi::Size; use rustc_codegen_ssa::traits::{ - BuilderMethods, ConstCodegenMethods, CoverageInfoBuilderMethods, MiscCodegenMethods, + ConstCodegenMethods, CoverageInfoBuilderMethods, MiscCodegenMethods, }; -use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; +use rustc_data_structures::fx::FxIndexMap; use rustc_middle::mir::coverage::CoverageKind; use rustc_middle::ty::Instance; use tracing::{debug, instrument}; @@ -28,34 +27,13 @@ pub(crate) struct CguCoverageContext<'ll, 'tcx> { /// symbol name, and `llvm-cov` will exit fatally if it can't resolve that /// hash back to an entry in the binary's `__llvm_prf_names` linker section. pub(crate) pgo_func_name_var_map: RefCell<FxIndexMap<Instance<'tcx>, &'ll llvm::Value>>, - pub(crate) mcdc_condition_bitmap_map: RefCell<FxHashMap<Instance<'tcx>, Vec<&'ll llvm::Value>>>, covfun_section_name: OnceCell<CString>, } impl<'ll, 'tcx> CguCoverageContext<'ll, 'tcx> { pub(crate) fn new() -> Self { - Self { - pgo_func_name_var_map: Default::default(), - mcdc_condition_bitmap_map: Default::default(), - covfun_section_name: Default::default(), - } - } - - /// LLVM use a temp value to record evaluated mcdc test vector of each decision, which is - /// called condition bitmap. In order to handle nested decisions, several condition bitmaps can - /// be allocated for a function body. These values are named `mcdc.addr.{i}` and are a 32-bit - /// integers. They respectively hold the condition bitmaps for decisions with a depth of `i`. - fn try_get_mcdc_condition_bitmap( - &self, - instance: &Instance<'tcx>, - decision_depth: u16, - ) -> Option<&'ll llvm::Value> { - self.mcdc_condition_bitmap_map - .borrow() - .get(instance) - .and_then(|bitmap_map| bitmap_map.get(decision_depth as usize)) - .copied() // Dereference Option<&&Value> to Option<&Value> + Self { pgo_func_name_var_map: Default::default(), covfun_section_name: Default::default() } } /// Returns the list of instances considered "used" in this CGU, as @@ -105,38 +83,6 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { } impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { - fn init_coverage(&mut self, instance: Instance<'tcx>) { - let Some(function_coverage_info) = - self.tcx.instance_mir(instance.def).function_coverage_info.as_deref() - else { - return; - }; - - // If there are no MC/DC bitmaps to set up, return immediately. - if function_coverage_info.mcdc_bitmap_bits == 0 { - return; - } - - let fn_name = self.ensure_pgo_func_name_var(instance); - let hash = self.const_u64(function_coverage_info.function_source_hash); - let bitmap_bits = self.const_u32(function_coverage_info.mcdc_bitmap_bits as u32); - self.mcdc_parameters(fn_name, hash, bitmap_bits); - - // Create pointers named `mcdc.addr.{i}` to stack-allocated condition bitmaps. - let mut cond_bitmaps = vec![]; - for i in 0..function_coverage_info.mcdc_num_condition_bitmaps { - // MC/DC intrinsics will perform loads/stores that use the ABI default - // alignment for i32, so our variable declaration should match. - let align = self.tcx.data_layout.i32_align.abi; - let cond_bitmap = self.alloca(Size::from_bytes(4), align); - llvm::set_value_name(cond_bitmap, format!("mcdc.addr.{i}").as_bytes()); - self.store(self.const_i32(0), cond_bitmap, align); - cond_bitmaps.push(cond_bitmap); - } - - self.coverage_cx().mcdc_condition_bitmap_map.borrow_mut().insert(instance, cond_bitmaps); - } - #[instrument(level = "debug", skip(self))] fn add_coverage(&mut self, instance: Instance<'tcx>, kind: &CoverageKind) { // Our caller should have already taken care of inlining subtleties, @@ -153,7 +99,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { // When that happens, we currently just discard those statements, so // the corresponding code will be undercounted. // FIXME(Zalathar): Find a better solution for mixed-coverage builds. - let Some(coverage_cx) = &bx.cx.coverage_cx else { return }; + let Some(_coverage_cx) = &bx.cx.coverage_cx else { return }; let Some(function_coverage_info) = bx.tcx.instance_mir(instance.def).function_coverage_info.as_deref() @@ -185,30 +131,6 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { } // If a BCB doesn't have an associated physical counter, there's nothing to codegen. CoverageKind::VirtualCounter { .. } => {} - CoverageKind::CondBitmapUpdate { index, decision_depth } => { - let cond_bitmap = coverage_cx - .try_get_mcdc_condition_bitmap(&instance, decision_depth) - .expect("mcdc cond bitmap should have been allocated for updating"); - let cond_index = bx.const_i32(index as i32); - bx.mcdc_condbitmap_update(cond_index, cond_bitmap); - } - CoverageKind::TestVectorBitmapUpdate { bitmap_idx, decision_depth } => { - let cond_bitmap = - coverage_cx.try_get_mcdc_condition_bitmap(&instance, decision_depth).expect( - "mcdc cond bitmap should have been allocated for merging \ - into the global bitmap", - ); - assert!( - bitmap_idx as usize <= function_coverage_info.mcdc_bitmap_bits, - "bitmap index of the decision out of range" - ); - - let fn_name = bx.ensure_pgo_func_name_var(instance); - let hash = bx.const_u64(function_coverage_info.function_source_hash); - let bitmap_index = bx.const_u32(bitmap_idx); - bx.mcdc_tvbitmap_update(fn_name, hash, bitmap_index, cond_bitmap); - bx.mcdc_condbitmap_reset(cond_bitmap); - } } } } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs index 61555ac2f6f..6eb7042da61 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs @@ -1,6 +1,5 @@ // .debug_gdb_scripts binary section. -use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_codegen_ssa::base::collect_debugger_visualizers_transitive; use rustc_codegen_ssa::traits::*; use rustc_hir::def_id::LOCAL_CRATE; @@ -85,9 +84,6 @@ pub(crate) fn get_or_insert_gdb_debug_scripts_section_global<'ll>( } pub(crate) fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool { - let omit_gdb_pretty_printer_section = - find_attr!(cx.tcx.hir_krate_attrs(), AttributeKind::OmitGdbPrettyPrinterSection); - // To ensure the section `__rustc_debug_gdb_scripts_section__` will not create // ODR violations at link time, this section will not be emitted for rlibs since // each rlib could produce a different set of visualizers that would be embedded @@ -116,8 +112,7 @@ pub(crate) fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool { } }); - !omit_gdb_pretty_printer_section - && cx.sess().opts.debuginfo != DebugInfo::None + cx.sess().opts.debuginfo != DebugInfo::None && cx.sess().target.emit_debug_gdb_scripts && embed_visualizers } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs index 56fb12d3c22..d1502d2b1e6 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs @@ -285,8 +285,8 @@ pub(super) fn build_type_with_children<'ll, 'tcx>( // Item(T), // } // ``` - let is_expanding_recursive = - debug_context(cx).adt_stack.borrow().iter().any(|(parent_def_id, parent_args)| { + let is_expanding_recursive = adt_def.is_enum() + && debug_context(cx).adt_stack.borrow().iter().any(|(parent_def_id, parent_args)| { if def_id == *parent_def_id { args.iter().zip(parent_args.iter()).any(|(arg, parent_arg)| { if let (Some(arg), Some(parent_arg)) = (arg.as_type(), parent_arg.as_type()) diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 0d0cb5f139e..75d3d27f74e 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -97,6 +97,16 @@ pub(crate) enum ModuleFlagMergeBehavior { // Consts for the LLVM CallConv type, pre-cast to usize. +#[derive(Copy, Clone, PartialEq, Debug)] +#[repr(C)] +#[allow(dead_code)] +pub(crate) enum TailCallKind { + None = 0, + Tail = 1, + MustTail = 2, + NoTail = 3, +} + /// LLVM CallingConv::ID. Should we wrap this? /// /// See <https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/IR/CallingConv.h> @@ -1186,6 +1196,7 @@ unsafe extern "C" { pub(crate) safe fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool; pub(crate) safe fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool); pub(crate) safe fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool); + pub(crate) safe fn LLVMRustSetTailCallKind(CallInst: &Value, Kind: TailCallKind); // Operations on attributes pub(crate) fn LLVMCreateStringAttribute( @@ -2045,10 +2056,6 @@ unsafe extern "C" { NumExpansionRegions: size_t, BranchRegions: *const crate::coverageinfo::ffi::BranchRegion, NumBranchRegions: size_t, - MCDCBranchRegions: *const crate::coverageinfo::ffi::MCDCBranchRegion, - NumMCDCBranchRegions: size_t, - MCDCDecisionRegions: *const crate::coverageinfo::ffi::MCDCDecisionRegion, - NumMCDCDecisionRegions: size_t, BufferOut: &RustString, ); diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 53899da183a..28d2100f478 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -262,6 +262,15 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea // Filter out features that are not supported by the current LLVM version ("aarch64", "fpmr") => None, // only existed in 18 ("arm", "fp16") => Some(LLVMFeature::new("fullfp16")), + // NVPTX targets added in LLVM 20 + ("nvptx64", "sm_100") if get_version().0 < 20 => None, + ("nvptx64", "sm_100a") if get_version().0 < 20 => None, + ("nvptx64", "sm_101") if get_version().0 < 20 => None, + ("nvptx64", "sm_101a") if get_version().0 < 20 => None, + ("nvptx64", "sm_120") if get_version().0 < 20 => None, + ("nvptx64", "sm_120a") if get_version().0 < 20 => None, + ("nvptx64", "ptx86") if get_version().0 < 20 => None, + ("nvptx64", "ptx87") if get_version().0 < 20 => None, // Filter out features that are not supported by the current LLVM version ("loongarch64", "div32" | "lam-bh" | "lamcas" | "ld-seq-sa" | "scq") if get_version().0 < 20 => @@ -324,15 +333,12 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea /// /// We do not have to worry about RUSTC_SPECIFIC_FEATURES here, those are handled outside codegen. pub(crate) fn target_config(sess: &Session) -> TargetConfig { - // Add base features for the target. - // We do *not* add the -Ctarget-features there, and instead duplicate the logic for that below. - // The reason is that if LLVM considers a feature implied but we do not, we don't want that to - // show up in `cfg`. That way, `cfg` is entirely under our control -- except for the handling of - // the target CPU, that is still expanded to target features (with all their implied features) - // by LLVM. let target_machine = create_informational_target_machine(sess, true); let (unstable_target_features, target_features) = cfg_target_feature(sess, |feature| { + // This closure determines whether the target CPU has the feature according to LLVM. We do + // *not* consider the `-Ctarget-feature`s here, as that will be handled later in + // `cfg_target_feature`. if let Some(feat) = to_llvm_features(sess, feature) { // All the LLVM features this expands to must be enabled. for llvm_feature in feat { @@ -371,24 +377,25 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) { let target_abi = sess.target.options.abi.as_ref(); let target_pointer_width = sess.target.pointer_width; let version = get_version(); + let lt_20_1_1 = version < (20, 1, 1); + let lt_21_0_0 = version < (21, 0, 0); cfg.has_reliable_f16 = match (target_arch, target_os) { - // Selection failure <https://github.com/llvm/llvm-project/issues/50374> - ("s390x", _) => false, - // LLVM crash without neon <https://github.com/llvm/llvm-project/issues/129394> (now fixed) + // LLVM crash without neon <https://github.com/llvm/llvm-project/issues/129394> (fixed in llvm20) ("aarch64", _) - if !cfg.target_features.iter().any(|f| f.as_str() == "neon") - && version < (20, 1, 1) => + if !cfg.target_features.iter().any(|f| f.as_str() == "neon") && lt_20_1_1 => { false } // Unsupported <https://github.com/llvm/llvm-project/issues/94434> ("arm64ec", _) => false, + // Selection failure <https://github.com/llvm/llvm-project/issues/50374> (fixed in llvm21) + ("s390x", _) if lt_21_0_0 => false, // MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054> ("x86_64", "windows") if target_env == "gnu" && target_abi != "llvm" => false, // Infinite recursion <https://github.com/llvm/llvm-project/issues/97981> ("csky", _) => false, - ("hexagon", _) => false, + ("hexagon", _) if lt_21_0_0 => false, // (fixed in llvm21) ("powerpc" | "powerpc64", _) => false, ("sparc" | "sparc64", _) => false, ("wasm32" | "wasm64", _) => false, @@ -401,9 +408,10 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) { cfg.has_reliable_f128 = match (target_arch, target_os) { // Unsupported <https://github.com/llvm/llvm-project/issues/94434> ("arm64ec", _) => false, - // Selection bug <https://github.com/llvm/llvm-project/issues/96432> - ("mips64" | "mips64r6", _) => false, - // Selection bug <https://github.com/llvm/llvm-project/issues/95471> + // Selection bug <https://github.com/llvm/llvm-project/issues/96432> (fixed in llvm20) + ("mips64" | "mips64r6", _) if lt_20_1_1 => false, + // Selection bug <https://github.com/llvm/llvm-project/issues/95471>. This issue is closed + // but basic math still does not work. ("nvptx64", _) => false, // Unsupported https://github.com/llvm/llvm-project/issues/121122 ("amdgpu", _) => false, @@ -413,8 +421,8 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) { // ABI unsupported <https://github.com/llvm/llvm-project/issues/41838> ("sparc", _) => false, // Stack alignment bug <https://github.com/llvm/llvm-project/issues/77401>. NB: tests may - // not fail if our compiler-builtins is linked. - ("x86", _) => false, + // not fail if our compiler-builtins is linked. (fixed in llvm21) + ("x86", _) if lt_21_0_0 => false, // MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054> ("x86_64", "windows") if target_env == "gnu" && target_abi != "llvm" => false, // There are no known problems on other platforms, so the only requirement is that symbols diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index cfae1b3ec98..30956fd1855 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -8,8 +8,8 @@ edition = "2024" ar_archive_writer = "0.4.2" bitflags = "2.4.1" bstr = "1.11.3" -# Pinned so `cargo update` bumps don't cause breakage. Please also update the -# `cc` in `rustc_llvm` if you update the `cc` here. +# `cc` updates often break things, so we pin it here. Cargo enforces "max 1 semver-compat version +# per crate", so if you change this, you need to also change it in `rustc_llvm`. cc = "=1.2.16" itertools = "0.12" pathdiff = "0.2.0" @@ -17,7 +17,6 @@ regex = "1.4" rustc_abi = { path = "../rustc_abi" } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } -rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index a70d0011d16..3ca070acc9d 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -101,6 +101,8 @@ codegen_ssa_invalid_monomorphization_basic_float_type = invalid monomorphization codegen_ssa_invalid_monomorphization_basic_integer_type = invalid monomorphization of `{$name}` intrinsic: expected basic integer type, found `{$ty}` +codegen_ssa_invalid_monomorphization_basic_integer_or_ptr_type = invalid monomorphization of `{$name}` intrinsic: expected basic integer or pointer type, found `{$ty}` + codegen_ssa_invalid_monomorphization_cannot_return = invalid monomorphization of `{$name}` intrinsic: cannot return `{$ret_ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]` codegen_ssa_invalid_monomorphization_cast_wide_pointer = invalid monomorphization of `{$name}` intrinsic: cannot cast wide pointer `{$ty}` @@ -178,6 +180,10 @@ codegen_ssa_ld64_unimplemented_modifier = `as-needed` modifier not implemented y codegen_ssa_lib_def_write_failure = failed to write lib.def file: {$error} +codegen_ssa_link_exe_status_stack_buffer_overrun = 0xc0000409 is `STATUS_STACK_BUFFER_OVERRUN` + .abort_note = this may have been caused by a program abort and not a stack buffer overrun + .event_log_note = consider checking the Application Event Log for Windows Error Reporting events to see the fail fast error code + codegen_ssa_link_exe_unexpected_error = `link.exe` returned an unexpected error codegen_ssa_link_script_unavailable = can only use link script when linking with GNU-like linker diff --git a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs index 3710625ac12..43e1e135a66 100644 --- a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs +++ b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs @@ -69,6 +69,15 @@ pub fn assert_module_sources(tcx: TyCtxt<'_>, set_reuse: &dyn Fn(&mut CguReuseTr set_reuse(&mut ams.cgu_reuse_tracker); + if tcx.sess.opts.unstable_opts.print_mono_items + && let Some(data) = &ams.cgu_reuse_tracker.data + { + data.actual_reuse.items().all(|(cgu, reuse)| { + println!("CGU_REUSE {cgu} {reuse}"); + true + }); + } + ams.cgu_reuse_tracker.check_expected_reuse(tcx.sess); }); } diff --git a/compiler/rustc_codegen_ssa/src/back/apple.rs b/compiler/rustc_codegen_ssa/src/back/apple.rs index d242efaf4fd..2f68bad1695 100644 --- a/compiler/rustc_codegen_ssa/src/back/apple.rs +++ b/compiler/rustc_codegen_ssa/src/back/apple.rs @@ -17,7 +17,7 @@ mod tests; /// The canonical name of the desired SDK for a given target. pub(super) fn sdk_name(target: &Target) -> &'static str { - match (&*target.os, &*target.abi) { + match (&*target.os, &*target.env) { ("macos", "") => "MacOSX", ("ios", "") => "iPhoneOS", ("ios", "sim") => "iPhoneSimulator", @@ -34,7 +34,7 @@ pub(super) fn sdk_name(target: &Target) -> &'static str { } pub(super) fn macho_platform(target: &Target) -> u32 { - match (&*target.os, &*target.abi) { + match (&*target.os, &*target.env) { ("macos", _) => object::macho::PLATFORM_MACOS, ("ios", "macabi") => object::macho::PLATFORM_MACCATALYST, ("ios", "sim") => object::macho::PLATFORM_IOSSIMULATOR, diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 162fbf3d6e2..3ec0d900994 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -880,6 +880,14 @@ fn link_natively( windows_registry::find_tool(&sess.target.arch, "link.exe").is_some(); sess.dcx().emit_note(errors::LinkExeUnexpectedError); + + // STATUS_STACK_BUFFER_OVERRUN is also used for fast abnormal program termination, e.g. abort(). + // Emit a special diagnostic to let people know that this most likely doesn't indicate a stack buffer overrun. + const STATUS_STACK_BUFFER_OVERRUN: i32 = 0xc0000409u32 as _; + if code == STATUS_STACK_BUFFER_OVERRUN { + sess.dcx().emit_note(errors::LinkExeStatusStackBufferOverrun); + } + if is_vs_installed && has_linker { // the linker is broken sess.dcx().emit_note(errors::RepairVSBuildTools); @@ -1011,11 +1019,12 @@ fn link_natively( (Strip::Debuginfo, _) => { strip_with_external_utility(sess, stripcmd, out_filename, &["--strip-debug"]) } - // Per the manpage, `-x` is the maximum safe strip level for dynamic libraries. (#93988) + + // Per the manpage, --discard-all is the maximum safe strip level for dynamic libraries. (#93988) ( Strip::Symbols, CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro | CrateType::Sdylib, - ) => strip_with_external_utility(sess, stripcmd, out_filename, &["-x"]), + ) => strip_with_external_utility(sess, stripcmd, out_filename, &["--discard-all"]), (Strip::Symbols, _) => { strip_with_external_utility(sess, stripcmd, out_filename, &["--strip-all"]) } @@ -3025,7 +3034,7 @@ pub(crate) fn are_upstream_rust_objects_already_included(sess: &Session) -> bool /// We need to communicate five things to the linker on Apple/Darwin targets: /// - The architecture. /// - The operating system (and that it's an Apple platform). -/// - The environment / ABI. +/// - The environment. /// - The deployment target. /// - The SDK version. fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { @@ -3039,7 +3048,7 @@ fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavo // `sess.target.arch` (`target_arch`) is not detailed enough. let llvm_arch = sess.target.llvm_target.split_once('-').expect("LLVM target must have arch").0; let target_os = &*sess.target.os; - let target_abi = &*sess.target.abi; + let target_env = &*sess.target.env; // The architecture name to forward to the linker. // @@ -3090,14 +3099,14 @@ fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavo // > - visionos-simulator // > - xros-simulator // > - driverkit - let platform_name = match (target_os, target_abi) { + let platform_name = match (target_os, target_env) { (os, "") => os, ("ios", "macabi") => "mac-catalyst", ("ios", "sim") => "ios-simulator", ("tvos", "sim") => "tvos-simulator", ("watchos", "sim") => "watchos-simulator", ("visionos", "sim") => "visionos-simulator", - _ => bug!("invalid OS/ABI combination for Apple target: {target_os}, {target_abi}"), + _ => bug!("invalid OS/env combination for Apple target: {target_os}, {target_env}"), }; let min_version = sess.apple_deployment_target().fmt_full().to_string(); diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 050797354b4..df1e91b12f9 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -1805,11 +1805,18 @@ pub(crate) fn exported_symbols( .collect(); } - if let CrateType::ProcMacro = crate_type { + let mut symbols = if let CrateType::ProcMacro = crate_type { exported_symbols_for_proc_macro_crate(tcx) } else { exported_symbols_for_non_proc_macro(tcx, crate_type) + }; + + if crate_type == CrateType::Dylib || crate_type == CrateType::ProcMacro { + let metadata_symbol_name = exported_symbols::metadata_symbol_name(tcx); + symbols.push((metadata_symbol_name, SymbolExportKind::Data)); } + + symbols } fn exported_symbols_for_non_proc_macro( @@ -1842,12 +1849,8 @@ fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<(String, Symbol let stable_crate_id = tcx.stable_crate_id(LOCAL_CRATE); let proc_macro_decls_name = tcx.sess.generate_proc_macro_decls_symbol(stable_crate_id); - let metadata_symbol_name = exported_symbols::metadata_symbol_name(tcx); - vec![ - (proc_macro_decls_name, SymbolExportKind::Data), - (metadata_symbol_name, SymbolExportKind::Data), - ] + vec![(proc_macro_decls_name, SymbolExportKind::Data)] } pub(crate) fn linked_symbols( diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 297bdec2bc2..7e124f65324 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -8,7 +8,7 @@ use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE, LocalDefId}; use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::exported_symbols::{ - ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel, metadata_symbol_name, + ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel, }; use rustc_middle::query::LocalCrate; use rustc_middle::ty::{self, GenericArgKind, GenericArgsRef, Instance, SymbolName, Ty, TyCtxt}; @@ -289,23 +289,6 @@ fn exported_non_generic_symbols_provider_local<'tcx>( })); } - if tcx.crate_types().contains(&CrateType::Dylib) - || tcx.crate_types().contains(&CrateType::ProcMacro) - { - let symbol_name = metadata_symbol_name(tcx); - let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name)); - - symbols.push(( - exported_symbol, - SymbolExportInfo { - level: SymbolExportLevel::C, - kind: SymbolExportKind::Data, - used: true, - rustc_std_internal_symbol: false, - }, - )); - } - // Sort so we get a stable incr. comp. hash. symbols.sort_by_cached_key(|s| s.0.symbol_name_for_local_instance(tcx)); @@ -384,7 +367,7 @@ fn exported_generic_symbols_provider_local<'tcx>( if !tcx.sess.opts.share_generics() { if tcx.codegen_fn_attrs(mono_item.def_id()).inline - == rustc_attr_data_structures::InlineAttr::Never + == rustc_hir::attrs::InlineAttr::Never { // this is OK, we explicitly allow sharing inline(never) across crates even // without share-generics. diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 6773d3e24e9..aa29afb7f5b 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -214,7 +214,9 @@ impl ModuleConfig { false ), emit_obj, - emit_thin_lto: sess.opts.unstable_opts.emit_thin_lto, + // thin lto summaries prevent fat lto, so do not emit them if fat + // lto is requested. See PR #136840 for background information. + emit_thin_lto: sess.opts.unstable_opts.emit_thin_lto && sess.lto() != Lto::Fat, emit_thin_lto_summary: if_regular!( sess.opts.output_types.contains_key(&OutputType::ThinLinkBitcode), false diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index a5807c56e31..b4556ced0b3 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -7,11 +7,11 @@ use itertools::Itertools; use rustc_abi::FIRST_VARIANT; use rustc_ast as ast; use rustc_ast::expand::allocator::AllocatorKind; -use rustc_attr_data_structures::OptimizeAttr; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; use rustc_data_structures::sync::{IntoDynSyncSend, par_map}; use rustc_data_structures::unord::UnordMap; +use rustc_hir::attrs::OptimizeAttr; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::lang_items::LangItem; use rustc_hir::{ItemId, Target}; diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index e187331c696..7f54a47327a 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -3,13 +3,11 @@ use std::str::FromStr; use rustc_abi::{Align, ExternAbi}; use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode}; use rustc_ast::{LitKind, MetaItem, MetaItemInner, attr}; -use rustc_attr_data_structures::{ - AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr, UsedBy, find_attr, -}; +use rustc_hir::attrs::{AttributeKind, InlineAttr, InstructionSetAttr, UsedBy}; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS; -use rustc_hir::{self as hir, LangItem, lang_items}; +use rustc_hir::{self as hir, Attribute, LangItem, find_attr, lang_items}; use rustc_middle::middle::codegen_fn_attrs::{ CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, }; @@ -53,77 +51,196 @@ fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage { } } -fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { - if cfg!(debug_assertions) { - let def_kind = tcx.def_kind(did); - assert!( - def_kind.has_codegen_attrs(), - "unexpected `def_kind` in `codegen_fn_attrs`: {def_kind:?}", - ); +/// In some cases, attributes are only valid on functions, but it's the `check_attr` +/// pass that checks that they aren't used anywhere else, rather than this module. +/// In these cases, we bail from performing further checks that are only meaningful for +/// functions (such as calling `fn_sig`, which ICEs if given a non-function). We also +/// report a delayed bug, just in case `check_attr` isn't doing its job. +fn try_fn_sig<'tcx>( + tcx: TyCtxt<'tcx>, + did: LocalDefId, + attr_span: Span, +) -> Option<ty::EarlyBinder<'tcx, ty::PolyFnSig<'tcx>>> { + use DefKind::*; + + let def_kind = tcx.def_kind(did); + if let Fn | AssocFn | Variant | Ctor(..) = def_kind { + Some(tcx.fn_sig(did)) + } else { + tcx.dcx().span_delayed_bug(attr_span, "this attribute can only be applied to functions"); + None } +} - let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(did)); - let mut codegen_fn_attrs = CodegenFnAttrs::new(); - if tcx.should_inherit_track_caller(did) { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER; +// FIXME(jdonszelmann): remove when instruction_set becomes a parsed attr +fn parse_instruction_set_attr(tcx: TyCtxt<'_>, attr: &Attribute) -> Option<InstructionSetAttr> { + let list = attr.meta_item_list()?; + + match &list[..] { + [MetaItemInner::MetaItem(set)] => { + let segments = set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>(); + match segments.as_slice() { + [sym::arm, sym::a32 | sym::t32] if !tcx.sess.target.has_thumb_interworking => { + tcx.dcx().emit_err(errors::UnsupportedInstructionSet { span: attr.span() }); + None + } + [sym::arm, sym::a32] => Some(InstructionSetAttr::ArmA32), + [sym::arm, sym::t32] => Some(InstructionSetAttr::ArmT32), + _ => { + tcx.dcx().emit_err(errors::InvalidInstructionSet { span: attr.span() }); + None + } + } + } + [] => { + tcx.dcx().emit_err(errors::BareInstructionSet { span: attr.span() }); + None + } + _ => { + tcx.dcx().emit_err(errors::MultipleInstructionSet { span: attr.span() }); + None + } } +} + +// FIXME(jdonszelmann): remove when linkage becomes a parsed attr +fn parse_linkage_attr(tcx: TyCtxt<'_>, did: LocalDefId, attr: &Attribute) -> Option<Linkage> { + let val = attr.value_str()?; + let linkage = linkage_by_name(tcx, did, val.as_str()); + Some(linkage) +} + +// FIXME(jdonszelmann): remove when no_sanitize becomes a parsed attr +fn parse_no_sanitize_attr(tcx: TyCtxt<'_>, attr: &Attribute) -> Option<SanitizerSet> { + let list = attr.meta_item_list()?; + let mut sanitizer_set = SanitizerSet::empty(); + + for item in list.iter() { + match item.name() { + Some(sym::address) => { + sanitizer_set |= SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS + } + Some(sym::cfi) => sanitizer_set |= SanitizerSet::CFI, + Some(sym::kcfi) => sanitizer_set |= SanitizerSet::KCFI, + Some(sym::memory) => sanitizer_set |= SanitizerSet::MEMORY, + Some(sym::memtag) => sanitizer_set |= SanitizerSet::MEMTAG, + Some(sym::shadow_call_stack) => sanitizer_set |= SanitizerSet::SHADOWCALLSTACK, + Some(sym::thread) => sanitizer_set |= SanitizerSet::THREAD, + Some(sym::hwaddress) => sanitizer_set |= SanitizerSet::HWADDRESS, + _ => { + tcx.dcx().emit_err(errors::InvalidNoSanitize { span: item.span() }); + } + } + } + + Some(sanitizer_set) +} + +// FIXME(jdonszelmann): remove when patchable_function_entry becomes a parsed attr +fn parse_patchable_function_entry( + tcx: TyCtxt<'_>, + attr: &Attribute, +) -> Option<PatchableFunctionEntry> { + attr.meta_item_list().and_then(|l| { + let mut prefix = None; + let mut entry = None; + for item in l { + let Some(meta_item) = item.meta_item() else { + tcx.dcx().emit_err(errors::ExpectedNameValuePair { span: item.span() }); + continue; + }; + + let Some(name_value_lit) = meta_item.name_value_literal() else { + tcx.dcx().emit_err(errors::ExpectedNameValuePair { span: item.span() }); + continue; + }; + + let attrib_to_write = match meta_item.name() { + Some(sym::prefix_nops) => &mut prefix, + Some(sym::entry_nops) => &mut entry, + _ => { + tcx.dcx().emit_err(errors::UnexpectedParameterName { + span: item.span(), + prefix_nops: sym::prefix_nops, + entry_nops: sym::entry_nops, + }); + continue; + } + }; + + let rustc_ast::LitKind::Int(val, _) = name_value_lit.kind else { + tcx.dcx().emit_err(errors::InvalidLiteralValue { span: name_value_lit.span }); + continue; + }; + + let Ok(val) = val.get().try_into() else { + tcx.dcx().emit_err(errors::OutOfRangeInteger { span: name_value_lit.span }); + continue; + }; + + *attrib_to_write = Some(val); + } + + if let (None, None) = (prefix, entry) { + tcx.dcx().span_err(attr.span(), "must specify at least one parameter"); + } + + Some(PatchableFunctionEntry::from_prefix_and_entry(prefix.unwrap_or(0), entry.unwrap_or(0))) + }) +} + +/// Spans that are collected when processing built-in attributes, +/// that are useful for emitting diagnostics later. +#[derive(Default)] +struct InterestingAttributeDiagnosticSpans { + link_ordinal: Option<Span>, + no_sanitize: Option<Span>, + inline: Option<Span>, + no_mangle: Option<Span>, +} + +/// Process the builtin attrs ([`hir::Attribute`]) on the item. +/// Many of them directly translate to codegen attrs. +fn process_builtin_attrs( + tcx: TyCtxt<'_>, + did: LocalDefId, + attrs: &[Attribute], + codegen_fn_attrs: &mut CodegenFnAttrs, +) -> InterestingAttributeDiagnosticSpans { + let mut interesting_spans = InterestingAttributeDiagnosticSpans::default(); + let rust_target_features = tcx.rust_target_features(LOCAL_CRATE); // If our rustc version supports autodiff/enzyme, then we call our handler // to check for any `#[rustc_autodiff(...)]` attributes. + // FIXME(jdonszelmann): merge with loop below if cfg!(llvm_enzyme) { let ad = autodiff_attrs(tcx, did.into()); codegen_fn_attrs.autodiff_item = ad; } - // When `no_builtins` is applied at the crate level, we should add the - // `no-builtins` attribute to each function to ensure it takes effect in LTO. - let crate_attrs = tcx.hir_attrs(rustc_hir::CRATE_HIR_ID); - let no_builtins = attr::contains_name(crate_attrs, sym::no_builtins); - if no_builtins { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_BUILTINS; - } - - let rust_target_features = tcx.rust_target_features(LOCAL_CRATE); - - let mut link_ordinal_span = None; - let mut no_sanitize_span = None; - for attr in attrs.iter() { - // In some cases, attribute are only valid on functions, but it's the `check_attr` - // pass that check that they aren't used anywhere else, rather this module. - // In these cases, we bail from performing further checks that are only meaningful for - // functions (such as calling `fn_sig`, which ICEs if given a non-function). We also - // report a delayed bug, just in case `check_attr` isn't doing its job. - let fn_sig = |attr_span| { - use DefKind::*; - - let def_kind = tcx.def_kind(did); - if let Fn | AssocFn | Variant | Ctor(..) = def_kind { - Some(tcx.fn_sig(did)) - } else { - tcx.dcx() - .span_delayed_bug(attr_span, "this attribute can only be applied to functions"); - None - } - }; - if let hir::Attribute::Parsed(p) = attr { match p { AttributeKind::Cold(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD, AttributeKind::ExportName { name, .. } => { - codegen_fn_attrs.export_name = Some(*name); + codegen_fn_attrs.export_name = Some(*name) + } + AttributeKind::Inline(inline, span) => { + codegen_fn_attrs.inline = *inline; + interesting_spans.inline = Some(*span); } AttributeKind::Naked(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED, AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align), AttributeKind::LinkName { name, .. } => codegen_fn_attrs.link_name = Some(*name), AttributeKind::LinkOrdinal { ordinal, span } => { codegen_fn_attrs.link_ordinal = Some(*ordinal); - link_ordinal_span = Some(*span); + interesting_spans.link_ordinal = Some(*span); } AttributeKind::LinkSection { name, .. } => { codegen_fn_attrs.link_section = Some(*name) } AttributeKind::NoMangle(attr_span) => { + interesting_spans.no_mangle = Some(*attr_span); if tcx.opt_item_name(did.to_def_id()).is_some() { codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE; } else { @@ -137,6 +254,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { }); } } + AttributeKind::Optimize(optimize, _) => codegen_fn_attrs.optimize = *optimize, AttributeKind::TargetFeature(features, attr_span) => { let Some(sig) = tcx.hir_node_by_def_id(did).fn_sig() else { tcx.dcx().span_delayed_bug(*attr_span, "target_feature applied to non-fn"); @@ -184,7 +302,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { let is_closure = tcx.is_closure_like(did.to_def_id()); if !is_closure - && let Some(fn_sig) = fn_sig(*attr_span) + && let Some(fn_sig) = try_fn_sig(tcx, did, *attr_span) && fn_sig.skip_binder().abi() != ExternAbi::Rust { tcx.dcx().emit_err(errors::RequiresRustAbi { span: *attr_span }); @@ -232,155 +350,49 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL, sym::linkage => { - if let Some(val) = attr.value_str() { - let linkage = Some(linkage_by_name(tcx, did, val.as_str())); - if tcx.is_foreign_item(did) { - codegen_fn_attrs.import_linkage = linkage; - - if tcx.is_mutable_static(did.into()) { - let mut diag = tcx.dcx().struct_span_err( - attr.span(), - "extern mutable statics are not allowed with `#[linkage]`", - ); - diag.note( - "marking the extern static mutable would allow changing which \ - symbol the static references rather than make the target of the \ - symbol mutable", - ); - diag.emit(); - } - } else { - codegen_fn_attrs.linkage = linkage; + let linkage = parse_linkage_attr(tcx, did, attr); + + if tcx.is_foreign_item(did) { + codegen_fn_attrs.import_linkage = linkage; + + if tcx.is_mutable_static(did.into()) { + let mut diag = tcx.dcx().struct_span_err( + attr.span(), + "extern mutable statics are not allowed with `#[linkage]`", + ); + diag.note( + "marking the extern static mutable would allow changing which \ + symbol the static references rather than make the target of the \ + symbol mutable", + ); + diag.emit(); } + } else { + codegen_fn_attrs.linkage = linkage; } } sym::no_sanitize => { - no_sanitize_span = Some(attr.span()); - if let Some(list) = attr.meta_item_list() { - for item in list.iter() { - match item.name() { - Some(sym::address) => { - codegen_fn_attrs.no_sanitize |= - SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS - } - Some(sym::cfi) => codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI, - Some(sym::kcfi) => codegen_fn_attrs.no_sanitize |= SanitizerSet::KCFI, - Some(sym::memory) => { - codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY - } - Some(sym::memtag) => { - codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMTAG - } - Some(sym::shadow_call_stack) => { - codegen_fn_attrs.no_sanitize |= SanitizerSet::SHADOWCALLSTACK - } - Some(sym::thread) => { - codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD - } - Some(sym::hwaddress) => { - codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS - } - _ => { - tcx.dcx().emit_err(errors::InvalidNoSanitize { span: item.span() }); - } - } - } - } + interesting_spans.no_sanitize = Some(attr.span()); + codegen_fn_attrs.no_sanitize |= + parse_no_sanitize_attr(tcx, attr).unwrap_or_default(); } sym::instruction_set => { - codegen_fn_attrs.instruction_set = - attr.meta_item_list().and_then(|l| match &l[..] { - [MetaItemInner::MetaItem(set)] => { - let segments = - set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>(); - match segments.as_slice() { - [sym::arm, sym::a32 | sym::t32] - if !tcx.sess.target.has_thumb_interworking => - { - tcx.dcx().emit_err(errors::UnsupportedInstructionSet { - span: attr.span(), - }); - None - } - [sym::arm, sym::a32] => Some(InstructionSetAttr::ArmA32), - [sym::arm, sym::t32] => Some(InstructionSetAttr::ArmT32), - _ => { - tcx.dcx().emit_err(errors::InvalidInstructionSet { - span: attr.span(), - }); - None - } - } - } - [] => { - tcx.dcx().emit_err(errors::BareInstructionSet { span: attr.span() }); - None - } - _ => { - tcx.dcx() - .emit_err(errors::MultipleInstructionSet { span: attr.span() }); - None - } - }) + codegen_fn_attrs.instruction_set = parse_instruction_set_attr(tcx, attr) } sym::patchable_function_entry => { - codegen_fn_attrs.patchable_function_entry = attr.meta_item_list().and_then(|l| { - let mut prefix = None; - let mut entry = None; - for item in l { - let Some(meta_item) = item.meta_item() else { - tcx.dcx().emit_err(errors::ExpectedNameValuePair { span: item.span() }); - continue; - }; - - let Some(name_value_lit) = meta_item.name_value_literal() else { - tcx.dcx().emit_err(errors::ExpectedNameValuePair { span: item.span() }); - continue; - }; - - let attrib_to_write = match meta_item.name() { - Some(sym::prefix_nops) => &mut prefix, - Some(sym::entry_nops) => &mut entry, - _ => { - tcx.dcx().emit_err(errors::UnexpectedParameterName { - span: item.span(), - prefix_nops: sym::prefix_nops, - entry_nops: sym::entry_nops, - }); - continue; - } - }; - - let rustc_ast::LitKind::Int(val, _) = name_value_lit.kind else { - tcx.dcx().emit_err(errors::InvalidLiteralValue { - span: name_value_lit.span, - }); - continue; - }; - - let Ok(val) = val.get().try_into() else { - tcx.dcx() - .emit_err(errors::OutOfRangeInteger { span: name_value_lit.span }); - continue; - }; - - *attrib_to_write = Some(val); - } - - if let (None, None) = (prefix, entry) { - tcx.dcx().span_err(attr.span(), "must specify at least one parameter"); - } - - Some(PatchableFunctionEntry::from_prefix_and_entry( - prefix.unwrap_or(0), - entry.unwrap_or(0), - )) - }) + codegen_fn_attrs.patchable_function_entry = + parse_patchable_function_entry(tcx, attr); } _ => {} } } + interesting_spans +} + +/// Applies overrides for codegen fn attrs. These often have a specific reason why they're necessary. +/// Please comment why when adding a new one! +fn apply_overrides(tcx: TyCtxt<'_>, did: LocalDefId, codegen_fn_attrs: &mut CodegenFnAttrs) { // Apply the minimum function alignment here. This ensures that a function's alignment is // determined by the `-C` flags of the crate it is defined in, not the `-C` flags of the crate // it happens to be codegen'd (or const-eval'd) in. @@ -390,15 +402,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { // On trait methods, inherit the `#[align]` of the trait's method prototype. codegen_fn_attrs.alignment = Ord::max(codegen_fn_attrs.alignment, tcx.inherited_align(did)); - let inline_span; - (codegen_fn_attrs.inline, inline_span) = if let Some((inline_attr, span)) = - find_attr!(attrs, AttributeKind::Inline(i, span) => (*i, *span)) - { - (inline_attr, Some(span)) - } else { - (InlineAttr::None, None) - }; - // naked function MUST NOT be inlined! This attribute is required for the rust compiler itself, // but not for the code generation backend because at that point the naked function will just be // a declaration, with a definition provided in global assembly. @@ -406,9 +409,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { codegen_fn_attrs.inline = InlineAttr::Never; } - codegen_fn_attrs.optimize = - find_attr!(attrs, AttributeKind::Optimize(i, _) => *i).unwrap_or(OptimizeAttr::Default); - // #73631: closures inherit `#[target_feature]` annotations // // If this closure is marked `#[inline(always)]`, simply skip adding `#[target_feature]`. @@ -431,6 +431,26 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } } + // When `no_builtins` is applied at the crate level, we should add the + // `no-builtins` attribute to each function to ensure it takes effect in LTO. + let crate_attrs = tcx.hir_attrs(rustc_hir::CRATE_HIR_ID); + let no_builtins = attr::contains_name(crate_attrs, sym::no_builtins); + if no_builtins { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_BUILTINS; + } + + // inherit track-caller properly + if tcx.should_inherit_track_caller(did) { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER; + } +} + +fn check_result( + tcx: TyCtxt<'_>, + did: LocalDefId, + interesting_spans: InterestingAttributeDiagnosticSpans, + codegen_fn_attrs: &CodegenFnAttrs, +) { // If a function uses `#[target_feature]` it can't be inlined into general // purpose functions as they wouldn't have the right target features // enabled. For that reason we also forbid `#[inline(always)]` as it can't be @@ -446,14 +466,16 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { // llvm/llvm-project#70563). if !codegen_fn_attrs.target_features.is_empty() && matches!(codegen_fn_attrs.inline, InlineAttr::Always) - && let Some(span) = inline_span + && let Some(span) = interesting_spans.inline { tcx.dcx().span_err(span, "cannot use `#[inline(always)]` with `#[target_feature]`"); } + // warn that inline has no effect when no_sanitize is present if !codegen_fn_attrs.no_sanitize.is_empty() && codegen_fn_attrs.inline.always() - && let (Some(no_sanitize_span), Some(inline_span)) = (no_sanitize_span, inline_span) + && let (Some(no_sanitize_span), Some(inline_span)) = + (interesting_spans.no_sanitize, interesting_spans.inline) { let hir_id = tcx.local_def_id_to_hir_id(did); tcx.node_span_lint(lint::builtin::INLINE_NO_SANITIZE, hir_id, no_sanitize_span, |lint| { @@ -462,14 +484,55 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { }) } + // error when specifying link_name together with link_ordinal + if let Some(_) = codegen_fn_attrs.link_name + && let Some(_) = codegen_fn_attrs.link_ordinal + { + let msg = "cannot use `#[link_name]` with `#[link_ordinal]`"; + if let Some(span) = interesting_spans.link_ordinal { + tcx.dcx().span_err(span, msg); + } else { + tcx.dcx().err(msg); + } + } + + if let Some(features) = check_tied_features( + tcx.sess, + &codegen_fn_attrs + .target_features + .iter() + .map(|features| (features.name.as_str(), true)) + .collect(), + ) { + let span = + find_attr!(tcx.get_all_attrs(did), AttributeKind::TargetFeature(_, span) => *span) + .unwrap_or_else(|| tcx.def_span(did)); + + tcx.dcx() + .create_err(errors::TargetFeatureDisableOrEnable { + features, + span: Some(span), + missing_features: Some(errors::MissingFeatures), + }) + .emit(); + } +} + +fn handle_lang_items( + tcx: TyCtxt<'_>, + did: LocalDefId, + interesting_spans: &InterestingAttributeDiagnosticSpans, + attrs: &[Attribute], + codegen_fn_attrs: &mut CodegenFnAttrs, +) { + let lang_item = lang_items::extract(attrs).and_then(|(name, _)| LangItem::from_name(name)); + // Weak lang items have the same semantics as "std internal" symbols in the // sense that they're preserved through all our LTO passes and only // strippable by the linker. // // Additionally weak lang items have predetermined symbol names. - if let Some((name, _)) = lang_items::extract(attrs) - && let Some(lang_item) = LangItem::from_name(name) - { + if let Some(lang_item) = lang_item { if WEAK_LANG_ITEMS.contains(&lang_item) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL; } @@ -478,20 +541,15 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { codegen_fn_attrs.link_name = Some(link_name); } } - check_link_name_xor_ordinal(tcx, &codegen_fn_attrs, link_ordinal_span); + // error when using no_mangle on a lang item item if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) && codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) { - let no_mangle_span = - find_attr!(attrs, AttributeKind::NoMangle(no_mangle_span) => *no_mangle_span) - .unwrap_or_default(); - let lang_item = - lang_items::extract(attrs).map_or(None, |(name, _span)| LangItem::from_name(name)); let mut err = tcx .dcx() .struct_span_err( - no_mangle_span, + interesting_spans.no_mangle.unwrap_or_default(), "`#[no_mangle]` cannot be used on internal language items", ) .with_note("Rustc requires this item to have a specific mangled name.") @@ -508,28 +566,33 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } err.emit(); } +} - if let Some(features) = check_tied_features( - tcx.sess, - &codegen_fn_attrs - .target_features - .iter() - .map(|features| (features.name.as_str(), true)) - .collect(), - ) { - let span = - find_attr!(tcx.get_all_attrs(did), AttributeKind::TargetFeature(_, span) => *span) - .unwrap_or_else(|| tcx.def_span(did)); - - tcx.dcx() - .create_err(errors::TargetFeatureDisableOrEnable { - features, - span: Some(span), - missing_features: Some(errors::MissingFeatures), - }) - .emit(); +/// Generate the [`CodegenFnAttrs`] for an item (identified by the [`LocalDefId`]). +/// +/// This happens in 4 stages: +/// - apply built-in attributes that directly translate to codegen attributes. +/// - handle lang items. These have special codegen attrs applied to them. +/// - apply overrides, like minimum requirements for alignment and other settings that don't rely directly the built-in attrs on the item. +/// overrides come after applying built-in attributes since they may only apply when certain attributes were already set in the stage before. +/// - check that the result is valid. There's various ways in which this may not be the case, such as certain combinations of attrs. +fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { + if cfg!(debug_assertions) { + let def_kind = tcx.def_kind(did); + assert!( + def_kind.has_codegen_attrs(), + "unexpected `def_kind` in `codegen_fn_attrs`: {def_kind:?}", + ); } + let mut codegen_fn_attrs = CodegenFnAttrs::new(); + let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(did)); + + let interesting_spans = process_builtin_attrs(tcx, did, attrs, &mut codegen_fn_attrs); + handle_lang_items(tcx, did, &interesting_spans, attrs, &mut codegen_fn_attrs); + apply_overrides(tcx, did, &mut codegen_fn_attrs); + check_result(tcx, did, interesting_spans, &codegen_fn_attrs); + codegen_fn_attrs } @@ -555,27 +618,12 @@ fn inherited_align<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option<Align> { tcx.codegen_fn_attrs(opt_trait_item(tcx, def_id)?).alignment } -fn check_link_name_xor_ordinal( - tcx: TyCtxt<'_>, - codegen_fn_attrs: &CodegenFnAttrs, - inline_span: Option<Span>, -) { - if codegen_fn_attrs.link_name.is_none() || codegen_fn_attrs.link_ordinal.is_none() { - return; - } - let msg = "cannot use `#[link_name]` with `#[link_ordinal]`"; - if let Some(span) = inline_span { - tcx.dcx().span_err(span, msg); - } else { - tcx.dcx().err(msg); - } -} - /// We now check the #\[rustc_autodiff\] attributes which we generated from the #[autodiff(...)] /// macros. There are two forms. The pure one without args to mark primal functions (the functions /// being differentiated). The other form is #[rustc_autodiff(Mode, ActivityList)] on top of the /// placeholder functions. We wrote the rustc_autodiff attributes ourself, so this should never /// panic, unless we introduced a bug when parsing the autodiff macro. +//FIXME(jdonszelmann): put in the main loop. No need to have two..... :/ Let's do that when we make autodiff parsed. fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option<AutoDiffAttrs> { let attrs = tcx.get_attrs(id, sym::rustc_autodiff); diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 3d787d8bdbd..7ac830bcda9 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -550,6 +550,18 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for LinkingFailed<'_> { #[diag(codegen_ssa_link_exe_unexpected_error)] pub(crate) struct LinkExeUnexpectedError; +pub(crate) struct LinkExeStatusStackBufferOverrun; + +impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for LinkExeStatusStackBufferOverrun { + fn into_diag(self, dcx: rustc_errors::DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { + let mut diag = + Diag::new(dcx, level, fluent::codegen_ssa_link_exe_status_stack_buffer_overrun); + diag.note(fluent::codegen_ssa_abort_note); + diag.note(fluent::codegen_ssa_event_log_note); + diag + } +} + #[derive(Diagnostic)] #[diag(codegen_ssa_repair_vs_build_tools)] pub(crate) struct RepairVSBuildTools; @@ -764,6 +776,14 @@ pub enum InvalidMonomorphization<'tcx> { ty: Ty<'tcx>, }, + #[diag(codegen_ssa_invalid_monomorphization_basic_integer_or_ptr_type, code = E0511)] + BasicIntegerOrPtrType { + #[primary_span] + span: Span, + name: Symbol, + ty: Ty<'tcx>, + }, + #[diag(codegen_ssa_invalid_monomorphization_basic_float_type, code = E0511)] BasicFloatType { #[primary_span] diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index bde63fd501a..e96590441fa 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -35,6 +35,14 @@ enum MergingSucc { True, } +/// Indicates to the call terminator codegen whether a cal +/// is a normal call or an explicit tail call. +#[derive(Debug, PartialEq)] +enum CallKind { + Normal, + Tail, +} + /// Used by `FunctionCx::codegen_terminator` for emitting common patterns /// e.g., creating a basic block, calling a function, etc. struct TerminatorCodegenHelper<'tcx> { @@ -160,6 +168,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { mut unwind: mir::UnwindAction, lifetime_ends_after_call: &[(Bx::Value, Size)], instance: Option<Instance<'tcx>>, + kind: CallKind, mergeable_succ: bool, ) -> MergingSucc { let tcx = bx.tcx(); @@ -221,6 +230,11 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { } }; + if kind == CallKind::Tail { + bx.tail_call(fn_ty, fn_attrs, fn_abi, fn_ptr, llargs, self.funclet(fx), instance); + return MergingSucc::False; + } + if let Some(unwind_block) = unwind_block { let ret_llbb = if let Some((_, target)) = destination { fx.llbb(target) @@ -659,6 +673,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { unwind, &[], Some(drop_instance), + CallKind::Normal, !maybe_null && mergeable_succ, ) } @@ -747,8 +762,19 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let (fn_abi, llfn, instance) = common::build_langcall(bx, span, lang_item); // Codegen the actual panic invoke/call. - let merging_succ = - helper.do_call(self, bx, fn_abi, llfn, &args, None, unwind, &[], Some(instance), false); + let merging_succ = helper.do_call( + self, + bx, + fn_abi, + llfn, + &args, + None, + unwind, + &[], + Some(instance), + CallKind::Normal, + false, + ); assert_eq!(merging_succ, MergingSucc::False); MergingSucc::False } @@ -777,6 +803,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::UnwindAction::Unreachable, &[], Some(instance), + CallKind::Normal, false, ); assert_eq!(merging_succ, MergingSucc::False); @@ -845,6 +872,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { unwind, &[], Some(instance), + CallKind::Normal, mergeable_succ, )) } @@ -860,6 +888,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { target: Option<mir::BasicBlock>, unwind: mir::UnwindAction, fn_span: Span, + kind: CallKind, mergeable_succ: bool, ) -> MergingSucc { let source_info = mir::SourceInfo { span: fn_span, ..terminator.source_info }; @@ -1003,8 +1032,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // We still need to call `make_return_dest` even if there's no `target`, since // `fn_abi.ret` could be `PassMode::Indirect`, even if it is uninhabited, // and `make_return_dest` adds the return-place indirect pointer to `llargs`. - let return_dest = self.make_return_dest(bx, destination, &fn_abi.ret, &mut llargs); - let destination = target.map(|target| (return_dest, target)); + let destination = match kind { + CallKind::Normal => { + let return_dest = self.make_return_dest(bx, destination, &fn_abi.ret, &mut llargs); + target.map(|target| (return_dest, target)) + } + CallKind::Tail => None, + }; // Split the rust-call tupled arguments off. let (first_args, untuple) = if sig.abi() == ExternAbi::RustCall @@ -1020,6 +1054,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // to generate `lifetime_end` when the call returns. let mut lifetime_ends_after_call: Vec<(Bx::Value, Size)> = Vec::new(); 'make_args: for (i, arg) in first_args.iter().enumerate() { + if kind == CallKind::Tail && matches!(fn_abi.args[i].mode, PassMode::Indirect { .. }) { + // FIXME: https://github.com/rust-lang/rust/pull/144232#discussion_r2218543841 + span_bug!( + fn_span, + "arguments using PassMode::Indirect are currently not supported for tail calls" + ); + } + let mut op = self.codegen_operand(bx, &arg.node); if let (0, Some(ty::InstanceKind::Virtual(_, idx))) = (i, instance.map(|i| i.def)) { @@ -1147,6 +1189,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { unwind, &lifetime_ends_after_call, instance, + kind, mergeable_succ, ) } @@ -1388,15 +1431,23 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { target, unwind, fn_span, + CallKind::Normal, mergeable_succ(), ), - mir::TerminatorKind::TailCall { .. } => { - // FIXME(explicit_tail_calls): implement tail calls in ssa backend - span_bug!( - terminator.source_info.span, - "`TailCall` terminator is not yet supported by `rustc_codegen_ssa`" - ) - } + mir::TerminatorKind::TailCall { ref func, ref args, fn_span } => self + .codegen_call_terminator( + helper, + bx, + terminator, + func, + args, + mir::Place::from(mir::RETURN_PLACE), + None, + mir::UnwindAction::Unreachable, + fn_span, + CallKind::Tail, + mergeable_succ(), + ), mir::TerminatorKind::CoroutineDrop | mir::TerminatorKind::Yield { .. } => { bug!("coroutine ops in codegen") } diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index fc95f62b4a4..3c667b8e882 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -92,6 +92,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let invalid_monomorphization_int_type = |ty| { bx.tcx().dcx().emit_err(InvalidMonomorphization::BasicIntegerType { span, name, ty }); }; + let invalid_monomorphization_int_or_ptr_type = |ty| { + bx.tcx().dcx().emit_err(InvalidMonomorphization::BasicIntegerOrPtrType { + span, + name, + ty, + }); + }; let parse_atomic_ordering = |ord: ty::Value<'tcx>| { let discr = ord.valtree.unwrap_branch()[0].unwrap_leaf(); @@ -351,7 +358,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { sym::atomic_load => { let ty = fn_args.type_at(0); if !(int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr()) { - invalid_monomorphization_int_type(ty); + invalid_monomorphization_int_or_ptr_type(ty); return Ok(()); } let ordering = fn_args.const_at(1).to_value(); @@ -367,7 +374,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { sym::atomic_store => { let ty = fn_args.type_at(0); if !(int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr()) { - invalid_monomorphization_int_type(ty); + invalid_monomorphization_int_or_ptr_type(ty); return Ok(()); } let ordering = fn_args.const_at(1).to_value(); @@ -377,10 +384,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.atomic_store(val, ptr, parse_atomic_ordering(ordering), size); return Ok(()); } + // These are all AtomicRMW ops sym::atomic_cxchg | sym::atomic_cxchgweak => { let ty = fn_args.type_at(0); if !(int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr()) { - invalid_monomorphization_int_type(ty); + invalid_monomorphization_int_or_ptr_type(ty); return Ok(()); } let succ_ordering = fn_args.const_at(1).to_value(); @@ -407,7 +415,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return Ok(()); } - // These are all AtomicRMW ops sym::atomic_max | sym::atomic_min => { let atom_op = if name == sym::atomic_max { AtomicRmwBinOp::AtomicMax @@ -420,7 +427,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let ordering = fn_args.const_at(1).to_value(); let ptr = args[0].immediate(); let val = args[1].immediate(); - bx.atomic_rmw(atom_op, ptr, val, parse_atomic_ordering(ordering)) + bx.atomic_rmw( + atom_op, + ptr, + val, + parse_atomic_ordering(ordering), + /* ret_ptr */ false, + ) } else { invalid_monomorphization_int_type(ty); return Ok(()); @@ -438,21 +451,44 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let ordering = fn_args.const_at(1).to_value(); let ptr = args[0].immediate(); let val = args[1].immediate(); - bx.atomic_rmw(atom_op, ptr, val, parse_atomic_ordering(ordering)) + bx.atomic_rmw( + atom_op, + ptr, + val, + parse_atomic_ordering(ordering), + /* ret_ptr */ false, + ) } else { invalid_monomorphization_int_type(ty); return Ok(()); } } - sym::atomic_xchg - | sym::atomic_xadd + sym::atomic_xchg => { + let ty = fn_args.type_at(0); + let ordering = fn_args.const_at(1).to_value(); + if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr() { + let ptr = args[0].immediate(); + let val = args[1].immediate(); + let atomic_op = AtomicRmwBinOp::AtomicXchg; + bx.atomic_rmw( + atomic_op, + ptr, + val, + parse_atomic_ordering(ordering), + /* ret_ptr */ ty.is_raw_ptr(), + ) + } else { + invalid_monomorphization_int_or_ptr_type(ty); + return Ok(()); + } + } + sym::atomic_xadd | sym::atomic_xsub | sym::atomic_and | sym::atomic_nand | sym::atomic_or | sym::atomic_xor => { let atom_op = match name { - sym::atomic_xchg => AtomicRmwBinOp::AtomicXchg, sym::atomic_xadd => AtomicRmwBinOp::AtomicAdd, sym::atomic_xsub => AtomicRmwBinOp::AtomicSub, sym::atomic_and => AtomicRmwBinOp::AtomicAnd, @@ -462,14 +498,28 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { _ => unreachable!(), }; - let ty = fn_args.type_at(0); - if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr() { - let ordering = fn_args.const_at(1).to_value(); - let ptr = args[0].immediate(); - let val = args[1].immediate(); - bx.atomic_rmw(atom_op, ptr, val, parse_atomic_ordering(ordering)) + // The type of the in-memory data. + let ty_mem = fn_args.type_at(0); + // The type of the 2nd operand, given by-value. + let ty_op = fn_args.type_at(1); + + let ordering = fn_args.const_at(2).to_value(); + // We require either both arguments to have the same integer type, or the first to + // be a pointer and the second to be `usize`. + if (int_type_width_signed(ty_mem, bx.tcx()).is_some() && ty_op == ty_mem) + || (ty_mem.is_raw_ptr() && ty_op == bx.tcx().types.usize) + { + let ptr = args[0].immediate(); // of type "pointer to `ty_mem`" + let val = args[1].immediate(); // of type `ty_op` + bx.atomic_rmw( + atom_op, + ptr, + val, + parse_atomic_ordering(ordering), + /* ret_ptr */ ty_mem.is_raw_ptr(), + ) } else { - invalid_monomorphization_int_type(ty); + invalid_monomorphization_int_or_ptr_type(ty_mem); return Ok(()); } } diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 50d0f910744..06873313e2e 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -296,10 +296,6 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // Apply debuginfo to the newly allocated locals. fx.debug_introduce_locals(&mut start_bx, consts_debug_info.unwrap_or_default()); - // If the backend supports coverage, and coverage is enabled for this function, - // do any necessary start-of-function codegen (e.g. locals for MC/DC bitmaps). - start_bx.init_coverage(instance); - // The builders will be created separately for each basic block at `codegen_block`. // So drop the builder of `start_llbb` to avoid having two at the same time. drop(start_bx); diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs index 42e435cf0a3..2a9b5c9019b 100644 --- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs @@ -1,5 +1,5 @@ use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind}; -use rustc_attr_data_structures::InstructionSetAttr; +use rustc_hir::attrs::InstructionSetAttr; use rustc_middle::mir::mono::{Linkage, MonoItemData, Visibility}; use rustc_middle::mir::{InlineAsmOperand, START_BLOCK}; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout}; diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 5459f95c186..d851c332980 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -498,6 +498,35 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { bx.cx().const_uint(cast_to, niche_variants.start().as_u32() as u64); (is_niche, tagged_discr, 0) } else { + // Thanks to parameter attributes and load metadata, LLVM already knows + // the general valid range of the tag. It's possible, though, for there + // to be an impossible value *in the middle*, which those ranges don't + // communicate, so it's worth an `assume` to let the optimizer know. + // Most importantly, this means when optimizing a variant test like + // `SELECT(is_niche, complex, CONST) == CONST` it's ok to simplify that + // to `!is_niche` because the `complex` part can't possibly match. + // + // This was previously asserted on `tagged_discr` below, where the + // impossible value is more obvious, but that caused an intermediate + // value to become multi-use and thus not optimize, so instead this + // assumes on the original input which is always multi-use. See + // <https://github.com/llvm/llvm-project/issues/134024#issuecomment-3131782555> + // + // FIXME: If we ever get range assume operand bundles in LLVM (so we + // don't need the `icmp`s in the instruction stream any more), it + // might be worth moving this back to being on the switch argument + // where it's more obviously applicable. + if niche_variants.contains(&untagged_variant) + && bx.cx().sess().opts.optimize != OptLevel::No + { + let impossible = niche_start + .wrapping_add(u128::from(untagged_variant.as_u32())) + .wrapping_sub(u128::from(niche_variants.start().as_u32())); + let impossible = bx.cx().const_uint_big(tag_llty, impossible); + let ne = bx.icmp(IntPredicate::IntNE, tag, impossible); + bx.assume(ne); + } + // With multiple niched variants we'll have to actually compute // the variant index from the stored tag. // @@ -588,20 +617,6 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { let untagged_variant_const = bx.cx().const_uint(cast_to, u64::from(untagged_variant.as_u32())); - // Thanks to parameter attributes and load metadata, LLVM already knows - // the general valid range of the tag. It's possible, though, for there - // to be an impossible value *in the middle*, which those ranges don't - // communicate, so it's worth an `assume` to let the optimizer know. - // Most importantly, this means when optimizing a variant test like - // `SELECT(is_niche, complex, CONST) == CONST` it's ok to simplify that - // to `!is_niche` because the `complex` part can't possibly match. - if niche_variants.contains(&untagged_variant) - && bx.cx().sess().opts.optimize != OptLevel::No - { - let ne = bx.icmp(IntPredicate::IntNE, tagged_discr, untagged_variant_const); - bx.assume(ne); - } - let discr = bx.select(is_niche, tagged_discr, untagged_variant_const); // In principle we could insert assumes on the possible range of `discr`, but diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index def4ec13e87..7e4341a8236 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -1,6 +1,6 @@ -use rustc_attr_data_structures::InstructionSetAttr; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_data_structures::unord::{UnordMap, UnordSet}; +use rustc_hir::attrs::InstructionSetAttr; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_middle::middle::codegen_fn_attrs::TargetFeature; @@ -197,7 +197,10 @@ fn parse_rust_feature_flag<'a>( /// 2nd component of the return value, respectively). /// /// `target_base_has_feature` should check whether the given feature (a Rust feature name!) is -/// enabled in the "base" target machine, i.e., without applying `-Ctarget-feature`. +/// enabled in the "base" target machine, i.e., without applying `-Ctarget-feature`. Note that LLVM +/// may consider features to be implied that we do not and vice-versa. We want `cfg` to be entirely +/// consistent with Rust feature implications, and thus only consult LLVM to expand the target CPU +/// to target features. /// /// We do not have to worry about RUSTC_SPECIFIC_FEATURES here, those are handled elsewhere. pub fn cfg_target_feature( @@ -211,7 +214,15 @@ pub fn cfg_target_feature( .rust_target_features() .iter() .filter(|(feature, _, _)| target_base_has_feature(feature)) - .map(|(feature, _, _)| Symbol::intern(feature)) + .flat_map(|(base_feature, _, _)| { + // Expand the direct base feature into all transitively-implied features. Note that we + // cannot simply use the `implied` field of the tuple since that only contains + // directly-implied features. + // + // Iteration order is irrelevant because we're collecting into an `UnordSet`. + #[allow(rustc::potential_query_instability)] + sess.target.implied_target_features(base_feature).into_iter().map(|f| Symbol::intern(f)) + }) .collect(); // Add enabled and remove disabled features. diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 979456a6ba7..f417d1a7bf7 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -548,12 +548,15 @@ pub trait BuilderMethods<'a, 'tcx>: failure_order: AtomicOrdering, weak: bool, ) -> (Self::Value, Self::Value); + /// `ret_ptr` indicates whether the return type (which is also the type `dst` points to) + /// is a pointer or the same type as `src`. fn atomic_rmw( &mut self, op: AtomicRmwBinOp, dst: Self::Value, src: Self::Value, order: AtomicOrdering, + ret_ptr: bool, ) -> Self::Value; fn atomic_fence(&mut self, order: AtomicOrdering, scope: SynchronizationScope); fn set_invariant_load(&mut self, load: Self::Value); @@ -595,6 +598,18 @@ pub trait BuilderMethods<'a, 'tcx>: funclet: Option<&Self::Funclet>, instance: Option<Instance<'tcx>>, ) -> Self::Value; + + fn tail_call( + &mut self, + llty: Self::Type, + fn_attrs: Option<&CodegenFnAttrs>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + llfn: Self::Value, + args: &[Self::Value], + funclet: Option<&Self::Funclet>, + instance: Option<Instance<'tcx>>, + ); + fn zext(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value; fn apply_attrs_to_cleanup_callsite(&mut self, llret: Self::Value); diff --git a/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs b/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs index 0b513dac503..31482a53b6d 100644 --- a/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs +++ b/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs @@ -2,11 +2,6 @@ use rustc_middle::mir::coverage::CoverageKind; use rustc_middle::ty::Instance; pub trait CoverageInfoBuilderMethods<'tcx> { - /// Performs any start-of-function codegen needed for coverage instrumentation. - /// - /// Can be a no-op in backends that don't support coverage instrumentation. - fn init_coverage(&mut self, _instance: Instance<'tcx>) {} - /// Handle the MIR coverage info in a backend-specific way. /// /// This can potentially be a no-op in backends that don't support diff --git a/compiler/rustc_const_eval/Cargo.toml b/compiler/rustc_const_eval/Cargo.toml index 93d0d5b9a71..51dcee8d882 100644 --- a/compiler/rustc_const_eval/Cargo.toml +++ b/compiler/rustc_const_eval/Cargo.toml @@ -9,7 +9,6 @@ either = "1" rustc_abi = { path = "../rustc_abi" } rustc_apfloat = "0.2.0" rustc_ast = { path = "../rustc_ast" } -rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 44e5d1d5ee7..8e2c138282a 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -6,7 +6,6 @@ use std::mem; use std::num::NonZero; use std::ops::Deref; -use rustc_attr_data_structures as attrs; use rustc_errors::{Diag, ErrorGuaranteed}; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; @@ -466,7 +465,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { /// Check the const stability of the given item (fn or trait). fn check_callee_stability(&mut self, def_id: DefId) { match self.tcx.lookup_const_stability(def_id) { - Some(attrs::ConstStability { level: attrs::StabilityLevel::Stable { .. }, .. }) => { + Some(hir::ConstStability { level: hir::StabilityLevel::Stable { .. }, .. }) => { // All good. } None => { @@ -482,8 +481,8 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { }); } } - Some(attrs::ConstStability { - level: attrs::StabilityLevel::Unstable { implied_by: implied_feature, issue, .. }, + Some(hir::ConstStability { + level: hir::StabilityLevel::Unstable { implied_by: implied_feature, issue, .. }, feature, .. }) => { @@ -891,8 +890,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { }); } } - Some(attrs::ConstStability { - level: attrs::StabilityLevel::Unstable { .. }, + Some(hir::ConstStability { + level: hir::StabilityLevel::Unstable { .. }, feature, .. }) => { @@ -902,8 +901,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { const_stable_indirect: is_const_stable, }); } - Some(attrs::ConstStability { - level: attrs::StabilityLevel::Stable { .. }, + Some(hir::ConstStability { + level: hir::StabilityLevel::Stable { .. }, .. }) => { // All good. Note that a `#[rustc_const_stable]` intrinsic (meaning it diff --git a/compiler/rustc_const_eval/src/check_consts/mod.rs b/compiler/rustc_const_eval/src/check_consts/mod.rs index ebf18c6f2ac..4a88d039ef3 100644 --- a/compiler/rustc_const_eval/src/check_consts/mod.rs +++ b/compiler/rustc_const_eval/src/check_consts/mod.rs @@ -5,11 +5,12 @@ //! it finds operations that are invalid in a certain context. use rustc_errors::DiagCtxtHandle; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::{self as hir, find_attr}; use rustc_middle::ty::{self, PolyFnSig, TyCtxt}; use rustc_middle::{bug, mir}; use rustc_span::Symbol; -use {rustc_attr_data_structures as attrs, rustc_hir as hir}; pub use self::qualifs::Qualif; @@ -82,7 +83,7 @@ pub fn rustc_allow_const_fn_unstable( ) -> bool { let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id)); - attrs::find_attr!(attrs, attrs::AttributeKind::AllowConstFnUnstable(syms, _) if syms.contains(&feature_gate)) + find_attr!(attrs, AttributeKind::AllowConstFnUnstable(syms, _) if syms.contains(&feature_gate)) } /// Returns `true` if the given `def_id` (trait or function) is "safe to expose on stable". diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index 5b3adba0265..b8a65369825 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -11,6 +11,7 @@ use rustc_middle::ty::{self, AdtDef, Instance, Ty, VariantDef}; use rustc_middle::{bug, mir, span_bug}; use rustc_span::sym; use rustc_target::callconv::{ArgAbi, FnAbi, PassMode}; +use tracing::field::Empty; use tracing::{info, instrument, trace}; use super::{ @@ -18,7 +19,8 @@ use super::{ Projectable, Provenance, ReturnAction, ReturnContinuation, Scalar, StackPopInfo, interp_ok, throw_ub, throw_ub_custom, throw_unsup_format, }; -use crate::fluent_generated as fluent; +use crate::interpret::EnteredTraceSpan; +use crate::{enter_trace_span, fluent_generated as fluent}; /// An argument passed to a function. #[derive(Clone, Debug)] @@ -344,6 +346,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { destination: &PlaceTy<'tcx, M::Provenance>, mut cont: ReturnContinuation, ) -> InterpResult<'tcx> { + let _span = enter_trace_span!(M, step::init_stack_frame, %instance, tracing_separate_thread = Empty); + // Compute callee information. // FIXME: for variadic support, do we have to somehow determine callee's extra_args? let callee_fn_abi = self.fn_abi_of_instance(instance, ty::List::empty())?; @@ -523,7 +527,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { target: Option<mir::BasicBlock>, unwind: mir::UnwindAction, ) -> InterpResult<'tcx> { - trace!("init_fn_call: {:#?}", fn_val); + let _span = + enter_trace_span!(M, step::init_fn_call, tracing_separate_thread = Empty, ?fn_val) + .or_if_tracing_disabled(|| trace!("init_fn_call: {:#?}", fn_val)); let instance = match fn_val { FnVal::Instance(instance) => instance, diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 0a8591ca140..c4b705d7124 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -113,7 +113,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// See [LayoutOf::layout_of] for the original documentation. #[inline(always)] pub fn layout_of(&self, ty: Ty<'tcx>) -> <Self as LayoutOfHelpers<'tcx>>::LayoutOfResult { - let _span = enter_trace_span!(M, "InterpCx::layout_of", ty = ?ty.kind()); + let _span = enter_trace_span!(M, layouting::layout_of, ty = ?ty.kind()); LayoutOf::layout_of(self, ty) } @@ -126,7 +126,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { sig: ty::PolyFnSig<'tcx>, extra_args: &'tcx ty::List<Ty<'tcx>>, ) -> <Self as FnAbiOfHelpers<'tcx>>::FnAbiOfResult { - let _span = enter_trace_span!(M, "InterpCx::fn_abi_of_fn_ptr", ?sig, ?extra_args); + let _span = enter_trace_span!(M, layouting::fn_abi_of_fn_ptr, ?sig, ?extra_args); FnAbiOf::fn_abi_of_fn_ptr(self, sig, extra_args) } @@ -139,7 +139,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { instance: ty::Instance<'tcx>, extra_args: &'tcx ty::List<Ty<'tcx>>, ) -> <Self as FnAbiOfHelpers<'tcx>>::FnAbiOfResult { - let _span = enter_trace_span!(M, "InterpCx::fn_abi_of_instance", ?instance, ?extra_args); + let _span = enter_trace_span!(M, layouting::fn_abi_of_instance, ?instance, ?extra_args); FnAbiOf::fn_abi_of_instance(self, instance, extra_args) } } diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 47bebf5371a..23b40894f16 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -937,8 +937,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // (both global from `alloc_map` and local from `extra_fn_ptr_map`) if let Some(fn_val) = self.get_fn_alloc(id) { let align = match fn_val { - FnVal::Instance(instance) => { - self.tcx.codegen_instance_attrs(instance.def).alignment.unwrap_or(Align::ONE) + FnVal::Instance(_instance) => { + // FIXME: Until we have a clear design for the effects of align(N) functions + // on the address of function pointers, we don't consider the align(N) + // attribute on functions in the interpreter. + // See <https://github.com/rust-lang/rust/issues/144661> for more context. + Align::ONE } // Machine-specific extra functions currently do not support alignment restrictions. FnVal::Other(_) => Align::ONE, diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 21afd082a05..14541809070 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -13,6 +13,7 @@ use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter}; use rustc_middle::ty::{ConstInt, ScalarInt, Ty, TyCtxt}; use rustc_middle::{bug, mir, span_bug, ty}; use rustc_span::DUMMY_SP; +use tracing::field::Empty; use tracing::trace; use super::{ @@ -20,6 +21,7 @@ use super::{ OffsetMode, PlaceTy, Pointer, Projectable, Provenance, Scalar, alloc_range, err_ub, from_known_layout, interp_ok, mir_assign_valid_types, throw_ub, }; +use crate::enter_trace_span; /// An `Immediate` represents a single immediate self-contained Rust value. /// @@ -186,18 +188,18 @@ pub struct ImmTy<'tcx, Prov: Provenance = CtfeProvenance> { impl<Prov: Provenance> std::fmt::Display for ImmTy<'_, Prov> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { /// Helper function for printing a scalar to a FmtPrinter - fn p<'a, 'tcx, Prov: Provenance>( - cx: &mut FmtPrinter<'a, 'tcx>, + fn print_scalar<'a, 'tcx, Prov: Provenance>( + p: &mut FmtPrinter<'a, 'tcx>, s: Scalar<Prov>, ty: Ty<'tcx>, ) -> Result<(), std::fmt::Error> { match s { - Scalar::Int(int) => cx.pretty_print_const_scalar_int(int, ty, true), + Scalar::Int(int) => p.pretty_print_const_scalar_int(int, ty, true), Scalar::Ptr(ptr, _sz) => { // Just print the ptr value. `pretty_print_const_scalar_ptr` would also try to // print what is points to, which would fail since it has no access to the local // memory. - cx.pretty_print_const_pointer(ptr, ty) + p.pretty_print_const_pointer(ptr, ty) } } } @@ -205,8 +207,9 @@ impl<Prov: Provenance> std::fmt::Display for ImmTy<'_, Prov> { match self.imm { Immediate::Scalar(s) => { if let Some(ty) = tcx.lift(self.layout.ty) { - let s = - FmtPrinter::print_string(tcx, Namespace::ValueNS, |cx| p(cx, s, ty))?; + let s = FmtPrinter::print_string(tcx, Namespace::ValueNS, |p| { + print_scalar(p, s, ty) + })?; f.write_str(&s)?; return Ok(()); } @@ -770,6 +773,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { mir_place: mir::Place<'tcx>, layout: Option<TyAndLayout<'tcx>>, ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { + let _span = enter_trace_span!( + M, + step::eval_place_to_op, + ?mir_place, + tracing_separate_thread = Empty + ); + // Do not use the layout passed in as argument if the base we are looking at // here is not the entire place. let layout = if mir_place.projection.is_empty() { layout } else { None }; @@ -813,6 +823,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { mir_op: &mir::Operand<'tcx>, layout: Option<TyAndLayout<'tcx>>, ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { + let _span = + enter_trace_span!(M, step::eval_operand, ?mir_op, tracing_separate_thread = Empty); + use rustc_middle::mir::Operand::*; let op = match mir_op { // FIXME: do some more logic on `move` to invalidate the old location diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index e2284729efd..45c4edb8503 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -9,6 +9,7 @@ use rustc_abi::{BackendRepr, HasDataLayout, Size}; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::{bug, mir, span_bug}; +use tracing::field::Empty; use tracing::{instrument, trace}; use super::{ @@ -16,6 +17,7 @@ use super::{ InterpResult, Machine, MemoryKind, Misalignment, OffsetMode, OpTy, Operand, Pointer, Projectable, Provenance, Scalar, alloc_range, interp_ok, mir_assign_valid_types, }; +use crate::enter_trace_span; #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)] /// Information required for the sound usage of a `MemPlace`. @@ -524,6 +526,9 @@ where &self, mir_place: mir::Place<'tcx>, ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> { + let _span = + enter_trace_span!(M, step::eval_place, ?mir_place, tracing_separate_thread = Empty); + let mut place = self.local_to_place(mir_place.local)?; // Using `try_fold` turned out to be bad for performance, hence the loop. for elem in mir_place.projection.iter() { diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index f72c4418081..d05871bfc77 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -199,6 +199,15 @@ where base.offset_with_meta(offset, OffsetMode::Inbounds, meta, field_layout, self) } + /// Projects multiple fields at once. See [`Self::project_field`] for details. + pub fn project_fields<P: Projectable<'tcx, M::Provenance>, const N: usize>( + &self, + base: &P, + fields: [FieldIdx; N], + ) -> InterpResult<'tcx, [P; N]> { + fields.try_map(|field| self.project_field(base, field)) + } + /// Downcasting to an enum variant. pub fn project_downcast<P: Projectable<'tcx, M::Provenance>>( &self, diff --git a/compiler/rustc_const_eval/src/interpret/stack.rs b/compiler/rustc_const_eval/src/interpret/stack.rs index 2e99bb4209f..73cc87508ef 100644 --- a/compiler/rustc_const_eval/src/interpret/stack.rs +++ b/compiler/rustc_const_eval/src/interpret/stack.rs @@ -397,11 +397,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Finish things up. M::after_stack_push(self)?; self.frame_mut().loc = Left(mir::Location::START); - // `tracing_separate_thread` is used to instruct the chrome_tracing [tracing::Layer] in Miri + // `tracing_separate_thread` is used to instruct the tracing_chrome [tracing::Layer] in Miri // to put the "frame" span on a separate trace thread/line than other spans, to make the - // visualization in https://ui.perfetto.dev easier to interpret. It is set to a value of + // visualization in <https://ui.perfetto.dev> easier to interpret. It is set to a value of // [tracing::field::Empty] so that other tracing layers (e.g. the logger) will ignore it. - let span = info_span!("frame", tracing_separate_thread = Empty, "{}", instance); + let span = info_span!("frame", tracing_separate_thread = Empty, frame = %instance); self.frame_mut().tracing_span.enter(span); interp_ok(()) diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 629dcc3523c..9df49c0f4cc 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -9,13 +9,15 @@ use rustc_middle::ty::{self, Instance, Ty}; use rustc_middle::{bug, mir, span_bug}; use rustc_span::source_map::Spanned; use rustc_target::callconv::FnAbi; +use tracing::field::Empty; use tracing::{info, instrument, trace}; use super::{ FnArg, FnVal, ImmTy, Immediate, InterpCx, InterpResult, Machine, MemPlaceMeta, PlaceTy, Projectable, Scalar, interp_ok, throw_ub, throw_unsup_format, }; -use crate::util; +use crate::interpret::EnteredTraceSpan; +use crate::{enter_trace_span, util}; struct EvaluatedCalleeAndArgs<'tcx, M: Machine<'tcx>> { callee: FnVal<'tcx, M::ExtraFnVal>, @@ -74,7 +76,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// /// This does NOT move the statement counter forward, the caller has to do that! pub fn eval_statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> { - info!("{:?}", stmt); + let _span = enter_trace_span!( + M, + step::eval_statement, + stmt = ?stmt.kind, + span = ?stmt.source_info.span, + tracing_separate_thread = Empty, + ) + .or_if_tracing_disabled(|| info!(stmt = ?stmt.kind)); use rustc_middle::mir::StatementKind::*; @@ -456,7 +465,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } fn eval_terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> InterpResult<'tcx> { - info!("{:?}", terminator.kind); + let _span = enter_trace_span!( + M, + step::eval_terminator, + terminator = ?terminator.kind, + span = ?terminator.source_info.span, + tracing_separate_thread = Empty, + ) + .or_if_tracing_disabled(|| info!(terminator = ?terminator.kind)); use rustc_middle::mir::TerminatorKind::*; match terminator.kind { diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index 72650d545c3..71800950faa 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -48,18 +48,104 @@ pub(crate) fn create_static_alloc<'tcx>( /// A marker trait returned by [crate::interpret::Machine::enter_trace_span], identifying either a /// real [tracing::span::EnteredSpan] in case tracing is enabled, or the dummy type `()` when -/// tracing is disabled. -pub trait EnteredTraceSpan {} -impl EnteredTraceSpan for () {} -impl EnteredTraceSpan for tracing::span::EnteredSpan {} +/// tracing is disabled. Also see [crate::enter_trace_span!] below. +pub trait EnteredTraceSpan { + /// Allows executing an alternative function when tracing is disabled. Useful for example if you + /// want to open a trace span when tracing is enabled, and alternatively just log a line when + /// tracing is disabled. + fn or_if_tracing_disabled(self, f: impl FnOnce()) -> Self; +} +impl EnteredTraceSpan for () { + fn or_if_tracing_disabled(self, f: impl FnOnce()) -> Self { + f(); // tracing is disabled, execute the function + self + } +} +impl EnteredTraceSpan for tracing::span::EnteredSpan { + fn or_if_tracing_disabled(self, _f: impl FnOnce()) -> Self { + self // tracing is enabled, don't execute anything + } +} -/// Shortand for calling [crate::interpret::Machine::enter_trace_span] on a [tracing::info_span]. +/// Shortand for calling [crate::interpret::Machine::enter_trace_span] on a [tracing::info_span!]. /// This is supposed to be compiled out when [crate::interpret::Machine::enter_trace_span] has the /// default implementation (i.e. when it does not actually enter the span but instead returns `()`). +/// This macro takes a type implementing the [crate::interpret::Machine] trait as its first argument +/// and otherwise accepts the same syntax as [tracing::span!] (see some tips below). /// Note: the result of this macro **must be used** because the span is exited when it's dropped. +/// +/// ### Syntax accepted by this macro +/// +/// The full documentation for the [tracing::span!] syntax can be found at [tracing] under "Using the +/// Macros". A few possibly confusing syntaxes are listed here: +/// ```rust +/// # use rustc_const_eval::enter_trace_span; +/// # type M = rustc_const_eval::const_eval::CompileTimeMachine<'static>; +/// # let my_display_var = String::new(); +/// # let my_debug_var = String::new(); +/// // logs a span named "hello" with a field named "arg" of value 42 (works only because +/// // 42 implements the tracing::Value trait, otherwise use one of the options below) +/// let _span = enter_trace_span!(M, "hello", arg = 42); +/// // logs a field called "my_display_var" using the Display implementation +/// let _span = enter_trace_span!(M, "hello", %my_display_var); +/// // logs a field called "my_debug_var" using the Debug implementation +/// let _span = enter_trace_span!(M, "hello", ?my_debug_var); +/// ``` +/// +/// ### `NAME::SUBNAME` syntax +/// +/// In addition to the syntax accepted by [tracing::span!], this macro optionally allows passing +/// the span name (i.e. the first macro argument) in the form `NAME::SUBNAME` (without quotes) to +/// indicate that the span has name "NAME" (usually the name of the component) and has an additional +/// more specific name "SUBNAME" (usually the function name). The latter is passed to the [tracing] +/// infrastructure as a span field with the name "NAME". This allows not being distracted by +/// subnames when looking at the trace in <https://ui.perfetto.dev>, but when deeper introspection +/// is needed within a component, it's still possible to view the subnames directly in the UI by +/// selecting a span, clicking on the "NAME" argument on the right, and clicking on "Visualize +/// argument values". +/// ```rust +/// # use rustc_const_eval::enter_trace_span; +/// # type M = rustc_const_eval::const_eval::CompileTimeMachine<'static>; +/// // for example, the first will expand to the second +/// let _span = enter_trace_span!(M, borrow_tracker::on_stack_pop, /* ... */); +/// let _span = enter_trace_span!(M, "borrow_tracker", borrow_tracker = "on_stack_pop", /* ... */); +/// ``` +/// +/// ### `tracing_separate_thread` parameter +/// +/// This macro was introduced to obtain better traces of Miri without impacting release performance. +/// Miri saves traces using the the `tracing_chrome` `tracing::Layer` so that they can be visualized +/// in <https://ui.perfetto.dev>. To instruct `tracing_chrome` to put some spans on a separate trace +/// thread/line than other spans when viewed in <https://ui.perfetto.dev>, you can pass +/// `tracing_separate_thread = tracing::field::Empty` to the tracing macros. This is useful to +/// separate out spans which just indicate the current step or program frame being processed by the +/// interpreter. You should use a value of [tracing::field::Empty] so that other tracing layers +/// (e.g. the logger) will ignore the `tracing_separate_thread` field. For example: +/// ```rust +/// # use rustc_const_eval::enter_trace_span; +/// # type M = rustc_const_eval::const_eval::CompileTimeMachine<'static>; +/// let _span = enter_trace_span!(M, step::eval_statement, tracing_separate_thread = tracing::field::Empty); +/// ``` +/// +/// ### Executing something else when tracing is disabled +/// +/// [crate::interpret::Machine::enter_trace_span] returns [EnteredTraceSpan], on which you can call +/// [EnteredTraceSpan::or_if_tracing_disabled], to e.g. log a line as an alternative to the tracing +/// span for when tracing is disabled. For example: +/// ```rust +/// # use rustc_const_eval::enter_trace_span; +/// # use rustc_const_eval::interpret::EnteredTraceSpan; +/// # type M = rustc_const_eval::const_eval::CompileTimeMachine<'static>; +/// let _span = enter_trace_span!(M, step::eval_statement) +/// .or_if_tracing_disabled(|| tracing::info!("eval_statement")); +/// ``` #[macro_export] macro_rules! enter_trace_span { - ($machine:ident, $($tt:tt)*) => { - $machine::enter_trace_span(|| tracing::info_span!($($tt)*)) - } + ($machine:ty, $name:ident :: $subname:ident $($tt:tt)*) => { + $crate::enter_trace_span!($machine, stringify!($name), $name = %stringify!($subname) $($tt)*) + }; + + ($machine:ty, $($tt:tt)*) => { + <$machine as $crate::interpret::Machine>::enter_trace_span(|| tracing::info_span!($($tt)*)) + }; } diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs index a27b6646131..82c50fac6c0 100644 --- a/compiler/rustc_const_eval/src/interpret/visitor.rs +++ b/compiler/rustc_const_eval/src/interpret/visitor.rs @@ -121,25 +121,24 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized { // `Box` has two fields: the pointer we care about, and the allocator. assert_eq!(v.layout().fields.count(), 2, "`Box` must have exactly 2 fields"); - let (unique_ptr, alloc) = ( - self.ecx().project_field(v, FieldIdx::ZERO)?, - self.ecx().project_field(v, FieldIdx::ONE)?, - ); + let [unique_ptr, alloc] = + self.ecx().project_fields(v, [FieldIdx::ZERO, FieldIdx::ONE])?; + // Unfortunately there is some type junk in the way here: `unique_ptr` is a `Unique`... // (which means another 2 fields, the second of which is a `PhantomData`) assert_eq!(unique_ptr.layout().fields.count(), 2); - let (nonnull_ptr, phantom) = ( - self.ecx().project_field(&unique_ptr, FieldIdx::ZERO)?, - self.ecx().project_field(&unique_ptr, FieldIdx::ONE)?, - ); + let [nonnull_ptr, phantom] = + self.ecx().project_fields(&unique_ptr, [FieldIdx::ZERO, FieldIdx::ONE])?; assert!( phantom.layout().ty.ty_adt_def().is_some_and(|adt| adt.is_phantom_data()), "2nd field of `Unique` should be PhantomData but is {:?}", phantom.layout().ty, ); + // ... that contains a `NonNull`... (gladly, only a single field here) assert_eq!(nonnull_ptr.layout().fields.count(), 1); let raw_ptr = self.ecx().project_field(&nonnull_ptr, FieldIdx::ZERO)?; // the actual raw ptr + // ... whose only field finally is a raw ptr we can dereference. self.visit_box(ty, &raw_ptr)?; diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index bf7a79dcb20..8ace560d85d 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -1,7 +1,9 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] +#![cfg_attr(bootstrap, feature(strict_overflow_ops))] #![doc(rust_logo)] +#![feature(array_try_map)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(decl_macro)] @@ -9,7 +11,6 @@ #![feature(never_type)] #![feature(rustdoc_internals)] #![feature(slice_ptr_get)] -#![feature(strict_overflow_ops)] #![feature(trait_alias)] #![feature(try_blocks)] #![feature(unqualified_local_imports)] diff --git a/compiler/rustc_const_eval/src/util/caller_location.rs b/compiler/rustc_const_eval/src/util/caller_location.rs index c437934eaab..5249b32eca4 100644 --- a/compiler/rustc_const_eval/src/util/caller_location.rs +++ b/compiler/rustc_const_eval/src/util/caller_location.rs @@ -42,12 +42,12 @@ fn alloc_caller_location<'tcx>( let location = ecx.allocate(loc_layout, MemoryKind::CallerLocation).unwrap(); // Initialize fields. - ecx.write_immediate(filename, &ecx.project_field(&location, FieldIdx::from_u32(0)).unwrap()) - .expect("writing to memory we just allocated cannot fail"); - ecx.write_scalar(line, &ecx.project_field(&location, FieldIdx::from_u32(1)).unwrap()) - .expect("writing to memory we just allocated cannot fail"); - ecx.write_scalar(col, &ecx.project_field(&location, FieldIdx::from_u32(2)).unwrap()) + let [filename_field, line_field, col_field] = + ecx.project_fields(&location, [0, 1, 2].map(FieldIdx::from_u32)).unwrap(); + ecx.write_immediate(filename, &filename_field) .expect("writing to memory we just allocated cannot fail"); + ecx.write_scalar(line, &line_field).expect("writing to memory we just allocated cannot fail"); + ecx.write_scalar(col, &col_field).expect("writing to memory we just allocated cannot fail"); location } diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs index e8f2728a772..2dc746754f8 100644 --- a/compiler/rustc_const_eval/src/util/type_name.rs +++ b/compiler/rustc_const_eval/src/util/type_name.rs @@ -4,7 +4,7 @@ use rustc_data_structures::intern::Interned; use rustc_hir::def_id::CrateNum; use rustc_hir::definitions::DisambiguatedDefPathData; use rustc_middle::bug; -use rustc_middle::ty::print::{PrettyPrinter, Print, PrintError, Printer}; +use rustc_middle::ty::print::{PrettyPrinter, PrintError, Printer}; use rustc_middle::ty::{self, GenericArg, GenericArgKind, Ty, TyCtxt}; struct AbsolutePathPrinter<'tcx> { @@ -18,6 +18,8 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { } fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> { + // This is reachable (via `pretty_print_dyn_existential`) even though + // `<Self As PrettyPrinter>::should_print_region` returns false. See #144994. Ok(()) } @@ -89,7 +91,6 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { fn path_append_impl( &mut self, print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, - _disambiguated_data: &DisambiguatedDefPathData, self_ty: Ty<'tcx>, trait_ref: Option<ty::TraitRef<'tcx>>, ) -> Result<(), PrintError> { @@ -138,19 +139,6 @@ impl<'tcx> PrettyPrinter<'tcx> for AbsolutePathPrinter<'tcx> { fn should_print_region(&self, _region: ty::Region<'_>) -> bool { false } - fn comma_sep<T>(&mut self, mut elems: impl Iterator<Item = T>) -> Result<(), PrintError> - where - T: Print<'tcx, Self>, - { - if let Some(first) = elems.next() { - first.print(self)?; - for elem in elems { - self.path.push_str(", "); - elem.print(self)?; - } - } - Ok(()) - } fn generic_delimiters( &mut self, @@ -179,7 +167,7 @@ impl Write for AbsolutePathPrinter<'_> { } pub fn type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> String { - let mut printer = AbsolutePathPrinter { tcx, path: String::new() }; - printer.print_type(ty).unwrap(); - printer.path + let mut p = AbsolutePathPrinter { tcx, path: String::new() }; + p.print_type(ty).unwrap(); + p.path } diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index 0d6b49607eb..ae1dbd2cf51 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -4,8 +4,8 @@ version = "0.0.0" edition = "2024" [dependencies] -jiff = { version = "0.2.5", default-features = false, features = ["std"] } # tidy-alphabetical-start +jiff = { version = "0.2.5", default-features = false, features = ["std"] } rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_lowering = { path = "../rustc_ast_lowering" } diff --git a/compiler/rustc_error_codes/src/error_codes/E0562.md b/compiler/rustc_error_codes/src/error_codes/E0562.md index 95f038df56d..af7b219fb12 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0562.md +++ b/compiler/rustc_error_codes/src/error_codes/E0562.md @@ -1,5 +1,4 @@ -Abstract return types (written `impl Trait` for some trait `Trait`) are only -allowed as function and inherent impl return types. +`impl Trait` is only allowed as a function return and argument type. Erroneous code example: @@ -14,7 +13,7 @@ fn main() { } ``` -Make sure `impl Trait` only appears in return-type position. +Make sure `impl Trait` appears in a function signature. ``` fn count_to_n(n: usize) -> impl Iterator<Item=usize> { @@ -28,6 +27,6 @@ fn main() { } ``` -See [RFC 1522] for more details. +See the [reference] for more details on `impl Trait`. -[RFC 1522]: https://github.com/rust-lang/rfcs/blob/master/text/1522-conservative-impl-trait.md +[reference]: https://doc.rust-lang.org/stable/reference/types/impl-trait.html diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index c4181a62a35..3e8cf6207ae 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -10,7 +10,6 @@ derive_setters = "0.1.6" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } -rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_error_codes = { path = "../rustc_error_codes" } rustc_error_messages = { path = "../rustc_error_messages" } @@ -25,7 +24,7 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_type_ir = { path = "../rustc_type_ir" } -serde = { version = "1.0.125", features = [ "derive" ] } +serde = { version = "1.0.125", features = ["derive"] } serde_json = "1.0.59" termcolor = "1.2.0" termize = "0.2" diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 96c7ba6ed27..5a5563c7bb2 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -1382,6 +1382,11 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { &mut self.long_ty_path } + pub fn with_long_ty_path(mut self, long_ty_path: Option<PathBuf>) -> Self { + self.long_ty_path = long_ty_path; + self + } + /// Most `emit_producing_guarantee` functions use this as a starting point. fn emit_producing_nothing(mut self) { let diag = self.take_diag(); diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index eeb9ac28808..eca5806fac5 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -8,7 +8,7 @@ use std::process::ExitStatus; use rustc_abi::TargetDataLayoutErrors; use rustc_ast::util::parser::ExprPrecedence; use rustc_ast_pretty::pprust; -use rustc_attr_data_structures::RustcVersion; +use rustc_hir::RustcVersion; use rustc_macros::Subdiagnostic; use rustc_span::edition::Edition; use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, Symbol}; diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 95400ac2ca3..0c839f94f7f 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -262,19 +262,11 @@ pub trait Emitter { format!("help: {msg}") } else { // Show the default suggestion text with the substitution - format!( - "help: {}{}: `{}`", - msg, - if self - .source_map() - .is_some_and(|sm| is_case_difference(sm, snippet, part.span,)) - { - " (notice the capitalization)" - } else { - "" - }, - snippet, - ) + let confusion_type = self + .source_map() + .map(|sm| detect_confusion_type(sm, snippet, part.span)) + .unwrap_or(ConfusionType::None); + format!("help: {}{}: `{}`", msg, confusion_type.label_text(), snippet,) }; primary_span.push_span_label(part.span, msg); @@ -417,7 +409,7 @@ pub trait Emitter { if !redundant_span || always_backtrace { let msg: Cow<'static, _> = match trace.kind { ExpnKind::Macro(MacroKind::Attr, _) => { - "this procedural macro expansion".into() + "this attribute macro expansion".into() } ExpnKind::Macro(MacroKind::Derive, _) => { "this derive macro expansion".into() @@ -713,8 +705,7 @@ impl HumanEmitter { Style::LineNumber, ); } - buffer.puts(line_offset, 0, &self.maybe_anonymized(line_index), Style::LineNumber); - + self.draw_line_num(buffer, line_index, line_offset, width_offset - 3); self.draw_col_separator_no_space(buffer, line_offset, width_offset - 2); left } @@ -1598,8 +1589,9 @@ impl HumanEmitter { annotated_files.swap(0, pos); } + let annotated_files_len = annotated_files.len(); // Print out the annotate source lines that correspond with the error - for annotated_file in annotated_files { + for (file_idx, annotated_file) in annotated_files.into_iter().enumerate() { // we can't annotate anything if the source is unavailable. if !should_show_source_code( &self.ignored_directories_in_source_blocks, @@ -1856,7 +1848,9 @@ impl HumanEmitter { width_offset, code_offset, margin, - !is_cont && line_idx + 1 == annotated_file.lines.len(), + !is_cont + && file_idx + 1 == annotated_files_len + && line_idx + 1 == annotated_file.lines.len(), ); let mut to_add = FxHashMap::default(); @@ -2029,12 +2023,12 @@ impl HumanEmitter { buffer.append(0, ": ", Style::HeaderMsg); let mut msg = vec![(suggestion.msg.to_owned(), Style::NoStyle)]; - if suggestions - .iter() - .take(MAX_SUGGESTIONS) - .any(|(_, _, _, only_capitalization)| *only_capitalization) + if let Some(confusion_type) = + suggestions.iter().take(MAX_SUGGESTIONS).find_map(|(_, _, _, confusion_type)| { + if confusion_type.has_confusion() { Some(*confusion_type) } else { None } + }) { - msg.push((" (notice the capitalization difference)".into(), Style::NoStyle)); + msg.push((confusion_type.label_text().into(), Style::NoStyle)); } self.msgs_to_buffer( &mut buffer, @@ -2128,11 +2122,11 @@ impl HumanEmitter { // Account for a suggestion to completely remove a line(s) with whitespace (#94192). let line_end = sm.lookup_char_pos(parts[0].span.hi()).line; for line in line_start..=line_end { - buffer.puts( + self.draw_line_num( + &mut buffer, + line, row_num - 1 + line - line_start, - 0, - &self.maybe_anonymized(line), - Style::LineNumber, + max_line_num_len, ); buffer.puts( row_num - 1 + line - line_start, @@ -2612,12 +2606,7 @@ impl HumanEmitter { // For more info: https://github.com/rust-lang/rust/issues/92741 let lines_to_remove = file_lines.lines.iter().take(file_lines.lines.len() - 1); for (index, line_to_remove) in lines_to_remove.enumerate() { - buffer.puts( - *row_num - 1, - 0, - &self.maybe_anonymized(line_num + index), - Style::LineNumber, - ); + self.draw_line_num(buffer, line_num + index, *row_num - 1, max_line_num_len); buffer.puts(*row_num - 1, max_line_num_len + 1, "- ", Style::Removal); let line = normalize_whitespace( &file_lines.file.get_line(line_to_remove.line_index).unwrap(), @@ -2634,11 +2623,11 @@ impl HumanEmitter { let last_line_index = file_lines.lines[file_lines.lines.len() - 1].line_index; let last_line = &file_lines.file.get_line(last_line_index).unwrap(); if last_line != line_to_add { - buffer.puts( + self.draw_line_num( + buffer, + line_num + file_lines.lines.len() - 1, *row_num - 1, - 0, - &self.maybe_anonymized(line_num + file_lines.lines.len() - 1), - Style::LineNumber, + max_line_num_len, ); buffer.puts(*row_num - 1, max_line_num_len + 1, "- ", Style::Removal); buffer.puts( @@ -2661,7 +2650,7 @@ impl HumanEmitter { // 2 - .await // | // *row_num -= 1; - buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber); + self.draw_line_num(buffer, line_num, *row_num, max_line_num_len); buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition); buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle); } else { @@ -2671,7 +2660,7 @@ impl HumanEmitter { *row_num -= 2; } } else if is_multiline { - buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber); + self.draw_line_num(buffer, line_num, *row_num, max_line_num_len); match &highlight_parts { [SubstitutionHighlight { start: 0, end }] if *end == line_to_add.len() => { buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition); @@ -2702,11 +2691,11 @@ impl HumanEmitter { Style::NoStyle, ); } else if let DisplaySuggestion::Add = show_code_change { - buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber); + self.draw_line_num(buffer, line_num, *row_num, max_line_num_len); buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition); buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle); } else { - buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber); + self.draw_line_num(buffer, line_num, *row_num, max_line_num_len); self.draw_col_separator(buffer, *row_num, max_line_num_len + 1); buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle); } @@ -2991,7 +2980,7 @@ impl HumanEmitter { fn secondary_file_start(&self) -> &'static str { match self.theme { OutputTheme::Ascii => "::: ", - OutputTheme::Unicode => " ⸬ ", + OutputTheme::Unicode => " ⸬ ", } } @@ -3016,6 +3005,22 @@ impl HumanEmitter { OutputTheme::Unicode => "…", } } + + fn draw_line_num( + &self, + buffer: &mut StyledBuffer, + line_num: usize, + line_offset: usize, + max_line_num_len: usize, + ) { + let line_num = self.maybe_anonymized(line_num); + buffer.puts( + line_offset, + max_line_num_len.saturating_sub(str_width(&line_num)), + &line_num, + Style::LineNumber, + ); + } } #[derive(Debug, Clone, Copy)] @@ -3518,24 +3523,107 @@ pub fn is_different(sm: &SourceMap, suggested: &str, sp: Span) -> bool { } /// Whether the original and suggested code are visually similar enough to warrant extra wording. -pub fn is_case_difference(sm: &SourceMap, suggested: &str, sp: Span) -> bool { - // FIXME: this should probably be extended to also account for `FO0` → `FOO` and unicode. +pub fn detect_confusion_type(sm: &SourceMap, suggested: &str, sp: Span) -> ConfusionType { let found = match sm.span_to_snippet(sp) { Ok(snippet) => snippet, Err(e) => { warn!(error = ?e, "Invalid span {:?}", sp); - return false; + return ConfusionType::None; } }; - let ascii_confusables = &['c', 'f', 'i', 'k', 'o', 's', 'u', 'v', 'w', 'x', 'y', 'z']; - // All the chars that differ in capitalization are confusable (above): - let confusable = iter::zip(found.chars(), suggested.chars()) - .filter(|(f, s)| f != s) - .all(|(f, s)| ascii_confusables.contains(&f) || ascii_confusables.contains(&s)); - confusable && found.to_lowercase() == suggested.to_lowercase() - // FIXME: We sometimes suggest the same thing we already have, which is a - // bug, but be defensive against that here. - && found != suggested + + let mut has_case_confusion = false; + let mut has_digit_letter_confusion = false; + + if found.len() == suggested.len() { + let mut has_case_diff = false; + let mut has_digit_letter_confusable = false; + let mut has_other_diff = false; + + let ascii_confusables = &['c', 'f', 'i', 'k', 'o', 's', 'u', 'v', 'w', 'x', 'y', 'z']; + + let digit_letter_confusables = [('0', 'O'), ('1', 'l'), ('5', 'S'), ('8', 'B'), ('9', 'g')]; + + for (f, s) in iter::zip(found.chars(), suggested.chars()) { + if f != s { + if f.to_lowercase().to_string() == s.to_lowercase().to_string() { + // Check for case differences (any character that differs only in case) + if ascii_confusables.contains(&f) || ascii_confusables.contains(&s) { + has_case_diff = true; + } else { + has_other_diff = true; + } + } else if digit_letter_confusables.contains(&(f, s)) + || digit_letter_confusables.contains(&(s, f)) + { + // Check for digit-letter confusables (like 0 vs O, 1 vs l, etc.) + has_digit_letter_confusable = true; + } else { + has_other_diff = true; + } + } + } + + // If we have case differences and no other differences + if has_case_diff && !has_other_diff && found != suggested { + has_case_confusion = true; + } + if has_digit_letter_confusable && !has_other_diff && found != suggested { + has_digit_letter_confusion = true; + } + } + + match (has_case_confusion, has_digit_letter_confusion) { + (true, true) => ConfusionType::Both, + (true, false) => ConfusionType::Case, + (false, true) => ConfusionType::DigitLetter, + (false, false) => ConfusionType::None, + } +} + +/// Represents the type of confusion detected between original and suggested code. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ConfusionType { + /// No confusion detected + None, + /// Only case differences (e.g., "hello" vs "Hello") + Case, + /// Only digit-letter confusion (e.g., "0" vs "O", "1" vs "l") + DigitLetter, + /// Both case and digit-letter confusion + Both, +} + +impl ConfusionType { + /// Returns the appropriate label text for this confusion type. + pub fn label_text(&self) -> &'static str { + match self { + ConfusionType::None => "", + ConfusionType::Case => " (notice the capitalization)", + ConfusionType::DigitLetter => " (notice the digit/letter confusion)", + ConfusionType::Both => " (notice the capitalization and digit/letter confusion)", + } + } + + /// Combines two confusion types. If either is `Both`, the result is `Both`. + /// If one is `Case` and the other is `DigitLetter`, the result is `Both`. + /// Otherwise, returns the non-`None` type, or `None` if both are `None`. + pub fn combine(self, other: ConfusionType) -> ConfusionType { + match (self, other) { + (ConfusionType::None, other) => other, + (this, ConfusionType::None) => this, + (ConfusionType::Both, _) | (_, ConfusionType::Both) => ConfusionType::Both, + (ConfusionType::Case, ConfusionType::DigitLetter) + | (ConfusionType::DigitLetter, ConfusionType::Case) => ConfusionType::Both, + (ConfusionType::Case, ConfusionType::Case) => ConfusionType::Case, + (ConfusionType::DigitLetter, ConfusionType::DigitLetter) => ConfusionType::DigitLetter, + } + } + + /// Returns true if this confusion type represents any kind of confusion. + pub fn has_confusion(&self) -> bool { + *self != ConfusionType::None + } } pub(crate) fn should_show_source_code( diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 381d780077d..2534cddf105 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -50,7 +50,7 @@ pub use diagnostic_impls::{ IndicateAnonymousLifetime, SingleLabelManySpans, }; pub use emitter::ColorConfig; -use emitter::{DynEmitter, Emitter, is_case_difference, is_different}; +use emitter::{ConfusionType, DynEmitter, Emitter, detect_confusion_type, is_different}; use rustc_data_structures::AtomicRef; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::stable_hasher::StableHasher; @@ -308,7 +308,7 @@ impl CodeSuggestion { pub(crate) fn splice_lines( &self, sm: &SourceMap, - ) -> Vec<(String, Vec<SubstitutionPart>, Vec<Vec<SubstitutionHighlight>>, bool)> { + ) -> Vec<(String, Vec<SubstitutionPart>, Vec<Vec<SubstitutionHighlight>>, ConfusionType)> { // For the `Vec<Vec<SubstitutionHighlight>>` value, the first level of the vector // corresponds to the output snippet's lines, while the second level corresponds to the // substrings within that line that should be highlighted. @@ -414,14 +414,15 @@ impl CodeSuggestion { // We need to keep track of the difference between the existing code and the added // or deleted code in order to point at the correct column *after* substitution. let mut acc = 0; - let mut only_capitalization = false; + let mut confusion_type = ConfusionType::None; for part in &mut substitution.parts { // If this is a replacement of, e.g. `"a"` into `"ab"`, adjust the // suggestion and snippet to look as if we just suggested to add // `"b"`, which is typically much easier for the user to understand. part.trim_trivial_replacements(sm); - only_capitalization |= is_case_difference(sm, &part.snippet, part.span); + let part_confusion = detect_confusion_type(sm, &part.snippet, part.span); + confusion_type = confusion_type.combine(part_confusion); let cur_lo = sm.lookup_char_pos(part.span.lo()); if prev_hi.line == cur_lo.line { let mut count = @@ -511,7 +512,7 @@ impl CodeSuggestion { if highlights.iter().all(|parts| parts.is_empty()) { None } else { - Some((buf, substitution.parts, highlights, only_capitalization)) + Some((buf, substitution.parts, highlights, confusion_type)) } }) .collect() diff --git a/compiler/rustc_expand/Cargo.toml b/compiler/rustc_expand/Cargo.toml index 57dd3a3128d..f897833d85c 100644 --- a/compiler/rustc_expand/Cargo.toml +++ b/compiler/rustc_expand/Cargo.toml @@ -12,7 +12,6 @@ doctest = false rustc_ast = { path = "../rustc_ast" } rustc_ast_passes = { path = "../rustc_ast_passes" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } -rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl index 5a53670c865..1f8f3be6809 100644 --- a/compiler/rustc_expand/messages.ftl +++ b/compiler/rustc_expand/messages.ftl @@ -70,6 +70,9 @@ expand_invalid_fragment_specifier = invalid fragment specifier `{$fragment}` .help = {$help} +expand_macro_args_bad_delim = macro attribute argument matchers require parentheses +expand_macro_args_bad_delim_sugg = the delimiters should be `(` and `)` + expand_macro_body_stability = macros cannot have body stability attributes .label = invalid body stability attribute diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index c01320fc644..c234aa43c09 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -7,17 +7,17 @@ use std::rc::Rc; use std::sync::Arc; use rustc_ast::attr::{AttributeExt, MarkedAttrs}; -use rustc_ast::ptr::P; use rustc_ast::token::MetaVarKind; use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{AssocCtxt, Visitor}; use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind}; -use rustc_attr_data_structures::{AttributeKind, CfgEntry, Deprecation, Stability, find_attr}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_data_structures::sync; use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, PResult}; use rustc_feature::Features; use rustc_hir as hir; +use rustc_hir::attrs::{AttributeKind, CfgEntry, Deprecation}; +use rustc_hir::{Stability, find_attr}; use rustc_lint_defs::{BufferedEarlyLint, RegisteredTools}; use rustc_parse::MACRO_ARGUMENTS; use rustc_parse::parser::{ForceCollect, Parser}; @@ -44,11 +44,11 @@ use crate::stats::MacroStat; // to use `assign_id!` #[derive(Debug, Clone)] pub enum Annotatable { - Item(P<ast::Item>), - AssocItem(P<ast::AssocItem>, AssocCtxt), - ForeignItem(P<ast::ForeignItem>), - Stmt(P<ast::Stmt>), - Expr(P<ast::Expr>), + Item(Box<ast::Item>), + AssocItem(Box<ast::AssocItem>, AssocCtxt), + ForeignItem(Box<ast::ForeignItem>), + Stmt(Box<ast::Stmt>), + Expr(Box<ast::Expr>), Arm(ast::Arm), ExprField(ast::ExprField), PatField(ast::PatField), @@ -140,28 +140,28 @@ impl Annotatable { } } - pub fn expect_item(self) -> P<ast::Item> { + pub fn expect_item(self) -> Box<ast::Item> { match self { Annotatable::Item(i) => i, _ => panic!("expected Item"), } } - pub fn expect_trait_item(self) -> P<ast::AssocItem> { + pub fn expect_trait_item(self) -> Box<ast::AssocItem> { match self { Annotatable::AssocItem(i, AssocCtxt::Trait) => i, _ => panic!("expected Item"), } } - pub fn expect_impl_item(self) -> P<ast::AssocItem> { + pub fn expect_impl_item(self) -> Box<ast::AssocItem> { match self { Annotatable::AssocItem(i, AssocCtxt::Impl { .. }) => i, _ => panic!("expected Item"), } } - pub fn expect_foreign_item(self) -> P<ast::ForeignItem> { + pub fn expect_foreign_item(self) -> Box<ast::ForeignItem> { match self { Annotatable::ForeignItem(i) => i, _ => panic!("expected foreign item"), @@ -175,7 +175,7 @@ impl Annotatable { } } - pub fn expect_expr(self) -> P<ast::Expr> { + pub fn expect_expr(self) -> Box<ast::Expr> { match self { Annotatable::Expr(expr) => expr, _ => panic!("expected expression"), @@ -411,37 +411,37 @@ macro_rules! make_stmts_default { /// methods are spliced into the AST at the callsite of the macro. pub trait MacResult { /// Creates an expression. - fn make_expr(self: Box<Self>) -> Option<P<ast::Expr>> { + fn make_expr(self: Box<Self>) -> Option<Box<ast::Expr>> { None } /// Creates zero or more items. - fn make_items(self: Box<Self>) -> Option<SmallVec<[P<ast::Item>; 1]>> { + fn make_items(self: Box<Self>) -> Option<SmallVec<[Box<ast::Item>; 1]>> { None } /// Creates zero or more impl items. - fn make_impl_items(self: Box<Self>) -> Option<SmallVec<[P<ast::AssocItem>; 1]>> { + fn make_impl_items(self: Box<Self>) -> Option<SmallVec<[Box<ast::AssocItem>; 1]>> { None } /// Creates zero or more impl items. - fn make_trait_impl_items(self: Box<Self>) -> Option<SmallVec<[P<ast::AssocItem>; 1]>> { + fn make_trait_impl_items(self: Box<Self>) -> Option<SmallVec<[Box<ast::AssocItem>; 1]>> { None } /// Creates zero or more trait items. - fn make_trait_items(self: Box<Self>) -> Option<SmallVec<[P<ast::AssocItem>; 1]>> { + fn make_trait_items(self: Box<Self>) -> Option<SmallVec<[Box<ast::AssocItem>; 1]>> { None } /// Creates zero or more items in an `extern {}` block - fn make_foreign_items(self: Box<Self>) -> Option<SmallVec<[P<ast::ForeignItem>; 1]>> { + fn make_foreign_items(self: Box<Self>) -> Option<SmallVec<[Box<ast::ForeignItem>; 1]>> { None } /// Creates a pattern. - fn make_pat(self: Box<Self>) -> Option<P<ast::Pat>> { + fn make_pat(self: Box<Self>) -> Option<Box<ast::Pat>> { None } @@ -453,7 +453,7 @@ pub trait MacResult { make_stmts_default!(self) } - fn make_ty(self: Box<Self>) -> Option<P<ast::Ty>> { + fn make_ty(self: Box<Self>) -> Option<Box<ast::Ty>> { None } @@ -520,38 +520,38 @@ macro_rules! make_MacEager { } make_MacEager! { - expr: P<ast::Expr>, - pat: P<ast::Pat>, - items: SmallVec<[P<ast::Item>; 1]>, - impl_items: SmallVec<[P<ast::AssocItem>; 1]>, - trait_items: SmallVec<[P<ast::AssocItem>; 1]>, - foreign_items: SmallVec<[P<ast::ForeignItem>; 1]>, + expr: Box<ast::Expr>, + pat: Box<ast::Pat>, + items: SmallVec<[Box<ast::Item>; 1]>, + impl_items: SmallVec<[Box<ast::AssocItem>; 1]>, + trait_items: SmallVec<[Box<ast::AssocItem>; 1]>, + foreign_items: SmallVec<[Box<ast::ForeignItem>; 1]>, stmts: SmallVec<[ast::Stmt; 1]>, - ty: P<ast::Ty>, + ty: Box<ast::Ty>, } impl MacResult for MacEager { - fn make_expr(self: Box<Self>) -> Option<P<ast::Expr>> { + fn make_expr(self: Box<Self>) -> Option<Box<ast::Expr>> { self.expr } - fn make_items(self: Box<Self>) -> Option<SmallVec<[P<ast::Item>; 1]>> { + fn make_items(self: Box<Self>) -> Option<SmallVec<[Box<ast::Item>; 1]>> { self.items } - fn make_impl_items(self: Box<Self>) -> Option<SmallVec<[P<ast::AssocItem>; 1]>> { + fn make_impl_items(self: Box<Self>) -> Option<SmallVec<[Box<ast::AssocItem>; 1]>> { self.impl_items } - fn make_trait_impl_items(self: Box<Self>) -> Option<SmallVec<[P<ast::AssocItem>; 1]>> { + fn make_trait_impl_items(self: Box<Self>) -> Option<SmallVec<[Box<ast::AssocItem>; 1]>> { self.impl_items } - fn make_trait_items(self: Box<Self>) -> Option<SmallVec<[P<ast::AssocItem>; 1]>> { + fn make_trait_items(self: Box<Self>) -> Option<SmallVec<[Box<ast::AssocItem>; 1]>> { self.trait_items } - fn make_foreign_items(self: Box<Self>) -> Option<SmallVec<[P<ast::ForeignItem>; 1]>> { + fn make_foreign_items(self: Box<Self>) -> Option<SmallVec<[Box<ast::ForeignItem>; 1]>> { self.foreign_items } @@ -562,13 +562,13 @@ impl MacResult for MacEager { } } - fn make_pat(self: Box<Self>) -> Option<P<ast::Pat>> { + fn make_pat(self: Box<Self>) -> Option<Box<ast::Pat>> { if let Some(p) = self.pat { return Some(p); } if let Some(e) = self.expr { if matches!(e.kind, ast::ExprKind::Lit(_) | ast::ExprKind::IncludedBytes(_)) { - return Some(P(ast::Pat { + return Some(Box::new(ast::Pat { id: ast::DUMMY_NODE_ID, span: e.span, kind: PatKind::Expr(e), @@ -579,7 +579,7 @@ impl MacResult for MacEager { None } - fn make_ty(self: Box<Self>) -> Option<P<ast::Ty>> { + fn make_ty(self: Box<Self>) -> Option<Box<ast::Ty>> { self.ty } } @@ -607,8 +607,8 @@ impl DummyResult { } /// A plain dummy expression. - pub fn raw_expr(sp: Span, guar: Option<ErrorGuaranteed>) -> P<ast::Expr> { - P(ast::Expr { + pub fn raw_expr(sp: Span, guar: Option<ErrorGuaranteed>) -> Box<ast::Expr> { + Box::new(ast::Expr { id: ast::DUMMY_NODE_ID, kind: if let Some(guar) = guar { ast::ExprKind::Err(guar) @@ -623,12 +623,12 @@ impl DummyResult { } impl MacResult for DummyResult { - fn make_expr(self: Box<DummyResult>) -> Option<P<ast::Expr>> { + fn make_expr(self: Box<DummyResult>) -> Option<Box<ast::Expr>> { Some(DummyResult::raw_expr(self.span, self.guar)) } - fn make_pat(self: Box<DummyResult>) -> Option<P<ast::Pat>> { - Some(P(ast::Pat { + fn make_pat(self: Box<DummyResult>) -> Option<Box<ast::Pat>> { + Some(Box::new(ast::Pat { id: ast::DUMMY_NODE_ID, kind: PatKind::Wild, span: self.span, @@ -636,23 +636,23 @@ impl MacResult for DummyResult { })) } - fn make_items(self: Box<DummyResult>) -> Option<SmallVec<[P<ast::Item>; 1]>> { + fn make_items(self: Box<DummyResult>) -> Option<SmallVec<[Box<ast::Item>; 1]>> { Some(SmallVec::new()) } - fn make_impl_items(self: Box<DummyResult>) -> Option<SmallVec<[P<ast::AssocItem>; 1]>> { + fn make_impl_items(self: Box<DummyResult>) -> Option<SmallVec<[Box<ast::AssocItem>; 1]>> { Some(SmallVec::new()) } - fn make_trait_impl_items(self: Box<DummyResult>) -> Option<SmallVec<[P<ast::AssocItem>; 1]>> { + fn make_trait_impl_items(self: Box<DummyResult>) -> Option<SmallVec<[Box<ast::AssocItem>; 1]>> { Some(SmallVec::new()) } - fn make_trait_items(self: Box<DummyResult>) -> Option<SmallVec<[P<ast::AssocItem>; 1]>> { + fn make_trait_items(self: Box<DummyResult>) -> Option<SmallVec<[Box<ast::AssocItem>; 1]>> { Some(SmallVec::new()) } - fn make_foreign_items(self: Box<Self>) -> Option<SmallVec<[P<ast::ForeignItem>; 1]>> { + fn make_foreign_items(self: Box<Self>) -> Option<SmallVec<[Box<ast::ForeignItem>; 1]>> { Some(SmallVec::new()) } @@ -664,11 +664,11 @@ impl MacResult for DummyResult { }]) } - fn make_ty(self: Box<DummyResult>) -> Option<P<ast::Ty>> { + fn make_ty(self: Box<DummyResult>) -> Option<Box<ast::Ty>> { // FIXME(nnethercote): you might expect `ast::TyKind::Dummy` to be used here, but some // values produced here end up being lowered to HIR, which `ast::TyKind::Dummy` does not // support, so we use an empty tuple instead. - Some(P(ast::Ty { + Some(Box::new(ast::Ty { id: ast::DUMMY_NODE_ID, kind: ast::TyKind::Tup(ThinVec::new()), span: self.span, @@ -1161,7 +1161,7 @@ pub trait LintStoreExpand { registered_tools: &RegisteredTools, node_id: NodeId, attrs: &[Attribute], - items: &[P<Item>], + items: &[Box<Item>], name: Symbol, ); } diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 51d6e43ab67..c3e86ec0614 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -1,4 +1,3 @@ -use rustc_ast::ptr::P; use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::TokenStream; use rustc_ast::util::literal; @@ -59,10 +58,10 @@ impl<'a> ExtCtxt<'a> { path: ast::Path, delim: Delimiter, tokens: TokenStream, - ) -> P<ast::MacCall> { - P(ast::MacCall { + ) -> Box<ast::MacCall> { + Box::new(ast::MacCall { path, - args: P(ast::DelimArgs { + args: Box::new(ast::DelimArgs { dspan: tokenstream::DelimSpan { open: span, close: span }, delim, tokens, @@ -70,32 +69,32 @@ impl<'a> ExtCtxt<'a> { }) } - pub fn ty_mt(&self, ty: P<ast::Ty>, mutbl: ast::Mutability) -> ast::MutTy { + pub fn ty_mt(&self, ty: Box<ast::Ty>, mutbl: ast::Mutability) -> ast::MutTy { ast::MutTy { ty, mutbl } } - pub fn ty(&self, span: Span, kind: ast::TyKind) -> P<ast::Ty> { - P(ast::Ty { id: ast::DUMMY_NODE_ID, span, kind, tokens: None }) + pub fn ty(&self, span: Span, kind: ast::TyKind) -> Box<ast::Ty> { + Box::new(ast::Ty { id: ast::DUMMY_NODE_ID, span, kind, tokens: None }) } - pub fn ty_infer(&self, span: Span) -> P<ast::Ty> { + pub fn ty_infer(&self, span: Span) -> Box<ast::Ty> { self.ty(span, ast::TyKind::Infer) } - pub fn ty_path(&self, path: ast::Path) -> P<ast::Ty> { + pub fn ty_path(&self, path: ast::Path) -> Box<ast::Ty> { self.ty(path.span, ast::TyKind::Path(None, path)) } // Might need to take bounds as an argument in the future, if you ever want // to generate a bounded existential trait type. - pub fn ty_ident(&self, span: Span, ident: Ident) -> P<ast::Ty> { + pub fn ty_ident(&self, span: Span, ident: Ident) -> Box<ast::Ty> { self.ty_path(self.path_ident(span, ident)) } pub fn anon_const(&self, span: Span, kind: ast::ExprKind) -> ast::AnonConst { ast::AnonConst { id: ast::DUMMY_NODE_ID, - value: P(ast::Expr { + value: Box::new(ast::Expr { id: ast::DUMMY_NODE_ID, kind, span, @@ -112,14 +111,14 @@ impl<'a> ExtCtxt<'a> { pub fn ty_ref( &self, span: Span, - ty: P<ast::Ty>, + ty: Box<ast::Ty>, lifetime: Option<ast::Lifetime>, mutbl: ast::Mutability, - ) -> P<ast::Ty> { + ) -> Box<ast::Ty> { self.ty(span, ast::TyKind::Ref(lifetime, self.ty_mt(ty, mutbl))) } - pub fn ty_ptr(&self, span: Span, ty: P<ast::Ty>, mutbl: ast::Mutability) -> P<ast::Ty> { + pub fn ty_ptr(&self, span: Span, ty: Box<ast::Ty>, mutbl: ast::Mutability) -> Box<ast::Ty> { self.ty(span, ast::TyKind::Ptr(self.ty_mt(ty, mutbl))) } @@ -128,7 +127,7 @@ impl<'a> ExtCtxt<'a> { span: Span, ident: Ident, bounds: ast::GenericBounds, - default: Option<P<ast::Ty>>, + default: Option<Box<ast::Ty>>, ) -> ast::GenericParam { ast::GenericParam { ident: ident.with_span_pos(span), @@ -163,7 +162,7 @@ impl<'a> ExtCtxt<'a> { span: Span, ident: Ident, bounds: ast::GenericBounds, - ty: P<ast::Ty>, + ty: Box<ast::Ty>, default: Option<AnonConst>, ) -> ast::GenericParam { ast::GenericParam { @@ -211,11 +210,11 @@ impl<'a> ExtCtxt<'a> { self.lifetime(span, Ident::new(kw::StaticLifetime, span)) } - pub fn stmt_expr(&self, expr: P<ast::Expr>) -> ast::Stmt { + pub fn stmt_expr(&self, expr: Box<ast::Expr>) -> ast::Stmt { ast::Stmt { id: ast::DUMMY_NODE_ID, span: expr.span, kind: ast::StmtKind::Expr(expr) } } - pub fn stmt_let(&self, sp: Span, mutbl: bool, ident: Ident, ex: P<ast::Expr>) -> ast::Stmt { + pub fn stmt_let(&self, sp: Span, mutbl: bool, ident: Ident, ex: Box<ast::Expr>) -> ast::Stmt { self.stmt_let_ty(sp, mutbl, ident, None, ex) } @@ -224,15 +223,15 @@ impl<'a> ExtCtxt<'a> { sp: Span, mutbl: bool, ident: Ident, - ty: Option<P<ast::Ty>>, - ex: P<ast::Expr>, + ty: Option<Box<ast::Ty>>, + ex: Box<ast::Expr>, ) -> ast::Stmt { let pat = if mutbl { self.pat_ident_binding_mode(sp, ident, ast::BindingMode::MUT) } else { self.pat_ident(sp, ident) }; - let local = P(ast::Local { + let local = Box::new(ast::Local { super_: None, pat, ty, @@ -247,8 +246,8 @@ impl<'a> ExtCtxt<'a> { } /// Generates `let _: Type;`, which is usually used for type assertions. - pub fn stmt_let_type_only(&self, span: Span, ty: P<ast::Ty>) -> ast::Stmt { - let local = P(ast::Local { + pub fn stmt_let_type_only(&self, span: Span, ty: Box<ast::Ty>) -> ast::Stmt { + let local = Box::new(ast::Local { super_: None, pat: self.pat_wild(span), ty: Some(ty), @@ -262,19 +261,19 @@ impl<'a> ExtCtxt<'a> { self.stmt_local(local, span) } - pub fn stmt_semi(&self, expr: P<ast::Expr>) -> ast::Stmt { + pub fn stmt_semi(&self, expr: Box<ast::Expr>) -> ast::Stmt { ast::Stmt { id: ast::DUMMY_NODE_ID, span: expr.span, kind: ast::StmtKind::Semi(expr) } } - pub fn stmt_local(&self, local: P<ast::Local>, span: Span) -> ast::Stmt { + pub fn stmt_local(&self, local: Box<ast::Local>, span: Span) -> ast::Stmt { ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Let(local), span } } - pub fn stmt_item(&self, sp: Span, item: P<ast::Item>) -> ast::Stmt { + pub fn stmt_item(&self, sp: Span, item: Box<ast::Item>) -> ast::Stmt { ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Item(item), span: sp } } - pub fn block_expr(&self, expr: P<ast::Expr>) -> P<ast::Block> { + pub fn block_expr(&self, expr: Box<ast::Expr>) -> Box<ast::Block> { self.block( expr.span, thin_vec![ast::Stmt { @@ -284,8 +283,8 @@ impl<'a> ExtCtxt<'a> { }], ) } - pub fn block(&self, span: Span, stmts: ThinVec<ast::Stmt>) -> P<ast::Block> { - P(ast::Block { + pub fn block(&self, span: Span, stmts: ThinVec<ast::Stmt>) -> Box<ast::Block> { + Box::new(ast::Block { stmts, id: ast::DUMMY_NODE_ID, rules: BlockCheckMode::Default, @@ -294,22 +293,28 @@ impl<'a> ExtCtxt<'a> { }) } - pub fn expr(&self, span: Span, kind: ast::ExprKind) -> P<ast::Expr> { - P(ast::Expr { id: ast::DUMMY_NODE_ID, kind, span, attrs: AttrVec::new(), tokens: None }) + pub fn expr(&self, span: Span, kind: ast::ExprKind) -> Box<ast::Expr> { + Box::new(ast::Expr { + id: ast::DUMMY_NODE_ID, + kind, + span, + attrs: AttrVec::new(), + tokens: None, + }) } - pub fn expr_path(&self, path: ast::Path) -> P<ast::Expr> { + pub fn expr_path(&self, path: ast::Path) -> Box<ast::Expr> { self.expr(path.span, ast::ExprKind::Path(None, path)) } - pub fn expr_ident(&self, span: Span, id: Ident) -> P<ast::Expr> { + pub fn expr_ident(&self, span: Span, id: Ident) -> Box<ast::Expr> { self.expr_path(self.path_ident(span, id)) } - pub fn expr_self(&self, span: Span) -> P<ast::Expr> { + pub fn expr_self(&self, span: Span) -> Box<ast::Expr> { self.expr_ident(span, Ident::with_dummy_span(kw::SelfLower)) } - pub fn expr_macro_call(&self, span: Span, call: P<ast::MacCall>) -> P<ast::Expr> { + pub fn expr_macro_call(&self, span: Span, call: Box<ast::MacCall>) -> Box<ast::Expr> { self.expr(span, ast::ExprKind::MacCall(call)) } @@ -317,31 +322,31 @@ impl<'a> ExtCtxt<'a> { &self, sp: Span, op: ast::BinOpKind, - lhs: P<ast::Expr>, - rhs: P<ast::Expr>, - ) -> P<ast::Expr> { + lhs: Box<ast::Expr>, + rhs: Box<ast::Expr>, + ) -> Box<ast::Expr> { self.expr(sp, ast::ExprKind::Binary(Spanned { node: op, span: sp }, lhs, rhs)) } - pub fn expr_deref(&self, sp: Span, e: P<ast::Expr>) -> P<ast::Expr> { + pub fn expr_deref(&self, sp: Span, e: Box<ast::Expr>) -> Box<ast::Expr> { self.expr(sp, ast::ExprKind::Unary(UnOp::Deref, e)) } - pub fn expr_addr_of(&self, sp: Span, e: P<ast::Expr>) -> P<ast::Expr> { + pub fn expr_addr_of(&self, sp: Span, e: Box<ast::Expr>) -> Box<ast::Expr> { self.expr(sp, ast::ExprKind::AddrOf(ast::BorrowKind::Ref, ast::Mutability::Not, e)) } - pub fn expr_paren(&self, sp: Span, e: P<ast::Expr>) -> P<ast::Expr> { + pub fn expr_paren(&self, sp: Span, e: Box<ast::Expr>) -> Box<ast::Expr> { self.expr(sp, ast::ExprKind::Paren(e)) } pub fn expr_method_call( &self, span: Span, - expr: P<ast::Expr>, + expr: Box<ast::Expr>, ident: Ident, - args: ThinVec<P<ast::Expr>>, - ) -> P<ast::Expr> { + args: ThinVec<Box<ast::Expr>>, + ) -> Box<ast::Expr> { let seg = ast::PathSegment::from_ident(ident); self.expr( span, @@ -357,38 +362,38 @@ impl<'a> ExtCtxt<'a> { pub fn expr_call( &self, span: Span, - expr: P<ast::Expr>, - args: ThinVec<P<ast::Expr>>, - ) -> P<ast::Expr> { + expr: Box<ast::Expr>, + args: ThinVec<Box<ast::Expr>>, + ) -> Box<ast::Expr> { self.expr(span, ast::ExprKind::Call(expr, args)) } - pub fn expr_loop(&self, sp: Span, block: P<ast::Block>) -> P<ast::Expr> { + pub fn expr_loop(&self, sp: Span, block: Box<ast::Block>) -> Box<ast::Expr> { self.expr(sp, ast::ExprKind::Loop(block, None, sp)) } - pub fn expr_asm(&self, sp: Span, expr: P<ast::InlineAsm>) -> P<ast::Expr> { + pub fn expr_asm(&self, sp: Span, expr: Box<ast::InlineAsm>) -> Box<ast::Expr> { self.expr(sp, ast::ExprKind::InlineAsm(expr)) } pub fn expr_call_ident( &self, span: Span, id: Ident, - args: ThinVec<P<ast::Expr>>, - ) -> P<ast::Expr> { + args: ThinVec<Box<ast::Expr>>, + ) -> Box<ast::Expr> { self.expr(span, ast::ExprKind::Call(self.expr_ident(span, id), args)) } pub fn expr_call_global( &self, sp: Span, fn_path: Vec<Ident>, - args: ThinVec<P<ast::Expr>>, - ) -> P<ast::Expr> { + args: ThinVec<Box<ast::Expr>>, + ) -> Box<ast::Expr> { let pathexpr = self.expr_path(self.path_global(sp, fn_path)); self.expr_call(sp, pathexpr, args) } - pub fn expr_block(&self, b: P<ast::Block>) -> P<ast::Expr> { + pub fn expr_block(&self, b: Box<ast::Block>) -> Box<ast::Expr> { self.expr(b.span, ast::ExprKind::Block(b, None)) } - pub fn field_imm(&self, span: Span, ident: Ident, e: P<ast::Expr>) -> ast::ExprField { + pub fn field_imm(&self, span: Span, ident: Ident, e: Box<ast::Expr>) -> ast::ExprField { ast::ExprField { ident: ident.with_span_pos(span), expr: e, @@ -404,10 +409,10 @@ impl<'a> ExtCtxt<'a> { span: Span, path: ast::Path, fields: ThinVec<ast::ExprField>, - ) -> P<ast::Expr> { + ) -> Box<ast::Expr> { self.expr( span, - ast::ExprKind::Struct(P(ast::StructExpr { + ast::ExprKind::Struct(Box::new(ast::StructExpr { qself: None, path, fields, @@ -420,61 +425,61 @@ impl<'a> ExtCtxt<'a> { span: Span, id: Ident, fields: ThinVec<ast::ExprField>, - ) -> P<ast::Expr> { + ) -> Box<ast::Expr> { self.expr_struct(span, self.path_ident(span, id), fields) } - pub fn expr_usize(&self, span: Span, n: usize) -> P<ast::Expr> { + pub fn expr_usize(&self, span: Span, n: usize) -> Box<ast::Expr> { let suffix = Some(ast::UintTy::Usize.name()); let lit = token::Lit::new(token::Integer, sym::integer(n), suffix); self.expr(span, ast::ExprKind::Lit(lit)) } - pub fn expr_u32(&self, span: Span, n: u32) -> P<ast::Expr> { + pub fn expr_u32(&self, span: Span, n: u32) -> Box<ast::Expr> { let suffix = Some(ast::UintTy::U32.name()); let lit = token::Lit::new(token::Integer, sym::integer(n), suffix); self.expr(span, ast::ExprKind::Lit(lit)) } - pub fn expr_bool(&self, span: Span, value: bool) -> P<ast::Expr> { + pub fn expr_bool(&self, span: Span, value: bool) -> Box<ast::Expr> { let lit = token::Lit::new(token::Bool, if value { kw::True } else { kw::False }, None); self.expr(span, ast::ExprKind::Lit(lit)) } - pub fn expr_str(&self, span: Span, s: Symbol) -> P<ast::Expr> { + pub fn expr_str(&self, span: Span, s: Symbol) -> Box<ast::Expr> { let lit = token::Lit::new(token::Str, literal::escape_string_symbol(s), None); self.expr(span, ast::ExprKind::Lit(lit)) } - pub fn expr_byte_str(&self, span: Span, bytes: Vec<u8>) -> P<ast::Expr> { + pub fn expr_byte_str(&self, span: Span, bytes: Vec<u8>) -> Box<ast::Expr> { let lit = token::Lit::new(token::ByteStr, literal::escape_byte_str_symbol(&bytes), None); self.expr(span, ast::ExprKind::Lit(lit)) } /// `[expr1, expr2, ...]` - pub fn expr_array(&self, sp: Span, exprs: ThinVec<P<ast::Expr>>) -> P<ast::Expr> { + pub fn expr_array(&self, sp: Span, exprs: ThinVec<Box<ast::Expr>>) -> Box<ast::Expr> { self.expr(sp, ast::ExprKind::Array(exprs)) } /// `&[expr1, expr2, ...]` - pub fn expr_array_ref(&self, sp: Span, exprs: ThinVec<P<ast::Expr>>) -> P<ast::Expr> { + pub fn expr_array_ref(&self, sp: Span, exprs: ThinVec<Box<ast::Expr>>) -> Box<ast::Expr> { self.expr_addr_of(sp, self.expr_array(sp, exprs)) } - pub fn expr_some(&self, sp: Span, expr: P<ast::Expr>) -> P<ast::Expr> { + pub fn expr_some(&self, sp: Span, expr: Box<ast::Expr>) -> Box<ast::Expr> { let some = self.std_path(&[sym::option, sym::Option, sym::Some]); self.expr_call_global(sp, some, thin_vec![expr]) } - pub fn expr_none(&self, sp: Span) -> P<ast::Expr> { + pub fn expr_none(&self, sp: Span) -> Box<ast::Expr> { let none = self.std_path(&[sym::option, sym::Option, sym::None]); self.expr_path(self.path_global(sp, none)) } - pub fn expr_tuple(&self, sp: Span, exprs: ThinVec<P<ast::Expr>>) -> P<ast::Expr> { + pub fn expr_tuple(&self, sp: Span, exprs: ThinVec<Box<ast::Expr>>) -> Box<ast::Expr> { self.expr(sp, ast::ExprKind::Tup(exprs)) } - pub fn expr_unreachable(&self, span: Span) -> P<ast::Expr> { + pub fn expr_unreachable(&self, span: Span) -> Box<ast::Expr> { self.expr_macro_call( span, self.macro_call( @@ -489,12 +494,12 @@ impl<'a> ExtCtxt<'a> { ) } - pub fn expr_ok(&self, sp: Span, expr: P<ast::Expr>) -> P<ast::Expr> { + pub fn expr_ok(&self, sp: Span, expr: Box<ast::Expr>) -> Box<ast::Expr> { let ok = self.std_path(&[sym::result, sym::Result, sym::Ok]); self.expr_call_global(sp, ok, thin_vec![expr]) } - pub fn expr_try(&self, sp: Span, head: P<ast::Expr>) -> P<ast::Expr> { + pub fn expr_try(&self, sp: Span, head: Box<ast::Expr>) -> Box<ast::Expr> { let ok = self.std_path(&[sym::result, sym::Result, sym::Ok]); let ok_path = self.path_global(sp, ok); let err = self.std_path(&[sym::result, sym::Result, sym::Err]); @@ -523,16 +528,16 @@ impl<'a> ExtCtxt<'a> { self.expr_match(sp, head, thin_vec![ok_arm, err_arm]) } - pub fn pat(&self, span: Span, kind: PatKind) -> P<ast::Pat> { - P(ast::Pat { id: ast::DUMMY_NODE_ID, kind, span, tokens: None }) + pub fn pat(&self, span: Span, kind: PatKind) -> Box<ast::Pat> { + Box::new(ast::Pat { id: ast::DUMMY_NODE_ID, kind, span, tokens: None }) } - pub fn pat_wild(&self, span: Span) -> P<ast::Pat> { + pub fn pat_wild(&self, span: Span) -> Box<ast::Pat> { self.pat(span, PatKind::Wild) } - pub fn pat_lit(&self, span: Span, expr: P<ast::Expr>) -> P<ast::Pat> { + pub fn pat_lit(&self, span: Span, expr: Box<ast::Expr>) -> Box<ast::Pat> { self.pat(span, PatKind::Expr(expr)) } - pub fn pat_ident(&self, span: Span, ident: Ident) -> P<ast::Pat> { + pub fn pat_ident(&self, span: Span, ident: Ident) -> Box<ast::Pat> { self.pat_ident_binding_mode(span, ident, ast::BindingMode::NONE) } @@ -541,19 +546,19 @@ impl<'a> ExtCtxt<'a> { span: Span, ident: Ident, ann: ast::BindingMode, - ) -> P<ast::Pat> { + ) -> Box<ast::Pat> { let pat = PatKind::Ident(ann, ident.with_span_pos(span), None); self.pat(span, pat) } - pub fn pat_path(&self, span: Span, path: ast::Path) -> P<ast::Pat> { + pub fn pat_path(&self, span: Span, path: ast::Path) -> Box<ast::Pat> { self.pat(span, PatKind::Path(None, path)) } pub fn pat_tuple_struct( &self, span: Span, path: ast::Path, - subpats: ThinVec<P<ast::Pat>>, - ) -> P<ast::Pat> { + subpats: ThinVec<Box<ast::Pat>>, + ) -> Box<ast::Pat> { self.pat(span, PatKind::TupleStruct(None, path, subpats)) } pub fn pat_struct( @@ -561,20 +566,20 @@ impl<'a> ExtCtxt<'a> { span: Span, path: ast::Path, field_pats: ThinVec<ast::PatField>, - ) -> P<ast::Pat> { + ) -> Box<ast::Pat> { self.pat(span, PatKind::Struct(None, path, field_pats, ast::PatFieldsRest::None)) } - pub fn pat_tuple(&self, span: Span, pats: ThinVec<P<ast::Pat>>) -> P<ast::Pat> { + pub fn pat_tuple(&self, span: Span, pats: ThinVec<Box<ast::Pat>>) -> Box<ast::Pat> { self.pat(span, PatKind::Tuple(pats)) } - pub fn pat_some(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> { + pub fn pat_some(&self, span: Span, pat: Box<ast::Pat>) -> Box<ast::Pat> { let some = self.std_path(&[sym::option, sym::Option, sym::Some]); let path = self.path_global(span, some); self.pat_tuple_struct(span, path, thin_vec![pat]) } - pub fn arm(&self, span: Span, pat: P<ast::Pat>, expr: P<ast::Expr>) -> ast::Arm { + pub fn arm(&self, span: Span, pat: Box<ast::Pat>, expr: Box<ast::Expr>) -> ast::Arm { ast::Arm { attrs: AttrVec::new(), pat, @@ -590,22 +595,27 @@ impl<'a> ExtCtxt<'a> { self.arm(span, self.pat_wild(span), self.expr_unreachable(span)) } - pub fn expr_match(&self, span: Span, arg: P<ast::Expr>, arms: ThinVec<ast::Arm>) -> P<Expr> { + pub fn expr_match( + &self, + span: Span, + arg: Box<ast::Expr>, + arms: ThinVec<ast::Arm>, + ) -> Box<Expr> { self.expr(span, ast::ExprKind::Match(arg, arms, MatchKind::Prefix)) } pub fn expr_if( &self, span: Span, - cond: P<ast::Expr>, - then: P<ast::Expr>, - els: Option<P<ast::Expr>>, - ) -> P<ast::Expr> { + cond: Box<ast::Expr>, + then: Box<ast::Expr>, + els: Option<Box<ast::Expr>>, + ) -> Box<ast::Expr> { let els = els.map(|x| self.expr_block(self.block_expr(x))); self.expr(span, ast::ExprKind::If(cond, self.block_expr(then), els)) } - pub fn lambda(&self, span: Span, ids: Vec<Ident>, body: P<ast::Expr>) -> P<ast::Expr> { + pub fn lambda(&self, span: Span, ids: Vec<Ident>, body: Box<ast::Expr>) -> Box<ast::Expr> { let fn_decl = self.fn_decl( ids.iter().map(|id| self.param(span, *id, self.ty(span, ast::TyKind::Infer))).collect(), ast::FnRetTy::Default(span), @@ -633,11 +643,11 @@ impl<'a> ExtCtxt<'a> { ) } - pub fn lambda0(&self, span: Span, body: P<ast::Expr>) -> P<ast::Expr> { + pub fn lambda0(&self, span: Span, body: Box<ast::Expr>) -> Box<ast::Expr> { self.lambda(span, Vec::new(), body) } - pub fn lambda1(&self, span: Span, body: P<ast::Expr>, ident: Ident) -> P<ast::Expr> { + pub fn lambda1(&self, span: Span, body: Box<ast::Expr>, ident: Ident) -> Box<ast::Expr> { self.lambda(span, vec![ident], body) } @@ -646,11 +656,11 @@ impl<'a> ExtCtxt<'a> { span: Span, stmts: ThinVec<ast::Stmt>, ident: Ident, - ) -> P<ast::Expr> { + ) -> Box<ast::Expr> { self.lambda1(span, self.expr_block(self.block(span, stmts)), ident) } - pub fn param(&self, span: Span, ident: Ident, ty: P<ast::Ty>) -> ast::Param { + pub fn param(&self, span: Span, ident: Ident, ty: Box<ast::Ty>) -> ast::Param { let arg_pat = self.pat_ident(span, ident); ast::Param { attrs: AttrVec::default(), @@ -663,12 +673,12 @@ impl<'a> ExtCtxt<'a> { } // `self` is unused but keep it as method for the convenience use. - pub fn fn_decl(&self, inputs: ThinVec<ast::Param>, output: ast::FnRetTy) -> P<ast::FnDecl> { - P(ast::FnDecl { inputs, output }) + pub fn fn_decl(&self, inputs: ThinVec<ast::Param>, output: ast::FnRetTy) -> Box<ast::FnDecl> { + Box::new(ast::FnDecl { inputs, output }) } - pub fn item(&self, span: Span, attrs: ast::AttrVec, kind: ast::ItemKind) -> P<ast::Item> { - P(ast::Item { + pub fn item(&self, span: Span, attrs: ast::AttrVec, kind: ast::ItemKind) -> Box<ast::Item> { + Box::new(ast::Item { attrs, id: ast::DUMMY_NODE_ID, kind, @@ -686,10 +696,10 @@ impl<'a> ExtCtxt<'a> { &self, span: Span, ident: Ident, - ty: P<ast::Ty>, + ty: Box<ast::Ty>, mutability: ast::Mutability, - expr: P<ast::Expr>, - ) -> P<ast::Item> { + expr: Box<ast::Expr>, + ) -> Box<ast::Item> { self.item( span, AttrVec::new(), @@ -711,9 +721,9 @@ impl<'a> ExtCtxt<'a> { &self, span: Span, ident: Ident, - ty: P<ast::Ty>, - expr: P<ast::Expr>, - ) -> P<ast::Item> { + ty: Box<ast::Ty>, + expr: Box<ast::Expr>, + ) -> Box<ast::Item> { let defaultness = ast::Defaultness::Final; self.item( span, diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index fd1391a554a..e58269991fc 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -482,3 +482,21 @@ mod metavar_exprs { pub key: MacroRulesNormalizedIdent, } } + +#[derive(Diagnostic)] +#[diag(expand_macro_args_bad_delim)] +pub(crate) struct MacroArgsBadDelim { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub sugg: MacroArgsBadDelimSugg, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(expand_macro_args_bad_delim_sugg, applicability = "machine-applicable")] +pub(crate) struct MacroArgsBadDelimSugg { + #[suggestion_part(code = "(")] + pub open: Span, + #[suggestion_part(code = ")")] + pub close: Span, +} diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 0517fd0419d..e7ae4416968 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -4,7 +4,6 @@ use std::sync::Arc; use std::{iter, mem}; use rustc_ast::mut_visit::*; -use rustc_ast::ptr::P; use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{self, AssocCtxt, Visitor, VisitorResult, try_visit, walk_list}; use rustc_ast::{ @@ -65,8 +64,8 @@ macro_rules! ast_fragments { /// A fragment of AST that can be produced by a single macro expansion. /// Can also serve as an input and intermediate result for macro expansion operations. pub enum AstFragment { - OptExpr(Option<P<ast::Expr>>), - MethodReceiverExpr(P<ast::Expr>), + OptExpr(Option<Box<ast::Expr>>), + MethodReceiverExpr(Box<ast::Expr>), $($Kind($AstTy),)* } @@ -112,14 +111,14 @@ macro_rules! ast_fragments { } } - pub(crate) fn make_opt_expr(self) -> Option<P<ast::Expr>> { + pub(crate) fn make_opt_expr(self) -> Option<Box<ast::Expr>> { match self { AstFragment::OptExpr(expr) => expr, _ => panic!("AstFragment::make_* called on the wrong kind of fragment"), } } - pub(crate) fn make_method_receiver_expr(self) -> P<ast::Expr> { + pub(crate) fn make_method_receiver_expr(self) -> Box<ast::Expr> { match self { AstFragment::MethodReceiverExpr(expr) => expr, _ => panic!("AstFragment::make_* called on the wrong kind of fragment"), @@ -188,17 +187,17 @@ macro_rules! ast_fragments { } ast_fragments! { - Expr(P<ast::Expr>) { + Expr(Box<ast::Expr>) { "expression"; one fn visit_expr; fn visit_expr; fn pprust::expr_to_string; fn make_expr; } - Pat(P<ast::Pat>) { + Pat(Box<ast::Pat>) { "pattern"; one fn visit_pat; fn visit_pat; fn pprust::pat_to_string; fn make_pat; } - Ty(P<ast::Ty>) { + Ty(Box<ast::Ty>) { "type"; one fn visit_ty; fn visit_ty; fn pprust::ty_to_string; fn make_ty; @@ -208,30 +207,30 @@ ast_fragments! { many fn flat_map_stmt; fn visit_stmt(); fn pprust::stmt_to_string; fn make_stmts; } - Items(SmallVec<[P<ast::Item>; 1]>) { + Items(SmallVec<[Box<ast::Item>; 1]>) { "item"; many fn flat_map_item; fn visit_item(); fn pprust::item_to_string; fn make_items; } - TraitItems(SmallVec<[P<ast::AssocItem>; 1]>) { + TraitItems(SmallVec<[Box<ast::AssocItem>; 1]>) { "trait item"; many fn flat_map_assoc_item; fn visit_assoc_item(AssocCtxt::Trait); fn pprust::assoc_item_to_string; fn make_trait_items; } - ImplItems(SmallVec<[P<ast::AssocItem>; 1]>) { + ImplItems(SmallVec<[Box<ast::AssocItem>; 1]>) { "impl item"; many fn flat_map_assoc_item; fn visit_assoc_item(AssocCtxt::Impl { of_trait: false }); fn pprust::assoc_item_to_string; fn make_impl_items; } - TraitImplItems(SmallVec<[P<ast::AssocItem>; 1]>) { + TraitImplItems(SmallVec<[Box<ast::AssocItem>; 1]>) { "impl item"; many fn flat_map_assoc_item; fn visit_assoc_item(AssocCtxt::Impl { of_trait: true }); fn pprust::assoc_item_to_string; fn make_trait_impl_items; } - ForeignItems(SmallVec<[P<ast::ForeignItem>; 1]>) { + ForeignItems(SmallVec<[Box<ast::ForeignItem>; 1]>) { "foreign item"; many fn flat_map_foreign_item; fn visit_foreign_item(); fn pprust::foreign_item_to_string; fn make_foreign_items; @@ -392,7 +391,7 @@ pub struct Invocation { pub enum InvocationKind { Bang { - mac: P<ast::MacCall>, + mac: Box<ast::MacCall>, span: Span, }, Attr { @@ -409,7 +408,7 @@ pub enum InvocationKind { item: Annotatable, }, GlobDelegation { - item: P<ast::AssocItem>, + item: Box<ast::AssocItem>, /// Whether this is a trait impl or an inherent impl of_trait: bool, }, @@ -948,15 +947,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> { _ => unreachable!(), }; - type Node = AstNodeWrapper<P<ast::AssocItem>, ImplItemTag>; + type Node = AstNodeWrapper<Box<ast::AssocItem>, ImplItemTag>; let single_delegations = build_single_delegations::<Node>( self.cx, deleg, &item, &suffixes, item.span, true, ); // `-Zmacro-stats` ignores these because they don't seem important. - fragment_kind.expect_from_annotatables( - single_delegations - .map(|item| Annotatable::AssocItem(P(item), AssocCtxt::Impl { of_trait })), - ) + fragment_kind.expect_from_annotatables(single_delegations.map(|item| { + Annotatable::AssocItem(Box::new(item), AssocCtxt::Impl { of_trait }) + })) } }) } @@ -1228,7 +1226,7 @@ trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized { fn is_mac_call(&self) -> bool { false } - fn take_mac_call(self) -> (P<ast::MacCall>, ast::AttrVec, AddSemicolon) { + fn take_mac_call(self) -> (Box<ast::MacCall>, ast::AttrVec, AddSemicolon) { unreachable!() } fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> { @@ -1269,7 +1267,7 @@ trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized { } } -impl InvocationCollectorNode for P<ast::Item> { +impl InvocationCollectorNode for Box<ast::Item> { const KIND: AstFragmentKind = AstFragmentKind::Items; fn to_annotatable(self) -> Annotatable { Annotatable::Item(self) @@ -1283,7 +1281,7 @@ impl InvocationCollectorNode for P<ast::Item> { fn is_mac_call(&self) -> bool { matches!(self.kind, ItemKind::MacCall(..)) } - fn take_mac_call(self) -> (P<ast::MacCall>, ast::AttrVec, AddSemicolon) { + fn take_mac_call(self) -> (Box<ast::MacCall>, ast::AttrVec, AddSemicolon) { match self.kind { ItemKind::MacCall(mac) => (mac, self.attrs, AddSemicolon::No), _ => unreachable!(), @@ -1299,7 +1297,7 @@ impl InvocationCollectorNode for P<ast::Item> { ItemKind::Delegation(deleg) } fn from_item(item: ast::Item<Self::ItemKind>) -> Self { - P(item) + Box::new(item) } fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy { items.flatten().collect() @@ -1411,9 +1409,8 @@ impl InvocationCollectorNode for P<ast::Item> { } } } - let mut idents = Vec::new(); - collect_use_tree_leaves(ut, &mut idents); + collect_use_tree_leaves(&ut, &mut idents); idents } else { self.kind.ident().into_iter().collect() @@ -1422,8 +1419,8 @@ impl InvocationCollectorNode for P<ast::Item> { } struct TraitItemTag; -impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitItemTag> { - type OutputTy = SmallVec<[P<ast::AssocItem>; 1]>; +impl InvocationCollectorNode for AstNodeWrapper<Box<ast::AssocItem>, TraitItemTag> { + type OutputTy = SmallVec<[Box<ast::AssocItem>; 1]>; type ItemKind = AssocItemKind; const KIND: AstFragmentKind = AstFragmentKind::TraitItems; fn to_annotatable(self) -> Annotatable { @@ -1438,7 +1435,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitItemTag> fn is_mac_call(&self) -> bool { matches!(self.wrapped.kind, AssocItemKind::MacCall(..)) } - fn take_mac_call(self) -> (P<ast::MacCall>, ast::AttrVec, AddSemicolon) { + fn take_mac_call(self) -> (Box<ast::MacCall>, ast::AttrVec, AddSemicolon) { let item = self.wrapped; match item.kind { AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No), @@ -1455,7 +1452,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitItemTag> AssocItemKind::Delegation(deleg) } fn from_item(item: ast::Item<Self::ItemKind>) -> Self { - AstNodeWrapper::new(P(item), TraitItemTag) + AstNodeWrapper::new(Box::new(item), TraitItemTag) } fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy { items.flatten().collect() @@ -1463,8 +1460,8 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitItemTag> } struct ImplItemTag; -impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, ImplItemTag> { - type OutputTy = SmallVec<[P<ast::AssocItem>; 1]>; +impl InvocationCollectorNode for AstNodeWrapper<Box<ast::AssocItem>, ImplItemTag> { + type OutputTy = SmallVec<[Box<ast::AssocItem>; 1]>; type ItemKind = AssocItemKind; const KIND: AstFragmentKind = AstFragmentKind::ImplItems; fn to_annotatable(self) -> Annotatable { @@ -1479,7 +1476,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, ImplItemTag> fn is_mac_call(&self) -> bool { matches!(self.wrapped.kind, AssocItemKind::MacCall(..)) } - fn take_mac_call(self) -> (P<ast::MacCall>, ast::AttrVec, AddSemicolon) { + fn take_mac_call(self) -> (Box<ast::MacCall>, ast::AttrVec, AddSemicolon) { let item = self.wrapped; match item.kind { AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No), @@ -1496,7 +1493,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, ImplItemTag> AssocItemKind::Delegation(deleg) } fn from_item(item: ast::Item<Self::ItemKind>) -> Self { - AstNodeWrapper::new(P(item), ImplItemTag) + AstNodeWrapper::new(Box::new(item), ImplItemTag) } fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy { items.flatten().collect() @@ -1504,8 +1501,8 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, ImplItemTag> } struct TraitImplItemTag; -impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitImplItemTag> { - type OutputTy = SmallVec<[P<ast::AssocItem>; 1]>; +impl InvocationCollectorNode for AstNodeWrapper<Box<ast::AssocItem>, TraitImplItemTag> { + type OutputTy = SmallVec<[Box<ast::AssocItem>; 1]>; type ItemKind = AssocItemKind; const KIND: AstFragmentKind = AstFragmentKind::TraitImplItems; fn to_annotatable(self) -> Annotatable { @@ -1520,7 +1517,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitImplItem fn is_mac_call(&self) -> bool { matches!(self.wrapped.kind, AssocItemKind::MacCall(..)) } - fn take_mac_call(self) -> (P<ast::MacCall>, ast::AttrVec, AddSemicolon) { + fn take_mac_call(self) -> (Box<ast::MacCall>, ast::AttrVec, AddSemicolon) { let item = self.wrapped; match item.kind { AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No), @@ -1537,14 +1534,14 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitImplItem AssocItemKind::Delegation(deleg) } fn from_item(item: ast::Item<Self::ItemKind>) -> Self { - AstNodeWrapper::new(P(item), TraitImplItemTag) + AstNodeWrapper::new(Box::new(item), TraitImplItemTag) } fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy { items.flatten().collect() } } -impl InvocationCollectorNode for P<ast::ForeignItem> { +impl InvocationCollectorNode for Box<ast::ForeignItem> { const KIND: AstFragmentKind = AstFragmentKind::ForeignItems; fn to_annotatable(self) -> Annotatable { Annotatable::ForeignItem(self) @@ -1558,7 +1555,7 @@ impl InvocationCollectorNode for P<ast::ForeignItem> { fn is_mac_call(&self) -> bool { matches!(self.kind, ForeignItemKind::MacCall(..)) } - fn take_mac_call(self) -> (P<ast::MacCall>, ast::AttrVec, AddSemicolon) { + fn take_mac_call(self) -> (Box<ast::MacCall>, ast::AttrVec, AddSemicolon) { match self.kind { ForeignItemKind::MacCall(mac) => (mac, self.attrs, AddSemicolon::No), _ => unreachable!(), @@ -1673,7 +1670,7 @@ impl InvocationCollectorNode for ast::Arm { impl InvocationCollectorNode for ast::Stmt { const KIND: AstFragmentKind = AstFragmentKind::Stmts; fn to_annotatable(self) -> Annotatable { - Annotatable::Stmt(P(self)) + Annotatable::Stmt(Box::new(self)) } fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_stmts() @@ -1690,7 +1687,7 @@ impl InvocationCollectorNode for ast::Stmt { StmtKind::Let(..) | StmtKind::Empty => false, } } - fn take_mac_call(self) -> (P<ast::MacCall>, ast::AttrVec, AddSemicolon) { + fn take_mac_call(self) -> (Box<ast::MacCall>, ast::AttrVec, AddSemicolon) { // We pull macro invocations (both attributes and fn-like macro calls) out of their // `StmtKind`s and treat them as statement macro invocations, not as items or expressions. let (add_semicolon, mac, attrs) = match self.kind { @@ -1727,7 +1724,7 @@ impl InvocationCollectorNode for ast::Stmt { ItemKind::Delegation(deleg) } fn from_item(item: ast::Item<Self::ItemKind>) -> Self { - ast::Stmt { id: ast::DUMMY_NODE_ID, span: item.span, kind: StmtKind::Item(P(item)) } + ast::Stmt { id: ast::DUMMY_NODE_ID, span: item.span, kind: StmtKind::Item(Box::new(item)) } } fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy { items.flatten().collect() @@ -1770,7 +1767,7 @@ impl InvocationCollectorNode for ast::Crate { } impl InvocationCollectorNode for ast::Ty { - type OutputTy = P<ast::Ty>; + type OutputTy = Box<ast::Ty>; const KIND: AstFragmentKind = AstFragmentKind::Ty; fn to_annotatable(self) -> Annotatable { unreachable!() @@ -1794,7 +1791,7 @@ impl InvocationCollectorNode for ast::Ty { fn is_mac_call(&self) -> bool { matches!(self.kind, ast::TyKind::MacCall(..)) } - fn take_mac_call(self) -> (P<ast::MacCall>, ast::AttrVec, AddSemicolon) { + fn take_mac_call(self) -> (Box<ast::MacCall>, ast::AttrVec, AddSemicolon) { match self.kind { TyKind::MacCall(mac) => (mac, AttrVec::new(), AddSemicolon::No), _ => unreachable!(), @@ -1803,7 +1800,7 @@ impl InvocationCollectorNode for ast::Ty { } impl InvocationCollectorNode for ast::Pat { - type OutputTy = P<ast::Pat>; + type OutputTy = Box<ast::Pat>; const KIND: AstFragmentKind = AstFragmentKind::Pat; fn to_annotatable(self) -> Annotatable { unreachable!() @@ -1817,7 +1814,7 @@ impl InvocationCollectorNode for ast::Pat { fn is_mac_call(&self) -> bool { matches!(self.kind, PatKind::MacCall(..)) } - fn take_mac_call(self) -> (P<ast::MacCall>, ast::AttrVec, AddSemicolon) { + fn take_mac_call(self) -> (Box<ast::MacCall>, ast::AttrVec, AddSemicolon) { match self.kind { PatKind::MacCall(mac) => (mac, AttrVec::new(), AddSemicolon::No), _ => unreachable!(), @@ -1826,10 +1823,10 @@ impl InvocationCollectorNode for ast::Pat { } impl InvocationCollectorNode for ast::Expr { - type OutputTy = P<ast::Expr>; + type OutputTy = Box<ast::Expr>; const KIND: AstFragmentKind = AstFragmentKind::Expr; fn to_annotatable(self) -> Annotatable { - Annotatable::Expr(P(self)) + Annotatable::Expr(Box::new(self)) } fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_expr() @@ -1843,7 +1840,7 @@ impl InvocationCollectorNode for ast::Expr { fn is_mac_call(&self) -> bool { matches!(self.kind, ExprKind::MacCall(..)) } - fn take_mac_call(self) -> (P<ast::MacCall>, ast::AttrVec, AddSemicolon) { + fn take_mac_call(self) -> (Box<ast::MacCall>, ast::AttrVec, AddSemicolon) { match self.kind { ExprKind::MacCall(mac) => (mac, self.attrs, AddSemicolon::No), _ => unreachable!(), @@ -1852,8 +1849,8 @@ impl InvocationCollectorNode for ast::Expr { } struct OptExprTag; -impl InvocationCollectorNode for AstNodeWrapper<P<ast::Expr>, OptExprTag> { - type OutputTy = Option<P<ast::Expr>>; +impl InvocationCollectorNode for AstNodeWrapper<Box<ast::Expr>, OptExprTag> { + type OutputTy = Option<Box<ast::Expr>>; const KIND: AstFragmentKind = AstFragmentKind::OptExpr; fn to_annotatable(self) -> Annotatable { Annotatable::Expr(self.wrapped) @@ -1868,7 +1865,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::Expr>, OptExprTag> { fn is_mac_call(&self) -> bool { matches!(self.wrapped.kind, ast::ExprKind::MacCall(..)) } - fn take_mac_call(self) -> (P<ast::MacCall>, ast::AttrVec, AddSemicolon) { + fn take_mac_call(self) -> (Box<ast::MacCall>, ast::AttrVec, AddSemicolon) { let node = self.wrapped; match node.kind { ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No), @@ -1885,13 +1882,13 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::Expr>, OptExprTag> { struct MethodReceiverTag; impl InvocationCollectorNode for AstNodeWrapper<ast::Expr, MethodReceiverTag> { - type OutputTy = AstNodeWrapper<P<ast::Expr>, MethodReceiverTag>; + type OutputTy = AstNodeWrapper<Box<ast::Expr>, MethodReceiverTag>; const KIND: AstFragmentKind = AstFragmentKind::MethodReceiverExpr; fn descr() -> &'static str { "an expression" } fn to_annotatable(self) -> Annotatable { - Annotatable::Expr(P(self.wrapped)) + Annotatable::Expr(Box::new(self.wrapped)) } fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { AstNodeWrapper::new(fragment.make_method_receiver_expr(), MethodReceiverTag) @@ -1902,7 +1899,7 @@ impl InvocationCollectorNode for AstNodeWrapper<ast::Expr, MethodReceiverTag> { fn is_mac_call(&self) -> bool { matches!(self.wrapped.kind, ast::ExprKind::MacCall(..)) } - fn take_mac_call(self) -> (P<ast::MacCall>, ast::AttrVec, AddSemicolon) { + fn take_mac_call(self) -> (Box<ast::MacCall>, ast::AttrVec, AddSemicolon) { let node = self.wrapped; match node.kind { ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No), @@ -2039,7 +2036,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { placeholder(fragment_kind, NodeId::placeholder_from_expn_id(expn_id), vis) } - fn collect_bang(&mut self, mac: P<ast::MacCall>, kind: AstFragmentKind) -> AstFragment { + fn collect_bang(&mut self, mac: Box<ast::MacCall>, kind: AstFragmentKind) -> AstFragment { // cache the macro call span so that it can be // easily adjusted for incremental compilation let span = mac.span(); @@ -2057,7 +2054,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { fn collect_glob_delegation( &mut self, - item: P<ast::AssocItem>, + item: Box<ast::AssocItem>, of_trait: bool, kind: AstFragmentKind, ) -> AstFragment { @@ -2329,15 +2326,15 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { } impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { - fn flat_map_item(&mut self, node: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> { + fn flat_map_item(&mut self, node: Box<ast::Item>) -> SmallVec<[Box<ast::Item>; 1]> { self.flat_map_node(node) } fn flat_map_assoc_item( &mut self, - node: P<ast::AssocItem>, + node: Box<ast::AssocItem>, ctxt: AssocCtxt, - ) -> SmallVec<[P<ast::AssocItem>; 1]> { + ) -> SmallVec<[Box<ast::AssocItem>; 1]> { match ctxt { AssocCtxt::Trait => self.flat_map_node(AstNodeWrapper::new(node, TraitItemTag)), AssocCtxt::Impl { of_trait: false } => { @@ -2351,8 +2348,8 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { fn flat_map_foreign_item( &mut self, - node: P<ast::ForeignItem>, - ) -> SmallVec<[P<ast::ForeignItem>; 1]> { + node: Box<ast::ForeignItem>, + ) -> SmallVec<[Box<ast::ForeignItem>; 1]> { self.flat_map_node(node) } @@ -2447,7 +2444,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { self.visit_node(AstNodeWrapper::from_mut(node, MethodReceiverTag)) } - fn filter_map_expr(&mut self, node: P<ast::Expr>) -> Option<P<ast::Expr>> { + fn filter_map_expr(&mut self, node: Box<ast::Expr>) -> Option<Box<ast::Expr>> { self.flat_map_node(AstNodeWrapper::new(node, OptExprTag)) } diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index 7a280d671f4..5b9d56ee2bc 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -7,29 +7,40 @@ use rustc_macros::Subdiagnostic; use rustc_parse::parser::{Parser, Recovery, token_descr}; use rustc_session::parse::ParseSess; use rustc_span::source_map::SourceMap; -use rustc_span::{ErrorGuaranteed, Ident, Span}; +use rustc_span::{DUMMY_SP, ErrorGuaranteed, Ident, Span}; use tracing::debug; use super::macro_rules::{MacroRule, NoopTracker, parser_from_cx}; use crate::expand::{AstFragmentKind, parse_ast_fragment}; use crate::mbe::macro_parser::ParseResult::*; use crate::mbe::macro_parser::{MatcherLoc, NamedParseResult, TtParser}; -use crate::mbe::macro_rules::{Tracker, try_match_macro}; +use crate::mbe::macro_rules::{Tracker, try_match_macro, try_match_macro_attr}; pub(super) fn failed_to_match_macro( psess: &ParseSess, sp: Span, def_span: Span, name: Ident, - arg: TokenStream, + attr_args: Option<&TokenStream>, + body: &TokenStream, rules: &[MacroRule], ) -> (Span, ErrorGuaranteed) { debug!("failed to match macro"); + let def_head_span = if !def_span.is_dummy() && !psess.source_map().is_imported(def_span) { + psess.source_map().guess_head_span(def_span) + } else { + DUMMY_SP + }; + // An error occurred, try the expansion again, tracking the expansion closely for better // diagnostics. let mut tracker = CollectTrackerAndEmitter::new(psess.dcx(), sp); - let try_success_result = try_match_macro(psess, name, &arg, rules, &mut tracker); + let try_success_result = if let Some(attr_args) = attr_args { + try_match_macro_attr(psess, name, attr_args, body, rules, &mut tracker) + } else { + try_match_macro(psess, name, body, rules, &mut tracker) + }; if try_success_result.is_ok() { // Nonterminal parser recovery might turn failed matches into successful ones, @@ -47,6 +58,18 @@ pub(super) fn failed_to_match_macro( let Some(BestFailure { token, msg: label, remaining_matcher, .. }) = tracker.best_failure else { + // FIXME: we should report this at macro resolution time, as we do for + // `resolve_macro_cannot_use_as_attr`. We can do that once we track multiple macro kinds for a + // Def. + if attr_args.is_none() && !rules.iter().any(|rule| matches!(rule, MacroRule::Func { .. })) { + let msg = format!("macro has no rules for function-like invocation `{name}!`"); + let mut err = psess.dcx().struct_span_err(sp, msg); + if !def_head_span.is_dummy() { + let msg = "this macro has no rules for function-like invocation"; + err.span_label(def_head_span, msg); + } + return (sp, err.emit()); + } return (sp, psess.dcx().span_delayed_bug(sp, "failed to match a macro")); }; @@ -54,8 +77,8 @@ pub(super) fn failed_to_match_macro( let mut err = psess.dcx().struct_span_err(span, parse_failure_msg(&token, None)); err.span_label(span, label); - if !def_span.is_dummy() && !psess.source_map().is_imported(def_span) { - err.span_label(psess.source_map().guess_head_span(def_span), "when calling this macro"); + if !def_head_span.is_dummy() { + err.span_label(def_head_span, "when calling this macro"); } annotate_doc_comment(&mut err, psess.source_map(), span); @@ -79,13 +102,16 @@ pub(super) fn failed_to_match_macro( } // Check whether there's a missing comma in this macro call, like `println!("{}" a);` - if let Some((arg, comma_span)) = arg.add_comma() { + if attr_args.is_none() + && let Some((body, comma_span)) = body.add_comma() + { for rule in rules { - let parser = parser_from_cx(psess, arg.clone(), Recovery::Allowed); + let MacroRule::Func { lhs, .. } = rule else { continue }; + let parser = parser_from_cx(psess, body.clone(), Recovery::Allowed); let mut tt_parser = TtParser::new(name); if let Success(_) = - tt_parser.parse_tt(&mut Cow::Borrowed(&parser), &rule.lhs, &mut NoopTracker) + tt_parser.parse_tt(&mut Cow::Borrowed(&parser), lhs, &mut NoopTracker) { if comma_span.is_dummy() { err.note("you might be missing a comma"); @@ -116,13 +142,13 @@ struct CollectTrackerAndEmitter<'dcx, 'matcher> { struct BestFailure { token: Token, - position_in_tokenstream: u32, + position_in_tokenstream: (bool, u32), msg: &'static str, remaining_matcher: MatcherLoc, } impl BestFailure { - fn is_better_position(&self, position: u32) -> bool { + fn is_better_position(&self, position: (bool, u32)) -> bool { position > self.position_in_tokenstream } } @@ -142,7 +168,7 @@ impl<'dcx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'dcx, 'match } } - fn after_arm(&mut self, result: &NamedParseResult<Self::Failure>) { + fn after_arm(&mut self, in_body: bool, result: &NamedParseResult<Self::Failure>) { match result { Success(_) => { // Nonterminal parser recovery might turn failed matches into successful ones, @@ -155,14 +181,15 @@ impl<'dcx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'dcx, 'match Failure((token, approx_position, msg)) => { debug!(?token, ?msg, "a new failure of an arm"); + let position_in_tokenstream = (in_body, *approx_position); if self .best_failure .as_ref() - .is_none_or(|failure| failure.is_better_position(*approx_position)) + .is_none_or(|failure| failure.is_better_position(position_in_tokenstream)) { self.best_failure = Some(BestFailure { token: *token, - position_in_tokenstream: *approx_position, + position_in_tokenstream, msg, remaining_matcher: self .remaining_matcher diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs index bbdff866feb..25987a50366 100644 --- a/compiler/rustc_expand/src/mbe/macro_check.rs +++ b/compiler/rustc_expand/src/mbe/macro_check.rs @@ -193,15 +193,19 @@ struct MacroState<'a> { /// Arguments: /// - `psess` is used to emit diagnostics and lints /// - `node_id` is used to emit lints -/// - `lhs` and `rhs` represent the rule +/// - `args`, `lhs`, and `rhs` represent the rule pub(super) fn check_meta_variables( psess: &ParseSess, node_id: NodeId, + args: Option<&TokenTree>, lhs: &TokenTree, rhs: &TokenTree, ) -> Result<(), ErrorGuaranteed> { let mut guar = None; let mut binders = Binders::default(); + if let Some(args) = args { + check_binders(psess, node_id, args, &Stack::Empty, &mut binders, &Stack::Empty, &mut guar); + } check_binders(psess, node_id, lhs, &Stack::Empty, &mut binders, &Stack::Empty, &mut guar); check_occurrences(psess, node_id, rhs, &Stack::Empty, &binders, &Stack::Empty, &mut guar); guar.map_or(Ok(()), Err) diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index febe6f8b88c..37b236a2e26 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -6,15 +6,16 @@ use std::{mem, slice}; use ast::token::IdentIsRaw; use rustc_ast::token::NtPatKind::*; use rustc_ast::token::TokenKind::*; -use rustc_ast::token::{self, NonterminalKind, Token, TokenKind}; -use rustc_ast::tokenstream::{DelimSpan, TokenStream}; +use rustc_ast::token::{self, Delimiter, NonterminalKind, Token, TokenKind}; +use rustc_ast::tokenstream::{self, DelimSpan, TokenStream}; use rustc_ast::{self as ast, DUMMY_NODE_ID, NodeId}; use rustc_ast_pretty::pprust; -use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; -use rustc_errors::{Applicability, Diag, ErrorGuaranteed}; +use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan}; use rustc_feature::Features; use rustc_hir as hir; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::find_attr; use rustc_lint_defs::BuiltinLintDiag; use rustc_lint_defs::builtin::{ RUST_2021_INCOMPATIBLE_OR_PATTERNS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS, @@ -22,23 +23,26 @@ use rustc_lint_defs::builtin::{ use rustc_parse::exp; use rustc_parse::parser::{Parser, Recovery}; use rustc_session::Session; -use rustc_session::parse::ParseSess; +use rustc_session::parse::{ParseSess, feature_err}; use rustc_span::edition::Edition; use rustc_span::hygiene::Transparency; use rustc_span::{Ident, Span, kw, sym}; use tracing::{debug, instrument, trace, trace_span}; +use super::diagnostics::failed_to_match_macro; use super::macro_parser::{NamedMatches, NamedParseResult}; use super::{SequenceRepetition, diagnostics}; use crate::base::{ - DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult, SyntaxExtension, - SyntaxExtensionKind, TTMacroExpander, + AttrProcMacro, DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult, + SyntaxExtension, SyntaxExtensionKind, TTMacroExpander, }; +use crate::errors; use crate::expand::{AstFragment, AstFragmentKind, ensure_complete_parse, parse_ast_fragment}; +use crate::mbe::macro_check::check_meta_variables; use crate::mbe::macro_parser::{Error, ErrorReported, Failure, MatcherLoc, Success, TtParser}; use crate::mbe::quoted::{RulePart, parse_one_tt}; use crate::mbe::transcribe::transcribe; -use crate::mbe::{self, KleeneOp, macro_check}; +use crate::mbe::{self, KleeneOp}; pub(crate) struct ParserAnyMacro<'a> { parser: Parser<'a>, @@ -122,10 +126,17 @@ impl<'a> ParserAnyMacro<'a> { } } -pub(super) struct MacroRule { - pub(super) lhs: Vec<MatcherLoc>, - lhs_span: Span, - rhs: mbe::TokenTree, +pub(super) enum MacroRule { + /// A function-style rule, for use with `m!()` + Func { lhs: Vec<MatcherLoc>, lhs_span: Span, rhs: mbe::TokenTree }, + /// An attr rule, for use with `#[m]` + Attr { + args: Vec<MatcherLoc>, + args_span: Span, + body: Vec<MatcherLoc>, + body_span: Span, + rhs: mbe::TokenTree, + }, } pub struct MacroRulesMacroExpander { @@ -137,10 +148,15 @@ pub struct MacroRulesMacroExpander { } impl MacroRulesMacroExpander { - pub fn get_unused_rule(&self, rule_i: usize) -> Option<(&Ident, Span)> { + pub fn get_unused_rule(&self, rule_i: usize) -> Option<(&Ident, MultiSpan)> { // If the rhs contains an invocation like `compile_error!`, don't report it as unused. - let rule = &self.rules[rule_i]; - if has_compile_error_macro(&rule.rhs) { None } else { Some((&self.name, rule.lhs_span)) } + let (span, rhs) = match self.rules[rule_i] { + MacroRule::Func { lhs_span, ref rhs, .. } => (MultiSpan::from_span(lhs_span), rhs), + MacroRule::Attr { args_span, body_span, ref rhs, .. } => { + (MultiSpan::from_spans(vec![args_span, body_span]), rhs) + } + }; + if has_compile_error_macro(rhs) { None } else { Some((&self.name, span)) } } } @@ -164,6 +180,28 @@ impl TTMacroExpander for MacroRulesMacroExpander { } } +impl AttrProcMacro for MacroRulesMacroExpander { + fn expand( + &self, + cx: &mut ExtCtxt<'_>, + sp: Span, + args: TokenStream, + body: TokenStream, + ) -> Result<TokenStream, ErrorGuaranteed> { + expand_macro_attr( + cx, + sp, + self.span, + self.node_id, + self.name, + self.transparency, + args, + body, + &self.rules, + ) + } +} + struct DummyExpander(ErrorGuaranteed); impl TTMacroExpander for DummyExpander { @@ -196,7 +234,7 @@ pub(super) trait Tracker<'matcher> { /// This is called after an arm has been parsed, either successfully or unsuccessfully. When /// this is called, `before_match_loc` was called at least once (with a `MatcherLoc::Eof`). - fn after_arm(&mut self, _result: &NamedParseResult<Self::Failure>) {} + fn after_arm(&mut self, _in_body: bool, _result: &NamedParseResult<Self::Failure>) {} /// For tracing. fn description() -> &'static str; @@ -244,14 +282,17 @@ fn expand_macro<'cx>( match try_success_result { Ok((rule_index, rule, named_matches)) => { - let mbe::TokenTree::Delimited(rhs_span, _, ref rhs) = rule.rhs else { + let MacroRule::Func { rhs, .. } = rule else { + panic!("try_match_macro returned non-func rule"); + }; + let mbe::TokenTree::Delimited(rhs_span, _, rhs) = rhs else { cx.dcx().span_bug(sp, "malformed macro rhs"); }; - let arm_span = rule.rhs.span(); + let arm_span = rhs_span.entire(); // rhs has holes ( `$id` and `$(...)` that need filled) let id = cx.current_expansion.id; - let tts = match transcribe(psess, &named_matches, rhs, rhs_span, transparency, id) { + let tts = match transcribe(psess, &named_matches, rhs, *rhs_span, transparency, id) { Ok(tts) => tts, Err(err) => { let guar = err.emit(); @@ -279,13 +320,76 @@ fn expand_macro<'cx>( Err(CanRetry::Yes) => { // Retry and emit a better error. let (span, guar) = - diagnostics::failed_to_match_macro(cx.psess(), sp, def_span, name, arg, rules); + failed_to_match_macro(cx.psess(), sp, def_span, name, None, &arg, rules); cx.macro_error_and_trace_macros_diag(); DummyResult::any(span, guar) } } } +/// Expands the rules based macro defined by `rules` for a given attribute `args` and `body`. +#[instrument(skip(cx, transparency, args, body, rules))] +fn expand_macro_attr( + cx: &mut ExtCtxt<'_>, + sp: Span, + def_span: Span, + node_id: NodeId, + name: Ident, + transparency: Transparency, + args: TokenStream, + body: TokenStream, + rules: &[MacroRule], +) -> Result<TokenStream, ErrorGuaranteed> { + let psess = &cx.sess.psess; + // Macros defined in the current crate have a real node id, + // whereas macros from an external crate have a dummy id. + let is_local = node_id != DUMMY_NODE_ID; + + if cx.trace_macros() { + let msg = format!( + "expanding `$[{name}({})] {}`", + pprust::tts_to_string(&args), + pprust::tts_to_string(&body), + ); + trace_macros_note(&mut cx.expansions, sp, msg); + } + + // Track nothing for the best performance. + match try_match_macro_attr(psess, name, &args, &body, rules, &mut NoopTracker) { + Ok((i, rule, named_matches)) => { + let MacroRule::Attr { rhs, .. } = rule else { + panic!("try_macro_match_attr returned non-attr rule"); + }; + let mbe::TokenTree::Delimited(rhs_span, _, rhs) = rhs else { + cx.dcx().span_bug(sp, "malformed macro rhs"); + }; + + let id = cx.current_expansion.id; + let tts = transcribe(psess, &named_matches, rhs, *rhs_span, transparency, id) + .map_err(|e| e.emit())?; + + if cx.trace_macros() { + let msg = format!("to `{}`", pprust::tts_to_string(&tts)); + trace_macros_note(&mut cx.expansions, sp, msg); + } + + if is_local { + cx.resolver.record_macro_rule_usage(node_id, i); + } + + Ok(tts) + } + Err(CanRetry::No(guar)) => Err(guar), + Err(CanRetry::Yes) => { + // Retry and emit a better error. + let (_, guar) = + failed_to_match_macro(cx.psess(), sp, def_span, name, Some(&args), &body, rules); + cx.trace_macros_diag(); + Err(guar) + } + } +} + pub(super) enum CanRetry { Yes, /// We are not allowed to retry macro expansion as a fatal error has been emitted already. @@ -326,6 +430,7 @@ pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>( // Try each arm's matchers. let mut tt_parser = TtParser::new(name); for (i, rule) in rules.iter().enumerate() { + let MacroRule::Func { lhs, .. } = rule else { continue }; let _tracing_span = trace_span!("Matching arm", %i); // Take a snapshot of the state of pre-expansion gating at this point. @@ -334,9 +439,9 @@ pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>( // are not recorded. On the first `Success(..)`ful matcher, the spans are merged. let mut gated_spans_snapshot = mem::take(&mut *psess.gated_spans.spans.borrow_mut()); - let result = tt_parser.parse_tt(&mut Cow::Borrowed(&parser), &rule.lhs, track); + let result = tt_parser.parse_tt(&mut Cow::Borrowed(&parser), lhs, track); - track.after_arm(&result); + track.after_arm(true, &result); match result { Success(named_matches) => { @@ -371,6 +476,60 @@ pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>( Err(CanRetry::Yes) } +/// Try expanding the macro attribute. Returns the index of the successful arm and its +/// named_matches if it was successful, and nothing if it failed. On failure, it's the caller's job +/// to use `track` accordingly to record all errors correctly. +#[instrument(level = "debug", skip(psess, attr_args, attr_body, rules, track), fields(tracking = %T::description()))] +pub(super) fn try_match_macro_attr<'matcher, T: Tracker<'matcher>>( + psess: &ParseSess, + name: Ident, + attr_args: &TokenStream, + attr_body: &TokenStream, + rules: &'matcher [MacroRule], + track: &mut T, +) -> Result<(usize, &'matcher MacroRule, NamedMatches), CanRetry> { + // This uses the same strategy as `try_match_macro` + let args_parser = parser_from_cx(psess, attr_args.clone(), T::recovery()); + let body_parser = parser_from_cx(psess, attr_body.clone(), T::recovery()); + let mut tt_parser = TtParser::new(name); + for (i, rule) in rules.iter().enumerate() { + let MacroRule::Attr { args, body, .. } = rule else { continue }; + + let mut gated_spans_snapshot = mem::take(&mut *psess.gated_spans.spans.borrow_mut()); + + let result = tt_parser.parse_tt(&mut Cow::Borrowed(&args_parser), args, track); + track.after_arm(false, &result); + + let mut named_matches = match result { + Success(named_matches) => named_matches, + Failure(_) => { + mem::swap(&mut gated_spans_snapshot, &mut psess.gated_spans.spans.borrow_mut()); + continue; + } + Error(_, _) => return Err(CanRetry::Yes), + ErrorReported(guar) => return Err(CanRetry::No(guar)), + }; + + let result = tt_parser.parse_tt(&mut Cow::Borrowed(&body_parser), body, track); + track.after_arm(true, &result); + + match result { + Success(body_named_matches) => { + psess.gated_spans.merge(gated_spans_snapshot); + named_matches.extend(body_named_matches); + return Ok((i, rule, named_matches)); + } + Failure(_) => { + mem::swap(&mut gated_spans_snapshot, &mut psess.gated_spans.spans.borrow_mut()) + } + Error(_, _) => return Err(CanRetry::Yes), + ErrorReported(guar) => return Err(CanRetry::No(guar)), + } + } + + Err(CanRetry::Yes) +} + /// Converts a macro item into a syntax extension. pub fn compile_declarative_macro( sess: &Session, @@ -381,13 +540,13 @@ pub fn compile_declarative_macro( span: Span, node_id: NodeId, edition: Edition, -) -> (SyntaxExtension, usize) { - let mk_syn_ext = |expander| { - let kind = SyntaxExtensionKind::LegacyBang(expander); +) -> (SyntaxExtension, Option<Arc<SyntaxExtension>>, usize) { + let mk_syn_ext = |kind| { let is_local = is_defined_in_current_crate(node_id); SyntaxExtension::new(sess, kind, span, Vec::new(), edition, ident.name, attrs, is_local) }; - let dummy_syn_ext = |guar| (mk_syn_ext(Arc::new(DummyExpander(guar))), 0); + let mk_bang_ext = |expander| mk_syn_ext(SyntaxExtensionKind::LegacyBang(expander)); + let dummy_syn_ext = |guar| (mk_bang_ext(Arc::new(DummyExpander(guar))), None, 0); let macro_rules = macro_def.macro_rules; let exp_sep = if macro_rules { exp!(Semi) } else { exp!(Comma) }; @@ -400,9 +559,30 @@ pub fn compile_declarative_macro( let mut guar = None; let mut check_emission = |ret: Result<(), ErrorGuaranteed>| guar = guar.or(ret.err()); + let mut has_attr_rules = false; let mut rules = Vec::new(); while p.token != token::Eof { + let args = if p.eat_keyword_noexpect(sym::attr) { + has_attr_rules = true; + if !features.macro_attr() { + feature_err(sess, sym::macro_attr, span, "`macro_rules!` attributes are unstable") + .emit(); + } + if let Some(guar) = check_no_eof(sess, &p, "expected macro attr args") { + return dummy_syn_ext(guar); + } + let args = p.parse_token_tree(); + check_args_parens(sess, &args); + let args = parse_one_tt(args, RulePart::Pattern, sess, node_id, features, edition); + check_emission(check_lhs(sess, node_id, &args)); + if let Some(guar) = check_no_eof(sess, &p, "expected macro attr body") { + return dummy_syn_ext(guar); + } + Some(args) + } else { + None + }; let lhs_tt = p.parse_token_tree(); let lhs_tt = parse_one_tt(lhs_tt, RulePart::Pattern, sess, node_id, features, edition); check_emission(check_lhs(sess, node_id, &lhs_tt)); @@ -415,7 +595,7 @@ pub fn compile_declarative_macro( let rhs_tt = p.parse_token_tree(); let rhs_tt = parse_one_tt(rhs_tt, RulePart::Body, sess, node_id, features, edition); check_emission(check_rhs(sess, &rhs_tt)); - check_emission(macro_check::check_meta_variables(&sess.psess, node_id, &lhs_tt, &rhs_tt)); + check_emission(check_meta_variables(&sess.psess, node_id, args.as_ref(), &lhs_tt, &rhs_tt)); let lhs_span = lhs_tt.span(); // Convert the lhs into `MatcherLoc` form, which is better for doing the // actual matching. @@ -424,7 +604,17 @@ pub fn compile_declarative_macro( } else { return dummy_syn_ext(guar.unwrap()); }; - rules.push(MacroRule { lhs, lhs_span, rhs: rhs_tt }); + if let Some(args) = args { + let args_span = args.span(); + let mbe::TokenTree::Delimited(.., delimited) = args else { + return dummy_syn_ext(guar.unwrap()); + }; + let args = mbe::macro_parser::compute_locs(&delimited.tts); + let body_span = lhs_span; + rules.push(MacroRule::Attr { args, args_span, body: lhs, body_span, rhs: rhs_tt }); + } else { + rules.push(MacroRule::Func { lhs, lhs_span, rhs: rhs_tt }); + } if p.token == token::Eof { break; } @@ -450,9 +640,12 @@ pub fn compile_declarative_macro( // Return the number of rules for unused rule linting, if this is a local macro. let nrules = if is_defined_in_current_crate(node_id) { rules.len() } else { 0 }; - let expander = - Arc::new(MacroRulesMacroExpander { name: ident, span, node_id, transparency, rules }); - (mk_syn_ext(expander), nrules) + let exp = Arc::new(MacroRulesMacroExpander { name: ident, span, node_id, transparency, rules }); + let opt_attr_ext = has_attr_rules.then(|| { + let exp = Arc::clone(&exp); + Arc::new(mk_syn_ext(SyntaxExtensionKind::Attr(exp))) + }); + (mk_bang_ext(exp), opt_attr_ext, nrules) } fn check_no_eof(sess: &Session, p: &Parser<'_>, msg: &'static str) -> Option<ErrorGuaranteed> { @@ -468,6 +661,18 @@ fn check_no_eof(sess: &Session, p: &Parser<'_>, msg: &'static str) -> Option<Err None } +fn check_args_parens(sess: &Session, args: &tokenstream::TokenTree) { + // This does not handle the non-delimited case; that gets handled separately by `check_lhs`. + if let tokenstream::TokenTree::Delimited(dspan, _, delim, _) = args + && *delim != Delimiter::Parenthesis + { + sess.dcx().emit_err(errors::MacroArgsBadDelim { + span: dspan.entire(), + sugg: errors::MacroArgsBadDelimSugg { open: dspan.open, close: dspan.close }, + }); + } +} + fn check_lhs(sess: &Session, node_id: NodeId, lhs: &mbe::TokenTree) -> Result<(), ErrorGuaranteed> { let e1 = check_lhs_nt_follows(sess, node_id, lhs); let e2 = check_lhs_no_empty_seq(sess, slice::from_ref(lhs)); diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs index e925052c607..662c67f2d3f 100644 --- a/compiler/rustc_expand/src/module.rs +++ b/compiler/rustc_expand/src/module.rs @@ -1,7 +1,6 @@ use std::iter::once; use std::path::{self, Path, PathBuf}; -use rustc_ast::ptr::P; use rustc_ast::{AttrVec, Attribute, Inline, Item, ModSpans}; use rustc_errors::{Diag, ErrorGuaranteed}; use rustc_parse::{exp, new_parser_from_file, unwrap_or_emit_fatal, validate_attr}; @@ -31,7 +30,7 @@ pub struct ModulePathSuccess { } pub(crate) struct ParsedExternalMod { - pub items: ThinVec<P<Item>>, + pub items: ThinVec<Box<Item>>, pub spans: ModSpans, pub file_path: PathBuf, pub dir_path: PathBuf, diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index 6e1c6df4bcb..05f9a5aa43f 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -1,5 +1,4 @@ use rustc_ast::mut_visit::*; -use rustc_ast::ptr::P; use rustc_ast::token::Delimiter; use rustc_ast::visit::AssocCtxt; use rustc_ast::{self as ast, Safety}; @@ -15,10 +14,10 @@ pub(crate) fn placeholder( id: ast::NodeId, vis: Option<ast::Visibility>, ) -> AstFragment { - fn mac_placeholder() -> P<ast::MacCall> { - P(ast::MacCall { + fn mac_placeholder() -> Box<ast::MacCall> { + Box::new(ast::MacCall { path: ast::Path { span: DUMMY_SP, segments: ThinVec::new(), tokens: None }, - args: P(ast::DelimArgs { + args: Box::new(ast::DelimArgs { dspan: ast::tokenstream::DelimSpan::dummy(), delim: Delimiter::Parenthesis, tokens: ast::tokenstream::TokenStream::new(Vec::new()), @@ -35,7 +34,7 @@ pub(crate) fn placeholder( }); let span = DUMMY_SP; let expr_placeholder = || { - P(ast::Expr { + Box::new(ast::Expr { id, span, attrs: ast::AttrVec::new(), @@ -43,10 +42,17 @@ pub(crate) fn placeholder( tokens: None, }) }; - let ty = - || P(ast::Ty { id, kind: ast::TyKind::MacCall(mac_placeholder()), span, tokens: None }); - let pat = - || P(ast::Pat { id, kind: ast::PatKind::MacCall(mac_placeholder()), span, tokens: None }); + let ty = || { + Box::new(ast::Ty { id, kind: ast::TyKind::MacCall(mac_placeholder()), span, tokens: None }) + }; + let pat = || { + Box::new(ast::Pat { + id, + kind: ast::PatKind::MacCall(mac_placeholder()), + span, + tokens: None, + }) + }; match kind { AstFragmentKind::Crate => AstFragment::Crate(ast::Crate { @@ -59,7 +65,7 @@ pub(crate) fn placeholder( AstFragmentKind::Expr => AstFragment::Expr(expr_placeholder()), AstFragmentKind::OptExpr => AstFragment::OptExpr(Some(expr_placeholder())), AstFragmentKind::MethodReceiverExpr => AstFragment::MethodReceiverExpr(expr_placeholder()), - AstFragmentKind::Items => AstFragment::Items(smallvec![P(ast::Item { + AstFragmentKind::Items => AstFragment::Items(smallvec![Box::new(ast::Item { id, span, vis, @@ -67,15 +73,17 @@ pub(crate) fn placeholder( kind: ast::ItemKind::MacCall(mac_placeholder()), tokens: None, })]), - AstFragmentKind::TraitItems => AstFragment::TraitItems(smallvec![P(ast::AssocItem { - id, - span, - vis, - attrs, - kind: ast::AssocItemKind::MacCall(mac_placeholder()), - tokens: None, - })]), - AstFragmentKind::ImplItems => AstFragment::ImplItems(smallvec![P(ast::AssocItem { + AstFragmentKind::TraitItems => { + AstFragment::TraitItems(smallvec![Box::new(ast::AssocItem { + id, + span, + vis, + attrs, + kind: ast::AssocItemKind::MacCall(mac_placeholder()), + tokens: None, + })]) + } + AstFragmentKind::ImplItems => AstFragment::ImplItems(smallvec![Box::new(ast::AssocItem { id, span, vis, @@ -84,7 +92,7 @@ pub(crate) fn placeholder( tokens: None, })]), AstFragmentKind::TraitImplItems => { - AstFragment::TraitImplItems(smallvec![P(ast::AssocItem { + AstFragment::TraitImplItems(smallvec![Box::new(ast::AssocItem { id, span, vis, @@ -94,7 +102,7 @@ pub(crate) fn placeholder( })]) } AstFragmentKind::ForeignItems => { - AstFragment::ForeignItems(smallvec![P(ast::ForeignItem { + AstFragment::ForeignItems(smallvec![Box::new(ast::ForeignItem { id, span, vis, @@ -103,20 +111,20 @@ pub(crate) fn placeholder( tokens: None, })]) } - AstFragmentKind::Pat => AstFragment::Pat(P(ast::Pat { + AstFragmentKind::Pat => AstFragment::Pat(Box::new(ast::Pat { id, span, kind: ast::PatKind::MacCall(mac_placeholder()), tokens: None, })), - AstFragmentKind::Ty => AstFragment::Ty(P(ast::Ty { + AstFragmentKind::Ty => AstFragment::Ty(Box::new(ast::Ty { id, span, kind: ast::TyKind::MacCall(mac_placeholder()), tokens: None, })), AstFragmentKind::Stmts => AstFragment::Stmts(smallvec![{ - let mac = P(ast::MacCallStmt { + let mac = Box::new(ast::MacCallStmt { mac: mac_placeholder(), style: ast::MacStmtStyle::Braces, attrs: ast::AttrVec::new(), @@ -297,7 +305,7 @@ impl MutVisitor for PlaceholderExpander { } } - fn flat_map_item(&mut self, item: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> { + fn flat_map_item(&mut self, item: Box<ast::Item>) -> SmallVec<[Box<ast::Item>; 1]> { match item.kind { ast::ItemKind::MacCall(_) => self.remove(item.id).make_items(), _ => walk_flat_map_item(self, item), @@ -306,9 +314,9 @@ impl MutVisitor for PlaceholderExpander { fn flat_map_assoc_item( &mut self, - item: P<ast::AssocItem>, + item: Box<ast::AssocItem>, ctxt: AssocCtxt, - ) -> SmallVec<[P<ast::AssocItem>; 1]> { + ) -> SmallVec<[Box<ast::AssocItem>; 1]> { match item.kind { ast::AssocItemKind::MacCall(_) => { let it = self.remove(item.id); @@ -324,8 +332,8 @@ impl MutVisitor for PlaceholderExpander { fn flat_map_foreign_item( &mut self, - item: P<ast::ForeignItem>, - ) -> SmallVec<[P<ast::ForeignItem>; 1]> { + item: Box<ast::ForeignItem>, + ) -> SmallVec<[Box<ast::ForeignItem>; 1]> { match item.kind { ast::ForeignItemKind::MacCall(_) => self.remove(item.id).make_foreign_items(), _ => walk_flat_map_foreign_item(self, item), @@ -346,7 +354,7 @@ impl MutVisitor for PlaceholderExpander { } } - fn filter_map_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> { + fn filter_map_expr(&mut self, expr: Box<ast::Expr>) -> Option<Box<ast::Expr>> { match expr.kind { ast::ExprKind::MacCall(_) => self.remove(expr.id).make_opt_expr(), _ => walk_filter_map_expr(self, expr), diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs index 84fbbbef061..9bfda8764f5 100644 --- a/compiler/rustc_expand/src/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -1,4 +1,3 @@ -use rustc_ast::ptr::P; use rustc_ast::tokenstream::TokenStream; use rustc_errors::ErrorGuaranteed; use rustc_parse::parser::{ForceCollect, Parser}; @@ -161,7 +160,7 @@ impl MultiItemModifier for DeriveProcMacro { Ok(None) => break, Ok(Some(item)) => { if is_stmt { - items.push(Annotatable::Stmt(P(ecx.stmt_item(span, item)))); + items.push(Annotatable::Stmt(Box::new(ecx.stmt_item(span, item)))); } else { items.push(Annotatable::Item(item)); } diff --git a/compiler/rustc_expand/src/stats.rs b/compiler/rustc_expand/src/stats.rs index b4c4eac028f..3e40632275b 100644 --- a/compiler/rustc_expand/src/stats.rs +++ b/compiler/rustc_expand/src/stats.rs @@ -1,6 +1,5 @@ use std::iter; -use rustc_ast::ptr::P; use rustc_ast::{self as ast, DUMMY_NODE_ID, Expr, ExprKind}; use rustc_ast_pretty::pprust; use rustc_span::hygiene::{ExpnKind, MacroKind}; @@ -41,7 +40,7 @@ pub(crate) fn update_bang_macro_stats( ecx: &mut ExtCtxt<'_>, fragment_kind: AstFragmentKind, span: Span, - mac: P<ast::MacCall>, + mac: Box<ast::MacCall>, fragment: &AstFragment, ) { // Does this path match any of the include macros, e.g. `include!`? diff --git a/compiler/rustc_feature/Cargo.toml b/compiler/rustc_feature/Cargo.toml index 78d7b698b72..a4746ac455c 100644 --- a/compiler/rustc_feature/Cargo.toml +++ b/compiler/rustc_feature/Cargo.toml @@ -5,8 +5,8 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_data_structures = { path = "../rustc_data_structures" } +rustc_hir = { path = "../rustc_hir" } rustc_span = { path = "../rustc_span" } serde = { version = "1.0.125", features = ["derive"] } serde_json = "1.0.59" diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 96df6aa19bc..5c63d4808db 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -5,8 +5,8 @@ use std::sync::LazyLock; use AttributeDuplicates::*; use AttributeGate::*; use AttributeType::*; -use rustc_attr_data_structures::EncodeCrossCrate; use rustc_data_structures::fx::FxHashMap; +use rustc_hir::attrs::EncodeCrossCrate; use rustc_span::edition::Edition; use rustc_span::{Symbol, sym}; @@ -112,7 +112,7 @@ pub enum AttributeGate { Ungated, } -// FIXME(jdonszelmann): move to rustc_attr_data_structures +// FIXME(jdonszelmann): move to rustc_hir::attrs /// A template that the attribute input must match. /// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now. #[derive(Clone, Copy, Default)] @@ -1257,11 +1257,6 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ TEST, rustc_dummy, Normal, template!(Word /* doesn't matter*/), DuplicatesOk, EncodeCrossCrate::No ), - gated!( - omit_gdb_pretty_printer_section, Normal, template!(Word), - WarnFollowing, EncodeCrossCrate::No, - "the `#[omit_gdb_pretty_printer_section]` attribute is just used for the Rust test suite", - ), rustc_attr!( TEST, pattern_complexity_limit, CrateLevel, template!(NameValueStr: "N"), ErrorFollowing, EncodeCrossCrate::No, diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 7e174c465d5..04f261ada06 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -54,7 +54,7 @@ declare_features! ( /// Allows using the `amdgpu-kernel` ABI. (removed, abi_amdgpu_kernel, "1.77.0", Some(51575), None, 120495), - (removed, abi_c_cmse_nonsecure_call, "CURRENT_RUSTC_VERSION", Some(81391), Some("renamed to abi_cmse_nonsecure_call"), 142146), + (removed, abi_c_cmse_nonsecure_call, "1.90.0", Some(81391), Some("renamed to abi_cmse_nonsecure_call"), 142146), (removed, advanced_slice_patterns, "1.42.0", Some(62254), Some("merged into `#![feature(slice_patterns)]`"), 67712), (removed, allocator, "1.0.0", None, None), @@ -199,6 +199,8 @@ declare_features! ( /// Renamed to `dyn_compatible_for_dispatch`. (removed, object_safe_for_dispatch, "1.83.0", Some(43561), Some("renamed to `dyn_compatible_for_dispatch`"), 131511), + /// Allows using `#[omit_gdb_pretty_printer_section]`. + (removed, omit_gdb_pretty_printer_section, "CURRENT_RUSTC_VERSION", None, None, 144738), /// Allows using `#[on_unimplemented(..)]` on traits. /// (Moved to `rustc_attrs`.) (removed, on_unimplemented, "1.40.0", None, None, 65794), @@ -298,7 +300,7 @@ declare_features! ( // FIXME(#141617): we should have a better way to track removed library features, but we reuse // the infrastructure here so users still get hints. The symbols used here can be remove from // `symbol.rs` when that happens. - (removed, concat_idents, "CURRENT_RUSTC_VERSION", Some(29599), + (removed, concat_idents, "1.90.0", Some(29599), Some("use the `${concat(..)}` metavariable expression instead"), 142704), // ------------------------------------------------------------------------- // feature-group-end: removed library features diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index e985e04ba33..ae1f57c1ef6 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -225,8 +225,6 @@ declare_features! ( (unstable, multiple_supertrait_upcastable, "1.69.0", None), /// Allow negative trait bounds. This is an internal-only feature for testing the trait solver! (internal, negative_bounds, "1.71.0", None), - /// Allows using `#[omit_gdb_pretty_printer_section]`. - (internal, omit_gdb_pretty_printer_section, "1.5.0", None), /// Set the maximum pattern complexity allowed (not limited by default). (internal, pattern_complexity_limit, "1.78.0", None), /// Allows using pattern types. @@ -329,6 +327,7 @@ declare_features! ( (unstable, m68k_target_feature, "1.85.0", Some(134328)), (unstable, mips_target_feature, "1.27.0", Some(44839)), (unstable, movrs_target_feature, "1.88.0", Some(137976)), + (unstable, nvptx_target_feature, "CURRENT_RUSTC_VERSION", Some(44839)), (unstable, powerpc_target_feature, "1.27.0", Some(44839)), (unstable, prfchw_target_feature, "1.78.0", Some(44839)), (unstable, riscv_target_feature, "1.45.0", Some(44839)), @@ -354,7 +353,7 @@ declare_features! ( /// Allows `extern "avr-interrupt" fn()` and `extern "avr-non-blocking-interrupt" fn()`. (unstable, abi_avr_interrupt, "1.45.0", Some(69664)), /// Allows `extern "cmse-nonsecure-call" fn()`. - (unstable, abi_cmse_nonsecure_call, "CURRENT_RUSTC_VERSION", Some(81391)), + (unstable, abi_cmse_nonsecure_call, "1.90.0", Some(81391)), /// Allows `extern "custom" fn()`. (unstable, abi_custom, "1.89.0", Some(140829)), /// Allows `extern "gpu-kernel" fn()`. @@ -554,7 +553,9 @@ declare_features! ( /// to pass custom arguments to the linker. (unstable, link_arg_attribute, "1.76.0", Some(99427)), /// Allows fused `loop`/`match` for direct intraprocedural jumps. - (incomplete, loop_match, "CURRENT_RUSTC_VERSION", Some(132306)), + (incomplete, loop_match, "1.90.0", Some(132306)), + /// Allow `macro_rules!` attribute rules + (unstable, macro_attr, "CURRENT_RUSTC_VERSION", Some(83527)), /// Give access to additional metadata about declarative macro meta-variables. (unstable, macro_metavar_expr, "1.61.0", Some(83527)), /// Provides a way to concatenate identifiers using metavariable expressions. diff --git a/compiler/rustc_hir/Cargo.toml b/compiler/rustc_hir/Cargo.toml index 7ca8539845a..539d2e6f0b1 100644 --- a/compiler/rustc_hir/Cargo.toml +++ b/compiler/rustc_hir/Cargo.toml @@ -9,7 +9,7 @@ odht = { version = "0.3.1", features = ["nightly"] } rustc_abi = { path = "../rustc_abi" } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } -rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } +rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_hashes = { path = "../rustc_hashes" } rustc_index = { path = "../rustc_index" } diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 610c93a253c..5f419315467 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -1,12 +1,15 @@ +pub use ReprAttr::*; use rustc_abi::Align; use rustc_ast::token::CommentKind; -use rustc_ast::{self as ast, AttrStyle}; +use rustc_ast::{AttrStyle, ast}; use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute}; +use rustc_span::def_id::DefId; use rustc_span::hygiene::Transparency; use rustc_span::{Ident, Span, Symbol}; use thin_vec::ThinVec; -use crate::{DefaultBodyStability, PartialConstStability, PrintAttribute, RustcVersion, Stability}; +use crate::attrs::pretty_printing::PrintAttribute; +use crate::{DefaultBodyStability, PartialConstStability, RustcVersion, Stability}; #[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, PrintAttribute)] pub enum InlineAttr { @@ -68,8 +71,6 @@ pub enum ReprAttr { ReprTransparent, ReprAlign(Align), } -pub use ReprAttr::*; -use rustc_span::def_id::DefId; pub enum TransparencyError { UnknownTransparency(Symbol, Span), @@ -110,18 +111,10 @@ pub enum DeprecatedSince { Err, } -#[derive( - Copy, - Debug, - Eq, - PartialEq, - Encodable, - Decodable, - Clone, - HashStable_Generic, - PrintAttribute -)] -pub enum CoverageStatus { +/// Successfully-parsed value of a `#[coverage(..)]` attribute. +#[derive(Copy, Debug, Eq, PartialEq, Encodable, Decodable, Clone)] +#[derive(HashStable_Generic, PrintAttribute)] +pub enum CoverageAttrKind { On, Off, } @@ -304,8 +297,11 @@ pub enum AttributeKind { /// Represents `#[const_trait]`. ConstTrait(Span), - /// Represents `#[coverage]`. - Coverage(Span, CoverageStatus), + /// Represents `#[coroutine]`. + Coroutine(Span), + + /// Represents `#[coverage(..)]`. + Coverage(Span, CoverageAttrKind), ///Represents `#[rustc_deny_explicit_impl]`. DenyExplicitImpl(Span), @@ -398,9 +394,6 @@ pub enum AttributeKind { /// Represents `#[non_exhaustive]` NonExhaustive(Span), - /// Represents `#[omit_gdb_pretty_printer_section]` - OmitGdbPrettyPrinterSection, - /// Represents `#[optimize(size|speed)]` Optimize(OptimizeAttr, Span), @@ -443,6 +436,9 @@ pub enum AttributeKind { /// Represents `#[rustc_object_lifetime_default]`. RustcObjectLifetimeDefault, + /// Represents `#[should_panic]` + ShouldPanic { reason: Option<Symbol>, span: Span }, + /// Represents `#[rustc_skip_during_method_dispatch]`. SkipDuringMethodDispatch { array: bool, boxed_slice: bool, span: Span }, diff --git a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index af2d46d0bc7..e3a7f0b97a8 100644 --- a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -1,4 +1,4 @@ -use crate::AttributeKind; +use crate::attrs::AttributeKind; #[derive(PartialEq)] pub enum EncodeCrossCrate { @@ -28,6 +28,7 @@ impl AttributeKind { ConstStability { .. } => Yes, ConstStabilityIndirect => No, ConstTrait(..) => No, + Coroutine(..) => No, Coverage(..) => No, DenyExplicitImpl(..) => No, Deprecation { .. } => Yes, @@ -55,7 +56,6 @@ impl AttributeKind { NoImplicitPrelude(..) => No, NoMangle(..) => Yes, // Needed for rustdoc NonExhaustive(..) => Yes, // Needed for rustdoc - OmitGdbPrettyPrinterSection => No, Optimize(..) => No, ParenSugar(..) => No, PassByValue(..) => Yes, @@ -70,6 +70,7 @@ impl AttributeKind { RustcLayoutScalarValidRangeEnd(..) => Yes, RustcLayoutScalarValidRangeStart(..) => Yes, RustcObjectLifetimeDefault => No, + ShouldPanic { .. } => No, SkipDuringMethodDispatch { .. } => No, SpecializationTrait(..) => No, Stability { .. } => Yes, diff --git a/compiler/rustc_hir/src/attrs/mod.rs b/compiler/rustc_hir/src/attrs/mod.rs new file mode 100644 index 00000000000..482e6c90739 --- /dev/null +++ b/compiler/rustc_hir/src/attrs/mod.rs @@ -0,0 +1,54 @@ +//! Data structures for representing parsed attributes in the Rust compiler. +//! Formerly `rustc_attr_data_structures`. +//! +//! For detailed documentation about attribute processing, +//! see [rustc_attr_parsing](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_parsing/index.html). + +pub use data_structures::*; +pub use encode_cross_crate::EncodeCrossCrate; +pub use pretty_printing::PrintAttribute; + +mod data_structures; +mod encode_cross_crate; +mod pretty_printing; + +/// Finds attributes in sequences of attributes by pattern matching. +/// +/// A little like `matches` but for attributes. +/// +/// ```rust,ignore (illustrative) +/// // finds the repr attribute +/// if let Some(r) = find_attr!(attrs, AttributeKind::Repr(r) => r) { +/// +/// } +/// +/// // checks if one has matched +/// if find_attr!(attrs, AttributeKind::Repr(_)) { +/// +/// } +/// ``` +/// +/// Often this requires you to first end up with a list of attributes. +/// A common way to get those is through `tcx.get_all_attrs(did)` +#[macro_export] +macro_rules! find_attr { + ($attributes_list: expr, $pattern: pat $(if $guard: expr)?) => {{ + $crate::find_attr!($attributes_list, $pattern $(if $guard)? => ()).is_some() + }}; + + ($attributes_list: expr, $pattern: pat $(if $guard: expr)? => $e: expr) => {{ + 'done: { + for i in $attributes_list { + let i: &rustc_hir::Attribute = i; + match i { + rustc_hir::Attribute::Parsed($pattern) $(if $guard)? => { + break 'done Some($e); + } + _ => {} + } + } + + None + } + }}; +} diff --git a/compiler/rustc_attr_data_structures/src/lib.rs b/compiler/rustc_hir/src/attrs/pretty_printing.rs index 4c5af805ca9..e44b29141da 100644 --- a/compiler/rustc_attr_data_structures/src/lib.rs +++ b/compiler/rustc_hir/src/attrs/pretty_printing.rs @@ -1,38 +1,12 @@ -//! Data structures for representing parsed attributes in the Rust compiler. -//! For detailed documentation about attribute processing, -//! see [rustc_attr_parsing](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_parsing/index.html). - -// tidy-alphabetical-start -#![allow(internal_features)] -#![doc(rust_logo)] -#![feature(rustdoc_internals)] -// tidy-alphabetical-end - -mod attributes; -mod encode_cross_crate; -mod stability; -mod version; - -pub mod lints; - use std::num::NonZero; -pub use attributes::*; -pub use encode_cross_crate::EncodeCrossCrate; use rustc_abi::Align; use rustc_ast::token::CommentKind; use rustc_ast::{AttrStyle, IntTy, UintTy}; use rustc_ast_pretty::pp::Printer; use rustc_span::hygiene::Transparency; use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol}; -pub use stability::*; use thin_vec::ThinVec; -pub use version::*; - -/// Requirements for a `StableHashingContext` to be used in this crate. -/// This is a hack to allow using the `HashStable_Generic` derive macro -/// instead of implementing everything in `rustc_middle`. -pub trait HashStableContext: rustc_ast::HashStableContext + rustc_abi::HashStableContext {} /// This trait is used to print attributes in `rustc_hir_pretty`. /// @@ -173,44 +147,3 @@ print_tup!(A B C D E F G H); print_skip!(Span, (), ErrorGuaranteed); print_disp!(u16, bool, NonZero<u32>); print_debug!(Symbol, Ident, UintTy, IntTy, Align, AttrStyle, CommentKind, Transparency); - -/// Finds attributes in sequences of attributes by pattern matching. -/// -/// A little like `matches` but for attributes. -/// -/// ```rust,ignore (illustrative) -/// // finds the repr attribute -/// if let Some(r) = find_attr!(attrs, AttributeKind::Repr(r) => r) { -/// -/// } -/// -/// // checks if one has matched -/// if find_attr!(attrs, AttributeKind::Repr(_)) { -/// -/// } -/// ``` -/// -/// Often this requires you to first end up with a list of attributes. -/// A common way to get those is through `tcx.get_all_attrs(did)` -#[macro_export] -macro_rules! find_attr { - ($attributes_list: expr, $pattern: pat $(if $guard: expr)?) => {{ - $crate::find_attr!($attributes_list, $pattern $(if $guard)? => ()).is_some() - }}; - - ($attributes_list: expr, $pattern: pat $(if $guard: expr)? => $e: expr) => {{ - 'done: { - for i in $attributes_list { - let i: &rustc_hir::Attribute = i; - match i { - rustc_hir::Attribute::Parsed($pattern) $(if $guard)? => { - break 'done Some($e); - } - _ => {} - } - } - - None - } - }}; -} diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index f2567f73d99..339d4e2eab7 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -402,7 +402,7 @@ impl DefKind { /// For example, everything prefixed with `/* Res */` in this example has /// an associated `Res`: /// -/// ``` +/// ```ignore (illustrative) /// fn str_to_string(s: & /* Res */ str) -> /* Res */ String { /// /* Res */ String::from(/* Res */ s) /// } @@ -463,7 +463,7 @@ pub enum Res<Id = hir::HirId> { /// } /// /// impl Foo for Bar { - /// fn foo() -> Box<Self> { // SelfTyAlias + /// fn foo() -> Box<Self /* SelfTyAlias */> { /// let _: Self; // SelfTyAlias /// /// todo!() diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 96501844264..34db6f92d92 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -14,7 +14,6 @@ pub use rustc_ast::{ BoundConstness, BoundPolarity, ByRef, CaptureBy, DelimArgs, ImplPolarity, IsAuto, MetaItemInner, MetaItemLit, Movability, Mutability, UnOp, }; -use rustc_attr_data_structures::AttributeKind; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::tagged_ptr::TaggedRef; @@ -30,6 +29,7 @@ use thin_vec::ThinVec; use tracing::debug; use crate::LangItem; +use crate::attrs::AttributeKind; use crate::def::{CtorKind, DefKind, PerNS, Res}; use crate::def_id::{DefId, LocalDefIdMap}; pub(crate) use crate::hir_id::{HirId, ItemLocalId, ItemLocalMap, OwnerId}; @@ -148,6 +148,11 @@ impl From<Ident> for LifetimeSyntax { /// `LifetimeSource::OutlivesBound` or `LifetimeSource::PreciseCapturing` /// — there's no way to "elide" these lifetimes. #[derive(Debug, Copy, Clone, HashStable_Generic)] +// Raise the aligement to at least 4 bytes - this is relied on in other parts of the compiler(for pointer tagging): +// https://github.com/rust-lang/rust/blob/ce5fdd7d42aba9a2925692e11af2bd39cf37798a/compiler/rustc_data_structures/src/tagged_ptr.rs#L163 +// Removing this `repr(4)` will cause the compiler to not build on platforms like `m68k` Linux, where the aligement of u32 and usize is only 2. +// Since `repr(align)` may only raise aligement, this has no effect on platforms where the aligement is already sufficient. +#[repr(align(4))] pub struct Lifetime { #[stable_hasher(ignore)] pub hir_id: HirId, @@ -407,10 +412,8 @@ impl<'hir> PathSegment<'hir> { /// that are [just paths](ConstArgKind::Path) (currently just bare const params) /// versus const args that are literals or have arbitrary computations (e.g., `{ 1 + 3 }`). /// -/// The `Unambig` generic parameter represents whether the position this const is from is -/// unambiguously a const or ambiguous as to whether it is a type or a const. When in an -/// ambiguous context the parameter is instantiated with an uninhabited type making the -/// [`ConstArgKind::Infer`] variant unusable and [`GenericArg::Infer`] is used instead. +/// For an explanation of the `Unambig` generic parameter see the dev-guide: +/// <https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html> #[derive(Clone, Copy, Debug, HashStable_Generic)] #[repr(C)] pub struct ConstArg<'hir, Unambig = ()> { @@ -422,7 +425,7 @@ pub struct ConstArg<'hir, Unambig = ()> { impl<'hir> ConstArg<'hir, AmbigArg> { /// Converts a `ConstArg` in an ambiguous position to one in an unambiguous position. /// - /// Functions accepting an unambiguous consts may expect the [`ConstArgKind::Infer`] variant + /// Functions accepting unambiguous consts may expect the [`ConstArgKind::Infer`] variant /// to be used. Care should be taken to separately handle infer consts when calling this /// function as it cannot be handled by downstream code making use of the returned const. /// @@ -1305,6 +1308,7 @@ impl AttributeExt for Attribute { Attribute::Parsed(AttributeKind::MacroUse { span, .. }) => *span, Attribute::Parsed(AttributeKind::MayDangle(span)) => *span, Attribute::Parsed(AttributeKind::Ignore { span, .. }) => *span, + Attribute::Parsed(AttributeKind::ShouldPanic { span, .. }) => *span, Attribute::Parsed(AttributeKind::AutomaticallyDerived(span)) => *span, a => panic!("can't get the span of an arbitrary parsed attribute: {a:?}"), } @@ -3011,7 +3015,7 @@ impl fmt::Display for LoopIdError { } } -#[derive(Copy, Clone, Debug, HashStable_Generic)] +#[derive(Copy, Clone, Debug, PartialEq, HashStable_Generic)] pub struct Destination { /// This is `Some(_)` iff there is an explicit user-specified 'label pub label: Option<Label>, @@ -3309,14 +3313,12 @@ impl<'hir> AssocItemConstraintKind<'hir> { #[derive(Debug, Clone, Copy, HashStable_Generic)] pub enum AmbigArg {} -#[derive(Debug, Clone, Copy, HashStable_Generic)] -#[repr(C)] /// Represents a type in the `HIR`. /// -/// The `Unambig` generic parameter represents whether the position this type is from is -/// unambiguously a type or ambiguous as to whether it is a type or a const. When in an -/// ambiguous context the parameter is instantiated with an uninhabited type making the -/// [`TyKind::Infer`] variant unusable and [`GenericArg::Infer`] is used instead. +/// For an explanation of the `Unambig` generic parameter see the dev-guide: +/// <https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html> +#[derive(Debug, Clone, Copy, HashStable_Generic)] +#[repr(C)] pub struct Ty<'hir, Unambig = ()> { #[stable_hasher(ignore)] pub hir_id: HirId, @@ -3651,9 +3653,12 @@ pub enum InferDelegationKind { } /// The various kinds of types recognized by the compiler. -#[derive(Debug, Clone, Copy, HashStable_Generic)] +/// +/// For an explanation of the `Unambig` generic parameter see the dev-guide: +/// <https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html> // SAFETY: `repr(u8)` is required so that `TyKind<()>` and `TyKind<!>` are layout compatible #[repr(u8, C)] +#[derive(Debug, Clone, Copy, HashStable_Generic)] pub enum TyKind<'hir, Unambig = ()> { /// Actual type should be inherited from `DefId` signature InferDelegation(DefId, InferDelegationKind), diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index f33915d5b07..23fa466859a 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -364,9 +364,6 @@ pub trait Visitor<'v>: Sized { /// All types are treated as ambiguous types for the purposes of hir visiting in /// order to ensure that visitors can handle infer vars without it being too error-prone. /// - /// See the doc comments on [`Ty`] for an explanation of what it means for a type to be - /// ambiguous. - /// /// The [`Visitor::visit_infer`] method should be overridden in order to handle infer vars. fn visit_ty(&mut self, t: &'v Ty<'v, AmbigArg>) -> Self::Result { walk_ty(self, t) @@ -375,12 +372,9 @@ pub trait Visitor<'v>: Sized { /// All consts are treated as ambiguous consts for the purposes of hir visiting in /// order to ensure that visitors can handle infer vars without it being too error-prone. /// - /// See the doc comments on [`ConstArg`] for an explanation of what it means for a const to be - /// ambiguous. - /// /// The [`Visitor::visit_infer`] method should be overridden in order to handle infer vars. fn visit_const_arg(&mut self, c: &'v ConstArg<'v, AmbigArg>) -> Self::Result { - walk_ambig_const_arg(self, c) + walk_const_arg(self, c) } #[allow(unused_variables)] @@ -522,7 +516,7 @@ pub trait VisitorExt<'v>: Visitor<'v> { /// Named `visit_const_arg_unambig` instead of `visit_unambig_const_arg` to aid in /// discovery by IDes when `v.visit_const_arg` is written. fn visit_const_arg_unambig(&mut self, c: &'v ConstArg<'v>) -> Self::Result { - walk_const_arg(self, c) + walk_unambig_const_arg(self, c) } } impl<'v, V: Visitor<'v>> VisitorExt<'v> for V {} @@ -985,7 +979,6 @@ pub fn walk_unambig_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> Some(ambig_ty) => visitor.visit_ty(ambig_ty), None => { let Ty { hir_id, span, kind: _ } = typ; - try_visit!(visitor.visit_id(*hir_id)); visitor.visit_infer(*hir_id, *span, InferKind::Ty(typ)) } } @@ -1043,7 +1036,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v, AmbigArg>) - V::Result::output() } -pub fn walk_const_arg<'v, V: Visitor<'v>>( +pub fn walk_unambig_const_arg<'v, V: Visitor<'v>>( visitor: &mut V, const_arg: &'v ConstArg<'v>, ) -> V::Result { @@ -1051,13 +1044,12 @@ pub fn walk_const_arg<'v, V: Visitor<'v>>( Some(ambig_ct) => visitor.visit_const_arg(ambig_ct), None => { let ConstArg { hir_id, kind: _ } = const_arg; - try_visit!(visitor.visit_id(*hir_id)); visitor.visit_infer(*hir_id, const_arg.span(), InferKind::Const(const_arg)) } } } -pub fn walk_ambig_const_arg<'v, V: Visitor<'v>>( +pub fn walk_const_arg<'v, V: Visitor<'v>>( visitor: &mut V, const_arg: &'v ConstArg<'v, AmbigArg>, ) -> V::Result { diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index dafd31336fb..f1212d07ff6 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -18,6 +18,7 @@ extern crate self as rustc_hir; mod arena; +pub mod attrs; pub mod def; pub mod def_path_hash_map; pub mod definitions; @@ -29,8 +30,10 @@ pub mod intravisit; pub mod lang_items; pub mod lints; pub mod pat_util; +mod stability; mod stable_hash_impls; mod target; +mod version; pub mod weak_lang_items; #[cfg(test)] @@ -40,7 +43,9 @@ mod tests; pub use hir::*; pub use hir_id::*; pub use lang_items::{LangItem, LanguageItems}; +pub use stability::*; pub use stable_hash_impls::HashStableContext; pub use target::{MethodKind, Target}; +pub use version::*; arena_types!(rustc_arena::declare_arena); diff --git a/compiler/rustc_hir/src/lints.rs b/compiler/rustc_hir/src/lints.rs index 7be6c32e57e..c55a41eb2b7 100644 --- a/compiler/rustc_hir/src/lints.rs +++ b/compiler/rustc_hir/src/lints.rs @@ -1,9 +1,16 @@ -use rustc_attr_data_structures::lints::AttributeLint; use rustc_data_structures::fingerprint::Fingerprint; use rustc_macros::HashStable_Generic; +use rustc_span::Span; use crate::HirId; +#[derive(Debug)] +pub struct DelayedLints { + pub lints: Box<[DelayedLint]>, + // Only present when the crate hash is needed. + pub opt_hash: Option<Fingerprint>, +} + /// During ast lowering, no lints can be emitted. /// That is because lints attach to nodes either in the AST, or on the built HIR. /// When attached to AST nodes, they're emitted just before building HIR, @@ -15,9 +22,16 @@ pub enum DelayedLint { AttributeParsing(AttributeLint<HirId>), } -#[derive(Debug)] -pub struct DelayedLints { - pub lints: Box<[DelayedLint]>, - // Only present when the crate hash is needed. - pub opt_hash: Option<Fingerprint>, +#[derive(Clone, Debug, HashStable_Generic)] +pub struct AttributeLint<Id> { + pub id: Id, + pub span: Span, + pub kind: AttributeLintKind, +} + +#[derive(Clone, Debug, HashStable_Generic)] +pub enum AttributeLintKind { + UnusedDuplicate { this: Span, other: Span, warning: bool }, + IllFormedAttributeInput { suggestions: Vec<String> }, + EmptyAttribute { first_span: Span }, } diff --git a/compiler/rustc_attr_data_structures/src/stability.rs b/compiler/rustc_hir/src/stability.rs index bd31c062117..2b3a2a79316 100644 --- a/compiler/rustc_attr_data_structures/src/stability.rs +++ b/compiler/rustc_hir/src/stability.rs @@ -3,7 +3,8 @@ use std::num::NonZero; use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute}; use rustc_span::{ErrorGuaranteed, Symbol, sym}; -use crate::{PrintAttribute, RustcVersion}; +use crate::RustcVersion; +use crate::attrs::PrintAttribute; /// The version placeholder that recently stabilized features contain inside the /// `since` field of the `#[stable]` attribute. diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs index 6acf1524b60..ecc608d437b 100644 --- a/compiler/rustc_hir/src/stable_hash_impls.rs +++ b/compiler/rustc_hir/src/stable_hash_impls.rs @@ -11,11 +11,7 @@ use crate::lints::DelayedLints; /// Requirements for a `StableHashingContext` to be used in this crate. /// This is a hack to allow using the `HashStable_Generic` derive macro /// instead of implementing everything in `rustc_middle`. -pub trait HashStableContext: - rustc_attr_data_structures::HashStableContext - + rustc_ast::HashStableContext - + rustc_abi::HashStableContext -{ +pub trait HashStableContext: rustc_ast::HashStableContext + rustc_abi::HashStableContext { fn hash_attr_id(&mut self, id: &HashIgnoredAttrId, hasher: &mut StableHasher); } diff --git a/compiler/rustc_attr_data_structures/src/version.rs b/compiler/rustc_hir/src/version.rs index 030e9520940..ab5ab026b4c 100644 --- a/compiler/rustc_attr_data_structures/src/version.rs +++ b/compiler/rustc_hir/src/version.rs @@ -5,7 +5,7 @@ use rustc_macros::{ Decodable, Encodable, HashStable_Generic, PrintAttribute, current_rustc_version, }; -use crate::PrintAttribute; +use crate::attrs::PrintAttribute; #[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(HashStable_Generic, PrintAttribute)] diff --git a/compiler/rustc_hir_analysis/Cargo.toml b/compiler/rustc_hir_analysis/Cargo.toml index 5d6c49ee862..e5017794d8f 100644 --- a/compiler/rustc_hir_analysis/Cargo.toml +++ b/compiler/rustc_hir_analysis/Cargo.toml @@ -13,7 +13,6 @@ itertools = "0.12" rustc_abi = { path = "../rustc_abi" } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } -rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 6e63ce31024..161a8566b04 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -2,13 +2,14 @@ use std::cell::LazyCell; use std::ops::ControlFlow; use rustc_abi::{ExternAbi, FieldIdx}; -use rustc_attr_data_structures::ReprAttr::ReprPacked; -use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::codes::*; use rustc_errors::{EmissionGuarantee, MultiSpan}; +use rustc_hir as hir; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::attrs::ReprAttr::ReprPacked; use rustc_hir::def::{CtorKind, DefKind}; -use rustc_hir::{LangItem, Node, intravisit}; +use rustc_hir::{LangItem, Node, attrs, find_attr, intravisit}; use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt}; use rustc_infer::traits::{Obligation, ObligationCauseCode, WellFormedLoc}; use rustc_lint_defs::builtin::{ @@ -32,7 +33,6 @@ use rustc_trait_selection::traits; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use tracing::{debug, instrument}; use ty::TypingMode; -use {rustc_attr_data_structures as attrs, rustc_hir as hir}; use super::compare_impl_item::check_type_bounds; use super::*; @@ -1401,7 +1401,7 @@ fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) { let repr = def.repr(); if repr.packed() { - if let Some(reprs) = attrs::find_attr!(tcx.get_all_attrs(def.did()), attrs::AttributeKind::Repr { reprs, .. } => reprs) + if let Some(reprs) = find_attr!(tcx.get_all_attrs(def.did()), attrs::AttributeKind::Repr { reprs, .. } => reprs) { for (r, _) in reprs { if let ReprPacked(pack) = r @@ -1536,7 +1536,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) ty::Array(ty, _) => check_non_exhaustive(tcx, *ty), ty::Adt(def, args) => { if !def.did().is_local() - && !attrs::find_attr!( + && !find_attr!( tcx.get_all_attrs(def.did()), AttributeKind::PubTransparent(_) ) @@ -1622,7 +1622,7 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) { def.destructor(tcx); // force the destructor to be evaluated if def.variants().is_empty() { - attrs::find_attr!( + find_attr!( tcx.get_all_attrs(def_id), attrs::AttributeKind::Repr { reprs, first_span } => { struct_span_code_err!( diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index e24426f9fed..6767e5ed88d 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -356,14 +356,14 @@ fn compare_method_predicate_entailment<'tcx>( } if !(impl_sig, trait_sig).references_error() { - ocx.register_obligation(traits::Obligation::new( - infcx.tcx, - cause, - param_env, - ty::ClauseKind::WellFormed( - Ty::new_fn_ptr(tcx, ty::Binder::dummy(unnormalized_impl_sig)).into(), - ), - )); + for ty in unnormalized_impl_sig.inputs_and_output { + ocx.register_obligation(traits::Obligation::new( + infcx.tcx, + cause.clone(), + param_env, + ty::ClauseKind::WellFormed(ty.into()), + )); + } } // Check that all obligations are satisfied by the implementation's @@ -425,7 +425,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RemapLateParam<'tcx> { /// /// trait Foo { /// fn bar() -> impl Deref<Target = impl Sized>; -/// // ^- RPITIT #1 ^- RPITIT #2 +/// // ^- RPITIT #1 ^- RPITIT #2 /// } /// /// impl Foo for () { @@ -2498,7 +2498,7 @@ fn param_env_with_gat_bounds<'tcx>( ty::Const::new_bound( tcx, ty::INNERMOST, - ty::BoundVar::from_usize(bound_vars.len() - 1), + ty::BoundConst { var: ty::BoundVar::from_usize(bound_vars.len() - 1) }, ) .into() } diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs index b556683e80a..97787270be7 100644 --- a/compiler/rustc_hir_analysis/src/check/entry.rs +++ b/compiler/rustc_hir_analysis/src/check/entry.rs @@ -1,9 +1,9 @@ use std::ops::Not; use rustc_abi::ExternAbi; -use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_hir as hir; -use rustc_hir::Node; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::{Node, find_attr}; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::span_bug; use rustc_middle::ty::{self, TyCtxt, TypingMode}; diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 6e5fe3823ab..4441dd6ebd6 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -652,16 +652,16 @@ pub(crate) fn check_intrinsic_type( sym::atomic_store => (1, 1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], tcx.types.unit), sym::atomic_xchg - | sym::atomic_xadd - | sym::atomic_xsub - | sym::atomic_and - | sym::atomic_nand - | sym::atomic_or - | sym::atomic_xor | sym::atomic_max | sym::atomic_min | sym::atomic_umax | sym::atomic_umin => (1, 1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], param(0)), + sym::atomic_xadd + | sym::atomic_xsub + | sym::atomic_and + | sym::atomic_nand + | sym::atomic_or + | sym::atomic_xor => (2, 1, vec![Ty::new_mut_ptr(tcx, param(0)), param(1)], param(0)), sym::atomic_fence | sym::atomic_singlethreadfence => (0, 1, Vec::new(), tcx.types.unit), other => { diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index b2cfab37c1f..85445cb3c00 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -493,7 +493,7 @@ fn suggestion_signature<'tcx>( let args = ty::GenericArgs::identity_for_item(tcx, assoc.def_id).rebase_onto( tcx, assoc.container_id(tcx), - impl_trait_ref.with_self_ty(tcx, tcx.types.self_param).args, + impl_trait_ref.with_replaced_self_ty(tcx, tcx.types.self_param).args, ); match assoc.kind { diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 95f6fba6487..f5770b7312d 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -199,6 +199,11 @@ fn resolve_arm<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, arm: &'tcx hir: resolve_pat(visitor, arm.pat); if let Some(guard) = arm.guard { + // We introduce a new scope to contain bindings and temporaries from `if let` guards, to + // ensure they're dropped before the arm's pattern's bindings. This extends to the end of + // the arm body and is the scope of its locals as well. + visitor.enter_scope(Scope { local_id: arm.hir_id.local_id, data: ScopeData::MatchGuard }); + visitor.cx.var_parent = visitor.cx.parent; resolve_cond(visitor, guard); } resolve_expr(visitor, arm.body, false); diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index 80bf13dc4b7..38ae7852ca9 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -7,10 +7,11 @@ //! `tcx.inherent_impls(def_id)`). That value, however, //! is computed by selecting an idea from this table. -use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_hir as hir; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::find_attr; use rustc_middle::bug; use rustc_middle::ty::fast_reject::{SimplifiedType, TreatParams, simplify_type}; use rustc_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt}; diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index afe79bed851..8ccbfbbb3b4 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -21,16 +21,16 @@ use std::ops::Bound; use rustc_abi::ExternAbi; use rustc_ast::Recovered; -use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::unord::UnordMap; use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, E0228, ErrorGuaranteed, StashKey, struct_span_code_err, }; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt}; -use rustc_hir::{self as hir, GenericParamKind, HirId, Node, PreciseCapturingArgKind}; +use rustc_hir::{self as hir, GenericParamKind, HirId, Node, PreciseCapturingArgKind, find_attr}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::{DynCompatibilityViolation, ObligationCause}; use rustc_middle::query::Providers; diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 31e9c3b80fb..ce0e51f106f 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -223,60 +223,27 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { "synthetic HIR should have its `generics_of` explicitly fed" ), - _ => span_bug!(tcx.def_span(def_id), "unhandled node {node:?}"), + _ => span_bug!(tcx.def_span(def_id), "generics_of: unexpected node kind {node:?}"), }; - enum Defaults { - Allowed, - // See #36887 - FutureCompatDisallowed, - Deny, - } - - let hir_generics = node.generics().unwrap_or(hir::Generics::empty()); - let (opt_self, allow_defaults) = match node { - Node::Item(item) => { - match item.kind { - ItemKind::Trait(..) | ItemKind::TraitAlias(..) => { - // Add in the self type parameter. - // - // Something of a hack: use the node id for the trait, also as - // the node id for the Self type parameter. - let opt_self = Some(ty::GenericParamDef { - index: 0, - name: kw::SelfUpper, - def_id: def_id.to_def_id(), - pure_wrt_drop: false, - kind: ty::GenericParamDefKind::Type { - has_default: false, - synthetic: false, - }, - }); - - (opt_self, Defaults::Allowed) - } - ItemKind::TyAlias(..) - | ItemKind::Enum(..) - | ItemKind::Struct(..) - | ItemKind::Union(..) => (None, Defaults::Allowed), - ItemKind::Const(..) => (None, Defaults::Deny), - _ => (None, Defaults::FutureCompatDisallowed), - } - } - - Node::OpaqueTy(..) => (None, Defaults::Allowed), - - // GATs - Node::TraitItem(item) if matches!(item.kind, TraitItemKind::Type(..)) => { - (None, Defaults::Deny) - } - Node::ImplItem(item) if matches!(item.kind, ImplItemKind::Type(..)) => { - (None, Defaults::Deny) - } - - _ => (None, Defaults::FutureCompatDisallowed), + // Add in the self type parameter. + let opt_self = if let Node::Item(item) = node + && let ItemKind::Trait(..) | ItemKind::TraitAlias(..) = item.kind + { + // Something of a hack: We reuse the node ID of the trait for the self type parameter. + Some(ty::GenericParamDef { + index: 0, + name: kw::SelfUpper, + def_id: def_id.to_def_id(), + pure_wrt_drop: false, + kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false }, + }) + } else { + None }; + let param_default_policy = param_default_policy(node); + let hir_generics = node.generics().unwrap_or(hir::Generics::empty()); let has_self = opt_self.is_some(); let mut parent_has_self = false; let mut own_start = has_self as u32; @@ -312,60 +279,53 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { prev + type_start }; - const TYPE_DEFAULT_NOT_ALLOWED: &'static str = "defaults for type parameters are only allowed in \ - `struct`, `enum`, `type`, or `trait` definitions"; - - own_params.extend(hir_generics.params.iter().filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => None, - GenericParamKind::Type { default, synthetic, .. } => { - if default.is_some() { - match allow_defaults { - Defaults::Allowed => {} - Defaults::FutureCompatDisallowed => { - tcx.node_span_lint( - lint::builtin::INVALID_TYPE_PARAM_DEFAULT, - param.hir_id, - param.span, - |lint| { - lint.primary_message(TYPE_DEFAULT_NOT_ALLOWED); - }, - ); - } - Defaults::Deny => { - tcx.dcx().span_err(param.span, TYPE_DEFAULT_NOT_ALLOWED); + own_params.extend(hir_generics.params.iter().filter_map(|param| { + const MESSAGE: &str = "defaults for generic parameters are not allowed here"; + let kind = match param.kind { + GenericParamKind::Lifetime { .. } => return None, + GenericParamKind::Type { default, synthetic } => { + if default.is_some() { + match param_default_policy.expect("no policy for generic param default") { + ParamDefaultPolicy::Allowed => {} + ParamDefaultPolicy::FutureCompatForbidden => { + tcx.node_span_lint( + lint::builtin::INVALID_TYPE_PARAM_DEFAULT, + param.hir_id, + param.span, + |lint| { + lint.primary_message(MESSAGE); + }, + ); + } + ParamDefaultPolicy::Forbidden => { + tcx.dcx().span_err(param.span, MESSAGE); + } } } - } - let kind = ty::GenericParamDefKind::Type { has_default: default.is_some(), synthetic }; - - Some(ty::GenericParamDef { - index: next_index(), - name: param.name.ident().name, - def_id: param.def_id.to_def_id(), - pure_wrt_drop: param.pure_wrt_drop, - kind, - }) - } - GenericParamKind::Const { ty: _, default, synthetic } => { - if !matches!(allow_defaults, Defaults::Allowed) && default.is_some() { - tcx.dcx().span_err( - param.span, - "defaults for const parameters are only allowed in \ - `struct`, `enum`, `type`, or `trait` definitions", - ); + ty::GenericParamDefKind::Type { has_default: default.is_some(), synthetic } } + GenericParamKind::Const { ty: _, default, synthetic } => { + if default.is_some() { + match param_default_policy.expect("no policy for generic param default") { + ParamDefaultPolicy::Allowed => {} + ParamDefaultPolicy::FutureCompatForbidden + | ParamDefaultPolicy::Forbidden => { + tcx.dcx().span_err(param.span, MESSAGE); + } + } + } - let index = next_index(); - - Some(ty::GenericParamDef { - index, - name: param.name.ident().name, - def_id: param.def_id.to_def_id(), - pure_wrt_drop: param.pure_wrt_drop, - kind: ty::GenericParamDefKind::Const { has_default: default.is_some(), synthetic }, - }) - } + ty::GenericParamDefKind::Const { has_default: default.is_some(), synthetic } + } + }; + Some(ty::GenericParamDef { + index: next_index(), + name: param.name.ident().name, + def_id: param.def_id.to_def_id(), + pure_wrt_drop: param.pure_wrt_drop, + kind, + }) })); // provide junk type parameter defs - the only place that @@ -379,20 +339,14 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { // for info on the usage of each of these fields. let dummy_args = match kind { ClosureKind::Closure => &["<closure_kind>", "<closure_signature>", "<upvars>"][..], - ClosureKind::Coroutine(_) => &[ - "<coroutine_kind>", - "<resume_ty>", - "<yield_ty>", - "<return_ty>", - "<witness>", - "<upvars>", - ][..], + ClosureKind::Coroutine(_) => { + &["<coroutine_kind>", "<resume_ty>", "<yield_ty>", "<return_ty>", "<upvars>"][..] + } ClosureKind::CoroutineClosure(_) => &[ "<closure_kind>", "<closure_signature_parts>", "<upvars>", "<bound_captures_by_ref>", - "<witness>", ][..], }; @@ -444,6 +398,48 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { } } +#[derive(Clone, Copy)] +enum ParamDefaultPolicy { + Allowed, + /// Tracked in <https://github.com/rust-lang/rust/issues/36887>. + FutureCompatForbidden, + Forbidden, +} + +fn param_default_policy(node: Node<'_>) -> Option<ParamDefaultPolicy> { + use rustc_hir::*; + + Some(match node { + Node::Item(item) => match item.kind { + ItemKind::Trait(..) + | ItemKind::TraitAlias(..) + | ItemKind::TyAlias(..) + | ItemKind::Enum(..) + | ItemKind::Struct(..) + | ItemKind::Union(..) => ParamDefaultPolicy::Allowed, + ItemKind::Fn { .. } | ItemKind::Impl(_) => ParamDefaultPolicy::FutureCompatForbidden, + // Re. GCI, we're not bound by backward compatibility. + ItemKind::Const(..) => ParamDefaultPolicy::Forbidden, + _ => return None, + }, + Node::TraitItem(item) => match item.kind { + // Re. GATs and GACs (generic_const_items), we're not bound by backward compatibility. + TraitItemKind::Const(..) | TraitItemKind::Type(..) => ParamDefaultPolicy::Forbidden, + TraitItemKind::Fn(..) => ParamDefaultPolicy::FutureCompatForbidden, + }, + Node::ImplItem(item) => match item.kind { + // Re. GATs and GACs (generic_const_items), we're not bound by backward compatibility. + ImplItemKind::Const(..) | ImplItemKind::Type(..) => ParamDefaultPolicy::Forbidden, + ImplItemKind::Fn(..) => ParamDefaultPolicy::FutureCompatForbidden, + }, + // Generic params are (semantically) invalid on foreign items. Still, for maximum forward + // compatibility, let's hard-reject defaults on them. + Node::ForeignItem(_) => ParamDefaultPolicy::Forbidden, + Node::OpaqueTy(..) => ParamDefaultPolicy::Allowed, + _ => return None, + }) +} + fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<Span> { struct LateBoundRegionsDetector<'tcx> { tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 548ba343aae..ba54fa8cc0d 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -189,7 +189,7 @@ fn remap_gat_vars_and_recurse_into_nested_projections<'tcx>( } ty::GenericArgKind::Const(ct) => { if let ty::ConstKind::Bound(ty::INNERMOST, bv) = ct.kind() { - mapping.insert(bv, tcx.mk_param_from_def(param)) + mapping.insert(bv.var, tcx.mk_param_from_def(param)) } else { return None; } @@ -307,16 +307,16 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for MapAndCompressBoundVars<'tcx> { return ct; } - if let ty::ConstKind::Bound(binder, old_var) = ct.kind() + if let ty::ConstKind::Bound(binder, old_bound) = ct.kind() && self.binder == binder { - let mapped = if let Some(mapped) = self.mapping.get(&old_var) { + let mapped = if let Some(mapped) = self.mapping.get(&old_bound.var) { mapped.expect_const() } else { let var = ty::BoundVar::from_usize(self.still_bound_vars.len()); self.still_bound_vars.push(ty::BoundVariableKind::Const); - let mapped = ty::Const::new_bound(self.tcx, ty::INNERMOST, var); - self.mapping.insert(old_var, mapped.into()); + let mapped = ty::Const::new_bound(self.tcx, ty::INNERMOST, ty::BoundConst { var }); + self.mapping.insert(old_bound.var, mapped.into()); mapped }; diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index cc53919626e..8dd13da4fa7 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -1,11 +1,12 @@ use std::assert_matches::assert_matches; use hir::Node; -use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::find_attr; use rustc_middle::ty::{ self, GenericPredicates, ImplTraitInTraitData, Ty, TyCtxt, TypeVisitable, TypeVisitor, Upcast, }; @@ -516,8 +517,7 @@ pub(super) fn explicit_predicates_of<'tcx>( projection.args == trait_identity_args // FIXME(return_type_notation): This check should be more robust && !tcx.is_impl_trait_in_trait(projection.def_id) - && tcx.associated_item(projection.def_id).container_id(tcx) - == def_id.to_def_id() + && tcx.parent(projection.def_id) == def_id.to_def_id() } else { false } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 7760642d8fb..386e1091ac4 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -1077,7 +1077,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'_, 't ty::ConstKind::Param(param) => { self.params.insert(param.index); } - ty::ConstKind::Bound(db, ty::BoundVar { .. }) if db >= self.depth => { + ty::ConstKind::Bound(db, _) if db >= self.depth => { let guar = self.cx.dcx().delayed_bug("unexpected escaping late-bound const var"); return ControlFlow::Break(guar); } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index f73442fdebd..93b82acf621 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -755,7 +755,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let limit = if candidates.len() == 5 { 5 } else { 4 }; for (index, &item) in candidates.iter().take(limit).enumerate() { - let impl_ = tcx.impl_of_assoc(item).unwrap(); + let impl_ = tcx.parent(item); let note_span = if item.is_local() { Some(tcx.def_span(item)) @@ -888,8 +888,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => { // `<Foo as Iterator>::Item = String`. let projection_term = pred.projection_term; - let quiet_projection_term = - projection_term.with_self_ty(tcx, Ty::new_var(tcx, ty::TyVid::ZERO)); + let quiet_projection_term = projection_term + .with_replaced_self_ty(tcx, Ty::new_var(tcx, ty::TyVid::ZERO)); let term = pred.term; let obligation = format!("{projection_term} = {term}"); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index d7687998358..1675aecd2b8 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -1135,9 +1135,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ); } } else { + let trait_ = + tcx.short_string(bound.print_only_trait_path(), err.long_ty_path()); err.note(format!( - "associated {assoc_kind_str} `{assoc_ident}` could derive from `{}`", - bound.print_only_trait_path(), + "associated {assoc_kind_str} `{assoc_ident}` could derive from `{trait_}`", )); } } @@ -2037,9 +2038,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { match prim_ty { hir::PrimTy::Bool => tcx.types.bool, hir::PrimTy::Char => tcx.types.char, - hir::PrimTy::Int(it) => Ty::new_int(tcx, ty::int_ty(it)), - hir::PrimTy::Uint(uit) => Ty::new_uint(tcx, ty::uint_ty(uit)), - hir::PrimTy::Float(ft) => Ty::new_float(tcx, ty::float_ty(ft)), + hir::PrimTy::Int(it) => Ty::new_int(tcx, it), + hir::PrimTy::Uint(uit) => Ty::new_uint(tcx, uit), + hir::PrimTy::Float(ft) => Ty::new_float(tcx, ft), hir::PrimTy::Str => tcx.types.str_, } } @@ -2107,9 +2108,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let name = tcx.item_name(param_def_id); ty::Const::new_param(tcx, ty::ParamConst::new(index, name)) } - Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => { - ty::Const::new_bound(tcx, debruijn, ty::BoundVar::from_u32(index)) - } + Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => ty::Const::new_bound( + tcx, + debruijn, + ty::BoundConst { var: ty::BoundVar::from_u32(index) }, + ), Some(rbv::ResolvedArg::Error(guar)) => ty::Const::new_error(tcx, guar), arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", path_hir_id), } diff --git a/compiler/rustc_hir_pretty/Cargo.toml b/compiler/rustc_hir_pretty/Cargo.toml index 91da8cb3fc5..f5d7dbd3f96 100644 --- a/compiler/rustc_hir_pretty/Cargo.toml +++ b/compiler/rustc_hir_pretty/Cargo.toml @@ -8,7 +8,6 @@ edition = "2024" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } -rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_hir = { path = "../rustc_hir" } rustc_span = { path = "../rustc_span" } # tidy-alphabetical-end diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index bda02042aa6..235eec96d74 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -15,7 +15,7 @@ use rustc_ast_pretty::pp::Breaks::{Consistent, Inconsistent}; use rustc_ast_pretty::pp::{self, BoxMarker, Breaks}; use rustc_ast_pretty::pprust::state::MacHeader; use rustc_ast_pretty::pprust::{Comments, PrintState}; -use rustc_attr_data_structures::{AttributeKind, PrintAttribute}; +use rustc_hir::attrs::{AttributeKind, PrintAttribute}; use rustc_hir::{ BindingMode, ByRef, ConstArgKind, GenericArg, GenericBound, GenericParam, GenericParamKind, HirId, ImplicitSelfKind, LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term, diff --git a/compiler/rustc_hir_typeck/Cargo.toml b/compiler/rustc_hir_typeck/Cargo.toml index c963f0ddefd..f00125c3e09 100644 --- a/compiler/rustc_hir_typeck/Cargo.toml +++ b/compiler/rustc_hir_typeck/Cargo.toml @@ -8,7 +8,6 @@ edition = "2024" itertools = "0.12" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } -rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index bac4d70103c..1ed0756fdd6 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -159,7 +159,7 @@ hir_typeck_lossy_provenance_ptr2int = .suggestion = use `.addr()` to obtain the address of a pointer .help = if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_provenance()` instead -hir_typeck_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}` +hir_typeck_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty}` hir_typeck_naked_asm_outside_naked_fn = the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]` @@ -184,7 +184,7 @@ hir_typeck_never_type_fallback_flowing_into_unsafe_path = never type fallback af hir_typeck_never_type_fallback_flowing_into_unsafe_union_field = never type fallback affects this union access .help = specify the type explicitly -hir_typeck_no_associated_item = no {$item_kind} named `{$item_ident}` found for {$ty_prefix} `{$ty_str}`{$trait_missing_method -> +hir_typeck_no_associated_item = no {$item_kind} named `{$item_ident}` found for {$ty_prefix} `{$ty}`{$trait_missing_method -> [true] {""} *[other] {" "}in the current scope } diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index a413f805873..82b7c578a1f 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -161,8 +161,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Resume type defaults to `()` if the coroutine has no argument. let resume_ty = liberated_sig.inputs().get(0).copied().unwrap_or(tcx.types.unit); - let interior = Ty::new_coroutine_witness(tcx, expr_def_id.to_def_id(), parent_args); - // Coroutines that come from coroutine closures have not yet determined // their kind ty, so make a fresh infer var which will be constrained // later during upvar analysis. Regular coroutines always have the kind @@ -182,7 +180,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { resume_ty, yield_ty, return_ty: liberated_sig.output(), - witness: interior, tupled_upvars_ty, }, ); @@ -210,7 +207,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // Compute all of the variables that will be used to populate the coroutine. let resume_ty = self.next_ty_var(expr_span); - let interior = self.next_ty_var(expr_span); let closure_kind_ty = match expected_kind { Some(kind) => Ty::from_closure_kind(tcx, kind), @@ -243,7 +239,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ), tupled_upvars_ty, coroutine_captures_by_ref_ty, - coroutine_witness_ty: interior, }, ); diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 6d67535da5f..e66601631fc 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -37,10 +37,10 @@ use std::ops::Deref; -use rustc_attr_data_structures::InlineAttr; use rustc_errors::codes::*; use rustc_errors::{Applicability, Diag, struct_span_code_err}; use rustc_hir as hir; +use rustc_hir::attrs::InlineAttr; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; use rustc_infer::infer::relate::RelateResult; @@ -1800,11 +1800,13 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { .kind() .map_bound(|clause| match clause { ty::ClauseKind::Trait(trait_pred) => Some(ty::ClauseKind::Trait( - trait_pred.with_self_ty(fcx.tcx, ty), + trait_pred.with_replaced_self_ty(fcx.tcx, ty), )), - ty::ClauseKind::Projection(proj_pred) => Some( - ty::ClauseKind::Projection(proj_pred.with_self_ty(fcx.tcx, ty)), - ), + ty::ClauseKind::Projection(proj_pred) => { + Some(ty::ClauseKind::Projection( + proj_pred.with_replaced_self_ty(fcx.tcx, ty), + )) + } _ => None, }) .transpose()?; diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index a8bb6956f10..d15d092b7d3 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -200,11 +200,11 @@ pub(crate) enum ExplicitDestructorCallSugg { #[derive(Diagnostic)] #[diag(hir_typeck_missing_parentheses_in_range, code = E0689)] -pub(crate) struct MissingParenthesesInRange { +pub(crate) struct MissingParenthesesInRange<'tcx> { #[primary_span] #[label(hir_typeck_missing_parentheses_in_range)] pub span: Span, - pub ty_str: String, + pub ty: Ty<'tcx>, pub method_name: String, #[subdiagnostic] pub add_missing_parentheses: Option<AddMissingParenthesesInRange>, @@ -828,13 +828,13 @@ pub(crate) struct UnlabeledCfInWhileCondition<'a> { #[derive(Diagnostic)] #[diag(hir_typeck_no_associated_item, code = E0599)] -pub(crate) struct NoAssociatedItem { +pub(crate) struct NoAssociatedItem<'tcx> { #[primary_span] pub span: Span, pub item_kind: &'static str, pub item_ident: Ident, pub ty_prefix: Cow<'static, str>, - pub ty_str: String, + pub ty: Ty<'tcx>, pub trait_missing_method: bool, } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 08e8164078c..0498a938366 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -7,7 +7,6 @@ use rustc_abi::{FIRST_VARIANT, FieldIdx}; use rustc_ast::util::parser::ExprPrecedence; -use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::unord::UnordMap; @@ -16,10 +15,11 @@ use rustc_errors::{ Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, Subdiagnostic, listify, pluralize, struct_span_code_err, }; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; -use rustc_hir::{ExprKind, HirId, QPath}; +use rustc_hir::{ExprKind, HirId, QPath, find_attr}; use rustc_hir_analysis::NoVariantNamed; use rustc_hir_analysis::hir_ty_lowering::{FeedConstTy, HirTyLowerer as _}; use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk, RegionVariableOrigin}; @@ -2745,6 +2745,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let available_field_names = self.available_field_names(variant, expr, skip_fields); if let Some(field_name) = find_best_match_for_name(&available_field_names, field.ident.name, None) + && !(field.ident.name.as_str().parse::<usize>().is_ok() + && field_name.as_str().parse::<usize>().is_ok()) { err.span_label(field.ident.span, "unknown field"); err.span_suggestion_verbose( @@ -3321,18 +3323,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { (base_ty, "") }; - for (found_fields, args) in + for found_fields in self.get_field_candidates_considering_privacy_for_diag(span, ty, mod_id, expr.hir_id) { - let field_names = found_fields.iter().map(|field| field.name).collect::<Vec<_>>(); + let field_names = found_fields.iter().map(|field| field.0.name).collect::<Vec<_>>(); let mut candidate_fields: Vec<_> = found_fields .into_iter() .filter_map(|candidate_field| { self.check_for_nested_field_satisfying_condition_for_diag( span, - &|candidate_field, _| candidate_field.ident(self.tcx()) == field, + &|candidate_field, _| candidate_field == field, candidate_field, - args, vec![], mod_id, expr.hir_id, @@ -3361,6 +3362,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } else if let Some(field_name) = find_best_match_for_name(&field_names, field.name, None) + && !(field.name.as_str().parse::<usize>().is_ok() + && field_name.as_str().parse::<usize>().is_ok()) { err.span_suggestion_verbose( field.span, @@ -3396,7 +3399,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { base_ty: Ty<'tcx>, mod_id: DefId, hir_id: HirId, - ) -> Vec<(Vec<&'tcx ty::FieldDef>, GenericArgsRef<'tcx>)> { + ) -> Vec<Vec<(Ident, Ty<'tcx>)>> { debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_ty); let mut autoderef = self.autoderef(span, base_ty).silence_errors(); @@ -3422,7 +3425,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if fields.iter().all(|field| !field.vis.is_accessible_from(mod_id, tcx)) { return None; } - return Some(( + return Some( fields .iter() .filter(move |field| { @@ -3431,9 +3434,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) // For compile-time reasons put a limit on number of fields we search .take(100) + .map(|field_def| { + ( + field_def.ident(self.tcx).normalize_to_macros_2_0(), + field_def.ty(self.tcx, args), + ) + }) + .collect::<Vec<_>>(), + ); + } + ty::Tuple(types) => { + return Some( + types + .iter() + .enumerate() + // For compile-time reasons put a limit on number of fields we search + .take(100) + .map(|(i, ty)| (Ident::from_str(&i.to_string()), ty)) .collect::<Vec<_>>(), - *args, - )); + ); } _ => None, } @@ -3443,56 +3462,46 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// This method is called after we have encountered a missing field error to recursively /// search for the field + #[instrument(skip(self, matches, mod_id, hir_id), level = "debug")] pub(crate) fn check_for_nested_field_satisfying_condition_for_diag( &self, span: Span, - matches: &impl Fn(&ty::FieldDef, Ty<'tcx>) -> bool, - candidate_field: &ty::FieldDef, - subst: GenericArgsRef<'tcx>, + matches: &impl Fn(Ident, Ty<'tcx>) -> bool, + (candidate_name, candidate_ty): (Ident, Ty<'tcx>), mut field_path: Vec<Ident>, mod_id: DefId, hir_id: HirId, ) -> Option<Vec<Ident>> { - debug!( - "check_for_nested_field_satisfying(span: {:?}, candidate_field: {:?}, field_path: {:?}", - span, candidate_field, field_path - ); - if field_path.len() > 3 { // For compile-time reasons and to avoid infinite recursion we only check for fields // up to a depth of three - None - } else { - field_path.push(candidate_field.ident(self.tcx).normalize_to_macros_2_0()); - let field_ty = candidate_field.ty(self.tcx, subst); - if matches(candidate_field, field_ty) { - return Some(field_path); - } else { - for (nested_fields, subst) in self - .get_field_candidates_considering_privacy_for_diag( - span, field_ty, mod_id, hir_id, - ) - { - // recursively search fields of `candidate_field` if it's a ty::Adt - for field in nested_fields { - if let Some(field_path) = self - .check_for_nested_field_satisfying_condition_for_diag( - span, - matches, - field, - subst, - field_path.clone(), - mod_id, - hir_id, - ) - { - return Some(field_path); - } - } + return None; + } + field_path.push(candidate_name); + if matches(candidate_name, candidate_ty) { + return Some(field_path); + } + for nested_fields in self.get_field_candidates_considering_privacy_for_diag( + span, + candidate_ty, + mod_id, + hir_id, + ) { + // recursively search fields of `candidate_field` if it's a ty::Adt + for field in nested_fields { + if let Some(field_path) = self.check_for_nested_field_satisfying_condition_for_diag( + span, + matches, + field, + field_path.clone(), + mod_id, + hir_id, + ) { + return Some(field_path); } } - None } + None } fn check_expr_index( diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index 9406697dfed..ef88e02fd98 100644 --- a/compiler/rustc_hir_typeck/src/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -18,6 +18,7 @@ use rustc_span::{DUMMY_SP, Span}; use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt}; use tracing::debug; +use crate::typeck_root_ctxt::InferVarInfo; use crate::{FnCtxt, errors}; #[derive(Copy, Clone)] @@ -345,7 +346,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { .map(|(_, info)| *info) .collect(); - let found_infer_var_info = ty::InferVarInfo { + let found_infer_var_info = InferVarInfo { self_in_trait: infer_var_infos.items().any(|info| info.self_in_trait), output: infer_var_infos.items().any(|info| info.output), }; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs index 4e4bf8a5562..ed88e32a273 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs @@ -17,6 +17,21 @@ enum ClauseFlavor { Const, } +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +enum ParamTerm { + Ty(ty::ParamTy), + Const(ty::ParamConst), +} + +impl ParamTerm { + fn index(self) -> usize { + match self { + ParamTerm::Ty(ty) => ty.index as usize, + ParamTerm::Const(ct) => ct.index as usize, + } + } +} + impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn adjust_fulfillment_error_for_expr_obligation( &self, @@ -77,17 +92,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => return false, }; - let find_param_matching = |matches: &dyn Fn(ty::ParamTerm) -> bool| { + let find_param_matching = |matches: &dyn Fn(ParamTerm) -> bool| { predicate_args.iter().find_map(|arg| { arg.walk().find_map(|arg| { if let ty::GenericArgKind::Type(ty) = arg.kind() && let ty::Param(param_ty) = *ty.kind() - && matches(ty::ParamTerm::Ty(param_ty)) + && matches(ParamTerm::Ty(param_ty)) { Some(arg) } else if let ty::GenericArgKind::Const(ct) = arg.kind() && let ty::ConstKind::Param(param_ct) = ct.kind() - && matches(ty::ParamTerm::Const(param_ct)) + && matches(ParamTerm::Const(param_ct)) { Some(arg) } else { @@ -106,14 +121,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // from a trait or impl, for example. let mut fallback_param_to_point_at = find_param_matching(&|param_term| { self.tcx.parent(generics.param_at(param_term.index(), self.tcx).def_id) != def_id - && !matches!(param_term, ty::ParamTerm::Ty(ty) if ty.name == kw::SelfUpper) + && !matches!(param_term, ParamTerm::Ty(ty) if ty.name == kw::SelfUpper) }); // Finally, the `Self` parameter is possibly the reason that the predicate // is unsatisfied. This is less likely to be true for methods, because // method probe means that we already kinda check that the predicates due // to the `Self` type are true. let mut self_param_to_point_at = find_param_matching( - &|param_term| matches!(param_term, ty::ParamTerm::Ty(ty) if ty.name == kw::SelfUpper), + &|param_term| matches!(param_term, ParamTerm::Ty(ty) if ty.name == kw::SelfUpper), ); // Finally, for ambiguity-related errors, we actually want to look diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 719989d5793..36abd7c8555 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1658,8 +1658,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ), ast::LitKind::Byte(_) => tcx.types.u8, ast::LitKind::Char(_) => tcx.types.char, - ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => Ty::new_int(tcx, ty::int_ty(t)), - ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => Ty::new_uint(tcx, ty::uint_ty(t)), + ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => Ty::new_int(tcx, t), + ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => Ty::new_uint(tcx, t), ast::LitKind::Int(i, ast::LitIntType::Unsuffixed) => { let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() { ty::Int(_) | ty::Uint(_) => Some(ty), @@ -1686,9 +1686,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); opt_ty.unwrap_or_else(|| self.next_int_var()) } - ast::LitKind::Float(_, ast::LitFloatType::Suffixed(t)) => { - Ty::new_float(tcx, ty::float_ty(t)) - } + ast::LitKind::Float(_, ast::LitFloatType::Suffixed(t)) => Ty::new_float(tcx, t), ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) => { let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() { ty::Float(_) => Some(ty), diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 33ae4f6c45c..2345cdab208 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1302,7 +1302,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None => ".clone()".to_string(), }; - let span = expr.span.find_oldest_ancestor_in_same_ctxt().shrink_to_hi(); + let span = expr.span.find_ancestor_not_from_macro().unwrap_or(expr.span).shrink_to_hi(); diag.span_suggestion_verbose( span, @@ -1395,7 +1395,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .macro_backtrace() .any(|x| matches!(x.kind, ExpnKind::Macro(MacroKind::Attr | MacroKind::Derive, ..))) { - let span = expr.span.find_oldest_ancestor_in_same_ctxt(); + let span = expr + .span + .find_ancestor_not_from_extern_macro(&self.tcx.sess.source_map()) + .unwrap_or(expr.span); let mut sugg = if self.precedence(expr) >= ExprPrecedence::Unambiguous { vec![(span.shrink_to_hi(), ".into()".to_owned())] @@ -2062,7 +2065,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None => sugg.to_string(), }; - let span = expr.span.find_oldest_ancestor_in_same_ctxt(); + let span = expr + .span + .find_ancestor_not_from_extern_macro(&self.tcx.sess.source_map()) + .unwrap_or(expr.span); err.span_suggestion_verbose(span.shrink_to_hi(), msg, sugg, Applicability::HasPlaceholders); true } diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 9e324286fa1..aae870f7ee3 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -42,18 +42,18 @@ mod writeback; pub use coercion::can_coerce; use fn_ctxt::FnCtxt; -use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::unord::UnordSet; use rustc_errors::codes::*; use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err}; use rustc_hir as hir; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{HirId, HirIdMap, Node}; +use rustc_hir::{HirId, HirIdMap, Node, find_attr}; use rustc_hir_analysis::check::{check_abi, check_custom_abi}; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; use rustc_infer::traits::{ObligationCauseCode, ObligationInspector, WellFormedLoc}; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::{bug, span_bug}; use rustc_session::config; use rustc_span::Span; @@ -259,6 +259,21 @@ fn typeck_with_inspect<'tcx>( let typeck_results = fcx.resolve_type_vars_in_body(body); + // Handle potentially region dependent goals, see `InferCtxt::in_hir_typeck`. + if let None = fcx.infcx.tainted_by_errors() { + for obligation in fcx.take_hir_typeck_potentially_region_dependent_goals() { + let obligation = fcx.resolve_vars_if_possible(obligation); + if obligation.has_non_region_infer() { + bug!("unexpected inference variable after writeback: {obligation:?}"); + } + fcx.register_predicate(obligation); + } + fcx.select_obligations_where_possible(|_| {}); + if let None = fcx.infcx.tainted_by_errors() { + fcx.report_ambiguity_errors(); + } + } + fcx.detect_opaque_types_added_during_writeback(); // Consistency check our TypeckResults instance can hold all ItemLocalIds diff --git a/compiler/rustc_hir_typeck/src/loops.rs b/compiler/rustc_hir_typeck/src/loops.rs index 80eab578f13..acfa5c473aa 100644 --- a/compiler/rustc_hir_typeck/src/loops.rs +++ b/compiler/rustc_hir_typeck/src/loops.rs @@ -2,13 +2,12 @@ use std::collections::BTreeMap; use std::fmt; use Context::*; -use rustc_ast::Label; -use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_hir as hir; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{Destination, Node}; +use rustc_hir::{Destination, Node, find_attr}; use rustc_middle::hir::nested_filter; use rustc_middle::span_bug; use rustc_middle::ty::TyCtxt; @@ -42,8 +41,8 @@ enum Context { ConstBlock, /// E.g. `#[loop_match] loop { state = 'label: { /* ... */ } }`. LoopMatch { - /// The label of the labeled block (not of the loop itself). - labeled_block: Label, + /// The destination pointing to the labeled block (not to the loop itself). + labeled_block: Destination, }, } @@ -186,18 +185,18 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> { { self.with_context(UnlabeledBlock(b.span.shrink_to_lo()), |v| v.visit_block(b)); } - hir::ExprKind::Break(break_label, ref opt_expr) => { + hir::ExprKind::Break(break_destination, ref opt_expr) => { if let Some(e) = opt_expr { self.visit_expr(e); } - if self.require_label_in_labeled_block(e.span, &break_label, "break") { + if self.require_label_in_labeled_block(e.span, &break_destination, "break") { // If we emitted an error about an unlabeled break in a labeled // block, we don't need any further checking for this break any more return; } - let loop_id = match break_label.target_id { + let loop_id = match break_destination.target_id { Ok(loop_id) => Some(loop_id), Err(hir::LoopIdError::OutsideLoopScope) => None, Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => { @@ -212,18 +211,25 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> { // A `#[const_continue]` must break to a block in a `#[loop_match]`. if find_attr!(self.tcx.hir_attrs(e.hir_id), AttributeKind::ConstContinue(_)) { - if let Some(break_label) = break_label.label { - let is_target_label = |cx: &Context| match cx { - Context::LoopMatch { labeled_block } => { - break_label.ident.name == labeled_block.ident.name - } - _ => false, - }; + let Some(label) = break_destination.label else { + let span = e.span; + self.tcx.dcx().emit_fatal(ConstContinueBadLabel { span }); + }; - if !self.cx_stack.iter().rev().any(is_target_label) { - let span = break_label.ident.span; - self.tcx.dcx().emit_fatal(ConstContinueBadLabel { span }); + let is_target_label = |cx: &Context| match cx { + Context::LoopMatch { labeled_block } => { + // NOTE: with macro expansion, the label's span might be different here + // even though it does still refer to the same HIR node. A block + // can't have two labels, so the hir_id is a unique identifier. + assert!(labeled_block.target_id.is_ok()); // see `is_loop_match`. + break_destination.target_id == labeled_block.target_id } + _ => false, + }; + + if !self.cx_stack.iter().rev().any(is_target_label) { + let span = label.ident.span; + self.tcx.dcx().emit_fatal(ConstContinueBadLabel { span }); } } @@ -249,7 +255,7 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> { Some(kind) => { let suggestion = format!( "break{}", - break_label + break_destination .label .map_or_else(String::new, |l| format!(" {}", l.ident)) ); @@ -259,7 +265,7 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> { kind: kind.name(), suggestion, loop_label, - break_label: break_label.label, + break_label: break_destination.label, break_expr_kind: &break_expr.kind, break_expr_span: break_expr.span, }); @@ -268,7 +274,7 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> { } let sp_lo = e.span.with_lo(e.span.lo() + BytePos("break".len() as u32)); - let label_sp = match break_label.label { + let label_sp = match break_destination.label { Some(label) => sp_lo.with_hi(label.ident.span.hi()), None => sp_lo.shrink_to_lo(), }; @@ -416,7 +422,7 @@ impl<'hir> CheckLoopVisitor<'hir> { &self, e: &'hir hir::Expr<'hir>, body: &'hir hir::Block<'hir>, - ) -> Option<Label> { + ) -> Option<Destination> { if !find_attr!(self.tcx.hir_attrs(e.hir_id), AttributeKind::LoopMatch(_)) { return None; } @@ -438,8 +444,8 @@ impl<'hir> CheckLoopVisitor<'hir> { let hir::ExprKind::Assign(_, rhs_expr, _) = loop_body_expr.kind else { return None }; - let hir::ExprKind::Block(_, label) = rhs_expr.kind else { return None }; + let hir::ExprKind::Block(block, label) = rhs_expr.kind else { return None }; - label + Some(Destination { label, target_id: Ok(block.hir_id) }) } } diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 8d9f7eaf177..a23910a2006 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -116,7 +116,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // If there is a `Self: Sized` bound and `Self` is a trait object, it is possible that // something which derefs to `Self` actually implements the trait and the caller // wanted to make a static dispatch on it but forgot to import the trait. - // See test `tests/ui/issue-35976.rs`. + // See test `tests/ui/issues/issue-35976.rs`. // // In that case, we'll error anyway, but we'll also re-run the search with all traits // in scope, and if we find another method which can be used, we'll output an @@ -142,7 +142,6 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { let (method_sig, method_predicates) = self.normalize(self.span, (method_sig, method_predicates)); - let method_sig = ty::Binder::dummy(method_sig); // Make sure nobody calls `drop()` explicitly. self.check_for_illegal_method_calls(pick); @@ -154,20 +153,11 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // We won't add these if we encountered an illegal sized bound, so that we can use // a custom error in that case. if illegal_sized_bound.is_none() { - self.add_obligations( - Ty::new_fn_ptr(self.tcx, method_sig), - all_args, - method_predicates, - pick.item.def_id, - ); + self.add_obligations(method_sig, all_args, method_predicates, pick.item.def_id); } // Create the final `MethodCallee`. - let callee = MethodCallee { - def_id: pick.item.def_id, - args: all_args, - sig: method_sig.skip_binder(), - }; + let callee = MethodCallee { def_id: pick.item.def_id, args: all_args, sig: method_sig }; ConfirmResult { callee, illegal_sized_bound } } @@ -601,14 +591,14 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { fn add_obligations( &mut self, - fty: Ty<'tcx>, + sig: ty::FnSig<'tcx>, all_args: GenericArgsRef<'tcx>, method_predicates: ty::InstantiatedPredicates<'tcx>, def_id: DefId, ) { debug!( - "add_obligations: fty={:?} all_args={:?} method_predicates={:?} def_id={:?}", - fty, all_args, method_predicates, def_id + "add_obligations: sig={:?} all_args={:?} method_predicates={:?} def_id={:?}", + sig, all_args, method_predicates, def_id ); // FIXME: could replace with the following, but we already calculated `method_predicates`, @@ -637,7 +627,13 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // the function type must also be well-formed (this is not // implied by the args being well-formed because of inherent // impls and late-bound regions - see issue #28609). - self.register_wf_obligation(fty.into(), self.span, ObligationCauseCode::WellFormed(None)); + for ty in sig.inputs_and_output { + self.register_wf_obligation( + ty.into(), + self.span, + ObligationCauseCode::WellFormed(None), + ); + } } /////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 316468b0a5d..e37ea031672 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -428,19 +428,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )); // Also add an obligation for the method type being well-formed. - let method_ty = Ty::new_fn_ptr(tcx, ty::Binder::dummy(fn_sig)); debug!( - "lookup_method_in_trait: matched method method_ty={:?} obligation={:?}", - method_ty, obligation + "lookup_method_in_trait: matched method fn_sig={:?} obligation={:?}", + fn_sig, obligation ); - obligations.push(traits::Obligation::new( - tcx, - obligation.cause, - self.param_env, - ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed( - method_ty.into(), - ))), - )); + for ty in fn_sig.inputs_and_output { + obligations.push(traits::Obligation::new( + tcx, + obligation.cause.clone(), + self.param_env, + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty.into()))), + )); + } let callee = MethodCallee { def_id, args, sig: fn_sig }; debug!("callee = {:?}", callee); diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 1f3969bd93c..3ca3b56b87e 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -2051,7 +2051,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { /// probe. This will result in a pending obligation so when more type-info is available we can /// make the final decision. /// - /// Example (`tests/ui/method-two-trait-defer-resolution-1.rs`): + /// Example (`tests/ui/methods/method-two-trait-defer-resolution-1.rs`): /// /// ```ignore (illustrative) /// trait Foo { ... } diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index e64af8fb7b3..f7430f7af4e 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -9,7 +9,6 @@ use std::path::PathBuf; use hir::Expr; use rustc_ast::ast::Mutability; -use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::unord::UnordSet; @@ -17,11 +16,12 @@ use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagStyledString, MultiSpan, StashKey, pluralize, struct_span_code_err, }; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::lang_items::LangItem; -use rustc_hir::{self as hir, ExprKind, HirId, Node, PathSegment, QPath}; +use rustc_hir::{self as hir, ExprKind, HirId, Node, PathSegment, QPath, find_attr}; use rustc_infer::infer::{BoundRegionConversionTime, RegionVariableOrigin}; use rustc_middle::bug; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, simplify_type}; @@ -376,16 +376,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn suggest_missing_writer(&self, rcvr_ty: Ty<'tcx>, rcvr_expr: &hir::Expr<'tcx>) -> Diag<'_> { - let mut file = None; + fn suggest_missing_writer( + &self, + rcvr_ty: Ty<'tcx>, + rcvr_expr: &hir::Expr<'tcx>, + mut long_ty_path: Option<PathBuf>, + ) -> Diag<'_> { let mut err = struct_span_code_err!( self.dcx(), rcvr_expr.span, E0599, "cannot write into `{}`", - self.tcx.short_string(rcvr_ty, &mut file), + self.tcx.short_string(rcvr_ty, &mut long_ty_path), ); - *err.long_ty_path() = file; + *err.long_ty_path() = long_ty_path; err.span_note( rcvr_expr.span, "must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method", @@ -403,7 +407,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, self_source: SelfSource<'tcx>, method_name: Ident, - ty_str_reported: &str, + ty: Ty<'tcx>, err: &mut Diag<'_>, ) { #[derive(Debug)] @@ -478,7 +482,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // If the shadowed binding has an itializer expression, - // use the initializer expression'ty to try to find the method again. + // use the initializer expression's ty to try to find the method again. // For example like: `let mut x = Vec::new();`, // `Vec::new()` is the itializer expression. if let Some(self_ty) = self.fcx.node_ty_opt(binding.init_hir_id) @@ -566,17 +570,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut span = MultiSpan::from_span(sugg_let.span); span.push_span_label(sugg_let.span, format!("`{rcvr_name}` of type `{self_ty}` that has method `{method_name}` defined earlier here")); + + let ty = self.tcx.short_string(ty, err.long_ty_path()); span.push_span_label( self.tcx.hir_span(recv_id), - format!( - "earlier `{rcvr_name}` shadowed here with type `{ty_str_reported}`" - ), + format!("earlier `{rcvr_name}` shadowed here with type `{ty}`"), ); err.span_note( span, format!( "there's an earlier shadowed binding `{rcvr_name}` of type `{self_ty}` \ - that has method `{method_name}` available" + that has method `{method_name}` available" ), ); } @@ -602,15 +606,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let tcx = self.tcx; let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty); let mut ty_file = None; - let (ty_str, short_ty_str) = - if trait_missing_method && let ty::Dynamic(predicates, _, _) = rcvr_ty.kind() { - (predicates.to_string(), with_forced_trimmed_paths!(predicates.to_string())) - } else { - ( - tcx.short_string(rcvr_ty, &mut ty_file), - with_forced_trimmed_paths!(rcvr_ty.to_string()), - ) - }; let is_method = mode == Mode::MethodCall; let unsatisfied_predicates = &no_match_data.unsatisfied_predicates; let similar_candidate = no_match_data.similar_candidate; @@ -629,15 +624,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We could pass the file for long types into these two, but it isn't strictly necessary // given how targeted they are. - if let Err(guar) = self.report_failed_method_call_on_range_end( - tcx, - rcvr_ty, - source, - span, - item_ident, - &short_ty_str, - &mut ty_file, - ) { + if let Err(guar) = + self.report_failed_method_call_on_range_end(tcx, rcvr_ty, source, span, item_ident) + { return guar; } if let Err(guar) = self.report_failed_method_call_on_numerical_infer_var( @@ -647,44 +636,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span, item_kind, item_ident, - &short_ty_str, &mut ty_file, ) { return guar; } span = item_ident.span; - // Don't show generic arguments when the method can't be found in any implementation (#81576). - let mut ty_str_reported = ty_str.clone(); - if let ty::Adt(_, generics) = rcvr_ty.kind() { - if generics.len() > 0 { - let mut autoderef = self.autoderef(span, rcvr_ty).silence_errors(); - let candidate_found = autoderef.any(|(ty, _)| { - if let ty::Adt(adt_def, _) = ty.kind() { - self.tcx - .inherent_impls(adt_def.did()) - .into_iter() - .any(|def_id| self.associated_value(*def_id, item_ident).is_some()) - } else { - false - } - }); - let has_deref = autoderef.step_count() > 0; - if !candidate_found && !has_deref && unsatisfied_predicates.is_empty() { - if let Some((path_string, _)) = ty_str.split_once('<') { - ty_str_reported = path_string.to_string(); - } - } - } - } - let is_write = sugg_span.ctxt().outer_expn_data().macro_def_id.is_some_and(|def_id| { tcx.is_diagnostic_item(sym::write_macro, def_id) || tcx.is_diagnostic_item(sym::writeln_macro, def_id) }) && item_ident.name == sym::write_fmt; let mut err = if is_write && let SelfSource::MethodCall(rcvr_expr) = source { - self.suggest_missing_writer(rcvr_ty, rcvr_expr) + self.suggest_missing_writer(rcvr_ty, rcvr_expr, ty_file) } else { + // Don't show expanded generic arguments when the method can't be found in any + // implementation (#81576). + let mut ty = rcvr_ty; + if let ty::Adt(def, generics) = rcvr_ty.kind() { + if generics.len() > 0 { + let mut autoderef = self.autoderef(span, rcvr_ty).silence_errors(); + let candidate_found = autoderef.any(|(ty, _)| { + if let ty::Adt(adt_def, _) = ty.kind() { + self.tcx + .inherent_impls(adt_def.did()) + .into_iter() + .any(|def_id| self.associated_value(*def_id, item_ident).is_some()) + } else { + false + } + }); + let has_deref = autoderef.step_count() > 0; + if !candidate_found && !has_deref && unsatisfied_predicates.is_empty() { + ty = self.tcx.at(span).type_of(def.did()).instantiate_identity(); + } + } + } + let mut err = self.dcx().create_err(NoAssociatedItem { span, item_kind, @@ -695,16 +682,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { rcvr_ty.prefix_string(self.tcx) }, - ty_str: ty_str_reported.clone(), + ty, trait_missing_method, }); if is_method { self.suggest_use_shadowed_binding_with_method( - source, - item_ident, - &ty_str_reported, - &mut err, + source, item_ident, rcvr_ty, &mut err, ); } @@ -734,6 +718,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err }; + if tcx.sess.source_map().is_multiline(sugg_span) { err.span_label(sugg_span.with_hi(span.lo()), ""); } @@ -750,6 +735,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if tcx.ty_is_opaque_future(rcvr_ty) && item_ident.name == sym::poll { + let ty_str = self.tcx.short_string(rcvr_ty, err.long_ty_path()); err.help(format!( "method `poll` found on `Pin<&mut {ty_str}>`, \ see documentation for `std::pin::Pin`" @@ -1053,8 +1039,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let pred = bound_predicate.rebind(pred); // `<Foo as Iterator>::Item = String`. let projection_term = pred.skip_binder().projection_term; - let quiet_projection_term = - projection_term.with_self_ty(tcx, Ty::new_var(tcx, ty::TyVid::ZERO)); + let quiet_projection_term = projection_term + .with_replaced_self_ty(tcx, Ty::new_var(tcx, ty::TyVid::ZERO)); let term = pred.skip_binder().term; @@ -1339,7 +1325,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let OnUnimplementedNote { message, label, notes, .. } = self .err_ctxt() - .on_unimplemented_note(trait_ref, &obligation, &mut ty_file); + .on_unimplemented_note(trait_ref, &obligation, err.long_ty_path()); (message, label, notes) }) .unwrap() @@ -1347,6 +1333,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (None, None, Vec::new()) }; let primary_message = primary_message.unwrap_or_else(|| { + let ty_str = self.tcx.short_string(rcvr_ty, err.long_ty_path()); format!( "the {item_kind} `{item_ident}` exists for {actual_prefix} `{ty_str}`, \ but its trait bounds were not satisfied" @@ -1409,6 +1396,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut find_candidate_for_method = false; let mut label_span_not_found = |err: &mut Diag<'_>| { + let ty_str = self.tcx.short_string(rcvr_ty, err.long_ty_path()); if unsatisfied_predicates.is_empty() { err.span_label(span, format!("{item_kind} not found in `{ty_str}`")); let is_string_or_ref_str = match rcvr_ty.kind() { @@ -2157,7 +2145,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx, self.fresh_args_for_item(sugg_span, impl_did), ) - .with_self_ty(self.tcx, rcvr_ty), + .with_replaced_self_ty(self.tcx, rcvr_ty), idx, sugg_span, item, @@ -2196,7 +2184,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { trait_did, self.fresh_args_for_item(sugg_span, trait_did), ) - .with_self_ty(self.tcx, rcvr_ty), + .with_replaced_self_ty(self.tcx, rcvr_ty), idx, sugg_span, item, @@ -2520,8 +2508,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { source: SelfSource<'tcx>, span: Span, item_name: Ident, - ty_str: &str, - long_ty_path: &mut Option<PathBuf>, ) -> Result<(), ErrorGuaranteed> { if let SelfSource::MethodCall(expr) = source { for (_, parent) in tcx.hir_parent_iter(expr.hir_id).take(5) { @@ -2583,18 +2569,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); if pick.is_ok() { let range_span = parent_expr.span.with_hi(expr.span.hi()); - let mut err = self.dcx().create_err(errors::MissingParenthesesInRange { + return Err(self.dcx().emit_err(errors::MissingParenthesesInRange { span, - ty_str: ty_str.to_string(), + ty: actual, method_name: item_name.as_str().to_string(), add_missing_parentheses: Some(errors::AddMissingParenthesesInRange { func_name: item_name.name.as_str().to_string(), left: range_span.shrink_to_lo(), right: range_span.shrink_to_hi(), }), - }); - *err.long_ty_path() = long_ty_path.take(); - return Err(err.emit()); + })); } } } @@ -2610,7 +2594,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, item_kind: &str, item_name: Ident, - ty_str: &str, long_ty_path: &mut Option<PathBuf>, ) -> Result<(), ErrorGuaranteed> { let found_candidate = all_traits(self.tcx) @@ -2643,14 +2626,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && !actual.has_concrete_skeleton() && let SelfSource::MethodCall(expr) = source { + let ty_str = self.tcx.short_string(actual, long_ty_path); let mut err = struct_span_code_err!( self.dcx(), span, E0689, - "can't call {} `{}` on ambiguous numeric type `{}`", - item_kind, - item_name, - ty_str + "can't call {item_kind} `{item_name}` on ambiguous numeric type `{ty_str}`" ); *err.long_ty_path() = long_ty_path.take(); let concrete_type = if actual.is_integral() { "i32" } else { "f32" }; @@ -2792,7 +2773,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { if let SelfSource::MethodCall(expr) = source { let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id(); - for (fields, args) in self.get_field_candidates_considering_privacy_for_diag( + for fields in self.get_field_candidates_considering_privacy_for_diag( span, actual, mod_id, @@ -2831,7 +2812,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) }, candidate_field, - args, vec![], mod_id, expr.hir_id, @@ -3671,7 +3651,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { debug!("try_alt_rcvr: pick candidate {:?}", pick); - let did = Some(pick.item.container_id(self.tcx)); + let did = pick.item.trait_container(self.tcx); // We don't want to suggest a container type when the missing // method is `.clone()` or `.deref()` otherwise we'd suggest // `Arc::new(foo).clone()`, which is far from what the user wants. @@ -3720,8 +3700,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && !alt_rcvr_sugg // `T: !Unpin` && !unpin - // The method isn't `as_ref`, as it would provide a wrong suggestion for `Pin`. - && sym::as_ref != item_name.name // Either `Pin::as_ref` or `Pin::as_mut`. && let Some(pin_call) = pin_call // Search for `item_name` as a method accessible on `Pin<T>`. @@ -3735,6 +3713,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We skip some common traits that we don't want to consider because autoderefs // would take care of them. && !skippable.contains(&Some(pick.item.container_id(self.tcx))) + // Do not suggest pinning when the method is directly on `Pin`. + && pick.item.impl_container(self.tcx).map_or(true, |did| { + match self.tcx.type_of(did).skip_binder().kind() { + ty::Adt(def, _) => Some(def.did()) != self.tcx.lang_items().pin_type(), + _ => true, + } + }) // We don't want to go through derefs. && pick.autoderefs == 0 // Check that the method of the same name that was found on the new `Pin<T>` diff --git a/compiler/rustc_hir_typeck/src/naked_functions.rs b/compiler/rustc_hir_typeck/src/naked_functions.rs index d055fa68fc3..d3fd63d871a 100644 --- a/compiler/rustc_hir_typeck/src/naked_functions.rs +++ b/compiler/rustc_hir_typeck/src/naked_functions.rs @@ -1,10 +1,10 @@ //! Checks validity of naked functions. -use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_hir as hir; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::Visitor; -use rustc_hir::{ExprKind, HirIdSet, StmtKind}; +use rustc_hir::{ExprKind, HirIdSet, StmtKind, find_attr}; use rustc_middle::span_bug; use rustc_middle::ty::TyCtxt; use rustc_span::Span; diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index bf4611e1e34..7dc736e5e6b 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -1756,7 +1756,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let missing_parentheses = match (expected.kind(), fields, had_err) { // #67037: only do this if we could successfully type-check the expected type against // the tuple struct pattern. Otherwise the args could get out of range on e.g., - // `let P() = U;` where `P != U` with `struct P<T>(T);`. + // `let P() = U;` where `P != U` with `struct Box<T>(T);`. (ty::Adt(_, args), [field], Ok(())) => { let field_ty = self.field_ty(pat_span, field, args); match field_ty.kind() { diff --git a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs index 6a985fc91e7..d8d217ca800 100644 --- a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs +++ b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs @@ -17,6 +17,19 @@ use tracing::{debug, instrument}; use super::callee::DeferredCallResolution; +#[derive(Debug, Default, Copy, Clone)] +pub(crate) struct InferVarInfo { + /// This is true if we identified that this Ty (`?T`) is found in a `?T: Foo` + /// obligation, where: + /// + /// * `Foo` is not `Sized` + /// * `(): Foo` may be satisfied + pub self_in_trait: bool, + /// This is true if we identified that this Ty (`?T`) is found in a `<_ as + /// _>::AssocType = ?T` + pub output: bool, +} + /// Data shared between a "typeck root" and its nested bodies, /// e.g. closures defined within the function. For example: /// ```ignore (illustrative) @@ -71,7 +84,7 @@ pub(crate) struct TypeckRootCtxt<'tcx> { /// fallback. See the `fallback` module for details. pub(super) diverging_type_vars: RefCell<UnordSet<Ty<'tcx>>>, - pub(super) infer_var_info: RefCell<UnordMap<ty::TyVid, ty::InferVarInfo>>, + pub(super) infer_var_info: RefCell<UnordMap<ty::TyVid, InferVarInfo>>, } impl<'tcx> Deref for TypeckRootCtxt<'tcx> { @@ -85,8 +98,11 @@ impl<'tcx> TypeckRootCtxt<'tcx> { pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self { let hir_owner = tcx.local_def_id_to_hir_id(def_id).owner; - let infcx = - tcx.infer_ctxt().ignoring_regions().build(TypingMode::typeck_for_body(tcx, def_id)); + let infcx = tcx + .infer_ctxt() + .ignoring_regions() + .in_hir_typeck() + .build(TypingMode::typeck_for_body(tcx, def_id)); let typeck_results = RefCell::new(ty::TypeckResults::new(hir_owner)); let fulfillment_cx = RefCell::new(<dyn TraitEngine<'_, _>>::new(&infcx)); @@ -151,7 +167,7 @@ impl<'tcx> TypeckRootCtxt<'tcx> { obligation.predicate.kind().rebind( // (*) binder moved here ty::PredicateKind::Clause(ty::ClauseKind::Trait( - tpred.with_self_ty(self.tcx, new_self_ty), + tpred.with_replaced_self_ty(self.tcx, new_self_ty), )), ), ); diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index df38c3a1214..50fa3f2cc9d 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -2391,13 +2391,11 @@ fn migration_suggestion_for_2229( /// let mut p = Point { x: 10, y: 10 }; /// /// let c = || { -/// p.x += 10; -/// // ^ E1 ^ +/// p.x += 10; // E1 /// // ... /// // More code /// // ... /// p.x += 10; // E2 -/// // ^ E2 ^ /// }; /// ``` /// `CaptureKind` associated with both `E1` and `E2` will be ByRef(MutBorrow), diff --git a/compiler/rustc_index/Cargo.toml b/compiler/rustc_index/Cargo.toml index 3d83a3c98da..e46a1a7f760 100644 --- a/compiler/rustc_index/Cargo.toml +++ b/compiler/rustc_index/Cargo.toml @@ -15,8 +15,8 @@ smallvec = "1.8.1" # tidy-alphabetical-start default = ["nightly"] nightly = [ - "dep:rustc_serialize", "dep:rustc_macros", + "dep:rustc_serialize", "rustc_index_macros/nightly", ] rustc_randomized_layouts = [] diff --git a/compiler/rustc_index_macros/Cargo.toml b/compiler/rustc_index_macros/Cargo.toml index 891e7ded619..34f3109a526 100644 --- a/compiler/rustc_index_macros/Cargo.toml +++ b/compiler/rustc_index_macros/Cargo.toml @@ -7,9 +7,14 @@ edition = "2024" proc-macro = true [dependencies] -syn = { version = "2.0.9", features = ["full", "extra-traits"] } +# tidy-alphabetical-start proc-macro2 = "1" quote = "1" +syn = { version = "2.0.9", features = ["full", "extra-traits"] } +# tidy-alphabetical-end [features] +# tidy-alphabetical-start nightly = [] +# tidy-alphabetical-end + diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 5fe795bd23a..ad19cdef4e7 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -71,6 +71,7 @@ impl<'tcx> InferCtxt<'tcx> { tcx: self.tcx, typing_mode: self.typing_mode, considering_regions: self.considering_regions, + in_hir_typeck: self.in_hir_typeck, skip_leak_check: self.skip_leak_check, inner: self.inner.clone(), lexical_region_resolutions: self.lexical_region_resolutions.clone(), @@ -95,6 +96,7 @@ impl<'tcx> InferCtxt<'tcx> { tcx: self.tcx, typing_mode, considering_regions: self.considering_regions, + in_hir_typeck: self.in_hir_typeck, skip_leak_check: self.skip_leak_check, inner: self.inner.clone(), lexical_region_resolutions: self.lexical_region_resolutions.clone(), diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 060447ba720..3ad14dc79d5 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -44,7 +44,7 @@ impl<'tcx> InferCtxt<'tcx> { where V: TypeFoldable<TyCtxt<'tcx>>, { - let (param_env, value) = value.into_parts(); + let ty::ParamEnvAnd { param_env, value } = value; let canonical_param_env = self.tcx.canonical_param_env_cache.get_or_insert( self.tcx, param_env, @@ -752,7 +752,8 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { ) -> Ty<'tcx> { debug_assert!(!self.infcx.is_some_and(|infcx| ty_var != infcx.shallow_resolve(ty_var))); let var = self.canonical_var(var_kind, ty_var.into()); - Ty::new_bound(self.tcx, self.binder_index, var.into()) + let bt = ty::BoundTy { var, kind: ty::BoundTyKind::Anon }; + Ty::new_bound(self.tcx, self.binder_index, bt) } /// Given a type variable `const_var` of the given kind, first check @@ -768,6 +769,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { !self.infcx.is_some_and(|infcx| ct_var != infcx.shallow_resolve_const(ct_var)) ); let var = self.canonical_var(var_kind, ct_var.into()); - ty::Const::new_bound(self.tcx, self.binder_index, var) + let bc = ty::BoundConst { var }; + ty::Const::new_bound(self.tcx, self.binder_index, bc) } } diff --git a/compiler/rustc_infer/src/infer/canonical/instantiate.rs b/compiler/rustc_infer/src/infer/canonical/instantiate.rs index 2385c68ef6b..cc052fbd85c 100644 --- a/compiler/rustc_infer/src/infer/canonical/instantiate.rs +++ b/compiler/rustc_infer/src/infer/canonical/instantiate.rs @@ -133,7 +133,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for CanonicalInstantiator<'tcx> { fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { match ct.kind() { ty::ConstKind::Bound(debruijn, bound_const) if debruijn == self.current_index => { - self.var_values[bound_const.as_usize()].expect_const() + self.var_values[bound_const.var.as_usize()].expect_const() } _ => ct.super_fold_with(self), } @@ -217,7 +217,7 @@ fn highest_var_in_clauses<'tcx>(c: ty::Clauses<'tcx>) -> usize { if let ty::ConstKind::Bound(debruijn, bound_const) = ct.kind() && debruijn == self.current_index { - self.max_var = self.max_var.max(bound_const.as_usize()); + self.max_var = self.max_var.max(bound_const.var.as_usize()); } else if ct.has_vars_bound_at_or_above(self.current_index) { ct.super_visit_with(self); } diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 6be53c948c8..09578598114 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -21,7 +21,7 @@ use crate::infer::canonical::{ Canonical, CanonicalQueryResponse, CanonicalVarValues, Certainty, OriginalQueryValues, QueryRegionConstraints, QueryResponse, }; -use crate::infer::region_constraints::{Constraint, RegionConstraintData}; +use crate::infer::region_constraints::RegionConstraintData; use crate::infer::{ DefineOpaqueTypes, InferCtxt, InferOk, InferResult, SubregionOrigin, TypeOutlivesConstraint, }; @@ -105,8 +105,6 @@ impl<'tcx> InferCtxt<'tcx> { where T: Debug + TypeFoldable<TyCtxt<'tcx>>, { - let tcx = self.tcx; - // Select everything, returning errors. let errors = fulfill_cx.select_all_or_error(self); @@ -120,7 +118,6 @@ impl<'tcx> InferCtxt<'tcx> { debug!(?region_obligations); let region_constraints = self.with_region_constraints(|region_constraints| { make_query_region_constraints( - tcx, region_obligations, region_constraints, region_assumptions, @@ -433,12 +430,12 @@ impl<'tcx> InferCtxt<'tcx> { } GenericArgKind::Lifetime(result_value) => { // e.g., here `result_value` might be `'?1` in the example above... - if let ty::ReBound(debruijn, br) = result_value.kind() { + if let ty::ReBound(debruijn, b) = result_value.kind() { // ... in which case we would set `canonical_vars[0]` to `Some('static)`. // We only allow a `ty::INNERMOST` index in generic parameters. assert_eq!(debruijn, ty::INNERMOST); - opt_values[br.var] = Some(*original_value); + opt_values[b.var] = Some(*original_value); } } GenericArgKind::Const(result_value) => { @@ -447,7 +444,7 @@ impl<'tcx> InferCtxt<'tcx> { // We only allow a `ty::INNERMOST` index in generic parameters. assert_eq!(debruijn, ty::INNERMOST); - opt_values[b] = Some(*original_value); + opt_values[b.var] = Some(*original_value); } } } @@ -587,7 +584,6 @@ impl<'tcx> InferCtxt<'tcx> { /// Given the region obligations and constraints scraped from the infcx, /// creates query region constraints. pub fn make_query_region_constraints<'tcx>( - tcx: TyCtxt<'tcx>, outlives_obligations: Vec<TypeOutlivesConstraint<'tcx>>, region_constraints: &RegionConstraintData<'tcx>, assumptions: Vec<ty::ArgOutlivesPredicate<'tcx>>, @@ -600,22 +596,9 @@ pub fn make_query_region_constraints<'tcx>( let outlives: Vec<_> = constraints .iter() - .map(|(k, origin)| { - let constraint = match *k { - // Swap regions because we are going from sub (<=) to outlives - // (>=). - Constraint::VarSubVar(v1, v2) => ty::OutlivesPredicate( - ty::Region::new_var(tcx, v2).into(), - ty::Region::new_var(tcx, v1), - ), - Constraint::VarSubReg(v1, r2) => { - ty::OutlivesPredicate(r2.into(), ty::Region::new_var(tcx, v1)) - } - Constraint::RegSubVar(r1, v2) => { - ty::OutlivesPredicate(ty::Region::new_var(tcx, v2).into(), r1) - } - Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r2.into(), r1), - }; + .map(|(c, origin)| { + // Swap regions because we are going from sub (<=) to outlives (>=). + let constraint = ty::OutlivesPredicate(c.sup.into(), c.sub); (constraint, origin.to_constraint_category()) }) .chain(outlives_obligations.into_iter().map(|obl| { diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index bb9c8850093..21e999b080d 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -22,6 +22,10 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { self.next_trait_solver } + fn in_hir_typeck(&self) -> bool { + self.in_hir_typeck + } + fn typing_mode(&self) -> ty::TypingMode<'tcx> { self.typing_mode() } diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index 2185886901e..3adcfb42727 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -19,7 +19,7 @@ use tracing::{debug, instrument}; use super::outlives::test_type_match; use crate::infer::region_constraints::{ - Constraint, GenericKind, RegionConstraintData, VarInfos, VerifyBound, + Constraint, ConstraintKind, GenericKind, RegionConstraintData, VarInfos, VerifyBound, }; use crate::infer::{RegionRelations, RegionVariableOrigin, SubregionOrigin}; @@ -187,91 +187,96 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { let mut constraints = IndexVec::from_elem(Vec::new(), &var_values.values); // Tracks the changed region vids. let mut changes = Vec::new(); - for (constraint, _) in &self.data.constraints { - match *constraint { - Constraint::RegSubVar(a_region, b_vid) => { - let b_data = var_values.value_mut(b_vid); - - if self.expand_node(a_region, b_vid, b_data) { - changes.push(b_vid); + for (c, _) in &self.data.constraints { + match c.kind { + ConstraintKind::RegSubVar => { + let sup_vid = c.sup.as_var(); + let sup_data = var_values.value_mut(sup_vid); + + if self.expand_node(c.sub, sup_vid, sup_data) { + changes.push(sup_vid); } } - Constraint::VarSubVar(a_vid, b_vid) => match *var_values.value(a_vid) { - VarValue::ErrorValue => continue, - VarValue::Empty(a_universe) => { - let b_data = var_values.value_mut(b_vid); - - let changed = match *b_data { - VarValue::Empty(b_universe) => { - // Empty regions are ordered according to the universe - // they are associated with. - let ui = a_universe.min(b_universe); - - debug!( - "Expanding value of {:?} \ + ConstraintKind::VarSubVar => { + let sub_vid = c.sub.as_var(); + let sup_vid = c.sup.as_var(); + match *var_values.value(sub_vid) { + VarValue::ErrorValue => continue, + VarValue::Empty(sub_universe) => { + let sup_data = var_values.value_mut(sup_vid); + + let changed = match *sup_data { + VarValue::Empty(sup_universe) => { + // Empty regions are ordered according to the universe + // they are associated with. + let ui = sub_universe.min(sup_universe); + + debug!( + "Expanding value of {:?} \ from empty lifetime with universe {:?} \ to empty lifetime with universe {:?}", - b_vid, b_universe, ui - ); + sup_vid, sup_universe, ui + ); - *b_data = VarValue::Empty(ui); - true - } - VarValue::Value(cur_region) => { - match cur_region.kind() { - // If this empty region is from a universe that can name the - // placeholder universe, then the LUB is the Placeholder region - // (which is the cur_region). Otherwise, the LUB is the Static - // lifetime. - RePlaceholder(placeholder) - if !a_universe.can_name(placeholder.universe) => - { - let lub = self.tcx().lifetimes.re_static; - debug!( - "Expanding value of {:?} from {:?} to {:?}", - b_vid, cur_region, lub - ); - - *b_data = VarValue::Value(lub); - true + *sup_data = VarValue::Empty(ui); + true + } + VarValue::Value(cur_region) => { + match cur_region.kind() { + // If this empty region is from a universe that can name + // the placeholder universe, then the LUB is the + // Placeholder region (which is the cur_region). Otherwise, + // the LUB is the Static lifetime. + RePlaceholder(placeholder) + if !sub_universe.can_name(placeholder.universe) => + { + let lub = self.tcx().lifetimes.re_static; + debug!( + "Expanding value of {:?} from {:?} to {:?}", + sup_vid, cur_region, lub + ); + + *sup_data = VarValue::Value(lub); + true + } + + _ => false, } - - _ => false, } - } - VarValue::ErrorValue => false, - }; + VarValue::ErrorValue => false, + }; - if changed { - changes.push(b_vid); - } - match b_data { - VarValue::Value(Region(Interned(ReStatic, _))) - | VarValue::ErrorValue => (), - _ => { - constraints[a_vid].push((a_vid, b_vid)); - constraints[b_vid].push((a_vid, b_vid)); + if changed { + changes.push(sup_vid); + } + match sup_data { + VarValue::Value(Region(Interned(ReStatic, _))) + | VarValue::ErrorValue => (), + _ => { + constraints[sub_vid].push((sub_vid, sup_vid)); + constraints[sup_vid].push((sub_vid, sup_vid)); + } } } - } - VarValue::Value(a_region) => { - let b_data = var_values.value_mut(b_vid); + VarValue::Value(sub_region) => { + let sup_data = var_values.value_mut(sup_vid); - if self.expand_node(a_region, b_vid, b_data) { - changes.push(b_vid); - } - match b_data { - VarValue::Value(Region(Interned(ReStatic, _))) - | VarValue::ErrorValue => (), - _ => { - constraints[a_vid].push((a_vid, b_vid)); - constraints[b_vid].push((a_vid, b_vid)); + if self.expand_node(sub_region, sup_vid, sup_data) { + changes.push(sup_vid); + } + match sup_data { + VarValue::Value(Region(Interned(ReStatic, _))) + | VarValue::ErrorValue => (), + _ => { + constraints[sub_vid].push((sub_vid, sup_vid)); + constraints[sup_vid].push((sub_vid, sup_vid)); + } } } } - }, - Constraint::RegSubReg(..) | Constraint::VarSubReg(..) => { + } + ConstraintKind::RegSubReg | ConstraintKind::VarSubReg => { // These constraints are checked after expansion // is done, in `collect_errors`. continue; @@ -528,49 +533,48 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { var_data: &mut LexicalRegionResolutions<'tcx>, errors: &mut Vec<RegionResolutionError<'tcx>>, ) { - for (constraint, origin) in &self.data.constraints { - debug!(?constraint, ?origin); - match *constraint { - Constraint::RegSubVar(..) | Constraint::VarSubVar(..) => { + for (c, origin) in &self.data.constraints { + debug!(?c, ?origin); + match c.kind { + ConstraintKind::RegSubVar | ConstraintKind::VarSubVar => { // Expansion will ensure that these constraints hold. Ignore. } - Constraint::RegSubReg(sub, sup) => { - if self.sub_concrete_regions(sub, sup) { + ConstraintKind::RegSubReg => { + if self.sub_concrete_regions(c.sub, c.sup) { continue; } debug!( - "region error at {:?}: \ - cannot verify that {:?} <= {:?}", - origin, sub, sup + "region error at {:?}: cannot verify that {:?} <= {:?}", + origin, c.sub, c.sup ); errors.push(RegionResolutionError::ConcreteFailure( (*origin).clone(), - sub, - sup, + c.sub, + c.sup, )); } - Constraint::VarSubReg(a_vid, b_region) => { - let a_data = var_data.value_mut(a_vid); - debug!("contraction: {:?} == {:?}, {:?}", a_vid, a_data, b_region); + ConstraintKind::VarSubReg => { + let sub_vid = c.sub.as_var(); + let sub_data = var_data.value_mut(sub_vid); + debug!("contraction: {:?} == {:?}, {:?}", sub_vid, sub_data, c.sup); - let VarValue::Value(a_region) = *a_data else { + let VarValue::Value(sub_region) = *sub_data else { continue; }; // Do not report these errors immediately: // instead, set the variable value to error and // collect them later. - if !self.sub_concrete_regions(a_region, b_region) { + if !self.sub_concrete_regions(sub_region, c.sup) { debug!( - "region error at {:?}: \ - cannot verify that {:?}={:?} <= {:?}", - origin, a_vid, a_region, b_region + "region error at {:?}: cannot verify that {:?}={:?} <= {:?}", + origin, sub_vid, sub_region, c.sup ); - *a_data = VarValue::ErrorValue; + *sub_data = VarValue::ErrorValue; } } } @@ -682,18 +686,20 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { let dummy_source = graph.add_node(()); let dummy_sink = graph.add_node(()); - for (constraint, _) in &self.data.constraints { - match *constraint { - Constraint::VarSubVar(a_id, b_id) => { - graph.add_edge(NodeIndex(a_id.index()), NodeIndex(b_id.index()), *constraint); + for (c, _) in &self.data.constraints { + match c.kind { + ConstraintKind::VarSubVar => { + let sub_vid = c.sub.as_var(); + let sup_vid = c.sup.as_var(); + graph.add_edge(NodeIndex(sub_vid.index()), NodeIndex(sup_vid.index()), *c); } - Constraint::RegSubVar(_, b_id) => { - graph.add_edge(dummy_source, NodeIndex(b_id.index()), *constraint); + ConstraintKind::RegSubVar => { + graph.add_edge(dummy_source, NodeIndex(c.sup.as_var().index()), *c); } - Constraint::VarSubReg(a_id, _) => { - graph.add_edge(NodeIndex(a_id.index()), dummy_sink, *constraint); + ConstraintKind::VarSubReg => { + graph.add_edge(NodeIndex(c.sub.as_var().index()), dummy_sink, *c); } - Constraint::RegSubReg(..) => { + ConstraintKind::RegSubReg => { // this would be an edge from `dummy_source` to // `dummy_sink`; just ignore it. } @@ -878,26 +884,30 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { let source_node_index = NodeIndex(source_vid.index()); for (_, edge) in graph.adjacent_edges(source_node_index, dir) { - match edge.data { - Constraint::VarSubVar(from_vid, to_vid) => { + let get_origin = + || this.constraints.iter().find(|(c, _)| *c == edge.data).unwrap().1.clone(); + + match edge.data.kind { + ConstraintKind::VarSubVar => { + let from_vid = edge.data.sub.as_var(); + let to_vid = edge.data.sup.as_var(); let opp_vid = if from_vid == source_vid { to_vid } else { from_vid }; if state.set.insert(opp_vid) { state.stack.push(opp_vid); } } - Constraint::RegSubVar(region, _) | Constraint::VarSubReg(_, region) => { - let origin = this - .constraints - .iter() - .find(|(c, _)| *c == edge.data) - .unwrap() - .1 - .clone(); - state.result.push(RegionAndOrigin { region, origin }); + ConstraintKind::RegSubVar => { + let origin = get_origin(); + state.result.push(RegionAndOrigin { region: edge.data.sub, origin }); + } + + ConstraintKind::VarSubReg => { + let origin = get_origin(); + state.result.push(RegionAndOrigin { region: edge.data.sup, origin }); } - Constraint::RegSubReg(..) => panic!( + ConstraintKind::RegSubReg => panic!( "cannot reach reg-sub-reg edge in region inference \ post-processing" ), diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 2d269e320b6..a2afdc45fa8 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -37,10 +37,11 @@ use snapshot::undo_log::InferCtxtUndoLogs; use tracing::{debug, instrument}; use type_variable::TypeVariableOrigin; -use crate::infer::region_constraints::UndoLog; +use crate::infer::snapshot::undo_log::UndoLog; use crate::infer::unify_key::{ConstVariableOrigin, ConstVariableValue, ConstVidKey}; use crate::traits::{ - self, ObligationCause, ObligationInspector, PredicateObligations, TraitEngine, + self, ObligationCause, ObligationInspector, PredicateObligation, PredicateObligations, + TraitEngine, }; pub mod at; @@ -156,6 +157,12 @@ pub struct InferCtxtInner<'tcx> { /// which may cause types to no longer be considered well-formed. region_assumptions: Vec<ty::ArgOutlivesPredicate<'tcx>>, + /// `-Znext-solver`: Successfully proven goals during HIR typeck which + /// reference inference variables and get reproven after writeback. + /// + /// See the documentation of `InferCtxt::in_hir_typeck` for more details. + hir_typeck_potentially_region_dependent_goals: Vec<PredicateObligation<'tcx>>, + /// Caches for opaque type inference. opaque_type_storage: OpaqueTypeStorage<'tcx>, } @@ -173,6 +180,7 @@ impl<'tcx> InferCtxtInner<'tcx> { region_constraint_storage: Some(Default::default()), region_obligations: Default::default(), region_assumptions: Default::default(), + hir_typeck_potentially_region_dependent_goals: Default::default(), opaque_type_storage: Default::default(), } } @@ -244,9 +252,29 @@ pub struct InferCtxt<'tcx> { typing_mode: TypingMode<'tcx>, /// Whether this inference context should care about region obligations in - /// the root universe. Most notably, this is used during hir typeck as region + /// the root universe. Most notably, this is used during HIR typeck as region /// solving is left to borrowck instead. pub considering_regions: bool, + /// `-Znext-solver`: Whether this inference context is used by HIR typeck. If so, we + /// need to make sure we don't rely on region identity in the trait solver or when + /// relating types. This is necessary as borrowck starts by replacing each occurrence of a + /// free region with a unique inference variable. If HIR typeck ends up depending on two + /// regions being equal we'd get unexpected mismatches between HIR typeck and MIR typeck, + /// resulting in an ICE. + /// + /// The trait solver sometimes depends on regions being identical. As a concrete example + /// the trait solver ignores other candidates if one candidate exists without any constraints. + /// The goal `&'a u32: Equals<&'a u32>` has no constraints right now. If we replace each + /// occurrence of `'a` with a unique region the goal now equates these regions. See + /// the tests in trait-system-refactor-initiative#27 for concrete examples. + /// + /// We handle this by *uniquifying* region when canonicalizing root goals during HIR typeck. + /// This is still insufficient as inference variables may *hide* region variables, so e.g. + /// `dyn TwoSuper<?x, ?x>: Super<?x>` may hold but MIR typeck could end up having to prove + /// `dyn TwoSuper<&'0 (), &'1 ()>: Super<&'2 ()>` which is now ambiguous. Because of this we + /// stash all successfully proven goals which reference inference variables and then reprove + /// them after writeback. + pub in_hir_typeck: bool, /// If set, this flag causes us to skip the 'leak check' during /// higher-ranked subtyping operations. This flag is a temporary one used @@ -456,6 +484,7 @@ pub enum NllRegionVariableOrigin { Placeholder(ty::PlaceholderRegion), Existential { + name: Option<Symbol>, /// If this is true, then this variable was created to represent a lifetime /// bound in a `for` binder. For example, it might have been created to /// represent the lifetime `'a` in a type like `for<'a> fn(&'a u32)`. @@ -506,6 +535,7 @@ pub struct TypeOutlivesConstraint<'tcx> { pub struct InferCtxtBuilder<'tcx> { tcx: TyCtxt<'tcx>, considering_regions: bool, + in_hir_typeck: bool, skip_leak_check: bool, /// Whether we should use the new trait solver in the local inference context, /// which affects things like which solver is used in `predicate_may_hold`. @@ -518,6 +548,7 @@ impl<'tcx> TyCtxt<'tcx> { InferCtxtBuilder { tcx: self, considering_regions: true, + in_hir_typeck: false, skip_leak_check: false, next_trait_solver: self.next_trait_solver_globally(), } @@ -535,6 +566,11 @@ impl<'tcx> InferCtxtBuilder<'tcx> { self } + pub fn in_hir_typeck(mut self) -> Self { + self.in_hir_typeck = true; + self + } + pub fn skip_leak_check(mut self, skip_leak_check: bool) -> Self { self.skip_leak_check = skip_leak_check; self @@ -568,12 +604,18 @@ impl<'tcx> InferCtxtBuilder<'tcx> { } pub fn build(&mut self, typing_mode: TypingMode<'tcx>) -> InferCtxt<'tcx> { - let InferCtxtBuilder { tcx, considering_regions, skip_leak_check, next_trait_solver } = - *self; + let InferCtxtBuilder { + tcx, + considering_regions, + in_hir_typeck, + skip_leak_check, + next_trait_solver, + } = *self; InferCtxt { tcx, typing_mode, considering_regions, + in_hir_typeck, skip_leak_check, inner: RefCell::new(InferCtxtInner::new()), lexical_region_resolutions: RefCell::new(None), @@ -978,6 +1020,22 @@ impl<'tcx> InferCtxt<'tcx> { } } + pub fn push_hir_typeck_potentially_region_dependent_goal( + &self, + goal: PredicateObligation<'tcx>, + ) { + let mut inner = self.inner.borrow_mut(); + inner.undo_log.push(UndoLog::PushHirTypeckPotentiallyRegionDependentGoal); + inner.hir_typeck_potentially_region_dependent_goals.push(goal); + } + + pub fn take_hir_typeck_potentially_region_dependent_goals( + &self, + ) -> Vec<PredicateObligation<'tcx>> { + assert!(!self.in_snapshot(), "cannot take goals in a snapshot"); + std::mem::take(&mut self.inner.borrow_mut().hir_typeck_potentially_region_dependent_goals) + } + pub fn ty_to_string(&self, t: Ty<'tcx>) -> String { self.resolve_vars_if_possible(t).to_string() } @@ -1208,8 +1266,8 @@ impl<'tcx> InferCtxt<'tcx> { fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx> { self.args[bt.var.index()].expect_ty() } - fn replace_const(&mut self, bv: ty::BoundVar) -> ty::Const<'tcx> { - self.args[bv.index()].expect_const() + fn replace_const(&mut self, bc: ty::BoundConst) -> ty::Const<'tcx> { + self.args[bc.var.index()].expect_const() } } let delegate = ToFreshVars { args }; diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index 19911bfbd48..c992cda8aae 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -10,7 +10,7 @@ use super::region_constraints::{RegionConstraintData, UndoLog}; use super::{InferCtxt, RegionResolutionError, SubregionOrigin}; use crate::infer::free_regions::RegionRelations; use crate::infer::lexical_region_resolve; -use crate::infer::region_constraints::Constraint; +use crate::infer::region_constraints::ConstraintKind; pub mod env; pub mod for_liveness; @@ -70,10 +70,10 @@ impl<'tcx> InferCtxt<'tcx> { // Filter out any region-region outlives assumptions that are implied by // coroutine well-formedness. if self.tcx.sess.opts.unstable_opts.higher_ranked_assumptions { - storage.data.constraints.retain(|(constraint, _)| match *constraint { - Constraint::RegSubReg(r1, r2) => !outlives_env + storage.data.constraints.retain(|(c, _)| match c.kind { + ConstraintKind::RegSubReg => !outlives_env .higher_ranked_assumptions() - .contains(&ty::OutlivesPredicate(r2.into(), r1)), + .contains(&ty::OutlivesPredicate(c.sup.into(), c.sub)), _ => true, }); } diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index a8520c0e71d..b989d419057 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -36,7 +36,7 @@ //! fn bar<T>(a: T, b: impl for<'a> Fn(&'a T)) {} //! fn foo<T>(x: T) { //! bar(x, |y| { /* ... */}) -//! // ^ closure arg +//! // ^ closure arg //! } //! ``` //! @@ -177,6 +177,7 @@ impl<'tcx> InferCtxt<'tcx> { } pub fn take_registered_region_assumptions(&self) -> Vec<ty::ArgOutlivesPredicate<'tcx>> { + assert!(!self.in_snapshot(), "cannot take registered region assumptions in a snapshot"); std::mem::take(&mut self.inner.borrow_mut().region_assumptions) } diff --git a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs index e332b6d0447..4d76bc2e17a 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs @@ -83,7 +83,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { return Ok(()); } - let mini_graph = MiniGraph::new(tcx, &self, only_consider_snapshot); + let mini_graph = MiniGraph::new(&self, only_consider_snapshot); let mut leak_check = LeakCheck::new(tcx, outer_universe, max_universe, mini_graph, self); leak_check.assign_placeholder_values()?; @@ -359,7 +359,6 @@ struct MiniGraph<'tcx> { impl<'tcx> MiniGraph<'tcx> { fn new( - tcx: TyCtxt<'tcx>, region_constraints: &RegionConstraintCollector<'_, 'tcx>, only_consider_snapshot: Option<&CombinedSnapshot<'tcx>>, ) -> Self { @@ -368,7 +367,6 @@ impl<'tcx> MiniGraph<'tcx> { // Note that if `R2: R1`, we get a callback `r1, r2`, so `target` is first parameter. Self::iterate_region_constraints( - tcx, region_constraints, only_consider_snapshot, |target, source| { @@ -384,33 +382,18 @@ impl<'tcx> MiniGraph<'tcx> { /// Invokes `each_edge(R1, R2)` for each edge where `R2: R1` fn iterate_region_constraints( - tcx: TyCtxt<'tcx>, region_constraints: &RegionConstraintCollector<'_, 'tcx>, only_consider_snapshot: Option<&CombinedSnapshot<'tcx>>, mut each_edge: impl FnMut(ty::Region<'tcx>, ty::Region<'tcx>), ) { - let mut each_constraint = |constraint| match constraint { - &Constraint::VarSubVar(a, b) => { - each_edge(ty::Region::new_var(tcx, a), ty::Region::new_var(tcx, b)); - } - &Constraint::RegSubVar(a, b) => { - each_edge(a, ty::Region::new_var(tcx, b)); - } - &Constraint::VarSubReg(a, b) => { - each_edge(ty::Region::new_var(tcx, a), b); - } - &Constraint::RegSubReg(a, b) => { - each_edge(a, b); - } - }; - if let Some(snapshot) = only_consider_snapshot { for undo_entry in region_constraints.undo_log.region_constraints_in_snapshot(&snapshot.undo_snapshot) { match undo_entry { &AddConstraint(i) => { - each_constraint(®ion_constraints.data().constraints[i].0); + let c = region_constraints.data().constraints[i].0; + each_edge(c.sub, c.sup); } &AddVerify(i) => span_bug!( region_constraints.data().verifys[i].origin.span(), @@ -420,11 +403,7 @@ impl<'tcx> MiniGraph<'tcx> { } } } else { - region_constraints - .data() - .constraints - .iter() - .for_each(|(constraint, _)| each_constraint(constraint)); + region_constraints.data().constraints.iter().for_each(|(c, _)| each_edge(c.sub, c.sup)) } } diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index a1744b4df80..85f5e55a8e1 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -80,31 +80,37 @@ pub struct RegionConstraintData<'tcx> { /// Represents a constraint that influences the inference process. #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] -pub enum Constraint<'tcx> { +pub enum ConstraintKind { /// A region variable is a subregion of another. - VarSubVar(RegionVid, RegionVid), + VarSubVar, /// A concrete region is a subregion of region variable. - RegSubVar(Region<'tcx>, RegionVid), + RegSubVar, /// A region variable is a subregion of a concrete region. This does not /// directly affect inference, but instead is checked after /// inference is complete. - VarSubReg(RegionVid, Region<'tcx>), + VarSubReg, /// A constraint where neither side is a variable. This does not /// directly affect inference, but instead is checked after /// inference is complete. - RegSubReg(Region<'tcx>, Region<'tcx>), + RegSubReg, +} + +/// Represents a constraint that influences the inference process. +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] +pub struct Constraint<'tcx> { + pub kind: ConstraintKind, + // If `kind` is `VarSubVar` or `VarSubReg`, this must be a `ReVar`. + pub sub: Region<'tcx>, + // If `kind` is `VarSubVar` or `RegSubVar`, this must be a `ReVar`. + pub sup: Region<'tcx>, } impl Constraint<'_> { pub fn involves_placeholders(&self) -> bool { - match self { - Constraint::VarSubVar(_, _) => false, - Constraint::VarSubReg(_, r) | Constraint::RegSubVar(r, _) => r.is_placeholder(), - Constraint::RegSubReg(r, s) => r.is_placeholder() || s.is_placeholder(), - } + self.sub.is_placeholder() || self.sup.is_placeholder() } } @@ -471,16 +477,24 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { // all regions are subregions of static, so we can ignore this } (ReVar(sub_id), ReVar(sup_id)) => { - self.add_constraint(Constraint::VarSubVar(sub_id, sup_id), origin); - } - (_, ReVar(sup_id)) => { - self.add_constraint(Constraint::RegSubVar(sub, sup_id), origin); - } - (ReVar(sub_id), _) => { - self.add_constraint(Constraint::VarSubReg(sub_id, sup), origin); + if sub_id != sup_id { + self.add_constraint( + Constraint { kind: ConstraintKind::VarSubVar, sub, sup }, + origin, + ); + } } + (_, ReVar(_)) => self + .add_constraint(Constraint { kind: ConstraintKind::RegSubVar, sub, sup }, origin), + (ReVar(_), _) => self + .add_constraint(Constraint { kind: ConstraintKind::VarSubReg, sub, sup }, origin), _ => { - self.add_constraint(Constraint::RegSubReg(sub, sup), origin); + if sub != sup { + self.add_constraint( + Constraint { kind: ConstraintKind::RegSubReg, sub, sup }, + origin, + ) + } } } } diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 9e451f16a9d..a000bb1123c 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -19,6 +19,24 @@ use crate::infer::type_variable::TypeVariableValue; use crate::infer::unify_key::ConstVariableValue; use crate::infer::{InferCtxt, RegionVariableOrigin, relate}; +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +enum TermVid { + Ty(ty::TyVid), + Const(ty::ConstVid), +} + +impl From<ty::TyVid> for TermVid { + fn from(value: ty::TyVid) -> Self { + TermVid::Ty(value) + } +} + +impl From<ty::ConstVid> for TermVid { + fn from(value: ty::ConstVid) -> Self { + TermVid::Const(value) + } +} + impl<'tcx> InferCtxt<'tcx> { /// The idea is that we should ensure that the type variable `target_vid` /// is equal to, a subtype of, or a supertype of `source_ty`. @@ -238,20 +256,18 @@ impl<'tcx> InferCtxt<'tcx> { &self, span: Span, structurally_relate_aliases: StructurallyRelateAliases, - target_vid: impl Into<ty::TermVid>, + target_vid: impl Into<TermVid>, ambient_variance: ty::Variance, source_term: T, ) -> RelateResult<'tcx, Generalization<T>> { assert!(!source_term.has_escaping_bound_vars()); let (for_universe, root_vid) = match target_vid.into() { - ty::TermVid::Ty(ty_vid) => { - (self.probe_ty_var(ty_vid).unwrap_err(), ty::TermVid::Ty(self.root_var(ty_vid))) + TermVid::Ty(ty_vid) => { + (self.probe_ty_var(ty_vid).unwrap_err(), TermVid::Ty(self.root_var(ty_vid))) } - ty::TermVid::Const(ct_vid) => ( + TermVid::Const(ct_vid) => ( self.probe_const_var(ct_vid).unwrap_err(), - ty::TermVid::Const( - self.inner.borrow_mut().const_unification_table().find(ct_vid).vid, - ), + TermVid::Const(self.inner.borrow_mut().const_unification_table().find(ct_vid).vid), ), }; @@ -299,7 +315,7 @@ struct Generalizer<'me, 'tcx> { /// The vid of the type variable that is in the process of being /// instantiated. If we find this within the value we are folding, /// that means we would have created a cyclic value. - root_vid: ty::TermVid, + root_vid: TermVid, /// The universe of the type variable that is in the process of being /// instantiated. If we find anything that this universe cannot name, @@ -469,7 +485,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> { ty::Infer(ty::TyVar(vid)) => { let mut inner = self.infcx.inner.borrow_mut(); let vid = inner.type_variables().root_var(vid); - if ty::TermVid::Ty(vid) == self.root_vid { + if TermVid::Ty(vid) == self.root_vid { // If sub-roots are equal, then `root_vid` and // `vid` are related via subtyping. Err(self.cyclic_term_error()) @@ -621,7 +637,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> { // If root const vids are equal, then `root_vid` and // `vid` are related and we'd be inferring an infinitely // deep const. - if ty::TermVid::Const( + if TermVid::Const( self.infcx.inner.borrow_mut().const_unification_table().find(vid).vid, ) == self.root_vid { diff --git a/compiler/rustc_infer/src/infer/relate/higher_ranked.rs b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs index 2143f72a3b0..16fe591b29b 100644 --- a/compiler/rustc_infer/src/infer/relate/higher_ranked.rs +++ b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs @@ -45,10 +45,10 @@ impl<'tcx> InferCtxt<'tcx> { ty::PlaceholderType { universe: next_universe, bound: bound_ty }, ) }, - consts: &mut |bound_var: ty::BoundVar| { + consts: &mut |bound_const: ty::BoundConst| { ty::Const::new_placeholder( self.tcx, - ty::PlaceholderConst { universe: next_universe, bound: bound_var }, + ty::PlaceholderConst { universe: next_universe, bound: bound_const }, ) }, }; diff --git a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs index 40e4c329446..fcc0ab3af41 100644 --- a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs +++ b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs @@ -29,6 +29,7 @@ pub(crate) enum UndoLog<'tcx> { ProjectionCache(traits::UndoLog<'tcx>), PushTypeOutlivesConstraint, PushRegionAssumption, + PushHirTypeckPotentiallyRegionDependentGoal, } macro_rules! impl_from { @@ -79,7 +80,12 @@ impl<'tcx> Rollback<UndoLog<'tcx>> for InferCtxtInner<'tcx> { assert_matches!(popped, Some(_), "pushed region constraint but could not pop it"); } UndoLog::PushRegionAssumption => { - self.region_assumptions.pop(); + let popped = self.region_assumptions.pop(); + assert_matches!(popped, Some(_), "pushed region assumption but could not pop it"); + } + UndoLog::PushHirTypeckPotentiallyRegionDependentGoal => { + let popped = self.hir_typeck_potentially_region_dependent_goals.pop(); + assert_matches!(popped, Some(_), "pushed goal but could not pop it"); } } } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 057fbe2fc4e..3ba224723e3 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -29,7 +29,7 @@ use rustc_parse::{ new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal, validate_attr, }; use rustc_passes::{abi_test, input_stats, layout_test}; -use rustc_resolve::Resolver; +use rustc_resolve::{Resolver, ResolverOutputs}; use rustc_session::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType}; use rustc_session::cstore::Untracked; use rustc_session::output::{collect_crate_types, filename_for_input}; @@ -108,7 +108,7 @@ impl LintStoreExpand for LintStoreExpandImpl<'_> { registered_tools: &RegisteredTools, node_id: ast::NodeId, attrs: &[ast::Attribute], - items: &[rustc_ast::ptr::P<ast::Item>], + items: &[Box<ast::Item>], name: Symbol, ) { pre_expansion_lint(sess, features, self.0, registered_tools, (node_id, attrs, items), name); @@ -371,7 +371,7 @@ fn print_macro_stats(ecx: &ExtCtxt<'_>) { // The name won't abut or overlap with the uses value, but it does // overlap with the empty part of the uses column. Shrink the width // of the uses column to account for the excess name length. - uses_w = uses_with_underscores.len() + 1 + uses_w -= name.len() - name_w; }; _ = writeln!( @@ -793,7 +793,7 @@ fn resolver_for_lowering_raw<'tcx>( // Make sure we don't mutate the cstore from here on. tcx.untracked().cstore.freeze(); - let ty::ResolverOutputs { + let ResolverOutputs { global_ctxt: untracked_resolutions, ast_lowering: untracked_resolver_for_lowering, } = resolver.into_outputs(); @@ -1151,7 +1151,9 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) { parallel!( { - tcx.ensure_ok().check_private_in_public(()); + tcx.par_hir_for_each_module(|module| { + tcx.ensure_ok().check_private_in_public(module) + }) }, { tcx.par_hir_for_each_module(|module| { diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 8771bb44050..16474b231e0 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -777,9 +777,9 @@ fn test_unstable_options_tracking_hash() { tracked!( coverage_options, CoverageOptions { - level: CoverageLevel::Mcdc, - no_mir_spans: true, - discard_all_spans_in_codegen: true + level: CoverageLevel::Branch, + // (don't collapse test-only options onto the same line) + discard_all_spans_in_codegen: true, } ); tracked!(crate_attr, vec!["abc".to_string()]); diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml index 64751eaf1fe..7718f16984d 100644 --- a/compiler/rustc_lint/Cargo.toml +++ b/compiler/rustc_lint/Cargo.toml @@ -8,7 +8,6 @@ edition = "2024" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } -rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 69fe7fe83ff..4d0c0c94a81 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -207,6 +207,12 @@ lint_confusable_identifier_pair = found both `{$existing_sym}` and `{$sym}` as i lint_custom_inner_attribute_unstable = custom inner attributes are unstable +lint_dangling_pointers_from_locals = a dangling pointer will be produced because the local variable `{$local_var_name}` will be dropped + .ret_ty = return type of the {$fn_kind} is `{$ret_ty}` + .local_var = `{$local_var_name}` is part the {$fn_kind} and will be dropped at the end of the {$fn_kind} + .created_at = dangling pointer created here + .note = pointers do not have a lifetime; after returning, the `{$local_var_ty}` will be deallocated at the end of the {$fn_kind} because nothing is referencing it as far as the type system is concerned + lint_dangling_pointers_from_temporaries = a dangling pointer will be produced because the temporary `{$ty}` will be dropped .label_ptr = this pointer will immediately be invalid .label_temporary = this `{$ty}` is deallocated at the end of the statement, bind it to a variable to extend its lifetime diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 152971c4ed6..c893b723375 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -21,14 +21,14 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast::visit::{FnCtxt, FnKind}; use rustc_ast::{self as ast, *}; use rustc_ast_pretty::pprust::expr_to_string; -use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_errors::{Applicability, LintDiagnostic}; use rustc_feature::GateIssue; use rustc_hir as hir; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; use rustc_hir::intravisit::FnKind as HirFnKind; -use rustc_hir::{Body, FnDecl, PatKind, PredicateOrigin}; +use rustc_hir::{Body, FnDecl, PatKind, PredicateOrigin, find_attr}; use rustc_middle::bug; use rustc_middle::lint::LevelAndSource; use rustc_middle::ty::layout::LayoutOf; diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index b694d3dd49b..11181d10af5 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -756,22 +756,22 @@ impl<'tcx> LateContext<'tcx> { } fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> { - Ok(()) + unreachable!(); // because `path_generic_args` ignores the `GenericArgs` } fn print_type(&mut self, _ty: Ty<'tcx>) -> Result<(), PrintError> { - Ok(()) + unreachable!(); // because `path_generic_args` ignores the `GenericArgs` } fn print_dyn_existential( &mut self, _predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, ) -> Result<(), PrintError> { - Ok(()) + unreachable!(); // because `path_generic_args` ignores the `GenericArgs` } fn print_const(&mut self, _ct: ty::Const<'tcx>) -> Result<(), PrintError> { - Ok(()) + unreachable!(); // because `path_generic_args` ignores the `GenericArgs` } fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> { @@ -784,10 +784,10 @@ impl<'tcx> LateContext<'tcx> { self_ty: Ty<'tcx>, trait_ref: Option<ty::TraitRef<'tcx>>, ) -> Result<(), PrintError> { - if trait_ref.is_none() { - if let ty::Adt(def, args) = self_ty.kind() { - return self.print_def_path(def.did(), args); - } + if trait_ref.is_none() + && let ty::Adt(def, args) = self_ty.kind() + { + return self.print_def_path(def.did(), args); } // This shouldn't ever be needed, but just in case: @@ -803,7 +803,6 @@ impl<'tcx> LateContext<'tcx> { fn path_append_impl( &mut self, print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, - _disambiguated_data: &DisambiguatedDefPathData, self_ty: Ty<'tcx>, trait_ref: Option<ty::TraitRef<'tcx>>, ) -> Result<(), PrintError> { @@ -854,9 +853,9 @@ impl<'tcx> LateContext<'tcx> { } } - let mut printer = AbsolutePathPrinter { tcx: self.tcx, path: vec![] }; - printer.print_def_path(def_id, &[]).unwrap(); - printer.path + let mut p = AbsolutePathPrinter { tcx: self.tcx, path: vec![] }; + p.print_def_path(def_id, &[]).unwrap(); + p.path } /// Returns the associated type `name` for `self_ty` as an implementation of `trait_id`. diff --git a/compiler/rustc_lint/src/dangling.rs b/compiler/rustc_lint/src/dangling.rs index c737919db9c..af4457f4314 100644 --- a/compiler/rustc_lint/src/dangling.rs +++ b/compiler/rustc_lint/src/dangling.rs @@ -1,13 +1,14 @@ use rustc_ast::visit::{visit_opt, walk_list}; -use rustc_attr_data_structures::{AttributeKind, find_attr}; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::def::Res; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{FnKind, Visitor, walk_expr}; -use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, LangItem}; -use rustc_middle::ty::{Ty, TyCtxt}; +use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, FnRetTy, LangItem, TyKind, find_attr}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::{declare_lint, impl_lint_pass}; use rustc_span::{Span, sym}; -use crate::lints::DanglingPointersFromTemporaries; +use crate::lints::{DanglingPointersFromLocals, DanglingPointersFromTemporaries}; use crate::{LateContext, LateLintPass}; declare_lint! { @@ -42,6 +43,36 @@ declare_lint! { "detects getting a pointer from a temporary" } +declare_lint! { + /// The `dangling_pointers_from_locals` lint detects getting a pointer to data + /// of a local that will be dropped at the end of the function. + /// + /// ### Example + /// + /// ```rust + /// fn f() -> *const u8 { + /// let x = 0; + /// &x // returns a dangling ptr to `x` + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Returning a pointer from a local value will not prolong its lifetime, + /// which means that the value can be dropped and the allocation freed + /// while the pointer still exists, making the pointer dangling. + /// This is not an error (as far as the type system is concerned) + /// but probably is not what the user intended either. + /// + /// If you need stronger guarantees, consider using references instead, + /// as they are statically verified by the borrow-checker to never dangle. + pub DANGLING_POINTERS_FROM_LOCALS, + Warn, + "detects returning a pointer from a local variable" +} + /// FIXME: false negatives (i.e. the lint is not emitted when it should be) /// 1. Ways to get a temporary that are not recognized: /// - `owning_temporary.field` @@ -53,20 +84,123 @@ declare_lint! { #[derive(Clone, Copy, Default)] pub(crate) struct DanglingPointers; -impl_lint_pass!(DanglingPointers => [DANGLING_POINTERS_FROM_TEMPORARIES]); +impl_lint_pass!(DanglingPointers => [DANGLING_POINTERS_FROM_TEMPORARIES, DANGLING_POINTERS_FROM_LOCALS]); // This skips over const blocks, but they cannot use or return a dangling pointer anyways. impl<'tcx> LateLintPass<'tcx> for DanglingPointers { fn check_fn( &mut self, cx: &LateContext<'tcx>, - _: FnKind<'tcx>, - _: &'tcx FnDecl<'tcx>, + fn_kind: FnKind<'tcx>, + fn_decl: &'tcx FnDecl<'tcx>, body: &'tcx Body<'tcx>, _: Span, - _: LocalDefId, + def_id: LocalDefId, ) { - DanglingPointerSearcher { cx, inside_call_args: false }.visit_body(body) + DanglingPointerSearcher { cx, inside_call_args: false }.visit_body(body); + + if let FnRetTy::Return(ret_ty) = &fn_decl.output + && let TyKind::Ptr(_) = ret_ty.kind + { + // get the return type of the function or closure + let ty = match cx.tcx.type_of(def_id).instantiate_identity().kind() { + ty::FnDef(..) => cx.tcx.fn_sig(def_id).instantiate_identity(), + ty::Closure(_, args) => args.as_closure().sig(), + _ => return, + }; + let ty = ty.output(); + + // this type is only used for layout computation and pretty-printing, neither of them rely on regions + let ty = cx.tcx.instantiate_bound_regions_with_erased(ty); + + // verify that we have a pointer type + let inner_ty = match ty.kind() { + ty::RawPtr(inner_ty, _) => *inner_ty, + _ => return, + }; + + if cx + .tcx + .layout_of(cx.typing_env().as_query_input(inner_ty)) + .is_ok_and(|layout| !layout.is_1zst()) + { + let dcx = &DanglingPointerLocalContext { + body: def_id, + fn_ret: ty, + fn_ret_span: ret_ty.span, + fn_ret_inner: inner_ty, + fn_kind: match fn_kind { + FnKind::ItemFn(..) => "function", + FnKind::Method(..) => "method", + FnKind::Closure => "closure", + }, + }; + + // look for `return`s + DanglingPointerReturnSearcher { cx, dcx }.visit_body(body); + + // analyze implicit return expression + if let ExprKind::Block(block, None) = &body.value.kind + && let innermost_block = block.innermost_block() + && let Some(expr) = innermost_block.expr + { + lint_addr_of_local(cx, dcx, expr); + } + } + } + } +} + +struct DanglingPointerLocalContext<'tcx> { + body: LocalDefId, + fn_ret: Ty<'tcx>, + fn_ret_span: Span, + fn_ret_inner: Ty<'tcx>, + fn_kind: &'static str, +} + +struct DanglingPointerReturnSearcher<'lcx, 'tcx> { + cx: &'lcx LateContext<'tcx>, + dcx: &'lcx DanglingPointerLocalContext<'tcx>, +} + +impl<'tcx> Visitor<'tcx> for DanglingPointerReturnSearcher<'_, 'tcx> { + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) -> Self::Result { + if let ExprKind::Ret(Some(expr)) = expr.kind { + lint_addr_of_local(self.cx, self.dcx, expr); + } + walk_expr(self, expr) + } +} + +/// Look for `&<path_to_local_in_same_body>` pattern and emit lint for it +fn lint_addr_of_local<'a>( + cx: &LateContext<'a>, + dcx: &DanglingPointerLocalContext<'a>, + expr: &'a Expr<'a>, +) { + // peel casts as they do not interest us here, we want the inner expression. + let (inner, _) = super::utils::peel_casts(cx, expr); + + if let ExprKind::AddrOf(_, _, inner_of) = inner.kind + && let ExprKind::Path(ref qpath) = inner_of.peel_blocks().kind + && let Res::Local(from) = cx.qpath_res(qpath, inner_of.hir_id) + && cx.tcx.hir_enclosing_body_owner(from) == dcx.body + { + cx.tcx.emit_node_span_lint( + DANGLING_POINTERS_FROM_LOCALS, + expr.hir_id, + expr.span, + DanglingPointersFromLocals { + ret_ty: dcx.fn_ret, + ret_ty_span: dcx.fn_ret_span, + fn_kind: dcx.fn_kind, + local_var: cx.tcx.hir_span(from), + local_var_name: cx.tcx.hir_ident(from), + local_var_ty: dcx.fn_ret_inner, + created_at: (expr.hir_id != inner.hir_id).then_some(inner.span), + }, + ); } } diff --git a/compiler/rustc_lint/src/default_could_be_derived.rs b/compiler/rustc_lint/src/default_could_be_derived.rs index b5fc083a095..1d92cfbc039 100644 --- a/compiler/rustc_lint/src/default_could_be_derived.rs +++ b/compiler/rustc_lint/src/default_could_be_derived.rs @@ -1,7 +1,8 @@ -use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, Diag}; use rustc_hir as hir; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::find_attr; use rustc_middle::ty; use rustc_middle::ty::TyCtxt; use rustc_session::{declare_lint, impl_lint_pass}; @@ -61,8 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived { // Look for manual implementations of `Default`. let Some(default_def_id) = cx.tcx.get_diagnostic_item(sym::Default) else { return }; let hir::ImplItemKind::Fn(_sig, body_id) = impl_item.kind else { return }; - let assoc = cx.tcx.associated_item(impl_item.owner_id); - let parent = assoc.container_id(cx.tcx); + let parent = cx.tcx.parent(impl_item.owner_id.to_def_id()); if find_attr!(cx.tcx.get_all_attrs(parent), AttributeKind::AutomaticallyDerived(..)) { // We don't care about what `#[derive(Default)]` produces in this lint. return; diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 48e3bbb79fa..58205087def 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -4,7 +4,6 @@ //! resolution, just before AST lowering. These lints are for purely //! syntactical lints. -use rustc_ast::ptr::P; use rustc_ast::visit::{self as ast_visit, Visitor, walk_list}; use rustc_ast::{self as ast, HasAttrs}; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -297,7 +296,7 @@ impl<'a> EarlyCheckNode<'a> for (&'a ast::Crate, &'a [ast::Attribute]) { } } -impl<'a> EarlyCheckNode<'a> for (ast::NodeId, &'a [ast::Attribute], &'a [P<ast::Item>]) { +impl<'a> EarlyCheckNode<'a> for (ast::NodeId, &'a [ast::Attribute], &'a [Box<ast::Item>]) { fn id(self) -> ast::NodeId { self.0 } diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs index d6c402d481f..759e6c927b8 100644 --- a/compiler/rustc_lint/src/foreign_modules.rs +++ b/compiler/rustc_lint/src/foreign_modules.rs @@ -1,9 +1,10 @@ use rustc_abi::FIRST_VARIANT; -use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_hir as hir; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::DefKind; +use rustc_hir::find_attr; use rustc_middle::query::Providers; use rustc_middle::ty::{self, AdtDef, Instance, Ty, TyCtxt}; use rustc_session::declare_lint; diff --git a/compiler/rustc_lint/src/lifetime_syntax.rs b/compiler/rustc_lint/src/lifetime_syntax.rs index 2a5a34cdc6e..464f4fc34b9 100644 --- a/compiler/rustc_lint/src/lifetime_syntax.rs +++ b/compiler/rustc_lint/src/lifetime_syntax.rs @@ -434,7 +434,7 @@ fn emit_mismatch_diagnostic<'tcx>( lints::MismatchedLifetimeSyntaxesSuggestion::Mixed { implicit_suggestions, explicit_anonymous_suggestions, - tool_only: false, + optional_alternative: false, } }); @@ -455,7 +455,10 @@ fn emit_mismatch_diagnostic<'tcx>( let implicit_suggestion = should_suggest_implicit.then(|| { let suggestions = make_implicit_suggestions(&suggest_change_to_implicit); - lints::MismatchedLifetimeSyntaxesSuggestion::Implicit { suggestions, tool_only: false } + lints::MismatchedLifetimeSyntaxesSuggestion::Implicit { + suggestions, + optional_alternative: false, + } }); tracing::debug!( @@ -508,7 +511,7 @@ fn build_mismatch_suggestion( lints::MismatchedLifetimeSyntaxesSuggestion::Explicit { lifetime_name, suggestions, - tool_only: false, + optional_alternative: false, } } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index fd8d0f832aa..73e69a1791a 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -902,9 +902,8 @@ pub(crate) struct MappingToUnit { pub argument_label: Span, #[label(lint_map_label)] pub map_label: Span, - #[suggestion(style = "verbose", code = "{replace}", applicability = "maybe-incorrect")] + #[suggestion(style = "verbose", code = "for_each", applicability = "maybe-incorrect")] pub suggestion: Span, - pub replace: String, } // internal.rs @@ -1188,6 +1187,22 @@ pub(crate) struct DanglingPointersFromTemporaries<'tcx> { pub temporary_span: Span, } +#[derive(LintDiagnostic)] +#[diag(lint_dangling_pointers_from_locals)] +#[note] +pub(crate) struct DanglingPointersFromLocals<'tcx> { + pub ret_ty: Ty<'tcx>, + #[label(lint_ret_ty)] + pub ret_ty_span: Span, + pub fn_kind: &'static str, + #[label(lint_local_var)] + pub local_var: Span, + pub local_var_name: Ident, + pub local_var_ty: Ty<'tcx>, + #[label(lint_created_at)] + pub created_at: Option<Span>, +} + // multiple_supertrait_upcastable.rs #[derive(LintDiagnostic)] #[diag(lint_multiple_supertrait_upcastable)] @@ -3276,7 +3291,7 @@ impl<'a, G: EmissionGuarantee> LintDiagnostic<'a, G> for MismatchedLifetimeSynta diag.subdiagnostic(s); for mut s in suggestions { - s.make_tool_only(); + s.make_optional_alternative(); diag.subdiagnostic(s); } } @@ -3287,33 +3302,33 @@ impl<'a, G: EmissionGuarantee> LintDiagnostic<'a, G> for MismatchedLifetimeSynta pub(crate) enum MismatchedLifetimeSyntaxesSuggestion { Implicit { suggestions: Vec<Span>, - tool_only: bool, + optional_alternative: bool, }, Mixed { implicit_suggestions: Vec<Span>, explicit_anonymous_suggestions: Vec<(Span, String)>, - tool_only: bool, + optional_alternative: bool, }, Explicit { lifetime_name: String, suggestions: Vec<(Span, String)>, - tool_only: bool, + optional_alternative: bool, }, } impl MismatchedLifetimeSyntaxesSuggestion { - fn make_tool_only(&mut self) { + fn make_optional_alternative(&mut self) { use MismatchedLifetimeSyntaxesSuggestion::*; - let tool_only = match self { - Implicit { tool_only, .. } | Mixed { tool_only, .. } | Explicit { tool_only, .. } => { - tool_only - } + let optional_alternative = match self { + Implicit { optional_alternative, .. } + | Mixed { optional_alternative, .. } + | Explicit { optional_alternative, .. } => optional_alternative, }; - *tool_only = true; + *optional_alternative = true; } } @@ -3321,22 +3336,40 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion { fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) { use MismatchedLifetimeSyntaxesSuggestion::*; - let style = |tool_only| { - if tool_only { SuggestionStyle::CompletelyHidden } else { SuggestionStyle::ShowAlways } + let style = |optional_alternative| { + if optional_alternative { + SuggestionStyle::CompletelyHidden + } else { + SuggestionStyle::ShowAlways + } + }; + + let applicability = |optional_alternative| { + // `cargo fix` can't handle more than one fix for the same issue, + // so hide alternative suggestions from it by marking them as maybe-incorrect + if optional_alternative { + Applicability::MaybeIncorrect + } else { + Applicability::MachineApplicable + } }; match self { - Implicit { suggestions, tool_only } => { + Implicit { suggestions, optional_alternative } => { let suggestions = suggestions.into_iter().map(|s| (s, String::new())).collect(); diag.multipart_suggestion_with_style( fluent::lint_mismatched_lifetime_syntaxes_suggestion_implicit, suggestions, - Applicability::MaybeIncorrect, - style(tool_only), + applicability(optional_alternative), + style(optional_alternative), ); } - Mixed { implicit_suggestions, explicit_anonymous_suggestions, tool_only } => { + Mixed { + implicit_suggestions, + explicit_anonymous_suggestions, + optional_alternative, + } => { let message = if implicit_suggestions.is_empty() { fluent::lint_mismatched_lifetime_syntaxes_suggestion_mixed_only_paths } else { @@ -3352,12 +3385,12 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion { diag.multipart_suggestion_with_style( message, suggestions, - Applicability::MaybeIncorrect, - style(tool_only), + applicability(optional_alternative), + style(optional_alternative), ); } - Explicit { lifetime_name, suggestions, tool_only } => { + Explicit { lifetime_name, suggestions, optional_alternative } => { diag.arg("lifetime_name", lifetime_name); let msg = diag.eagerly_translate( fluent::lint_mismatched_lifetime_syntaxes_suggestion_explicit, @@ -3366,8 +3399,8 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion { diag.multipart_suggestion_with_style( msg, suggestions, - Applicability::MaybeIncorrect, - style(tool_only), + applicability(optional_alternative), + style(optional_alternative), ); } } diff --git a/compiler/rustc_lint/src/map_unit_fn.rs b/compiler/rustc_lint/src/map_unit_fn.rs index 34210137bde..18a947dc1ee 100644 --- a/compiler/rustc_lint/src/map_unit_fn.rs +++ b/compiler/rustc_lint/src/map_unit_fn.rs @@ -1,6 +1,7 @@ -use rustc_hir::{Expr, ExprKind, HirId, Stmt, StmtKind}; -use rustc_middle::ty::{self, Ty}; +use rustc_hir::{Expr, ExprKind, Stmt, StmtKind}; +use rustc_middle::ty::{self}; use rustc_session::{declare_lint, declare_lint_pass}; +use rustc_span::sym; use crate::lints::MappingToUnit; use crate::{LateContext, LateLintPass, LintContext}; @@ -39,58 +40,43 @@ declare_lint_pass!(MapUnitFn => [MAP_UNIT_FN]); impl<'tcx> LateLintPass<'tcx> for MapUnitFn { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &Stmt<'_>) { - if stmt.span.from_expansion() { + let StmtKind::Semi(expr) = stmt.kind else { return; - } - - if let StmtKind::Semi(expr) = stmt.kind - && let ExprKind::MethodCall(path, receiver, args, span) = expr.kind + }; + let ExprKind::MethodCall(path, receiver, [arg], span) = expr.kind else { + return; + }; + if path.ident.name != sym::map + || stmt.span.from_expansion() + || receiver.span.from_expansion() + || arg.span.from_expansion() + || !is_impl_slice(cx, receiver) + || !cx + .typeck_results() + .type_dependent_def_id(expr.hir_id) + .is_some_and(|id| cx.tcx.is_diagnostic_item(sym::IteratorMap, id)) { - if path.ident.name.as_str() == "map" { - if receiver.span.from_expansion() - || args.iter().any(|e| e.span.from_expansion()) - || !is_impl_slice(cx, receiver) - || !is_diagnostic_name(cx, expr.hir_id, "IteratorMap") - { - return; - } - let arg_ty = cx.typeck_results().expr_ty(&args[0]); - let default_span = args[0].span; - if let ty::FnDef(id, _) = arg_ty.kind() { - let fn_ty = cx.tcx.fn_sig(id).skip_binder(); - let ret_ty = fn_ty.output().skip_binder(); - if is_unit_type(ret_ty) { - cx.emit_span_lint( - MAP_UNIT_FN, - span, - MappingToUnit { - function_label: cx.tcx.span_of_impl(*id).unwrap_or(default_span), - argument_label: args[0].span, - map_label: span, - suggestion: path.ident.span, - replace: "for_each".to_string(), - }, - ) - } - } else if let ty::Closure(id, subs) = arg_ty.kind() { - let cl_ty = subs.as_closure().sig(); - let ret_ty = cl_ty.output().skip_binder(); - if is_unit_type(ret_ty) { - cx.emit_span_lint( - MAP_UNIT_FN, - span, - MappingToUnit { - function_label: cx.tcx.span_of_impl(*id).unwrap_or(default_span), - argument_label: args[0].span, - map_label: span, - suggestion: path.ident.span, - replace: "for_each".to_string(), - }, - ) - } - } - } + return; } + let (id, sig) = match *cx.typeck_results().expr_ty(arg).kind() { + ty::Closure(id, subs) => (id, subs.as_closure().sig()), + ty::FnDef(id, _) => (id, cx.tcx.fn_sig(id).skip_binder()), + _ => return, + }; + let ret_ty = sig.output().skip_binder(); + if !(ret_ty.is_unit() || ret_ty.is_never()) { + return; + } + cx.emit_span_lint( + MAP_UNIT_FN, + span, + MappingToUnit { + function_label: cx.tcx.span_of_impl(id).unwrap_or(arg.span), + argument_label: arg.span, + map_label: span, + suggestion: path.ident.span, + }, + ); } } @@ -102,18 +88,3 @@ fn is_impl_slice(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { } false } - -fn is_unit_type(ty: Ty<'_>) -> bool { - ty.is_unit() || ty.is_never() -} - -fn is_diagnostic_name(cx: &LateContext<'_>, id: HirId, name: &str) -> bool { - if let Some(def_id) = cx.typeck_results().type_dependent_def_id(id) - && let Some(item) = cx.tcx.get_diagnostic_name(def_id) - { - if item.as_str() == name { - return true; - } - } - false -} diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 76e374deef6..7e5f43ba77f 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -1,11 +1,11 @@ use rustc_abi::ExternAbi; -use rustc_attr_data_structures::{AttributeKind, ReprAttr, find_attr}; use rustc_attr_parsing::AttributeParser; use rustc_errors::Applicability; +use rustc_hir::attrs::{AttributeKind, ReprAttr}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{FnKind, Visitor}; -use rustc_hir::{AttrArgs, AttrItem, Attribute, GenericParamKind, PatExprKind, PatKind}; +use rustc_hir::{AttrArgs, AttrItem, Attribute, GenericParamKind, PatExprKind, PatKind, find_attr}; use rustc_middle::hir::nested_filter::All; use rustc_middle::ty; use rustc_session::config::CrateType; diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs index a3cf3d568b1..4f65acd8001 100644 --- a/compiler/rustc_lint/src/pass_by_value.rs +++ b/compiler/rustc_lint/src/pass_by_value.rs @@ -1,6 +1,6 @@ -use rustc_attr_data_structures::{AttributeKind, find_attr}; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::Res; -use rustc_hir::{self as hir, AmbigArg, GenericArg, PathSegment, QPath, TyKind}; +use rustc_hir::{self as hir, AmbigArg, GenericArg, PathSegment, QPath, TyKind, find_attr}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/compiler/rustc_lint/src/types/literal.rs b/compiler/rustc_lint/src/types/literal.rs index 2bac58ba23d..1febbff4bbf 100644 --- a/compiler/rustc_lint/src/types/literal.rs +++ b/compiler/rustc_lint/src/types/literal.rs @@ -1,11 +1,11 @@ use hir::{ExprKind, Node, is_range_literal}; use rustc_abi::{Integer, Size}; -use rustc_hir::HirId; +use rustc_hir::{HirId, attrs}; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::{bug, ty}; use rustc_span::Span; -use {rustc_ast as ast, rustc_attr_data_structures as attrs, rustc_hir as hir}; +use {rustc_ast as ast, rustc_hir as hir}; use crate::LateContext; use crate::context::LintContext; @@ -272,7 +272,7 @@ fn lint_int_literal<'tcx>( cx, hir_id, span, - attrs::IntType::SignedInt(ty::ast_int_ty(t)), + attrs::IntType::SignedInt(t), Integer::from_int_ty(cx, t).size(), repr_str, v, @@ -358,7 +358,7 @@ fn lint_uint_literal<'tcx>( cx, hir_id, span, - attrs::IntType::UnsignedInt(ty::ast_uint_ty(t)), + attrs::IntType::UnsignedInt(t), Integer::from_uint_ty(cx, t).size(), repr_str, lit_val, diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 11df071f068..22d89d24612 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -2,12 +2,12 @@ use std::iter; use rustc_ast::util::{classify, parser}; use rustc_ast::{self as ast, ExprKind, FnRetTy, HasAttrs as _, StmtKind}; -use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{MultiSpan, pluralize}; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::{self as hir, LangItem}; +use rustc_hir::{self as hir, LangItem, find_attr}; use rustc_infer::traits::util::elaborate; use rustc_middle::ty::{self, Ty, adjustment}; use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass}; @@ -185,7 +185,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { let mut op_warned = false; if let Some(must_use_op) = must_use_op { - let span = expr.span.find_oldest_ancestor_in_same_ctxt(); + let span = expr.span.find_ancestor_not_from_macro().unwrap_or(expr.span); cx.emit_span_lint( UNUSED_MUST_USE, expr.span, @@ -511,7 +511,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { ); } MustUsePath::Def(span, def_id, reason) => { - let span = span.find_oldest_ancestor_in_same_ctxt(); + let span = span.find_ancestor_not_from_macro().unwrap_or(*span); cx.emit_span_lint( UNUSED_MUST_USE, span, diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index b1edb5c3044..e660b950262 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -125,6 +125,7 @@ declare_lint_pass! { UNSAFE_OP_IN_UNSAFE_FN, UNSTABLE_NAME_COLLISIONS, UNSTABLE_SYNTAX_PRE_EXPANSION, + UNSUPPORTED_CALLING_CONVENTIONS, UNUSED_ASSIGNMENTS, UNUSED_ASSOCIATED_TYPE_BOUNDS, UNUSED_ATTRIBUTES, @@ -2155,6 +2156,7 @@ declare_lint! { @future_incompatible = FutureIncompatibleInfo { reason: FutureIncompatibilityReason::FutureReleaseError, reference: "issue #52234 <https://github.com/rust-lang/rust/issues/52234>", + report_in_deps: true, }; crate_level_only } @@ -2838,7 +2840,7 @@ declare_lint! { /// [issue #79813]: https://github.com/rust-lang/rust/issues/79813 /// [future-incompatible]: ../index.md#future-incompatible-lints pub SEMICOLON_IN_EXPRESSIONS_FROM_MACROS, - Warn, + Deny, "trailing semicolon in macro body used as expression", @future_incompatible = FutureIncompatibleInfo { reason: FutureIncompatibilityReason::FutureReleaseError, @@ -2886,11 +2888,12 @@ declare_lint! { /// struct S { /* fields */ } /// ``` pub LEGACY_DERIVE_HELPERS, - Warn, + Deny, "detects derive helper attributes that are used before they are introduced", @future_incompatible = FutureIncompatibleInfo { reason: FutureIncompatibilityReason::FutureReleaseError, reference: "issue #79202 <https://github.com/rust-lang/rust/issues/79202>", + report_in_deps: true, }; } @@ -4623,11 +4626,12 @@ declare_lint! { /// /// [future-incompatible]: ../index.md#future-incompatible-lints pub PRIVATE_MACRO_USE, - Warn, + Deny, "detects certain macro bindings that should not be re-exported", @future_incompatible = FutureIncompatibleInfo { reason: FutureIncompatibilityReason::FutureReleaseError, reference: "issue #120192 <https://github.com/rust-lang/rust/issues/120192>", + report_in_deps: true, }; } @@ -4827,7 +4831,7 @@ declare_lint! { /// /// ### Example /// - /// ```rust + /// ```rust,compile_fail /// #![doc = in_root!()] /// /// macro_rules! in_root { () => { "" } } @@ -4852,11 +4856,12 @@ declare_lint! { /// /// [future-incompatible]: ../index.md#future-incompatible-lints pub OUT_OF_SCOPE_MACRO_CALLS, - Warn, + Deny, "detects out of scope calls to `macro_rules` in key-value attributes", @future_incompatible = FutureIncompatibleInfo { reason: FutureIncompatibilityReason::FutureReleaseError, reference: "issue #124535 <https://github.com/rust-lang/rust/issues/124535>", + report_in_deps: true, }; } diff --git a/compiler/rustc_llvm/Cargo.toml b/compiler/rustc_llvm/Cargo.toml index 39de4783238..cd352ce3d0f 100644 --- a/compiler/rustc_llvm/Cargo.toml +++ b/compiler/rustc_llvm/Cargo.toml @@ -10,11 +10,13 @@ libc = "0.2.73" [build-dependencies] # tidy-alphabetical-start -# Pinned so `cargo update` bumps don't cause breakage. Please also update the -# pinned `cc` in `rustc_codegen_ssa` if you update `cc` here. +# `cc` updates often break things, so we pin it here. Cargo enforces "max 1 semver-compat version +# per crate", so if you change this, you need to also change it in `rustc_codegen_ssa`. cc = "=1.2.16" # tidy-alphabetical-end [features] +# tidy-alphabetical-start # Used by ./x.py check --compile-time-deps to skip building C++ code check_only = [] +# tidy-alphabetical-end diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index 069b684ad09..6c740156c4d 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -171,6 +171,16 @@ fn main() { let cxxflags = output(&mut cmd); let mut cfg = cc::Build::new(); cfg.warnings(false); + + // Prevent critical warnings when we're compiling from rust-lang/rust CI, + // except on MSVC, as the compiler throws warnings that are only reported + // for this platform. See https://github.com/rust-lang/rust/pull/145031#issuecomment-3162677202 + // FIXME(llvm22): It looks like the specific problem code has been removed + // in https://github.com/llvm/llvm-project/commit/e8fc808bf8e78a3c80d1f8e293a92677b92366dd, + // retry msvc once we bump our LLVM version. + if std::env::var_os("CI").is_some() && !target.contains("msvc") { + cfg.warnings_into_errors(true); + } for flag in cxxflags.split_whitespace() { // Ignore flags like `-m64` when we're doing a cross build if is_crossed && flag.starts_with("-m") { diff --git a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp index 4695de8ea09..22e7c7a160f 100644 --- a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp @@ -37,28 +37,6 @@ static coverage::Counter fromRust(LLVMRustCounter Counter) { report_fatal_error("Bad LLVMRustCounterKind!"); } -struct LLVMRustMCDCDecisionParameters { - uint32_t BitmapIdx; - uint16_t NumConditions; -}; - -struct LLVMRustMCDCBranchParameters { - int16_t ConditionID; - int16_t ConditionIDs[2]; -}; - -static coverage::mcdc::BranchParameters -fromRust(LLVMRustMCDCBranchParameters Params) { - return coverage::mcdc::BranchParameters( - Params.ConditionID, {Params.ConditionIDs[0], Params.ConditionIDs[1]}); -} - -static coverage::mcdc::DecisionParameters -fromRust(LLVMRustMCDCDecisionParameters Params) { - return coverage::mcdc::DecisionParameters(Params.BitmapIdx, - Params.NumConditions); -} - // Must match the layout of // `rustc_codegen_llvm::coverageinfo::ffi::CoverageSpan`. struct LLVMRustCoverageSpan { @@ -90,22 +68,6 @@ struct LLVMRustCoverageBranchRegion { LLVMRustCounter FalseCount; }; -// Must match the layout of -// `rustc_codegen_llvm::coverageinfo::ffi::MCDCBranchRegion`. -struct LLVMRustCoverageMCDCBranchRegion { - LLVMRustCoverageSpan Span; - LLVMRustCounter TrueCount; - LLVMRustCounter FalseCount; - LLVMRustMCDCBranchParameters MCDCBranchParams; -}; - -// Must match the layout of -// `rustc_codegen_llvm::coverageinfo::ffi::MCDCDecisionRegion`. -struct LLVMRustCoverageMCDCDecisionRegion { - LLVMRustCoverageSpan Span; - LLVMRustMCDCDecisionParameters MCDCDecisionParams; -}; - // FFI equivalent of enum `llvm::coverage::CounterExpression::ExprKind` // https://github.com/rust-lang/llvm-project/blob/ea6fa9c2/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L154 enum class LLVMRustCounterExprKind { @@ -159,10 +121,7 @@ extern "C" void LLVMRustCoverageWriteFunctionMappingsToBuffer( const LLVMRustCoverageExpansionRegion *ExpansionRegions, size_t NumExpansionRegions, const LLVMRustCoverageBranchRegion *BranchRegions, size_t NumBranchRegions, - const LLVMRustCoverageMCDCBranchRegion *MCDCBranchRegions, - size_t NumMCDCBranchRegions, - const LLVMRustCoverageMCDCDecisionRegion *MCDCDecisionRegions, - size_t NumMCDCDecisionRegions, RustStringRef BufferOut) { + RustStringRef BufferOut) { // Convert from FFI representation to LLVM representation. // Expressions: @@ -176,8 +135,8 @@ extern "C" void LLVMRustCoverageWriteFunctionMappingsToBuffer( } std::vector<coverage::CounterMappingRegion> MappingRegions; - MappingRegions.reserve(NumCodeRegions + NumBranchRegions + - NumMCDCBranchRegions + NumMCDCDecisionRegions); + MappingRegions.reserve(NumCodeRegions + NumExpansionRegions + + NumBranchRegions); // Code regions: for (const auto &Region : ArrayRef(CodeRegions, NumCodeRegions)) { @@ -201,24 +160,6 @@ extern "C" void LLVMRustCoverageWriteFunctionMappingsToBuffer( Region.Span.LineEnd, Region.Span.ColumnEnd)); } - // MC/DC branch regions: - for (const auto &Region : ArrayRef(MCDCBranchRegions, NumMCDCBranchRegions)) { - MappingRegions.push_back(coverage::CounterMappingRegion::makeBranchRegion( - fromRust(Region.TrueCount), fromRust(Region.FalseCount), - Region.Span.FileID, Region.Span.LineStart, Region.Span.ColumnStart, - Region.Span.LineEnd, Region.Span.ColumnEnd, - fromRust(Region.MCDCBranchParams))); - } - - // MC/DC decision regions: - for (const auto &Region : - ArrayRef(MCDCDecisionRegions, NumMCDCDecisionRegions)) { - MappingRegions.push_back(coverage::CounterMappingRegion::makeDecisionRegion( - fromRust(Region.MCDCDecisionParams), Region.Span.FileID, - Region.Span.LineStart, Region.Span.ColumnStart, Region.Span.LineEnd, - Region.Span.ColumnEnd)); - } - // Write the converted expressions and mappings to a byte buffer. auto CoverageMappingWriter = coverage::CoverageMappingWriter( ArrayRef<unsigned>(VirtualFileMappingIDs, NumVirtualFileMappingIDs), diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index c9814beedd6..588d867bbbf 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1986,3 +1986,29 @@ extern "C" void LLVMRustSetNoSanitizeHWAddress(LLVMValueRef Global) { MD.NoHWAddress = true; GV.setSanitizerMetadata(MD); } + +enum class LLVMRustTailCallKind { + None = 0, + Tail = 1, + MustTail = 2, + NoTail = 3 +}; + +extern "C" void LLVMRustSetTailCallKind(LLVMValueRef Call, + LLVMRustTailCallKind Kind) { + CallInst *CI = unwrap<CallInst>(Call); + switch (Kind) { + case LLVMRustTailCallKind::None: + CI->setTailCallKind(CallInst::TCK_None); + break; + case LLVMRustTailCallKind::Tail: + CI->setTailCallKind(CallInst::TCK_Tail); + break; + case LLVMRustTailCallKind::MustTail: + CI->setTailCallKind(CallInst::TCK_MustTail); + break; + case LLVMRustTailCallKind::NoTail: + CI->setTailCallKind(CallInst::TCK_NoTail); + break; + } +} diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index 101f5ccb7a4..803b3621c88 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -187,7 +187,7 @@ decl_derive! { decl_derive! { [PrintAttribute] => /// Derives `PrintAttribute` for `AttributeKind`. - /// This macro is pretty specific to `rustc_attr_data_structures` and likely not that useful in + /// This macro is pretty specific to `rustc_hir::attrs` and likely not that useful in /// other places. It's deriving something close to `Debug` without printing some extraneous /// things like spans. print_attribute::print_attribute diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml index 0edc1d18ecc..1b40d9f684e 100644 --- a/compiler/rustc_metadata/Cargo.toml +++ b/compiler/rustc_metadata/Cargo.toml @@ -10,7 +10,6 @@ libloading = "0.8.0" odht = { version = "0.3.1", features = ["nightly"] } rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } -rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 438eff33054..6bfb3769f24 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -12,6 +12,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::owned_slice::OwnedSlice; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{self, FreezeReadGuard, FreezeWriteGuard}; +use rustc_data_structures::unord::UnordMap; use rustc_expand::base::SyntaxExtension; use rustc_fs_util::try_canonicalize; use rustc_hir as hir; @@ -69,6 +70,9 @@ pub struct CStore { /// This crate has a `#[alloc_error_handler]` item. has_alloc_error_handler: bool, + /// Names that were used to load the crates via `extern crate` or paths. + resolved_externs: UnordMap<Symbol, CrateNum>, + /// Unused externs of the crate unused_externs: Vec<Symbol>, @@ -249,6 +253,22 @@ impl CStore { self.metas[cnum] = Some(Box::new(data)); } + /// Save the name used to resolve the extern crate in the local crate + /// + /// The name isn't always the crate's own name, because `sess.opts.externs` can assign it another name. + /// It's also not always the same as the `DefId`'s symbol due to renames `extern crate resolved_name as defid_name`. + pub(crate) fn set_resolved_extern_crate_name(&mut self, name: Symbol, extern_crate: CrateNum) { + self.resolved_externs.insert(name, extern_crate); + } + + /// Crate resolved and loaded via the given extern name + /// (corresponds to names in `sess.opts.externs`) + /// + /// May be `None` if the crate wasn't used + pub fn resolved_extern_crate(&self, externs_name: Symbol) -> Option<CrateNum> { + self.resolved_externs.get(&externs_name).copied() + } + pub(crate) fn iter_crate_data(&self) -> impl Iterator<Item = (CrateNum, &CrateMetadata)> { self.metas .iter_enumerated() @@ -475,6 +495,7 @@ impl CStore { alloc_error_handler_kind: None, has_global_allocator: false, has_alloc_error_handler: false, + resolved_externs: UnordMap::default(), unused_externs: Vec::new(), used_extern_options: Default::default(), } @@ -511,7 +532,7 @@ impl CStore { // We're also sure to compare *paths*, not actual byte slices. The // `source` stores paths which are normalized which may be different // from the strings on the command line. - let source = self.get_crate_data(cnum).cdata.source(); + let source = data.source(); if let Some(entry) = externs.get(name.as_str()) { // Only use `--extern crate_name=path` here, not `--extern crate_name`. if let Some(mut files) = entry.files() { @@ -1308,6 +1329,7 @@ impl CStore { let path_len = definitions.def_path(def_id).data.len(); self.update_extern_crate( cnum, + name, ExternCrate { src: ExternCrateSource::Extern(def_id.to_def_id()), span: item.span, @@ -1332,6 +1354,7 @@ impl CStore { self.update_extern_crate( cnum, + name, ExternCrate { src: ExternCrateSource::Path, span, diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index ed0f084ea83..958e314efab 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -3,9 +3,10 @@ use std::path::{Path, PathBuf}; use rustc_abi::ExternAbi; use rustc_ast::CRATE_NODE_ID; -use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_attr_parsing as attr; use rustc_data_structures::fx::FxHashSet; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::find_attr; use rustc_middle::query::LocalCrate; use rustc_middle::ty::{self, List, Ty, TyCtxt}; use rustc_session::Session; @@ -82,7 +83,7 @@ pub fn walk_native_lib_search_dirs<R>( // Mac Catalyst uses the macOS SDK, but to link to iOS-specific frameworks // we must have the support library stubs in the library search path (#121430). if let Some(sdk_root) = apple_sdk_root - && sess.target.llvm_target.contains("macabi") + && sess.target.env == "macabi" { f(&sdk_root.join("System/iOSSupport/usr/lib"), false)?; f(&sdk_root.join("System/iOSSupport/System/Library/Frameworks"), true)?; diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index e6aedc61338..548c56a97bc 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1530,7 +1530,7 @@ impl<'a> CrateMetadataRef<'a> { let macro_rules = self.root.tables.is_macro_rules.get(self, id); let body = self.root.tables.macro_definition.get(self, id).unwrap().decode((self, sess)); - ast::MacroDef { macro_rules, body: ast::ptr::P(body) } + ast::MacroDef { macro_rules, body: Box::new(body) } } _ => bug!(), } @@ -1937,9 +1937,13 @@ impl CrateMetadata { self.root.decode_target_modifiers(&self.blob).collect() } - pub(crate) fn update_extern_crate(&mut self, new_extern_crate: ExternCrate) -> bool { + /// Keep `new_extern_crate` if it looks better in diagnostics + pub(crate) fn update_extern_crate_diagnostics( + &mut self, + new_extern_crate: ExternCrate, + ) -> bool { let update = - Some(new_extern_crate.rank()) > self.extern_crate.as_ref().map(ExternCrate::rank); + self.extern_crate.as_ref().is_none_or(|old| old.rank() < new_extern_crate.rank()); if update { self.extern_crate = Some(new_extern_crate); } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 57a672c45f7..df95ed602cd 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -2,7 +2,7 @@ use std::any::Any; use std::mem; use std::sync::Arc; -use rustc_attr_data_structures::Deprecation; +use rustc_hir::attrs::Deprecation; use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; @@ -75,24 +75,6 @@ impl<'a, 'tcx, T: Copy + Decodable<DecodeContext<'a, 'tcx>>> ProcessQueryValue<' } impl<'a, 'tcx, T: Copy + Decodable<DecodeContext<'a, 'tcx>>> - ProcessQueryValue<'tcx, ty::EarlyBinder<'tcx, &'tcx [T]>> - for Option<DecodeIterator<'a, 'tcx, T>> -{ - #[inline(always)] - fn process_decoded( - self, - tcx: TyCtxt<'tcx>, - err: impl Fn() -> !, - ) -> ty::EarlyBinder<'tcx, &'tcx [T]> { - ty::EarlyBinder::bind(if let Some(iter) = self { - tcx.arena.alloc_from_iter(iter) - } else { - err() - }) - } -} - -impl<'a, 'tcx, T: Copy + Decodable<DecodeContext<'a, 'tcx>>> ProcessQueryValue<'tcx, Option<&'tcx [T]>> for Option<DecodeIterator<'a, 'tcx, T>> { #[inline(always)] @@ -627,14 +609,37 @@ impl CStore { } } - pub(crate) fn update_extern_crate(&mut self, cnum: CrateNum, extern_crate: ExternCrate) { + /// Track how an extern crate has been loaded. Called after resolving an import in the local crate. + /// + /// * the `name` is for [`Self::set_resolved_extern_crate_name`] saving `--extern name=` + /// * `extern_crate` is for diagnostics + pub(crate) fn update_extern_crate( + &mut self, + cnum: CrateNum, + name: Symbol, + extern_crate: ExternCrate, + ) { + debug_assert_eq!( + extern_crate.dependency_of, LOCAL_CRATE, + "this function should not be called on transitive dependencies" + ); + self.set_resolved_extern_crate_name(name, cnum); + self.update_transitive_extern_crate_diagnostics(cnum, extern_crate); + } + + /// `CrateMetadata` uses `ExternCrate` only for diagnostics + fn update_transitive_extern_crate_diagnostics( + &mut self, + cnum: CrateNum, + extern_crate: ExternCrate, + ) { let cmeta = self.get_crate_data_mut(cnum); - if cmeta.update_extern_crate(extern_crate) { + if cmeta.update_extern_crate_diagnostics(extern_crate) { // Propagate the extern crate info to dependencies if it was updated. let extern_crate = ExternCrate { dependency_of: cnum, ..extern_crate }; let dependencies = mem::take(&mut cmeta.dependencies); for &dep_cnum in &dependencies { - self.update_extern_crate(dep_cnum, extern_crate); + self.update_transitive_extern_crate_diagnostics(dep_cnum, extern_crate); } self.get_crate_data_mut(cnum).dependencies = dependencies; } diff --git a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs index 19369425f81..f3917b55782 100644 --- a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs +++ b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs @@ -1,6 +1,5 @@ use rustc_data_structures::owned_slice::OwnedSlice; use rustc_hir::def_path_hash_map::{Config as HashMapConfig, DefPathHashMap}; -use rustc_middle::parameterized_over_tcx; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_span::def_id::{DefIndex, DefPathHash}; @@ -11,10 +10,6 @@ pub(crate) enum DefPathHashMapRef<'tcx> { BorrowedFromTcx(&'tcx DefPathHashMap), } -parameterized_over_tcx! { - DefPathHashMapRef, -} - impl DefPathHashMapRef<'_> { #[inline] pub(crate) fn def_path_hash_to_def_index(&self, def_path_hash: &DefPathHash) -> DefIndex { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 4075bee707c..d42c8b947a4 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -5,7 +5,6 @@ use std::io::{Read, Seek, Write}; use std::path::{Path, PathBuf}; use std::sync::Arc; -use rustc_attr_data_structures::{AttributeKind, EncodeCrossCrate, find_attr}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::memmap::{Mmap, MmapMut}; use rustc_data_structures::sync::{join, par_for_each_in}; @@ -13,18 +12,19 @@ use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_data_structures::thousands::usize_with_underscores; use rustc_feature::Features; use rustc_hir as hir; +use rustc_hir::attrs::{AttributeKind, EncodeCrossCrate}; use rustc_hir::def_id::{CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE, LocalDefId, LocalDefIdSet}; use rustc_hir::definitions::DefPathData; +use rustc_hir::find_attr; use rustc_hir_pretty::id_to_string; use rustc_middle::dep_graph::WorkProductId; use rustc_middle::middle::dependency_format::Linkage; -use rustc_middle::middle::exported_symbols::metadata_symbol_name; use rustc_middle::mir::interpret; use rustc_middle::query::Providers; use rustc_middle::traits::specialization_graph; +use rustc_middle::ty::AssocItemContainer; use rustc_middle::ty::codec::TyEncoder; use rustc_middle::ty::fast_reject::{self, TreatParams}; -use rustc_middle::ty::{AssocItemContainer, SymbolName}; use rustc_middle::{bug, span_bug}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder, opaque}; use rustc_session::config::{CrateType, OptLevel, TargetModifier}; @@ -2206,19 +2206,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { exported_symbols: &[(ExportedSymbol<'tcx>, SymbolExportInfo)], ) -> LazyArray<(ExportedSymbol<'static>, SymbolExportInfo)> { empty_proc_macro!(self); - // The metadata symbol name is special. It should not show up in - // downstream crates. - let metadata_symbol_name = SymbolName::new(self.tcx, &metadata_symbol_name(self.tcx)); - self.lazy_array( - exported_symbols - .iter() - .filter(|&(exported_symbol, _)| match *exported_symbol { - ExportedSymbol::NoDefId(symbol_name) => symbol_name != metadata_symbol_name, - _ => true, - }) - .cloned(), - ) + self.lazy_array(exported_symbols.iter().cloned()) } fn encode_dylib_dependency_formats(&mut self) -> LazyArray<Option<LinkagePreference>> { diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 915c9731688..99174e4ad2f 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -6,15 +6,16 @@ use decoder::{DecodeContext, Metadata}; use def_path_hash_map::DefPathHashMapRef; use encoder::EncodeContext; pub use encoder::{EncodedMetadata, encode_metadata, rendered_const}; +pub(crate) use parameterized::ParameterizedOverTcx; use rustc_abi::{FieldIdx, ReprOptions, VariantIdx}; -use rustc_attr_data_structures::StrippedCfgItem; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::svh::Svh; -use rustc_hir::PreciseCapturingArgKind; +use rustc_hir::attrs::StrippedCfgItem; use rustc_hir::def::{CtorKind, DefKind, DocLinkResMap}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIndex, DefPathHash, StableCrateId}; use rustc_hir::definitions::DefKey; use rustc_hir::lang_items::LangItem; +use rustc_hir::{PreciseCapturingArgKind, attrs}; use rustc_index::IndexVec; use rustc_index::bit_set::DenseBitSet; use rustc_macros::{ @@ -26,12 +27,10 @@ use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; use rustc_middle::middle::lib_features::FeatureStability; use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault; +use rustc_middle::mir; use rustc_middle::ty::fast_reject::SimplifiedType; -use rustc_middle::ty::{ - self, DeducedParamAttrs, ParameterizedOverTcx, Ty, TyCtxt, UnusedGenericParams, -}; +use rustc_middle::ty::{self, DeducedParamAttrs, Ty, TyCtxt, UnusedGenericParams}; use rustc_middle::util::Providers; -use rustc_middle::{mir, trivially_parameterized_over_tcx}; use rustc_serialize::opaque::FileEncoder; use rustc_session::config::{SymbolManglingVersion, TargetModifier}; use rustc_session::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib}; @@ -40,13 +39,14 @@ use rustc_span::hygiene::{ExpnIndex, MacroKind, SyntaxContextKey}; use rustc_span::{self, ExpnData, ExpnHash, ExpnId, Ident, Span, Symbol}; use rustc_target::spec::{PanicStrategy, TargetTuple}; use table::TableBuilder; -use {rustc_ast as ast, rustc_attr_data_structures as attrs, rustc_hir as hir}; +use {rustc_ast as ast, rustc_hir as hir}; use crate::creader::CrateMetadataRef; mod decoder; mod def_path_hash_map; mod encoder; +mod parameterized; mod table; pub(crate) fn rustc_version(cfg_version: &'static str) -> String { @@ -86,10 +86,6 @@ struct LazyValue<T> { _marker: PhantomData<fn() -> T>, } -impl<T: ParameterizedOverTcx> ParameterizedOverTcx for LazyValue<T> { - type Value<'tcx> = LazyValue<T::Value<'tcx>>; -} - impl<T> LazyValue<T> { fn from_position(position: NonZero<usize>) -> LazyValue<T> { LazyValue { position, _marker: PhantomData } @@ -112,10 +108,6 @@ struct LazyArray<T> { _marker: PhantomData<fn() -> T>, } -impl<T: ParameterizedOverTcx> ParameterizedOverTcx for LazyArray<T> { - type Value<'tcx> = LazyArray<T::Value<'tcx>>; -} - impl<T> Default for LazyArray<T> { fn default() -> LazyArray<T> { LazyArray::from_position_and_num_elems(NonZero::new(1).unwrap(), 0) @@ -143,10 +135,6 @@ struct LazyTable<I, T> { _marker: PhantomData<fn(I) -> T>, } -impl<I: 'static, T: ParameterizedOverTcx> ParameterizedOverTcx for LazyTable<I, T> { - type Value<'tcx> = LazyTable<I, T::Value<'tcx>>; -} - impl<I, T> LazyTable<I, T> { fn from_position_and_encoded_size( position: NonZero<usize>, @@ -200,7 +188,7 @@ type ExpnHashTable = LazyTable<ExpnIndex, Option<LazyValue<ExpnHash>>>; #[derive(MetadataEncodable, MetadataDecodable)] pub(crate) struct ProcMacroData { proc_macro_decls_static: DefIndex, - stability: Option<attrs::Stability>, + stability: Option<hir::Stability>, macros: LazyArray<DefIndex>, } @@ -422,9 +410,9 @@ define_tables! { safety: Table<DefIndex, hir::Safety>, def_span: Table<DefIndex, LazyValue<Span>>, def_ident_span: Table<DefIndex, LazyValue<Span>>, - lookup_stability: Table<DefIndex, LazyValue<attrs::Stability>>, - lookup_const_stability: Table<DefIndex, LazyValue<attrs::ConstStability>>, - lookup_default_body_stability: Table<DefIndex, LazyValue<attrs::DefaultBodyStability>>, + lookup_stability: Table<DefIndex, LazyValue<hir::Stability>>, + lookup_const_stability: Table<DefIndex, LazyValue<hir::ConstStability>>, + lookup_default_body_stability: Table<DefIndex, LazyValue<hir::DefaultBodyStability>>, lookup_deprecation_entry: Table<DefIndex, LazyValue<attrs::Deprecation>>, explicit_predicates_of: Table<DefIndex, LazyValue<ty::GenericPredicates<'static>>>, generics_of: Table<DefIndex, LazyValue<ty::Generics>>, @@ -594,14 +582,3 @@ pub fn provide(providers: &mut Providers) { encoder::provide(providers); decoder::provide(providers); } - -trivially_parameterized_over_tcx! { - VariantData, - RawDefId, - TraitImpls, - IncoherentImpls, - CrateHeader, - CrateRoot, - CrateDep, - AttrFlags, -} diff --git a/compiler/rustc_metadata/src/rmeta/parameterized.rs b/compiler/rustc_metadata/src/rmeta/parameterized.rs new file mode 100644 index 00000000000..34180001f80 --- /dev/null +++ b/compiler/rustc_metadata/src/rmeta/parameterized.rs @@ -0,0 +1,161 @@ +use std::hash::Hash; + +use rustc_data_structures::unord::UnordMap; +use rustc_hir::def_id::DefIndex; +use rustc_index::{Idx, IndexVec}; +use rustc_middle::ty::{Binder, EarlyBinder}; +use rustc_span::Symbol; + +use crate::rmeta::{LazyArray, LazyValue}; + +pub(crate) trait ParameterizedOverTcx: 'static { + type Value<'tcx>; +} + +impl<T: ParameterizedOverTcx> ParameterizedOverTcx for Option<T> { + type Value<'tcx> = Option<T::Value<'tcx>>; +} + +impl<A: ParameterizedOverTcx, B: ParameterizedOverTcx> ParameterizedOverTcx for (A, B) { + type Value<'tcx> = (A::Value<'tcx>, B::Value<'tcx>); +} + +impl<T: ParameterizedOverTcx> ParameterizedOverTcx for Vec<T> { + type Value<'tcx> = Vec<T::Value<'tcx>>; +} + +impl<I: Idx + 'static, T: ParameterizedOverTcx> ParameterizedOverTcx for IndexVec<I, T> { + type Value<'tcx> = IndexVec<I, T::Value<'tcx>>; +} + +impl<I: Hash + Eq + 'static, T: ParameterizedOverTcx> ParameterizedOverTcx for UnordMap<I, T> { + type Value<'tcx> = UnordMap<I, T::Value<'tcx>>; +} + +impl<T: ParameterizedOverTcx> ParameterizedOverTcx for Binder<'static, T> { + type Value<'tcx> = Binder<'tcx, T::Value<'tcx>>; +} + +impl<T: ParameterizedOverTcx> ParameterizedOverTcx for EarlyBinder<'static, T> { + type Value<'tcx> = EarlyBinder<'tcx, T::Value<'tcx>>; +} + +impl<T: ParameterizedOverTcx> ParameterizedOverTcx for LazyValue<T> { + type Value<'tcx> = LazyValue<T::Value<'tcx>>; +} + +impl<T: ParameterizedOverTcx> ParameterizedOverTcx for LazyArray<T> { + type Value<'tcx> = LazyArray<T::Value<'tcx>>; +} + +macro_rules! trivially_parameterized_over_tcx { + ($($ty:ty),+ $(,)?) => { + $( + impl ParameterizedOverTcx for $ty { + #[allow(unused_lifetimes)] + type Value<'tcx> = $ty; + } + )* + } +} + +trivially_parameterized_over_tcx! { + bool, + u64, + usize, + std::string::String, + // tidy-alphabetical-start + crate::rmeta::AttrFlags, + crate::rmeta::CrateDep, + crate::rmeta::CrateHeader, + crate::rmeta::CrateRoot, + crate::rmeta::IncoherentImpls, + crate::rmeta::RawDefId, + crate::rmeta::TraitImpls, + crate::rmeta::VariantData, + rustc_abi::ReprOptions, + rustc_ast::DelimArgs, + rustc_hir::Attribute, + rustc_hir::ConstStability, + rustc_hir::Constness, + rustc_hir::CoroutineKind, + rustc_hir::DefaultBodyStability, + rustc_hir::Defaultness, + rustc_hir::LangItem, + rustc_hir::OpaqueTyOrigin<rustc_hir::def_id::DefId>, + rustc_hir::PreciseCapturingArgKind<Symbol, Symbol>, + rustc_hir::Safety, + rustc_hir::Stability, + rustc_hir::attrs::Deprecation, + rustc_hir::attrs::StrippedCfgItem<rustc_hir::def_id::DefIndex>, + rustc_hir::def::DefKind, + rustc_hir::def::DocLinkResMap, + rustc_hir::def_id::DefId, + rustc_hir::def_id::DefIndex, + rustc_hir::definitions::DefKey, + rustc_index::bit_set::DenseBitSet<u32>, + rustc_middle::metadata::ModChild, + rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs, + rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile, + rustc_middle::middle::exported_symbols::SymbolExportInfo, + rustc_middle::middle::lib_features::FeatureStability, + rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault, + rustc_middle::mir::ConstQualifs, + rustc_middle::ty::AnonConstKind, + rustc_middle::ty::AssocItemContainer, + rustc_middle::ty::AsyncDestructor, + rustc_middle::ty::Asyncness, + rustc_middle::ty::DeducedParamAttrs, + rustc_middle::ty::Destructor, + rustc_middle::ty::Generics, + rustc_middle::ty::ImplTraitInTraitData, + rustc_middle::ty::IntrinsicDef, + rustc_middle::ty::TraitDef, + rustc_middle::ty::Variance, + rustc_middle::ty::Visibility<DefIndex>, + rustc_middle::ty::adjustment::CoerceUnsizedInfo, + rustc_middle::ty::fast_reject::SimplifiedType, + rustc_session::config::TargetModifier, + rustc_session::cstore::ForeignModule, + rustc_session::cstore::LinkagePreference, + rustc_session::cstore::NativeLib, + rustc_span::ExpnData, + rustc_span::ExpnHash, + rustc_span::ExpnId, + rustc_span::Ident, + rustc_span::SourceFile, + rustc_span::Span, + rustc_span::Symbol, + rustc_span::hygiene::SyntaxContextKey, + // tidy-alphabetical-end +} + +// HACK(compiler-errors): This macro rule can only take a fake path, +// not a real, due to parsing ambiguity reasons. +macro_rules! parameterized_over_tcx { + ($($( $fake_path:ident )::+ ),+ $(,)?) => { + $( + impl ParameterizedOverTcx for $( $fake_path )::+ <'static> { + type Value<'tcx> = $( $fake_path )::+ <'tcx>; + } + )* + } +} + +parameterized_over_tcx! { + // tidy-alphabetical-start + crate::rmeta::DefPathHashMapRef, + rustc_middle::middle::exported_symbols::ExportedSymbol, + rustc_middle::mir::Body, + rustc_middle::mir::CoroutineLayout, + rustc_middle::mir::interpret::ConstAllocation, + rustc_middle::ty::Clause, + rustc_middle::ty::Const, + rustc_middle::ty::ConstConditions, + rustc_middle::ty::FnSig, + rustc_middle::ty::GenericPredicates, + rustc_middle::ty::ImplTraitHeader, + rustc_middle::ty::TraitRef, + rustc_middle::ty::Ty, + // tidy-alphabetical-end +} diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 28f406fbc96..0671aa20399 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -66,22 +66,6 @@ pub(super) trait FixedSizeEncoding: IsDefault { fn write_to_bytes(self, b: &mut Self::ByteArray); } -/// This implementation is not used generically, but for reading/writing -/// concrete `u32` fields in `Lazy*` structures, which may be zero. -impl FixedSizeEncoding for u32 { - type ByteArray = [u8; 4]; - - #[inline] - fn from_bytes(b: &[u8; 4]) -> Self { - Self::from_le_bytes(*b) - } - - #[inline] - fn write_to_bytes(self, b: &mut [u8; 4]) { - *b = self.to_le_bytes(); - } -} - impl FixedSizeEncoding for u64 { type ByteArray = [u8; 8]; @@ -175,14 +159,6 @@ fixed_size_enum! { } fixed_size_enum! { - ty::ImplPolarity { - ( Positive ) - ( Negative ) - ( Reservation ) - } -} - -fixed_size_enum! { hir::Constness { ( NotConst ) ( Const ) @@ -306,45 +282,6 @@ impl FixedSizeEncoding for bool { } } -impl FixedSizeEncoding for Option<bool> { - type ByteArray = [u8; 1]; - - #[inline] - fn from_bytes(b: &[u8; 1]) -> Self { - match b[0] { - 0 => Some(false), - 1 => Some(true), - 2 => None, - _ => unreachable!(), - } - } - - #[inline] - fn write_to_bytes(self, b: &mut [u8; 1]) { - debug_assert!(!self.is_default()); - b[0] = match self { - Some(false) => 0, - Some(true) => 1, - None => 2, - }; - } -} - -impl FixedSizeEncoding for UnusedGenericParams { - type ByteArray = [u8; 4]; - - #[inline] - fn from_bytes(b: &[u8; 4]) -> Self { - let x: u32 = u32::from_bytes(b); - UnusedGenericParams::from_bits(x) - } - - #[inline] - fn write_to_bytes(self, b: &mut [u8; 4]) { - self.bits().write_to_bytes(b); - } -} - // NOTE(eddyb) there could be an impl for `usize`, which would enable a more // generic `LazyValue<T>` impl, but in the general case we might not need / want // to fit every `usize` in `u32`. diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index edd0af6e4f5..fbcce16cedc 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -14,7 +14,6 @@ rustc_apfloat = "0.2.0" rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } rustc_ast_ir = { path = "../rustc_ast_ir" } -rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_error_messages = { path = "../rustc_error_messages" } # Used for intra-doc links rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl index 69aa4383f13..69adb2fe391 100644 --- a/compiler/rustc_middle/messages.ftl +++ b/compiler/rustc_middle/messages.ftl @@ -122,8 +122,6 @@ middle_strict_coherence_needs_negative_coherence = to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled .label = due to this attribute -middle_type_length_limit = reached the type-length limit while instantiating `{$shrunk}` +middle_type_length_limit = reached the type-length limit while instantiating `{$instance}` middle_unsupported_union = we don't support unions yet: '{$ty_name}' - -middle_written_to_path = the full type name has been written to '{$path}' diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 43a7af9ce38..4b6e38cd52d 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -110,7 +110,7 @@ macro_rules! arena_types { [] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData<rustc_middle::ty::TyCtxt<'tcx>>, [] predefined_opaques_in_body: rustc_middle::traits::solve::PredefinedOpaquesData<rustc_middle::ty::TyCtxt<'tcx>>, [decode] doc_link_resolutions: rustc_hir::def::DocLinkResMap, - [] stripped_cfg_items: rustc_attr_data_structures::StrippedCfgItem, + [] stripped_cfg_items: rustc_hir::attrs::StrippedCfgItem, [] mod_child: rustc_middle::metadata::ModChild, [] features: rustc_feature::Features, [decode] specialization_graph: rustc_middle::traits::specialization_graph::Graph, diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index f36ae831653..7520bc262c6 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -1,4 +1,4 @@ -use std::path::{Path, PathBuf}; +use std::path::Path; use std::{fmt, io}; use rustc_errors::codes::*; @@ -6,7 +6,7 @@ use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; -use crate::ty::Ty; +use crate::ty::{Instance, Ty}; #[derive(Diagnostic)] #[diag(middle_drop_check_overflow, code = E0320)] @@ -161,13 +161,10 @@ pub(crate) struct ErroneousConstant { #[derive(Diagnostic)] #[diag(middle_type_length_limit)] #[help(middle_consider_type_length_limit)] -pub(crate) struct TypeLengthLimit { +pub(crate) struct TypeLengthLimit<'tcx> { #[primary_span] pub span: Span, - pub shrunk: String, - #[note(middle_written_to_path)] - pub was_written: bool, - pub path: PathBuf, + pub instance: Instance<'tcx>, pub type_length: usize, } diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index 42a1e7377f4..4370816d38e 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -4,11 +4,11 @@ use rustc_abi::ExternAbi; use rustc_ast::visit::{VisitorResult, walk_list}; -use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{DynSend, DynSync, par_for_each_in, try_par_for_each_in}; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId, LocalModDefId}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; @@ -533,8 +533,10 @@ impl<'tcx> TyCtxt<'tcx> { /// ``` /// fn foo(x: usize) -> bool { /// if x == 1 { - /// true // If `get_fn_id_for_return_block` gets passed the `id` corresponding - /// } else { // to this, it will return `foo`'s `HirId`. + /// // If `get_fn_id_for_return_block` gets passed the `id` corresponding to this, it + /// // will return `foo`'s `HirId`. + /// true + /// } else { /// false /// } /// } @@ -543,8 +545,10 @@ impl<'tcx> TyCtxt<'tcx> { /// ```compile_fail,E0308 /// fn foo(x: usize) -> bool { /// loop { - /// true // If `get_fn_id_for_return_block` gets passed the `id` corresponding - /// } // to this, it will return `None`. + /// // If `get_fn_id_for_return_block` gets passed the `id` corresponding to this, it + /// // will return `None`. + /// true + /// } /// false /// } /// ``` diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 6c07e49734a..67bc89692ff 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -174,36 +174,52 @@ impl<'tcx> TyCtxt<'tcx> { attrs: &SortedMap<ItemLocalId, &[Attribute]>, delayed_lints: &[DelayedLint], define_opaque: Option<&[(Span, LocalDefId)]>, - ) -> (Option<Fingerprint>, Option<Fingerprint>, Option<Fingerprint>) { - if self.needs_crate_hash() { - self.with_stable_hashing_context(|mut hcx| { - let mut stable_hasher = StableHasher::new(); - node.hash_stable(&mut hcx, &mut stable_hasher); - // Bodies are stored out of line, so we need to pull them explicitly in the hash. - bodies.hash_stable(&mut hcx, &mut stable_hasher); - let h1 = stable_hasher.finish(); - - let mut stable_hasher = StableHasher::new(); - attrs.hash_stable(&mut hcx, &mut stable_hasher); - - // Hash the defined opaque types, which are not present in the attrs. - define_opaque.hash_stable(&mut hcx, &mut stable_hasher); - - let h2 = stable_hasher.finish(); - - // hash lints emitted during ast lowering - let mut stable_hasher = StableHasher::new(); - delayed_lints.hash_stable(&mut hcx, &mut stable_hasher); - let h3 = stable_hasher.finish(); - - (Some(h1), Some(h2), Some(h3)) - }) - } else { - (None, None, None) + ) -> Hashes { + if !self.needs_crate_hash() { + return Hashes { + opt_hash_including_bodies: None, + attrs_hash: None, + delayed_lints_hash: None, + }; } + + self.with_stable_hashing_context(|mut hcx| { + let mut stable_hasher = StableHasher::new(); + node.hash_stable(&mut hcx, &mut stable_hasher); + // Bodies are stored out of line, so we need to pull them explicitly in the hash. + bodies.hash_stable(&mut hcx, &mut stable_hasher); + let h1 = stable_hasher.finish(); + + let mut stable_hasher = StableHasher::new(); + attrs.hash_stable(&mut hcx, &mut stable_hasher); + + // Hash the defined opaque types, which are not present in the attrs. + define_opaque.hash_stable(&mut hcx, &mut stable_hasher); + + let h2 = stable_hasher.finish(); + + // hash lints emitted during ast lowering + let mut stable_hasher = StableHasher::new(); + delayed_lints.hash_stable(&mut hcx, &mut stable_hasher); + let h3 = stable_hasher.finish(); + + Hashes { + opt_hash_including_bodies: Some(h1), + attrs_hash: Some(h2), + delayed_lints_hash: Some(h3), + } + }) } } +/// Hashes computed by [`TyCtxt::hash_owner_nodes`] if necessary. +#[derive(Clone, Copy, Debug)] +pub struct Hashes { + pub opt_hash_including_bodies: Option<Fingerprint>, + pub attrs_hash: Option<Fingerprint>, + pub delayed_lints_hash: Option<Fingerprint>, +} + pub fn provide(providers: &mut Providers) { providers.hir_crate_items = map::hir_crate_items; providers.crate_hash = map::crate_hash; diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 803b645c8f7..e5cc23c213d 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -57,6 +57,7 @@ #![feature(sized_hierarchy)] #![feature(try_blocks)] #![feature(try_trait_v2)] +#![feature(try_trait_v2_residual)] #![feature(try_trait_v2_yeet)] #![feature(type_alias_impl_trait)] #![feature(yeet_expr)] diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 34a29acdc85..94384e64afd 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use rustc_abi::Align; use rustc_ast::expand::autodiff_attrs::AutoDiffAttrs; -use rustc_attr_data_structures::{InlineAttr, InstructionSetAttr, OptimizeAttr}; +use rustc_hir::attrs::{InlineAttr, InstructionSetAttr, OptimizeAttr}; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_span::Symbol; use rustc_target::spec::SanitizerSet; diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs index 800c1af660a..857d041224f 100644 --- a/compiler/rustc_middle/src/middle/region.rs +++ b/compiler/rustc_middle/src/middle/region.rs @@ -96,6 +96,7 @@ impl fmt::Debug for Scope { ScopeData::Destruction => write!(fmt, "Destruction({:?})", self.local_id), ScopeData::IfThen => write!(fmt, "IfThen({:?})", self.local_id), ScopeData::IfThenRescope => write!(fmt, "IfThen[edition2024]({:?})", self.local_id), + ScopeData::MatchGuard => write!(fmt, "MatchGuard({:?})", self.local_id), ScopeData::Remainder(fsi) => write!( fmt, "Remainder {{ block: {:?}, first_statement_index: {}}}", @@ -131,6 +132,11 @@ pub enum ScopeData { /// whose lifetimes do not cross beyond this scope. IfThenRescope, + /// Scope of the condition and body of a match arm with a guard + /// Used for variables introduced in an if-let guard, + /// whose lifetimes do not cross beyond this scope. + MatchGuard, + /// Scope following a `let id = expr;` binding in a block. Remainder(FirstStatementIndex), } diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index dc9311188e8..4a19cf1563c 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -4,13 +4,11 @@ use std::num::NonZero; use rustc_ast::NodeId; -use rustc_attr_data_structures::{ - self as attrs, ConstStability, DefaultBodyStability, DeprecatedSince, Deprecation, Stability, -}; use rustc_errors::{Applicability, Diag, EmissionGuarantee}; use rustc_feature::GateIssue; +use rustc_hir::attrs::{DeprecatedSince, Deprecation}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::{self as hir, HirId}; +use rustc_hir::{self as hir, ConstStability, DefaultBodyStability, HirId, Stability}; use rustc_macros::{Decodable, Encodable, HashStable, Subdiagnostic}; use rustc_session::Session; use rustc_session::lint::builtin::{DEPRECATED, DEPRECATED_IN_FUTURE, SOFT_UNSTABLE}; @@ -368,7 +366,7 @@ impl<'tcx> TyCtxt<'tcx> { match stability { Some(Stability { - level: attrs::StabilityLevel::Unstable { reason, issue, is_soft, implied_by, .. }, + level: hir::StabilityLevel::Unstable { reason, issue, is_soft, implied_by, .. }, feature, .. }) => { @@ -451,7 +449,7 @@ impl<'tcx> TyCtxt<'tcx> { match stability { Some(DefaultBodyStability { - level: attrs::StabilityLevel::Unstable { reason, issue, is_soft, .. }, + level: hir::StabilityLevel::Unstable { reason, issue, is_soft, .. }, feature, }) => { if span.allows_unstable(feature) { @@ -600,7 +598,7 @@ impl<'tcx> TyCtxt<'tcx> { match stability { Some(ConstStability { - level: attrs::StabilityLevel::Unstable { reason, issue, is_soft, implied_by, .. }, + level: hir::StabilityLevel::Unstable { reason, issue, is_soft, implied_by, .. }, feature, .. }) => { diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index e26575b552e..fd4c64b9a61 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -50,25 +50,6 @@ rustc_index::newtype_index! { pub struct ExpressionId {} } -rustc_index::newtype_index! { - /// ID of a mcdc condition. Used by llvm to check mcdc coverage. - /// - /// Note for future: the max limit of 0xFFFF is probably too loose. Actually llvm does not - /// support decisions with too many conditions (7 and more at LLVM 18 while may be hundreds at 19) - /// and represents it with `int16_t`. This max value may be changed once we could - /// figure out an accurate limit. - #[derive(HashStable)] - #[encodable] - #[orderable] - #[max = 0xFFFF] - #[debug_format = "ConditionId({})"] - pub struct ConditionId {} -} - -impl ConditionId { - pub const START: Self = Self::from_usize(0); -} - /// Enum that can hold a constant zero value, the ID of an physical coverage /// counter, or the ID of a coverage-counter expression. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] @@ -109,16 +90,6 @@ pub enum CoverageKind { /// During codegen, this might be lowered to `llvm.instrprof.increment` or /// to a no-op, depending on the outcome of counter-creation. VirtualCounter { bcb: BasicCoverageBlock }, - - /// Marks the point in MIR control flow represented by a evaluated condition. - /// - /// This is eventually lowered to instruments updating mcdc temp variables. - CondBitmapUpdate { index: u32, decision_depth: u16 }, - - /// Marks the point in MIR control flow represented by a evaluated decision. - /// - /// This is eventually lowered to `llvm.instrprof.mcdc.tvbitmap.update` in LLVM IR. - TestVectorBitmapUpdate { bitmap_idx: u32, decision_depth: u16 }, } impl Debug for CoverageKind { @@ -128,12 +99,6 @@ impl Debug for CoverageKind { SpanMarker => write!(fmt, "SpanMarker"), BlockMarker { id } => write!(fmt, "BlockMarker({:?})", id.index()), VirtualCounter { bcb } => write!(fmt, "VirtualCounter({bcb:?})"), - CondBitmapUpdate { index, decision_depth } => { - write!(fmt, "CondBitmapUpdate(index={:?}, depth={:?})", index, decision_depth) - } - TestVectorBitmapUpdate { bitmap_idx, decision_depth } => { - write!(fmt, "TestVectorUpdate({:?}, depth={:?})", bitmap_idx, decision_depth) - } } } } @@ -170,14 +135,6 @@ pub enum MappingKind { Code { bcb: BasicCoverageBlock }, /// Associates a branch region with separate counters for true and false. Branch { true_bcb: BasicCoverageBlock, false_bcb: BasicCoverageBlock }, - /// Associates a branch region with separate counters for true and false. - MCDCBranch { - true_bcb: BasicCoverageBlock, - false_bcb: BasicCoverageBlock, - mcdc_params: ConditionInfo, - }, - /// Associates a decision region with a bitmap and number of conditions. - MCDCDecision(DecisionInfo), } #[derive(Clone, Debug)] @@ -201,11 +158,6 @@ pub struct FunctionCoverageInfo { pub priority_list: Vec<BasicCoverageBlock>, pub mappings: Vec<Mapping>, - - pub mcdc_bitmap_bits: usize, - /// The depth of the deepest decision is used to know how many - /// temp condbitmaps should be allocated for the function. - pub mcdc_num_condition_bitmaps: usize, } /// Coverage information for a function, recorded during MIR building and @@ -222,10 +174,6 @@ pub struct CoverageInfoHi { /// data structures without having to scan the entire body first. pub num_block_markers: usize, pub branch_spans: Vec<BranchSpan>, - /// Branch spans generated by mcdc. Because of some limits mcdc builder give up generating - /// decisions including them so that they are handled as normal branch spans. - pub mcdc_degraded_branch_spans: Vec<MCDCBranchSpan>, - pub mcdc_spans: Vec<(MCDCDecisionSpan, Vec<MCDCBranchSpan>)>, } #[derive(Clone, Debug)] @@ -236,39 +184,6 @@ pub struct BranchSpan { pub false_marker: BlockMarkerId, } -#[derive(Copy, Clone, Debug)] -#[derive(TyEncodable, TyDecodable, Hash, HashStable)] -pub struct ConditionInfo { - pub condition_id: ConditionId, - pub true_next_id: Option<ConditionId>, - pub false_next_id: Option<ConditionId>, -} - -#[derive(Clone, Debug)] -#[derive(TyEncodable, TyDecodable, Hash, HashStable)] -pub struct MCDCBranchSpan { - pub span: Span, - pub condition_info: ConditionInfo, - pub true_marker: BlockMarkerId, - pub false_marker: BlockMarkerId, -} - -#[derive(Copy, Clone, Debug)] -#[derive(TyEncodable, TyDecodable, Hash, HashStable)] -pub struct DecisionInfo { - pub bitmap_idx: u32, - pub num_conditions: u16, -} - -#[derive(Clone, Debug)] -#[derive(TyEncodable, TyDecodable, Hash, HashStable)] -pub struct MCDCDecisionSpan { - pub span: Span, - pub end_markers: Vec<BlockMarkerId>, - pub decision_depth: u16, - pub num_conditions: usize, -} - /// Contains information needed during codegen, obtained by inspecting the /// function's MIR after MIR optimizations. /// diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 3e895c6b280..77427a12d11 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -793,36 +793,37 @@ impl Drop for Guard { /// We also make things panic if this type is ever implicitly dropped. #[derive(Debug)] #[must_use] -pub struct InterpResult_<'tcx, T> { +pub struct InterpResult<'tcx, T = ()> { res: Result<T, InterpErrorInfo<'tcx>>, guard: Guard, } -// Type alias to be able to set a default type argument. -pub type InterpResult<'tcx, T = ()> = InterpResult_<'tcx, T>; - -impl<'tcx, T> ops::Try for InterpResult_<'tcx, T> { +impl<'tcx, T> ops::Try for InterpResult<'tcx, T> { type Output = T; - type Residual = InterpResult_<'tcx, convert::Infallible>; + type Residual = InterpResult<'tcx, convert::Infallible>; #[inline] fn from_output(output: Self::Output) -> Self { - InterpResult_::new(Ok(output)) + InterpResult::new(Ok(output)) } #[inline] fn branch(self) -> ops::ControlFlow<Self::Residual, Self::Output> { match self.disarm() { Ok(v) => ops::ControlFlow::Continue(v), - Err(e) => ops::ControlFlow::Break(InterpResult_::new(Err(e))), + Err(e) => ops::ControlFlow::Break(InterpResult::new(Err(e))), } } } -impl<'tcx, T> ops::FromResidual for InterpResult_<'tcx, T> { +impl<'tcx, T> ops::Residual<T> for InterpResult<'tcx, convert::Infallible> { + type TryType = InterpResult<'tcx, T>; +} + +impl<'tcx, T> ops::FromResidual for InterpResult<'tcx, T> { #[inline] #[track_caller] - fn from_residual(residual: InterpResult_<'tcx, convert::Infallible>) -> Self { + fn from_residual(residual: InterpResult<'tcx, convert::Infallible>) -> Self { match residual.disarm() { Err(e) => Self::new(Err(e)), } @@ -830,7 +831,7 @@ impl<'tcx, T> ops::FromResidual for InterpResult_<'tcx, T> { } // Allow `yeet`ing `InterpError` in functions returning `InterpResult_`. -impl<'tcx, T> ops::FromResidual<ops::Yeet<InterpErrorKind<'tcx>>> for InterpResult_<'tcx, T> { +impl<'tcx, T> ops::FromResidual<ops::Yeet<InterpErrorKind<'tcx>>> for InterpResult<'tcx, T> { #[inline] fn from_residual(ops::Yeet(e): ops::Yeet<InterpErrorKind<'tcx>>) -> Self { Self::new(Err(e.into())) @@ -840,7 +841,7 @@ impl<'tcx, T> ops::FromResidual<ops::Yeet<InterpErrorKind<'tcx>>> for InterpResu // Allow `?` on `Result<_, InterpError>` in functions returning `InterpResult_`. // This is useful e.g. for `option.ok_or_else(|| err_ub!(...))`. impl<'tcx, T, E: Into<InterpErrorInfo<'tcx>>> ops::FromResidual<Result<convert::Infallible, E>> - for InterpResult_<'tcx, T> + for InterpResult<'tcx, T> { #[inline] fn from_residual(residual: Result<convert::Infallible, E>) -> Self { @@ -863,7 +864,7 @@ impl<'tcx, T, V: FromIterator<T>> FromIterator<InterpResult<'tcx, T>> for Interp } } -impl<'tcx, T> InterpResult_<'tcx, T> { +impl<'tcx, T> InterpResult<'tcx, T> { #[inline(always)] fn new(res: Result<T, InterpErrorInfo<'tcx>>) -> Self { Self { res, guard: Guard } @@ -890,7 +891,7 @@ impl<'tcx, T> InterpResult_<'tcx, T> { #[inline] pub fn map<U>(self, f: impl FnOnce(T) -> U) -> InterpResult<'tcx, U> { - InterpResult_::new(self.disarm().map(f)) + InterpResult::new(self.disarm().map(f)) } #[inline] @@ -898,7 +899,7 @@ impl<'tcx, T> InterpResult_<'tcx, T> { self, f: impl FnOnce(InterpErrorInfo<'tcx>) -> InterpErrorInfo<'tcx>, ) -> InterpResult<'tcx, T> { - InterpResult_::new(self.disarm().map_err(f)) + InterpResult::new(self.disarm().map_err(f)) } #[inline] @@ -906,7 +907,7 @@ impl<'tcx, T> InterpResult_<'tcx, T> { self, f: impl FnOnce(InterpErrorKind<'tcx>) -> InterpErrorKind<'tcx>, ) -> InterpResult<'tcx, T> { - InterpResult_::new(self.disarm().map_err(|mut e| { + InterpResult::new(self.disarm().map_err(|mut e| { e.0.kind = f(e.0.kind); e })) @@ -914,7 +915,7 @@ impl<'tcx, T> InterpResult_<'tcx, T> { #[inline] pub fn inspect_err_kind(self, f: impl FnOnce(&InterpErrorKind<'tcx>)) -> InterpResult<'tcx, T> { - InterpResult_::new(self.disarm().inspect_err(|e| f(&e.0.kind))) + InterpResult::new(self.disarm().inspect_err(|e| f(&e.0.kind))) } #[inline] @@ -937,7 +938,7 @@ impl<'tcx, T> InterpResult_<'tcx, T> { #[inline] pub fn and_then<U>(self, f: impl FnOnce(T) -> InterpResult<'tcx, U>) -> InterpResult<'tcx, U> { - InterpResult_::new(self.disarm().and_then(|t| f(t).disarm())) + InterpResult::new(self.disarm().and_then(|t| f(t).disarm())) } /// Returns success if both `self` and `other` succeed, while ensuring we don't @@ -952,7 +953,7 @@ impl<'tcx, T> InterpResult_<'tcx, T> { // Discard the other error. drop(other.disarm()); // Return `self`. - InterpResult_::new(Err(e)) + InterpResult::new(Err(e)) } } } @@ -960,5 +961,5 @@ impl<'tcx, T> InterpResult_<'tcx, T> { #[inline(always)] pub fn interp_ok<'tcx, T>(x: T) -> InterpResult<'tcx, T> { - InterpResult_::new(Ok(x)) + InterpResult::new(Ok(x)) } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index e819aa2d8f8..c55c7fc6002 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1017,7 +1017,8 @@ pub struct LocalDecl<'tcx> { /// ``` /// fn foo(x: &str) { /// #[allow(unused_mut)] - /// let mut x: u32 = { // <- one unused mut + /// let mut x: u32 = { + /// //^ one unused mut /// let mut y: u32 = x.parse().unwrap(); /// y + 2 /// }; diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 105736b9e24..e5864660575 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -3,7 +3,6 @@ use std::fmt; use std::hash::Hash; use rustc_ast::expand::autodiff_attrs::AutoDiffItem; -use rustc_attr_data_structures::InlineAttr; use rustc_data_structures::base_n::{BaseNString, CASE_INSENSITIVE, ToBaseN}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxIndexMap; @@ -11,6 +10,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHas use rustc_data_structures::unord::UnordMap; use rustc_hashes::Hash128; use rustc_hir::ItemId; +use rustc_hir::attrs::InlineAttr; use rustc_hir::def_id::{CrateNum, DefId, DefIdSet, LOCAL_CRATE}; use rustc_index::Idx; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 809cdb329f7..84abcf550d2 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -585,12 +585,7 @@ fn write_coverage_info_hi( coverage_info_hi: &coverage::CoverageInfoHi, w: &mut dyn io::Write, ) -> io::Result<()> { - let coverage::CoverageInfoHi { - num_block_markers: _, - branch_spans, - mcdc_degraded_branch_spans, - mcdc_spans, - } = coverage_info_hi; + let coverage::CoverageInfoHi { num_block_markers: _, branch_spans } = coverage_info_hi; // Only add an extra trailing newline if we printed at least one thing. let mut did_print = false; @@ -603,38 +598,6 @@ fn write_coverage_info_hi( did_print = true; } - for coverage::MCDCBranchSpan { span, true_marker, false_marker, .. } in - mcdc_degraded_branch_spans - { - writeln!( - w, - "{INDENT}coverage branch {{ true: {true_marker:?}, false: {false_marker:?} }} => {span:?}", - )?; - did_print = true; - } - - for ( - coverage::MCDCDecisionSpan { span, end_markers, decision_depth, num_conditions: _ }, - conditions, - ) in mcdc_spans - { - let num_conditions = conditions.len(); - writeln!( - w, - "{INDENT}coverage mcdc decision {{ num_conditions: {num_conditions:?}, end: {end_markers:?}, depth: {decision_depth:?} }} => {span:?}" - )?; - for coverage::MCDCBranchSpan { span, condition_info, true_marker, false_marker } in - conditions - { - writeln!( - w, - "{INDENT}coverage mcdc branch {{ condition_id: {:?}, true: {true_marker:?}, false: {false_marker:?} }} => {span:?}", - condition_info.condition_id - )?; - } - did_print = true; - } - if did_print { writeln!(w)?; } @@ -970,11 +933,11 @@ impl<'tcx> TerminatorKind<'tcx> { Call { func, args, destination, .. } => { write!(fmt, "{destination:?} = ")?; write!(fmt, "{func:?}(")?; - for (index, arg) in args.iter().map(|a| &a.node).enumerate() { + for (index, arg) in args.iter().enumerate() { if index > 0 { write!(fmt, ", ")?; } - write!(fmt, "{arg:?}")?; + write!(fmt, "{:?}", arg.node)?; } write!(fmt, ")") } @@ -984,7 +947,7 @@ impl<'tcx> TerminatorKind<'tcx> { if index > 0 { write!(fmt, ", ")?; } - write!(fmt, "{:?}", arg)?; + write!(fmt, "{:?}", arg.node)?; } write!(fmt, ")") } @@ -1197,8 +1160,8 @@ impl<'tcx> Debug for Rvalue<'tcx> { ty::tls::with(|tcx| { let variant_def = &tcx.adt_def(adt_did).variant(variant); let args = tcx.lift(args).expect("could not lift for printing"); - let name = FmtPrinter::print_string(tcx, Namespace::ValueNS, |cx| { - cx.print_def_path(variant_def.def_id, args) + let name = FmtPrinter::print_string(tcx, Namespace::ValueNS, |p| { + p.print_def_path(variant_def.def_id, args) })?; match variant_def.ctor_kind() { @@ -1473,9 +1436,9 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> { }; let fmt_valtree = |cv: &ty::Value<'tcx>| { - let mut cx = FmtPrinter::new(self.tcx, Namespace::ValueNS); - cx.pretty_print_const_valtree(*cv, /*print_ty*/ true).unwrap(); - cx.into_buffer() + let mut p = FmtPrinter::new(self.tcx, Namespace::ValueNS); + p.pretty_print_const_valtree(*cv, /*print_ty*/ true).unwrap(); + p.into_buffer() }; let val = match const_ { @@ -1967,10 +1930,10 @@ fn pretty_print_const_value_tcx<'tcx>( .expect("destructed mir constant of adt without variant idx"); let variant_def = &def.variant(variant_idx); let args = tcx.lift(args).unwrap(); - let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS); - cx.print_alloc_ids = true; - cx.print_value_path(variant_def.def_id, args)?; - fmt.write_str(&cx.into_buffer())?; + let mut p = FmtPrinter::new(tcx, Namespace::ValueNS); + p.print_alloc_ids = true; + p.print_value_path(variant_def.def_id, args)?; + fmt.write_str(&p.into_buffer())?; match variant_def.ctor_kind() { Some(CtorKind::Const) => {} @@ -2001,18 +1964,18 @@ fn pretty_print_const_value_tcx<'tcx>( } } (ConstValue::Scalar(scalar), _) => { - let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS); - cx.print_alloc_ids = true; + let mut p = FmtPrinter::new(tcx, Namespace::ValueNS); + p.print_alloc_ids = true; let ty = tcx.lift(ty).unwrap(); - cx.pretty_print_const_scalar(scalar, ty)?; - fmt.write_str(&cx.into_buffer())?; + p.pretty_print_const_scalar(scalar, ty)?; + fmt.write_str(&p.into_buffer())?; return Ok(()); } (ConstValue::ZeroSized, ty::FnDef(d, s)) => { - let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS); - cx.print_alloc_ids = true; - cx.print_value_path(*d, s)?; - fmt.write_str(&cx.into_buffer())?; + let mut p = FmtPrinter::new(tcx, Namespace::ValueNS); + p.print_alloc_ids = true; + p.print_value_path(*d, s)?; + fmt.write_str(&p.into_buffer())?; return Ok(()); } // FIXME(oli-obk): also pretty print arrays and other aggregate constants by reading diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 929ebe1aee1..42a68b29ec7 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -1205,18 +1205,19 @@ macro_rules! visit_place_fns { self.super_projection_elem(place_ref, elem, context, location); } - fn super_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { - let mut context = context; - - if !place.projection.is_empty() { - if context.is_use() { - // ^ Only change the context if it is a real use, not a "use" in debuginfo. - context = if context.is_mutating_use() { - PlaceContext::MutatingUse(MutatingUseContext::Projection) - } else { - PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) - }; - } + fn super_place( + &mut self, + place: &Place<'tcx>, + mut context: PlaceContext, + location: Location, + ) { + if !place.projection.is_empty() && context.is_use() { + // ^ Only change the context if it is a real use, not a "use" in debuginfo. + context = if context.is_mutating_use() { + PlaceContext::MutatingUse(MutatingUseContext::Projection) + } else { + PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) + }; } self.visit_local(place.local, context, location); @@ -1239,7 +1240,7 @@ macro_rules! visit_place_fns { &mut self, _place_ref: PlaceRef<'tcx>, elem: PlaceElem<'tcx>, - _context: PlaceContext, + context: PlaceContext, location: Location, ) { match elem { @@ -1252,7 +1253,12 @@ macro_rules! visit_place_fns { ProjectionElem::Index(local) => { self.visit_local( local, - PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), + if context.is_use() { + // ^ Only change the context if it is a real use, not a "use" in debuginfo. + PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) + } else { + context + }, location, ); } diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index dab5900b4ab..a8b357bf105 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -246,9 +246,9 @@ trivial! { bool, Option<(rustc_span::def_id::DefId, rustc_session::config::EntryFnType)>, Option<rustc_ast::expand::allocator::AllocatorKind>, - Option<rustc_attr_data_structures::ConstStability>, - Option<rustc_attr_data_structures::DefaultBodyStability>, - Option<rustc_attr_data_structures::Stability>, + Option<rustc_hir::ConstStability>, + Option<rustc_hir::DefaultBodyStability>, + Option<rustc_hir::Stability>, Option<rustc_data_structures::svh::Svh>, Option<rustc_hir::def::DefKind>, Option<rustc_hir::CoroutineKind>, @@ -272,13 +272,12 @@ trivial! { Result<rustc_middle::traits::EvaluationResult, rustc_middle::traits::OverflowError>, rustc_abi::ReprOptions, rustc_ast::expand::allocator::AllocatorKind, - rustc_attr_data_structures::ConstStability, - rustc_attr_data_structures::DefaultBodyStability, - rustc_attr_data_structures::Deprecation, - rustc_attr_data_structures::Stability, + rustc_hir::DefaultBodyStability, + rustc_hir::attrs::Deprecation, rustc_data_structures::svh::Svh, rustc_errors::ErrorGuaranteed, rustc_hir::Constness, + rustc_hir::ConstStability, rustc_hir::def_id::DefId, rustc_hir::def_id::DefIndex, rustc_hir::def_id::LocalDefId, @@ -293,6 +292,7 @@ trivial! { rustc_hir::LangItem, rustc_hir::OpaqueTyOrigin<rustc_hir::def_id::DefId>, rustc_hir::OwnerId, + rustc_hir::Stability, rustc_hir::Upvar, rustc_index::bit_set::FiniteBitSet<u32>, rustc_middle::middle::dependency_format::Linkage, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index b0d579a546f..a4589576594 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -70,7 +70,6 @@ use std::sync::Arc; use rustc_abi::Align; use rustc_arena::TypedArena; use rustc_ast::expand::allocator::AllocatorKind; -use rustc_attr_data_structures::StrippedCfgItem; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::sorted_map::SortedMap; @@ -78,6 +77,7 @@ use rustc_data_structures::steal::Steal; use rustc_data_structures::svh::Svh; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::ErrorGuaranteed; +use rustc_hir::attrs::StrippedCfgItem; use rustc_hir::def::{DefKind, DocLinkResMap}; use rustc_hir::def_id::{ CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap, LocalDefIdSet, LocalModDefId, @@ -101,7 +101,7 @@ use rustc_span::def_id::LOCAL_CRATE; use rustc_span::source_map::Spanned; use rustc_span::{DUMMY_SP, Span, Symbol}; use rustc_target::spec::PanicStrategy; -use {rustc_abi as abi, rustc_ast as ast, rustc_attr_data_structures as attr, rustc_hir as hir}; +use {rustc_abi as abi, rustc_ast as ast, rustc_hir as hir}; use crate::infer::canonical::{self, Canonical}; use crate::lint::LintExpectation; @@ -1178,11 +1178,10 @@ rustc_queries! { /// Return the live symbols in the crate for dead code check. /// - /// The second return value maps from ADTs to ignored derived traits (e.g. Debug and Clone) and - /// their respective impl (i.e., part of the derive macro) + /// The second return value maps from ADTs to ignored derived traits (e.g. Debug and Clone). query live_symbols_and_ignored_derived_traits(_: ()) -> &'tcx ( LocalDefIdSet, - LocalDefIdMap<FxIndexSet<(DefId, DefId)>> + LocalDefIdMap<FxIndexSet<DefId>>, ) { arena_cache desc { "finding live symbols in crate" } @@ -1390,9 +1389,11 @@ rustc_queries! { eval_always desc { "checking effective visibilities" } } - query check_private_in_public(_: ()) { - eval_always - desc { "checking for private elements in public interfaces" } + query check_private_in_public(module_def_id: LocalModDefId) { + desc { |tcx| + "checking for private elements in public interfaces for {}", + describe_as_module(module_def_id, tcx) + } } query reachable_set(_: ()) -> &'tcx LocalDefIdSet { @@ -1455,19 +1456,19 @@ rustc_queries! { cache_on_disk_if { true } } - query lookup_stability(def_id: DefId) -> Option<attr::Stability> { + query lookup_stability(def_id: DefId) -> Option<hir::Stability> { desc { |tcx| "looking up stability of `{}`", tcx.def_path_str(def_id) } cache_on_disk_if { def_id.is_local() } separate_provide_extern } - query lookup_const_stability(def_id: DefId) -> Option<attr::ConstStability> { + query lookup_const_stability(def_id: DefId) -> Option<hir::ConstStability> { desc { |tcx| "looking up const stability of `{}`", tcx.def_path_str(def_id) } cache_on_disk_if { def_id.is_local() } separate_provide_extern } - query lookup_default_body_stability(def_id: DefId) -> Option<attr::DefaultBodyStability> { + query lookup_default_body_stability(def_id: DefId) -> Option<hir::DefaultBodyStability> { desc { |tcx| "looking up default body stability of `{}`", tcx.def_path_str(def_id) } separate_provide_extern } diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 730c1147684..3dd6d2c8928 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -838,6 +838,8 @@ pub enum PatKind<'tcx> { /// * integer, bool, char or float (represented as a valtree), which will be handled by /// exhaustiveness to cover exactly its own value, similar to `&str`, but these values are /// much simpler. + /// * raw pointers derived from integers, other raw pointers will have already resulted in an + // error. /// * `String`, if `string_deref_patterns` is enabled. Constant { value: mir::Const<'tcx>, diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 3bf80d37e65..df82c7a826b 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -4,15 +4,15 @@ use std::ops::Range; use std::str; use rustc_abi::{FIRST_VARIANT, ReprOptions, VariantIdx}; -use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hasher::{HashStable, HashingControls, StableHasher}; use rustc_errors::ErrorGuaranteed; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::{self as hir, LangItem}; +use rustc_hir::{self as hir, LangItem, find_attr}; use rustc_index::{IndexSlice, IndexVec}; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_query_system::ich::StableHashingContext; diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index 1d15e4de7b6..a902a8a61e5 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -1,8 +1,9 @@ -use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::sorted_map::SortedIndexMultiMap; use rustc_hir as hir; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{DefKind, Namespace}; use rustc_hir::def_id::DefId; +use rustc_hir::find_attr; use rustc_macros::{Decodable, Encodable, HashStable}; use rustc_span::{Ident, Symbol}; diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 335b889b14d..95759d1f31a 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -510,12 +510,9 @@ impl_decodable_via_ref! { &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, &'tcx traits::ImplSource<'tcx, ()>, &'tcx mir::Body<'tcx>, - &'tcx mir::ConcreteOpaqueTypes<'tcx>, &'tcx ty::List<ty::BoundVariableKind>, &'tcx ty::List<ty::Pattern<'tcx>>, &'tcx ty::ListWithCachedTypeInfo<ty::Clause<'tcx>>, - &'tcx ty::List<FieldIdx>, - &'tcx ty::List<(VariantIdx, FieldIdx)>, } #[macro_export] diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index fd1aa4042bc..614b6471f18 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -93,9 +93,9 @@ impl<'tcx> Const<'tcx> { pub fn new_bound( tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, - var: ty::BoundVar, + bound_const: ty::BoundConst, ) -> Const<'tcx> { - Const::new(tcx, ty::ConstKind::Bound(debruijn, var)) + Const::new(tcx, ty::ConstKind::Bound(debruijn, bound_const)) } #[inline] @@ -168,12 +168,16 @@ impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> { Const::new_var(tcx, vid) } - fn new_bound(interner: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self { - Const::new_bound(interner, debruijn, var) + fn new_bound( + interner: TyCtxt<'tcx>, + debruijn: ty::DebruijnIndex, + bound_const: ty::BoundConst, + ) -> Self { + Const::new_bound(interner, debruijn, bound_const) } fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self { - Const::new_bound(tcx, debruijn, var) + Const::new_bound(tcx, debruijn, ty::BoundConst { var }) } fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderConst) -> Self { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 6f21160d1f6..db56082c71a 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -17,7 +17,6 @@ use std::{fmt, iter, mem}; use rustc_abi::{ExternAbi, FieldIdx, Layout, LayoutData, TargetDataLayout, VariantIdx}; use rustc_ast as ast; -use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::defer; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; @@ -33,12 +32,13 @@ use rustc_data_structures::sync::{ use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, LintDiagnostic, LintEmitter, MultiSpan, }; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::definitions::{DefPathData, Definitions, DisambiguatorState}; use rustc_hir::intravisit::VisitorExt; use rustc_hir::lang_items::LangItem; -use rustc_hir::{self as hir, Attribute, HirId, Node, TraitCandidate}; +use rustc_hir::{self as hir, Attribute, HirId, Node, TraitCandidate, find_attr}; use rustc_index::IndexVec; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_query_system::cache::WithDepNode; @@ -152,7 +152,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type PlaceholderConst = ty::PlaceholderConst; type ParamConst = ty::ParamConst; - type BoundConst = ty::BoundVar; + type BoundConst = ty::BoundConst; type ValueConst = ty::Value<'tcx>; type ExprConst = ty::Expr<'tcx>; type ValTree = ty::ValTree<'tcx>; @@ -1381,7 +1381,7 @@ impl<'tcx> TyCtxtFeed<'tcx, LocalDefId> { let bodies = Default::default(); let attrs = hir::AttributeMap::EMPTY; - let (opt_hash_including_bodies, _, _) = + let rustc_middle::hir::Hashes { opt_hash_including_bodies, .. } = self.tcx.hash_owner_nodes(node, &bodies, &attrs.map, &[], attrs.define_opaque); let node = node.into(); self.opt_hir_owner_nodes(Some(self.tcx.arena.alloc(hir::OwnerNodes { diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index b122ada0925..b3042904a29 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -7,14 +7,14 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_errors::{ Applicability, Diag, DiagArgValue, IntoDiagArg, into_diag_arg_using_display, listify, pluralize, }; -use rustc_hir::def::DefKind; +use rustc_hir::def::{DefKind, Namespace}; use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, AmbigArg, LangItem, PredicateOrigin, WherePredicateKind}; use rustc_span::{BytePos, Span}; use rustc_type_ir::TyKind::*; use crate::ty::{ - self, AliasTy, Const, ConstKind, FallibleTypeFolder, InferConst, InferTy, Opaque, + self, AliasTy, Const, ConstKind, FallibleTypeFolder, InferConst, InferTy, Instance, Opaque, PolyTraitPredicate, Projection, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor, }; @@ -28,6 +28,15 @@ impl IntoDiagArg for Ty<'_> { } } +impl IntoDiagArg for Instance<'_> { + fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue { + ty::tls::with(|tcx| { + let instance = tcx.short_string_namespace(self, path, Namespace::ValueNS); + rustc_errors::DiagArgValue::Str(std::borrow::Cow::Owned(instance)) + }) + } +} + into_diag_arg_using_display! { ty::Region<'_>, } diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 13723874ad3..3f854038651 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -160,7 +160,11 @@ impl<'tcx> Ty<'tcx> { _ => { let width = tcx.sess.diagnostic_width(); let length_limit = std::cmp::max(width / 4, 40); - format!("`{}`", tcx.string_with_limit(self, length_limit)).into() + format!( + "`{}`", + tcx.string_with_limit(self, length_limit, hir::def::Namespace::TypeNS) + ) + .into() } } } @@ -213,13 +217,13 @@ impl<'tcx> Ty<'tcx> { } impl<'tcx> TyCtxt<'tcx> { - pub fn string_with_limit<T>(self, p: T, length_limit: usize) -> String + pub fn string_with_limit<T>(self, t: T, length_limit: usize, ns: hir::def::Namespace) -> String where T: Copy + for<'a, 'b> Lift<TyCtxt<'b>, Lifted: Print<'b, FmtPrinter<'a, 'b>>>, { let mut type_limit = 50; - let regular = FmtPrinter::print_string(self, hir::def::Namespace::TypeNS, |cx| { - self.lift(p).expect("could not lift for printing").print(cx) + let regular = FmtPrinter::print_string(self, ns, |p| { + self.lift(t).expect("could not lift for printing").print(p) }) .expect("could not write to `String`"); if regular.len() <= length_limit { @@ -229,16 +233,12 @@ impl<'tcx> TyCtxt<'tcx> { loop { // Look for the longest properly trimmed path that still fits in length_limit. short = with_forced_trimmed_paths!({ - let mut cx = FmtPrinter::new_with_limit( - self, - hir::def::Namespace::TypeNS, - rustc_session::Limit(type_limit), - ); - self.lift(p) + let mut p = FmtPrinter::new_with_limit(self, ns, rustc_session::Limit(type_limit)); + self.lift(t) .expect("could not lift for printing") - .print(&mut cx) + .print(&mut p) .expect("could not print type"); - cx.into_buffer() + p.into_buffer() }); if short.len() <= length_limit || type_limit == 0 { break; @@ -251,13 +251,29 @@ impl<'tcx> TyCtxt<'tcx> { /// When calling this after a `Diag` is constructed, the preferred way of doing so is /// `tcx.short_string(ty, diag.long_ty_path())`. The diagnostic itself is the one that keeps /// the existence of a "long type" anywhere in the diagnostic, so the note telling the user + /// where we wrote the file to is only printed once. The path will use the type namespace. + pub fn short_string<T>(self, t: T, path: &mut Option<PathBuf>) -> String + where + T: Copy + Hash + for<'a, 'b> Lift<TyCtxt<'b>, Lifted: Print<'b, FmtPrinter<'a, 'b>>>, + { + self.short_string_namespace(t, path, hir::def::Namespace::TypeNS) + } + + /// When calling this after a `Diag` is constructed, the preferred way of doing so is + /// `tcx.short_string(ty, diag.long_ty_path())`. The diagnostic itself is the one that keeps + /// the existence of a "long type" anywhere in the diagnostic, so the note telling the user /// where we wrote the file to is only printed once. - pub fn short_string<T>(self, p: T, path: &mut Option<PathBuf>) -> String + pub fn short_string_namespace<T>( + self, + t: T, + path: &mut Option<PathBuf>, + namespace: hir::def::Namespace, + ) -> String where T: Copy + Hash + for<'a, 'b> Lift<TyCtxt<'b>, Lifted: Print<'b, FmtPrinter<'a, 'b>>>, { - let regular = FmtPrinter::print_string(self, hir::def::Namespace::TypeNS, |cx| { - self.lift(p).expect("could not lift for printing").print(cx) + let regular = FmtPrinter::print_string(self, namespace, |p| { + self.lift(t).expect("could not lift for printing").print(p) }) .expect("could not write to `String`"); @@ -270,13 +286,13 @@ impl<'tcx> TyCtxt<'tcx> { if regular.len() <= width * 2 / 3 { return regular; } - let short = self.string_with_limit(p, length_limit); + let short = self.string_with_limit(t, length_limit, namespace); if regular == short { return regular; } // Ensure we create an unique file for the type passed in when we create a file. let mut s = DefaultHasher::new(); - p.hash(&mut s); + t.hash(&mut s); let hash = s.finish(); *path = Some(path.take().unwrap_or_else(|| { self.output_filenames(()).temp_path_for_diagnostic(&format!("long-type-{hash}.txt")) diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index b2057fa36d7..7d56ec1635f 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -3,7 +3,7 @@ use rustc_hir::def_id::DefId; use rustc_type_ir::data_structures::DelayedMap; use crate::ty::{ - self, Binder, BoundTy, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, + self, Binder, BoundConst, BoundTy, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; @@ -60,7 +60,7 @@ where pub trait BoundVarReplacerDelegate<'tcx> { fn replace_region(&mut self, br: ty::BoundRegion) -> ty::Region<'tcx>; fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx>; - fn replace_const(&mut self, bv: ty::BoundVar) -> ty::Const<'tcx>; + fn replace_const(&mut self, bc: ty::BoundConst) -> ty::Const<'tcx>; } /// A simple delegate taking 3 mutable functions. The used functions must @@ -69,7 +69,7 @@ pub trait BoundVarReplacerDelegate<'tcx> { pub struct FnMutDelegate<'a, 'tcx> { pub regions: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a), pub types: &'a mut (dyn FnMut(ty::BoundTy) -> Ty<'tcx> + 'a), - pub consts: &'a mut (dyn FnMut(ty::BoundVar) -> ty::Const<'tcx> + 'a), + pub consts: &'a mut (dyn FnMut(ty::BoundConst) -> ty::Const<'tcx> + 'a), } impl<'a, 'tcx> BoundVarReplacerDelegate<'tcx> for FnMutDelegate<'a, 'tcx> { @@ -79,8 +79,8 @@ impl<'a, 'tcx> BoundVarReplacerDelegate<'tcx> for FnMutDelegate<'a, 'tcx> { fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx> { (self.types)(bt) } - fn replace_const(&mut self, bv: ty::BoundVar) -> ty::Const<'tcx> { - (self.consts)(bv) + fn replace_const(&mut self, bc: ty::BoundConst) -> ty::Const<'tcx> { + (self.consts)(bc) } } @@ -300,7 +300,13 @@ impl<'tcx> TyCtxt<'tcx> { ty::BoundTy { var: shift_bv(t.var), kind: t.kind }, ) }, - consts: &mut |c| ty::Const::new_bound(self, ty::INNERMOST, shift_bv(c)), + consts: &mut |c| { + ty::Const::new_bound( + self, + ty::INNERMOST, + ty::BoundConst { var: shift_bv(c.var) }, + ) + }, }, ) } @@ -343,12 +349,12 @@ impl<'tcx> TyCtxt<'tcx> { .expect_ty(); Ty::new_bound(self.tcx, ty::INNERMOST, BoundTy { var, kind }) } - fn replace_const(&mut self, bv: ty::BoundVar) -> ty::Const<'tcx> { - let entry = self.map.entry(bv); + fn replace_const(&mut self, bc: ty::BoundConst) -> ty::Const<'tcx> { + let entry = self.map.entry(bc.var); let index = entry.index(); let var = ty::BoundVar::from_usize(index); let () = entry.or_insert_with(|| ty::BoundVariableKind::Const).expect_const(); - ty::Const::new_bound(self.tcx, ty::INNERMOST, var) + ty::Const::new_bound(self.tcx, ty::INNERMOST, BoundConst { var }) } } diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 7d34d8df3f3..648709e88e6 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -96,14 +96,12 @@ impl<'tcx> rustc_type_ir::inherent::GenericArgs<TyCtxt<'tcx>> for ty::GenericArg signature_parts_ty, tupled_upvars_ty, coroutine_captures_by_ref_ty, - coroutine_witness_ty, ] => ty::CoroutineClosureArgsParts { parent_args, closure_kind_ty: closure_kind_ty.expect_ty(), signature_parts_ty: signature_parts_ty.expect_ty(), tupled_upvars_ty: tupled_upvars_ty.expect_ty(), coroutine_captures_by_ref_ty: coroutine_captures_by_ref_ty.expect_ty(), - coroutine_witness_ty: coroutine_witness_ty.expect_ty(), }, _ => bug!("closure args missing synthetics"), } @@ -111,23 +109,16 @@ impl<'tcx> rustc_type_ir::inherent::GenericArgs<TyCtxt<'tcx>> for ty::GenericArg fn split_coroutine_args(self) -> ty::CoroutineArgsParts<TyCtxt<'tcx>> { match self[..] { - [ - ref parent_args @ .., - kind_ty, - resume_ty, - yield_ty, - return_ty, - witness, - tupled_upvars_ty, - ] => ty::CoroutineArgsParts { - parent_args, - kind_ty: kind_ty.expect_ty(), - resume_ty: resume_ty.expect_ty(), - yield_ty: yield_ty.expect_ty(), - return_ty: return_ty.expect_ty(), - witness: witness.expect_ty(), - tupled_upvars_ty: tupled_upvars_ty.expect_ty(), - }, + [ref parent_args @ .., kind_ty, resume_ty, yield_ty, return_ty, tupled_upvars_ty] => { + ty::CoroutineArgsParts { + parent_args, + kind_ty: kind_ty.expect_ty(), + resume_ty: resume_ty.expect_ty(), + yield_ty: yield_ty.expect_ty(), + return_ty: return_ty.expect_ty(), + tupled_upvars_ty: tupled_upvars_ty.expect_ty(), + } + } _ => bug!("coroutine args missing synthetics"), } } @@ -536,21 +527,28 @@ impl<'tcx> GenericArgs<'tcx> { #[inline] #[track_caller] pub fn type_at(&self, i: usize) -> Ty<'tcx> { - self[i].as_type().unwrap_or_else(|| bug!("expected type for param #{} in {:?}", i, self)) + self[i].as_type().unwrap_or_else( + #[track_caller] + || bug!("expected type for param #{} in {:?}", i, self), + ) } #[inline] #[track_caller] pub fn region_at(&self, i: usize) -> ty::Region<'tcx> { - self[i] - .as_region() - .unwrap_or_else(|| bug!("expected region for param #{} in {:?}", i, self)) + self[i].as_region().unwrap_or_else( + #[track_caller] + || bug!("expected region for param #{} in {:?}", i, self), + ) } #[inline] #[track_caller] pub fn const_at(&self, i: usize) -> ty::Const<'tcx> { - self[i].as_const().unwrap_or_else(|| bug!("expected const for param #{} in {:?}", i, self)) + self[i].as_const().unwrap_or_else( + #[track_caller] + || bug!("expected const for param #{} in {:?}", i, self), + ) } #[inline] diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index d5767ca3786..3a51f79f121 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -1,6 +1,5 @@ use std::assert_matches::assert_matches; use std::fmt; -use std::path::PathBuf; use rustc_data_structures::fx::FxHashMap; use rustc_errors::ErrorGuaranteed; @@ -17,7 +16,7 @@ use tracing::{debug, instrument}; use crate::error; use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::ty::normalize_erasing_regions::NormalizationError; -use crate::ty::print::{FmtPrinter, Printer, shrunk_instance_name}; +use crate::ty::print::{FmtPrinter, Print}; use crate::ty::{ self, EarlyBinder, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, @@ -212,7 +211,7 @@ impl<'tcx> Instance<'tcx> { if !tcx.sess.opts.share_generics() // However, if the def_id is marked inline(never), then it's fine to just reuse the // upstream monomorphization. - && tcx.codegen_fn_attrs(self.def_id()).inline != rustc_attr_data_structures::InlineAttr::Never + && tcx.codegen_fn_attrs(self.def_id()).inline != rustc_hir::attrs::InlineAttr::Never { return None; } @@ -389,59 +388,15 @@ fn type_length<'tcx>(item: impl TypeVisitable<TyCtxt<'tcx>>) -> usize { visitor.type_length } -pub fn fmt_instance( - f: &mut fmt::Formatter<'_>, - instance: Instance<'_>, - type_length: Option<rustc_session::Limit>, -) -> fmt::Result { - ty::tls::with(|tcx| { - let args = tcx.lift(instance.args).expect("could not lift for printing"); - - let mut cx = if let Some(type_length) = type_length { - FmtPrinter::new_with_limit(tcx, Namespace::ValueNS, type_length) - } else { - FmtPrinter::new(tcx, Namespace::ValueNS) - }; - cx.print_def_path(instance.def_id(), args)?; - let s = cx.into_buffer(); - f.write_str(&s) - })?; - - match instance.def { - InstanceKind::Item(_) => Ok(()), - InstanceKind::VTableShim(_) => write!(f, " - shim(vtable)"), - InstanceKind::ReifyShim(_, None) => write!(f, " - shim(reify)"), - InstanceKind::ReifyShim(_, Some(ReifyReason::FnPtr)) => write!(f, " - shim(reify-fnptr)"), - InstanceKind::ReifyShim(_, Some(ReifyReason::Vtable)) => write!(f, " - shim(reify-vtable)"), - InstanceKind::ThreadLocalShim(_) => write!(f, " - shim(tls)"), - InstanceKind::Intrinsic(_) => write!(f, " - intrinsic"), - InstanceKind::Virtual(_, num) => write!(f, " - virtual#{num}"), - InstanceKind::FnPtrShim(_, ty) => write!(f, " - shim({ty})"), - InstanceKind::ClosureOnceShim { .. } => write!(f, " - shim"), - InstanceKind::ConstructCoroutineInClosureShim { .. } => write!(f, " - shim"), - InstanceKind::DropGlue(_, None) => write!(f, " - shim(None)"), - InstanceKind::DropGlue(_, Some(ty)) => write!(f, " - shim(Some({ty}))"), - InstanceKind::CloneShim(_, ty) => write!(f, " - shim({ty})"), - InstanceKind::FnPtrAddrShim(_, ty) => write!(f, " - shim({ty})"), - InstanceKind::FutureDropPollShim(_, proxy_ty, impl_ty) => { - write!(f, " - dropshim({proxy_ty}-{impl_ty})") - } - InstanceKind::AsyncDropGlue(_, ty) => write!(f, " - shim({ty})"), - InstanceKind::AsyncDropGlueCtorShim(_, ty) => write!(f, " - shim(Some({ty}))"), - } -} - -pub struct ShortInstance<'tcx>(pub Instance<'tcx>, pub usize); - -impl<'tcx> fmt::Display for ShortInstance<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt_instance(f, self.0, Some(rustc_session::Limit(self.1))) - } -} - impl<'tcx> fmt::Display for Instance<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt_instance(f, *self, None) + ty::tls::with(|tcx| { + let mut p = FmtPrinter::new(tcx, Namespace::ValueNS); + let instance = tcx.lift(*self).expect("could not lift for printing"); + instance.print(&mut p)?; + let s = p.into_buffer(); + f.write_str(&s) + }) } } @@ -610,23 +565,12 @@ impl<'tcx> Instance<'tcx> { Ok(None) => { let type_length = type_length(args); if !tcx.type_length_limit().value_within_limit(type_length) { - let (shrunk, written_to_path) = - shrunk_instance_name(tcx, Instance::new_raw(def_id, args)); - let mut path = PathBuf::new(); - let was_written = if let Some(path2) = written_to_path { - path = path2; - true - } else { - false - }; tcx.dcx().emit_fatal(error::TypeLengthLimit { // We don't use `def_span(def_id)` so that diagnostics point // to the crate root during mono instead of to foreign items. // This is arguably better. span: span_or_local_def_span(), - shrunk, - was_written, - path, + instance: Instance::new_raw(def_id, args), type_length, }); } else { diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index a5123576fc6..aed94f9aa04 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -107,8 +107,8 @@ impl abi::Integer { abi::Integer::I8 }; - // If there are no negative values, we can use the unsigned fit. - if min >= 0 { + // Pick the smallest fit. + if unsigned_fit <= signed_fit { (cmp::max(unsigned_fit, at_least), false) } else { (cmp::max(signed_fit, at_least), true) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index bb70c61cd14..73e1661106e 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -27,17 +27,17 @@ pub use intrinsic::IntrinsicDef; use rustc_abi::{Align, FieldIdx, Integer, IntegerType, ReprFlags, ReprOptions, VariantIdx}; use rustc_ast::node_id::NodeMap; pub use rustc_ast_ir::{Movability, Mutability, try_visit}; -use rustc_attr_data_structures::{AttributeKind, StrippedCfgItem, find_attr}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::steal::Steal; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::{Diag, ErrorGuaranteed}; -use rustc_hir::LangItem; +use rustc_hir::attrs::{AttributeKind, StrippedCfgItem}; use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap}; use rustc_hir::definitions::DisambiguatorState; +use rustc_hir::{LangItem, attrs as attr, find_attr}; use rustc_index::IndexVec; use rustc_index::bit_set::BitMatrix; use rustc_macros::{ @@ -49,7 +49,7 @@ use rustc_serialize::{Decodable, Encodable}; use rustc_session::lint::LintBuffer; pub use rustc_session::lint::RegisteredTools; use rustc_span::hygiene::MacroKind; -use rustc_span::{DUMMY_SP, ExpnId, ExpnKind, Ident, Span, Symbol, kw, sym}; +use rustc_span::{DUMMY_SP, ExpnId, ExpnKind, Ident, Span, Symbol, sym}; pub use rustc_type_ir::data_structures::{DelayedMap, DelayedSet}; pub use rustc_type_ir::fast_reject::DeepRejectCtxt; #[allow( @@ -65,7 +65,7 @@ pub use rustc_type_ir::*; use rustc_type_ir::{InferCtxtLike, Interner}; use tracing::{debug, instrument}; pub use vtable::*; -use {rustc_ast as ast, rustc_attr_data_structures as attr, rustc_hir as hir}; +use {rustc_ast as ast, rustc_hir as hir}; pub use self::closure::{ BorrowKind, CAPTURE_STRUCT_LOCAL, CaptureInfo, CapturedPlace, ClosureTypeInfo, @@ -82,10 +82,9 @@ pub use self::context::{ TyCtxtFeed, tls, }; pub use self::fold::*; -pub use self::instance::{Instance, InstanceKind, ReifyReason, ShortInstance, UnusedGenericParams}; +pub use self::instance::{Instance, InstanceKind, ReifyReason, UnusedGenericParams}; pub use self::list::{List, ListWithCachedTypeInfo}; pub use self::opaque_types::OpaqueTypeKey; -pub use self::parameterized::ParameterizedOverTcx; pub use self::pattern::{Pattern, PatternKind}; pub use self::predicate::{ AliasTerm, ArgOutlivesPredicate, Clause, ClauseKind, CoercePredicate, ExistentialPredicate, @@ -158,7 +157,6 @@ mod instance; mod intrinsic; mod list; mod opaque_types; -mod parameterized; mod predicate; mod region; mod rvalue_scopes; @@ -170,11 +168,6 @@ mod visit; // Data types -pub struct ResolverOutputs { - pub global_ctxt: ResolverGlobalCtxt, - pub ast_lowering: ResolverAstLowering, -} - #[derive(Debug, HashStable)] pub struct ResolverGlobalCtxt { pub visibilities_for_hashing: Vec<(LocalDefId, Visibility)>, @@ -255,18 +248,6 @@ impl MainDefinition { } } -/// The "header" of an impl is everything outside the body: a Self type, a trait -/// ref (in the case of a trait impl), and a set of predicates (from the -/// bounds / where-clauses). -#[derive(Clone, Debug, TypeFoldable, TypeVisitable)] -pub struct ImplHeader<'tcx> { - pub impl_def_id: DefId, - pub impl_args: ty::GenericArgsRef<'tcx>, - pub self_ty: Ty<'tcx>, - pub trait_ref: Option<TraitRef<'tcx>>, - pub predicates: Vec<Predicate<'tcx>>, -} - #[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)] pub struct ImplTraitHeader<'tcx> { pub trait_ref: ty::EarlyBinder<'tcx, ty::TraitRef<'tcx>>, @@ -470,14 +451,6 @@ impl<'tcx> rustc_type_ir::Flags for Ty<'tcx> { } } -impl EarlyParamRegion { - /// Does this early bound region have a name? Early bound regions normally - /// always have names except when using anonymous lifetimes (`'_`). - pub fn is_named(&self) -> bool { - self.name != kw::UnderscoreLifetime - } -} - /// The crate outlives map is computed during typeck and contains the /// outlives of every item in the local crate. You should not use it /// directly, because to do so will make your pass dependent on the @@ -698,39 +671,6 @@ impl<'tcx> TermKind<'tcx> { } } -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum ParamTerm { - Ty(ParamTy), - Const(ParamConst), -} - -impl ParamTerm { - pub fn index(self) -> usize { - match self { - ParamTerm::Ty(ty) => ty.index as usize, - ParamTerm::Const(ct) => ct.index as usize, - } - } -} - -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub enum TermVid { - Ty(ty::TyVid), - Const(ty::ConstVid), -} - -impl From<ty::TyVid> for TermVid { - fn from(value: ty::TyVid) -> Self { - TermVid::Ty(value) - } -} - -impl From<ty::ConstVid> for TermVid { - fn from(value: ty::ConstVid) -> Self { - TermVid::Const(value) - } -} - /// Represents the bounds declared on a particular set of type /// parameters. Should eventually be generalized into a flag list of /// where-clauses. You can obtain an `InstantiatedPredicates` list from a @@ -968,34 +908,43 @@ impl<'tcx> rustc_type_ir::inherent::PlaceholderLike<TyCtxt<'tcx>> for Placeholde #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)] #[derive(TyEncodable, TyDecodable)] -pub struct BoundConst<'tcx> { +pub struct BoundConst { pub var: BoundVar, - pub ty: Ty<'tcx>, } -pub type PlaceholderConst = Placeholder<BoundVar>; +impl<'tcx> rustc_type_ir::inherent::BoundVarLike<TyCtxt<'tcx>> for BoundConst { + fn var(self) -> BoundVar { + self.var + } + + fn assert_eq(self, var: ty::BoundVariableKind) { + var.expect_const() + } +} + +pub type PlaceholderConst = Placeholder<BoundConst>; impl<'tcx> rustc_type_ir::inherent::PlaceholderLike<TyCtxt<'tcx>> for PlaceholderConst { - type Bound = BoundVar; + type Bound = BoundConst; fn universe(self) -> UniverseIndex { self.universe } fn var(self) -> BoundVar { - self.bound + self.bound.var } fn with_updated_universe(self, ui: UniverseIndex) -> Self { Placeholder { universe: ui, ..self } } - fn new(ui: UniverseIndex, bound: BoundVar) -> Self { + fn new(ui: UniverseIndex, bound: BoundConst) -> Self { Placeholder { universe: ui, bound } } fn new_anon(ui: UniverseIndex, var: BoundVar) -> Self { - Placeholder { universe: ui, bound: var } + Placeholder { universe: ui, bound: BoundConst { var } } } } @@ -1069,12 +1018,6 @@ pub struct ParamEnvAnd<'tcx, T> { pub value: T, } -impl<'tcx, T> ParamEnvAnd<'tcx, T> { - pub fn into_parts(self) -> (ParamEnv<'tcx>, T) { - (self.param_env, self.value) - } -} - /// The environment in which to do trait solving. /// /// Most of the time you only need to care about the `ParamEnv` @@ -1088,6 +1031,8 @@ impl<'tcx, T> ParamEnvAnd<'tcx, T> { #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)] #[derive(TypeVisitable, TypeFoldable)] pub struct TypingEnv<'tcx> { + #[type_foldable(identity)] + #[type_visitable(ignore)] pub typing_mode: TypingMode<'tcx>, pub param_env: ParamEnv<'tcx>, } @@ -1525,7 +1470,7 @@ impl<'tcx> TyCtxt<'tcx> { } if let Some(reprs) = - attr::find_attr!(self.get_all_attrs(did), AttributeKind::Repr { reprs, .. } => reprs) + find_attr!(self.get_all_attrs(did), AttributeKind::Repr { reprs, .. } => reprs) { for (r, _) in reprs { flags.insert(match *r { @@ -1770,15 +1715,6 @@ impl<'tcx> TyCtxt<'tcx> { } } - // FIXME(@lcnr): Remove this function. - pub fn get_attrs_unchecked(self, did: DefId) -> &'tcx [hir::Attribute] { - if let Some(did) = did.as_local() { - self.hir_attrs(self.local_def_id_to_hir_id(did)) - } else { - self.attrs_for_def(did) - } - } - /// Gets all attributes with the given name. pub fn get_attrs( self, @@ -1790,7 +1726,8 @@ impl<'tcx> TyCtxt<'tcx> { /// Gets all attributes. /// - /// To see if an item has a specific attribute, you should use [`rustc_attr_data_structures::find_attr!`] so you can use matching. + /// To see if an item has a specific attribute, you should use + /// [`rustc_hir::find_attr!`] so you can use matching. pub fn get_all_attrs(self, did: impl Into<DefId>) -> &'tcx [hir::Attribute] { let did: DefId = did.into(); if let Some(did) = did.as_local() { @@ -2198,59 +2135,6 @@ impl<'tcx> TyCtxt<'tcx> { } } -pub fn int_ty(ity: ast::IntTy) -> IntTy { - match ity { - ast::IntTy::Isize => IntTy::Isize, - ast::IntTy::I8 => IntTy::I8, - ast::IntTy::I16 => IntTy::I16, - ast::IntTy::I32 => IntTy::I32, - ast::IntTy::I64 => IntTy::I64, - ast::IntTy::I128 => IntTy::I128, - } -} - -pub fn uint_ty(uty: ast::UintTy) -> UintTy { - match uty { - ast::UintTy::Usize => UintTy::Usize, - ast::UintTy::U8 => UintTy::U8, - ast::UintTy::U16 => UintTy::U16, - ast::UintTy::U32 => UintTy::U32, - ast::UintTy::U64 => UintTy::U64, - ast::UintTy::U128 => UintTy::U128, - } -} - -pub fn float_ty(fty: ast::FloatTy) -> FloatTy { - match fty { - ast::FloatTy::F16 => FloatTy::F16, - ast::FloatTy::F32 => FloatTy::F32, - ast::FloatTy::F64 => FloatTy::F64, - ast::FloatTy::F128 => FloatTy::F128, - } -} - -pub fn ast_int_ty(ity: IntTy) -> ast::IntTy { - match ity { - IntTy::Isize => ast::IntTy::Isize, - IntTy::I8 => ast::IntTy::I8, - IntTy::I16 => ast::IntTy::I16, - IntTy::I32 => ast::IntTy::I32, - IntTy::I64 => ast::IntTy::I64, - IntTy::I128 => ast::IntTy::I128, - } -} - -pub fn ast_uint_ty(uty: UintTy) -> ast::UintTy { - match uty { - UintTy::Usize => ast::UintTy::Usize, - UintTy::U8 => ast::UintTy::U8, - UintTy::U16 => ast::UintTy::U16, - UintTy::U32 => ast::UintTy::U32, - UintTy::U64 => ast::UintTy::U64, - UintTy::U128 => ast::UintTy::U128, - } -} - pub fn provide(providers: &mut Providers) { closure::provide(providers); context::provide(providers); @@ -2304,34 +2188,9 @@ impl<'tcx> fmt::Debug for SymbolName<'tcx> { } } -#[derive(Debug, Default, Copy, Clone)] -pub struct InferVarInfo { - /// This is true if we identified that this Ty (`?T`) is found in a `?T: Foo` - /// obligation, where: - /// - /// * `Foo` is not `Sized` - /// * `(): Foo` may be satisfied - pub self_in_trait: bool, - /// This is true if we identified that this Ty (`?T`) is found in a `<_ as - /// _>::AssocType = ?T` - pub output: bool, -} - /// The constituent parts of a type level constant of kind ADT or array. #[derive(Copy, Clone, Debug, HashStable)] pub struct DestructuredConst<'tcx> { pub variant: Option<VariantIdx>, pub fields: &'tcx [ty::Const<'tcx>], } - -// Some types are used a lot. Make sure they don't unintentionally get bigger. -#[cfg(target_pointer_width = "64")] -mod size_asserts { - use rustc_data_structures::static_assert_size; - - use super::*; - // tidy-alphabetical-start - static_assert_size!(PredicateKind<'_>, 32); - static_assert_size!(WithCachedTypeInfo<TyKind<'_>>, 48); - // tidy-alphabetical-end -} diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs deleted file mode 100644 index dbacbe21edb..00000000000 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ /dev/null @@ -1,155 +0,0 @@ -use std::hash::Hash; - -use rustc_data_structures::unord::UnordMap; -use rustc_hir::def_id::DefIndex; -use rustc_index::{Idx, IndexVec}; -use rustc_span::Symbol; - -use crate::ty; - -pub trait ParameterizedOverTcx: 'static { - type Value<'tcx>; -} - -impl<T: ParameterizedOverTcx> ParameterizedOverTcx for &'static [T] { - type Value<'tcx> = &'tcx [T::Value<'tcx>]; -} - -impl<T: ParameterizedOverTcx> ParameterizedOverTcx for Option<T> { - type Value<'tcx> = Option<T::Value<'tcx>>; -} - -impl<A: ParameterizedOverTcx, B: ParameterizedOverTcx> ParameterizedOverTcx for (A, B) { - type Value<'tcx> = (A::Value<'tcx>, B::Value<'tcx>); -} - -impl<T: ParameterizedOverTcx> ParameterizedOverTcx for Vec<T> { - type Value<'tcx> = Vec<T::Value<'tcx>>; -} - -impl<I: Idx + 'static, T: ParameterizedOverTcx> ParameterizedOverTcx for IndexVec<I, T> { - type Value<'tcx> = IndexVec<I, T::Value<'tcx>>; -} - -impl<I: Hash + Eq + 'static, T: ParameterizedOverTcx> ParameterizedOverTcx for UnordMap<I, T> { - type Value<'tcx> = UnordMap<I, T::Value<'tcx>>; -} - -impl<T: ParameterizedOverTcx> ParameterizedOverTcx for ty::Binder<'static, T> { - type Value<'tcx> = ty::Binder<'tcx, T::Value<'tcx>>; -} - -impl<T: ParameterizedOverTcx> ParameterizedOverTcx for ty::EarlyBinder<'static, T> { - type Value<'tcx> = ty::EarlyBinder<'tcx, T::Value<'tcx>>; -} - -#[macro_export] -macro_rules! trivially_parameterized_over_tcx { - ($($ty:ty),+ $(,)?) => { - $( - impl $crate::ty::ParameterizedOverTcx for $ty { - #[allow(unused_lifetimes)] - type Value<'tcx> = $ty; - } - )* - } -} - -trivially_parameterized_over_tcx! { - usize, - (), - u32, - u64, - bool, - std::string::String, - crate::metadata::ModChild, - crate::middle::codegen_fn_attrs::CodegenFnAttrs, - crate::middle::debugger_visualizer::DebuggerVisualizerFile, - crate::middle::exported_symbols::SymbolExportInfo, - crate::middle::lib_features::FeatureStability, - crate::middle::resolve_bound_vars::ObjectLifetimeDefault, - crate::mir::ConstQualifs, - ty::AsyncDestructor, - ty::AssocItemContainer, - ty::Asyncness, - ty::AnonConstKind, - ty::DeducedParamAttrs, - ty::Destructor, - ty::Generics, - ty::ImplPolarity, - ty::ImplTraitInTraitData, - ty::ReprOptions, - ty::TraitDef, - ty::UnusedGenericParams, - ty::Visibility<DefIndex>, - ty::adjustment::CoerceUnsizedInfo, - ty::fast_reject::SimplifiedType, - ty::IntrinsicDef, - rustc_ast::Attribute, - rustc_ast::DelimArgs, - rustc_attr_data_structures::StrippedCfgItem<rustc_hir::def_id::DefIndex>, - rustc_attr_data_structures::ConstStability, - rustc_attr_data_structures::DefaultBodyStability, - rustc_attr_data_structures::Deprecation, - rustc_attr_data_structures::Stability, - rustc_hir::Constness, - rustc_hir::Defaultness, - rustc_hir::Safety, - rustc_hir::CoroutineKind, - rustc_hir::IsAsync, - rustc_hir::LangItem, - rustc_hir::def::DefKind, - rustc_hir::def::DocLinkResMap, - rustc_hir::def_id::DefId, - rustc_hir::def_id::DefIndex, - rustc_hir::definitions::DefKey, - rustc_hir::OpaqueTyOrigin<rustc_hir::def_id::DefId>, - rustc_hir::PreciseCapturingArgKind<Symbol, Symbol>, - rustc_index::bit_set::DenseBitSet<u32>, - rustc_index::bit_set::FiniteBitSet<u32>, - rustc_session::cstore::ForeignModule, - rustc_session::cstore::LinkagePreference, - rustc_session::cstore::NativeLib, - rustc_session::config::TargetModifier, - rustc_span::ExpnData, - rustc_span::ExpnHash, - rustc_span::ExpnId, - rustc_span::SourceFile, - rustc_span::Span, - rustc_span::Symbol, - rustc_span::def_id::DefPathHash, - rustc_span::hygiene::SyntaxContextKey, - rustc_span::Ident, - rustc_type_ir::Variance, - rustc_hir::Attribute, -} - -// HACK(compiler-errors): This macro rule can only take a fake path, -// not a real, due to parsing ambiguity reasons. -#[macro_export] -macro_rules! parameterized_over_tcx { - ($($($fake_path:ident)::+),+ $(,)?) => { - $( - impl $crate::ty::ParameterizedOverTcx for $($fake_path)::+<'static> { - type Value<'tcx> = $($fake_path)::+<'tcx>; - } - )* - } -} - -parameterized_over_tcx! { - crate::middle::exported_symbols::ExportedSymbol, - crate::mir::Body, - crate::mir::CoroutineLayout, - crate::mir::interpret::ConstAllocation, - ty::Ty, - ty::FnSig, - ty::GenericPredicates, - ty::ConstConditions, - ty::TraitRef, - ty::Const, - ty::Predicate, - ty::Clause, - ty::ClauseKind, - ty::ImplTraitHeader, -} diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index 46f254e9d30..59e00f85957 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -6,8 +6,7 @@ use rustc_macros::{HashStable, extension}; use rustc_type_ir as ir; use crate::ty::{ - self, DebruijnIndex, EarlyBinder, PredicatePolarity, Ty, TyCtxt, TypeFlags, Upcast, UpcastFrom, - WithCachedTypeInfo, + self, DebruijnIndex, EarlyBinder, Ty, TyCtxt, TypeFlags, Upcast, UpcastFrom, WithCachedTypeInfo, }; pub type TraitRef<'tcx> = ir::TraitRef<TyCtxt<'tcx>>; @@ -536,15 +535,6 @@ impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ty::Binder<'tcx, TraitRef<'tcx>>> for Clause } } -impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ty::Binder<'tcx, TraitRef<'tcx>>> for PolyTraitPredicate<'tcx> { - fn upcast_from(from: ty::Binder<'tcx, TraitRef<'tcx>>, _tcx: TyCtxt<'tcx>) -> Self { - from.map_bound(|trait_ref| TraitPredicate { - trait_ref, - polarity: PredicatePolarity::Positive, - }) - } -} - impl<'tcx> UpcastFrom<TyCtxt<'tcx>, TraitPredicate<'tcx>> for Predicate<'tcx> { fn upcast_from(from: TraitPredicate<'tcx>, tcx: TyCtxt<'tcx>) -> Self { PredicateKind::Clause(ClauseKind::Trait(from)).upcast(tcx) @@ -704,3 +694,15 @@ impl<'tcx> Predicate<'tcx> { } } } + +// Some types are used a lot. Make sure they don't unintentionally get bigger. +#[cfg(target_pointer_width = "64")] +mod size_asserts { + use rustc_data_structures::static_assert_size; + + use super::*; + // tidy-alphabetical-start + static_assert_size!(PredicateKind<'_>, 32); + static_assert_size!(WithCachedTypeInfo<PredicateKind<'_>>, 56); + // tidy-alphabetical-end +} diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 9172c5d3ab7..efa017074db 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -1,5 +1,3 @@ -use std::path::PathBuf; - use hir::def::Namespace; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sso::SsoHashSet; @@ -8,7 +6,7 @@ use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; use tracing::{debug, instrument, trace}; -use crate::ty::{self, GenericArg, ShortInstance, Ty, TyCtxt}; +use crate::ty::{self, GenericArg, Ty, TyCtxt}; // `pretty` is a separate module only for organization. mod pretty; @@ -18,7 +16,7 @@ use super::Lift; pub type PrintError = std::fmt::Error; pub trait Print<'tcx, P> { - fn print(&self, cx: &mut P) -> Result<(), PrintError>; + fn print(&self, p: &mut P) -> Result<(), PrintError>; } /// Interface for outputting user-facing "type-system entities" @@ -88,7 +86,6 @@ pub trait Printer<'tcx>: Sized { fn path_append_impl( &mut self, print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, - disambiguated_data: &DisambiguatedDefPathData, self_ty: Ty<'tcx>, trait_ref: Option<ty::TraitRef<'tcx>>, ) -> Result<(), PrintError>; @@ -148,7 +145,7 @@ pub trait Printer<'tcx>: Sized { && args.len() > parent_args.len() { return self.path_generic_args( - |cx| cx.print_def_path(def_id, parent_args), + |p| p.print_def_path(def_id, parent_args), &args[..parent_args.len() + 1][..1], ); } else { @@ -170,7 +167,7 @@ pub trait Printer<'tcx>: Sized { if !generics.is_own_empty() && args.len() >= generics.count() { let args = generics.own_args_no_defaults(self.tcx(), args); return self.path_generic_args( - |cx| cx.print_def_path(def_id, parent_args), + |p| p.print_def_path(def_id, parent_args), args, ); } @@ -186,16 +183,16 @@ pub trait Printer<'tcx>: Sized { } self.path_append( - |cx: &mut Self| { + |p: &mut Self| { if trait_qualify_parent { let trait_ref = ty::TraitRef::new( - cx.tcx(), + p.tcx(), parent_def_id, parent_args.iter().copied(), ); - cx.path_qualified(trait_ref.self_ty(), Some(trait_ref)) + p.path_qualified(trait_ref.self_ty(), Some(trait_ref)) } else { - cx.print_def_path(parent_def_id, parent_args) + p.print_def_path(parent_def_id, parent_args) } }, &key.disambiguated_data, @@ -236,12 +233,7 @@ pub trait Printer<'tcx>: Sized { // If the impl is not co-located with either self-type or // trait-type, then fallback to a format that identifies // the module more clearly. - self.path_append_impl( - |cx| cx.print_def_path(parent_def_id, &[]), - &key.disambiguated_data, - self_ty, - impl_trait_ref, - ) + self.path_append_impl(|p| p.print_def_path(parent_def_id, &[]), self_ty, impl_trait_ref) } else { // Otherwise, try to give a good form that would be valid language // syntax. Preferably using associated item notation. @@ -312,26 +304,63 @@ pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> { } impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Region<'tcx> { - fn print(&self, cx: &mut P) -> Result<(), PrintError> { - cx.print_region(*self) + fn print(&self, p: &mut P) -> Result<(), PrintError> { + p.print_region(*self) } } impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for Ty<'tcx> { + fn print(&self, p: &mut P) -> Result<(), PrintError> { + p.print_type(*self) + } +} + +impl<'tcx, P: Printer<'tcx> + std::fmt::Write> Print<'tcx, P> for ty::Instance<'tcx> { fn print(&self, cx: &mut P) -> Result<(), PrintError> { - cx.print_type(*self) + cx.print_def_path(self.def_id(), self.args)?; + match self.def { + ty::InstanceKind::Item(_) => {} + ty::InstanceKind::VTableShim(_) => cx.write_str(" - shim(vtable)")?, + ty::InstanceKind::ReifyShim(_, None) => cx.write_str(" - shim(reify)")?, + ty::InstanceKind::ReifyShim(_, Some(ty::ReifyReason::FnPtr)) => { + cx.write_str(" - shim(reify-fnptr)")? + } + ty::InstanceKind::ReifyShim(_, Some(ty::ReifyReason::Vtable)) => { + cx.write_str(" - shim(reify-vtable)")? + } + ty::InstanceKind::ThreadLocalShim(_) => cx.write_str(" - shim(tls)")?, + ty::InstanceKind::Intrinsic(_) => cx.write_str(" - intrinsic")?, + ty::InstanceKind::Virtual(_, num) => cx.write_str(&format!(" - virtual#{num}"))?, + ty::InstanceKind::FnPtrShim(_, ty) => cx.write_str(&format!(" - shim({ty})"))?, + ty::InstanceKind::ClosureOnceShim { .. } => cx.write_str(" - shim")?, + ty::InstanceKind::ConstructCoroutineInClosureShim { .. } => cx.write_str(" - shim")?, + ty::InstanceKind::DropGlue(_, None) => cx.write_str(" - shim(None)")?, + ty::InstanceKind::DropGlue(_, Some(ty)) => { + cx.write_str(&format!(" - shim(Some({ty}))"))? + } + ty::InstanceKind::CloneShim(_, ty) => cx.write_str(&format!(" - shim({ty})"))?, + ty::InstanceKind::FnPtrAddrShim(_, ty) => cx.write_str(&format!(" - shim({ty})"))?, + ty::InstanceKind::FutureDropPollShim(_, proxy_ty, impl_ty) => { + cx.write_str(&format!(" - dropshim({proxy_ty}-{impl_ty})"))? + } + ty::InstanceKind::AsyncDropGlue(_, ty) => cx.write_str(&format!(" - shim({ty})"))?, + ty::InstanceKind::AsyncDropGlueCtorShim(_, ty) => { + cx.write_str(&format!(" - shim(Some({ty}))"))? + } + }; + Ok(()) } } impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> { - fn print(&self, cx: &mut P) -> Result<(), PrintError> { - cx.print_dyn_existential(self) + fn print(&self, p: &mut P) -> Result<(), PrintError> { + p.print_dyn_existential(self) } } impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Const<'tcx> { - fn print(&self, cx: &mut P) -> Result<(), PrintError> { - cx.print_const(*self) + fn print(&self, p: &mut P) -> Result<(), PrintError> { + p.print_const(*self) } } @@ -351,9 +380,9 @@ where { fn print(t: &T, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { ty::tls::with(|tcx| { - let mut cx = FmtPrinter::new(tcx, Namespace::TypeNS); - tcx.lift(*t).expect("could not lift for printing").print(&mut cx)?; - fmt.write_str(&cx.into_buffer())?; + let mut p = FmtPrinter::new(tcx, Namespace::TypeNS); + tcx.lift(*t).expect("could not lift for printing").print(&mut p)?; + fmt.write_str(&p.into_buffer())?; Ok(()) }) } @@ -362,31 +391,3 @@ where with_no_trimmed_paths!(Self::print(t, fmt)) } } - -/// Format instance name that is already known to be too long for rustc. -/// Show only the first 2 types if it is longer than 32 characters to avoid blasting -/// the user's terminal with thousands of lines of type-name. -/// -/// If the type name is longer than before+after, it will be written to a file. -pub fn shrunk_instance_name<'tcx>( - tcx: TyCtxt<'tcx>, - instance: ty::Instance<'tcx>, -) -> (String, Option<PathBuf>) { - let s = instance.to_string(); - - // Only use the shrunk version if it's really shorter. - // This also avoids the case where before and after slices overlap. - if s.chars().nth(33).is_some() { - let shrunk = format!("{}", ShortInstance(instance, 4)); - if shrunk == s { - return (s, None); - } - - let path = tcx.output_filenames(()).temp_path_for_diagnostic("long-type.txt"); - let written_to_path = std::fs::write(&path, s).ok().map(|_| path); - - (shrunk, written_to_path) - } else { - (s, None) - } -} diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 5c44b10ba71..67244e767cb 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -29,33 +29,6 @@ use crate::ty::{ TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, }; -macro_rules! p { - (@$lit:literal) => { - write!(scoped_cx!(), $lit)? - }; - (@write($($data:expr),+)) => { - write!(scoped_cx!(), $($data),+)? - }; - (@print($x:expr)) => { - $x.print(scoped_cx!())? - }; - (@$method:ident($($arg:expr),*)) => { - scoped_cx!().$method($($arg),*)? - }; - ($($elem:tt $(($($args:tt)*))?),+) => {{ - $(p!(@ $elem $(($($args)*))?);)+ - }}; -} -macro_rules! define_scoped_cx { - ($cx:ident) => { - macro_rules! scoped_cx { - () => { - $cx - }; - } - }; -} - thread_local! { static FORCE_IMPL_FILENAME_LINE: Cell<bool> = const { Cell::new(false) }; static SHOULD_PREFIX_WITH_CRATE: Cell<bool> = const { Cell::new(false) }; @@ -689,12 +662,11 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } } - self.generic_delimiters(|cx| { - define_scoped_cx!(cx); - - p!(print(self_ty)); + self.generic_delimiters(|p| { + self_ty.print(p)?; if let Some(trait_ref) = trait_ref { - p!(" as ", print(trait_ref.print_only_trait_path())); + write!(p, " as ")?; + trait_ref.print_only_trait_path().print(p)?; } Ok(()) }) @@ -708,121 +680,121 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ) -> Result<(), PrintError> { print_prefix(self)?; - self.generic_delimiters(|cx| { - define_scoped_cx!(cx); - - p!("impl "); + self.generic_delimiters(|p| { + write!(p, "impl ")?; if let Some(trait_ref) = trait_ref { - p!(print(trait_ref.print_only_trait_path()), " for "); + trait_ref.print_only_trait_path().print(p)?; + write!(p, " for ")?; } - p!(print(self_ty)); + self_ty.print(p)?; Ok(()) }) } fn pretty_print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> { - define_scoped_cx!(self); - match *ty.kind() { - ty::Bool => p!("bool"), - ty::Char => p!("char"), - ty::Int(t) => p!(write("{}", t.name_str())), - ty::Uint(t) => p!(write("{}", t.name_str())), - ty::Float(t) => p!(write("{}", t.name_str())), + ty::Bool => write!(self, "bool")?, + ty::Char => write!(self, "char")?, + ty::Int(t) => write!(self, "{}", t.name_str())?, + ty::Uint(t) => write!(self, "{}", t.name_str())?, + ty::Float(t) => write!(self, "{}", t.name_str())?, ty::Pat(ty, pat) => { - p!("(", print(ty), ") is ", write("{pat:?}")) + write!(self, "(")?; + ty.print(self)?; + write!(self, ") is {pat:?}")?; } ty::RawPtr(ty, mutbl) => { - p!(write("*{} ", mutbl.ptr_str())); - p!(print(ty)) + write!(self, "*{} ", mutbl.ptr_str())?; + ty.print(self)?; } ty::Ref(r, ty, mutbl) => { - p!("&"); + write!(self, "&")?; if self.should_print_region(r) { - p!(print(r), " "); + r.print(self)?; + write!(self, " ")?; } - p!(print(ty::TypeAndMut { ty, mutbl })) + ty::TypeAndMut { ty, mutbl }.print(self)?; } - ty::Never => p!("!"), + ty::Never => write!(self, "!")?, ty::Tuple(tys) => { - p!("(", comma_sep(tys.iter())); + write!(self, "(")?; + self.comma_sep(tys.iter())?; if tys.len() == 1 { - p!(","); + write!(self, ",")?; } - p!(")") + write!(self, ")")?; } ty::FnDef(def_id, args) => { if with_reduced_queries() { - p!(print_def_path(def_id, args)); + self.print_def_path(def_id, args)?; } else { let mut sig = self.tcx().fn_sig(def_id).instantiate(self.tcx(), args); if self.tcx().codegen_fn_attrs(def_id).safe_target_features { - p!("#[target_features] "); + write!(self, "#[target_features] ")?; sig = sig.map_bound(|mut sig| { sig.safety = hir::Safety::Safe; sig }); } - p!(print(sig), " {{", print_value_path(def_id, args), "}}"); + sig.print(self)?; + write!(self, " {{")?; + self.print_value_path(def_id, args)?; + write!(self, "}}")?; } } - ty::FnPtr(ref sig_tys, hdr) => p!(print(sig_tys.with(hdr))), + ty::FnPtr(ref sig_tys, hdr) => sig_tys.with(hdr).print(self)?, ty::UnsafeBinder(ref bound_ty) => { - self.wrap_binder(bound_ty, WrapBinderMode::Unsafe, |ty, cx| { - cx.pretty_print_type(*ty) + self.wrap_binder(bound_ty, WrapBinderMode::Unsafe, |ty, p| { + p.pretty_print_type(*ty) })?; } ty::Infer(infer_ty) => { if self.should_print_verbose() { - p!(write("{:?}", ty.kind())); + write!(self, "{:?}", ty.kind())?; return Ok(()); } if let ty::TyVar(ty_vid) = infer_ty { if let Some(name) = self.ty_infer_name(ty_vid) { - p!(write("{}", name)) + write!(self, "{name}")?; } else { - p!(write("{}", infer_ty)) + write!(self, "{infer_ty}")?; } } else { - p!(write("{}", infer_ty)) + write!(self, "{infer_ty}")?; } } - ty::Error(_) => p!("{{type error}}"), - ty::Param(ref param_ty) => p!(print(param_ty)), + ty::Error(_) => write!(self, "{{type error}}")?, + ty::Param(ref param_ty) => param_ty.print(self)?, ty::Bound(debruijn, bound_ty) => match bound_ty.kind { ty::BoundTyKind::Anon => { rustc_type_ir::debug_bound_var(self, debruijn, bound_ty.var)? } ty::BoundTyKind::Param(def_id) => match self.should_print_verbose() { - true => p!(write("{:?}", ty.kind())), - false => p!(write("{}", self.tcx().item_name(def_id))), + true => write!(self, "{:?}", ty.kind())?, + false => write!(self, "{}", self.tcx().item_name(def_id))?, }, }, - ty::Adt(def, args) => { - p!(print_def_path(def.did(), args)); - } + ty::Adt(def, args) => self.print_def_path(def.did(), args)?, ty::Dynamic(data, r, repr) => { let print_r = self.should_print_region(r); if print_r { - p!("("); + write!(self, "(")?; } match repr { - ty::Dyn => p!("dyn "), + ty::Dyn => write!(self, "dyn ")?, } - p!(print(data)); + data.print(self)?; if print_r { - p!(" + ", print(r), ")"); + write!(self, " + ")?; + r.print(self)?; + write!(self, ")")?; } } - ty::Foreign(def_id) => { - p!(print_def_path(def_id, &[])); - } - ty::Alias(ty::Projection | ty::Inherent | ty::Free, ref data) => { - p!(print(data)) - } - ty::Placeholder(placeholder) => p!(print(placeholder)), + ty::Foreign(def_id) => self.print_def_path(def_id, &[])?, + ty::Alias(ty::Projection | ty::Inherent | ty::Free, ref data) => data.print(self)?, + ty::Placeholder(placeholder) => placeholder.print(self)?, ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => { // We use verbose printing in 'NO_QUERIES' mode, to // avoid needing to call `predicates_of`. This should @@ -834,7 +806,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { // example.] if self.should_print_verbose() { // FIXME(eddyb) print this with `print_def_path`. - p!(write("Opaque({:?}, {})", def_id, args.print_as_list())); + write!(self, "Opaque({:?}, {})", def_id, args.print_as_list())?; return Ok(()); } @@ -849,17 +821,17 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { if d == def_id { // If the type alias directly starts with the `impl` of the // opaque type we're printing, then skip the `::{opaque#1}`. - p!(print_def_path(parent, args)); + self.print_def_path(parent, args)?; return Ok(()); } } // Complex opaque type, e.g. `type Foo = (i32, impl Debug);` - p!(print_def_path(def_id, args)); + self.print_def_path(def_id, args)?; return Ok(()); } _ => { if with_reduced_queries() { - p!(print_def_path(def_id, &[])); + self.print_def_path(def_id, &[])?; return Ok(()); } else { return self.pretty_print_opaque_impl_type(def_id, args); @@ -867,9 +839,9 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } } } - ty::Str => p!("str"), + ty::Str => write!(self, "str")?, ty::Coroutine(did, args) => { - p!("{{"); + write!(self, "{{")?; let coroutine_kind = self.tcx().coroutine_kind(did).unwrap(); let should_print_movability = self.should_print_verbose() || matches!(coroutine_kind, hir::CoroutineKind::Coroutine(_)); @@ -877,12 +849,12 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { if should_print_movability { match coroutine_kind.movability() { hir::Movability::Movable => {} - hir::Movability::Static => p!("static "), + hir::Movability::Static => write!(self, "static ")?, } } if !self.should_print_verbose() { - p!(write("{}", coroutine_kind)); + write!(self, "{coroutine_kind}")?; if coroutine_kind.is_fn_like() { // If we are printing an `async fn` coroutine type, then give the path // of the fn, instead of its span, because that will in most cases be @@ -891,68 +863,71 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { // This will look like: // {async fn body of some_fn()} let did_of_the_fn_item = self.tcx().parent(did); - p!(" of ", print_def_path(did_of_the_fn_item, args), "()"); + write!(self, " of ")?; + self.print_def_path(did_of_the_fn_item, args)?; + write!(self, "()")?; } else if let Some(local_did) = did.as_local() { let span = self.tcx().def_span(local_did); - p!(write( + write!( + self, "@{}", // This may end up in stderr diagnostics but it may also be emitted // into MIR. Hence we use the remapped path if available self.tcx().sess.source_map().span_to_embeddable_string(span) - )); + )?; } else { - p!("@", print_def_path(did, args)); + write!(self, "@")?; + self.print_def_path(did, args)?; } } else { - p!(print_def_path(did, args)); - p!( - " upvar_tys=", - print(args.as_coroutine().tupled_upvars_ty()), - " resume_ty=", - print(args.as_coroutine().resume_ty()), - " yield_ty=", - print(args.as_coroutine().yield_ty()), - " return_ty=", - print(args.as_coroutine().return_ty()), - " witness=", - print(args.as_coroutine().witness()) - ); + self.print_def_path(did, args)?; + write!(self, " upvar_tys=")?; + args.as_coroutine().tupled_upvars_ty().print(self)?; + write!(self, " resume_ty=")?; + args.as_coroutine().resume_ty().print(self)?; + write!(self, " yield_ty=")?; + args.as_coroutine().yield_ty().print(self)?; + write!(self, " return_ty=")?; + args.as_coroutine().return_ty().print(self)?; } - p!("}}") + write!(self, "}}")? } ty::CoroutineWitness(did, args) => { - p!(write("{{")); + write!(self, "{{")?; if !self.tcx().sess.verbose_internals() { - p!("coroutine witness"); + write!(self, "coroutine witness")?; if let Some(did) = did.as_local() { let span = self.tcx().def_span(did); - p!(write( + write!( + self, "@{}", // This may end up in stderr diagnostics but it may also be emitted // into MIR. Hence we use the remapped path if available self.tcx().sess.source_map().span_to_embeddable_string(span) - )); + )?; } else { - p!(write("@"), print_def_path(did, args)); + write!(self, "@")?; + self.print_def_path(did, args)?; } } else { - p!(print_def_path(did, args)); + self.print_def_path(did, args)?; } - p!("}}") + write!(self, "}}")? } ty::Closure(did, args) => { - p!(write("{{")); + write!(self, "{{")?; if !self.should_print_verbose() { - p!(write("closure")); + write!(self, "closure")?; if self.should_truncate() { write!(self, "@...}}")?; return Ok(()); } else { if let Some(did) = did.as_local() { if self.tcx().sess.opts.unstable_opts.span_free_formats { - p!("@", print_def_path(did.to_def_id(), args)); + write!(self, "@")?; + self.print_def_path(did.to_def_id(), args)?; } else { let span = self.tcx().def_span(did); let preference = if with_forced_trimmed_paths() { @@ -960,54 +935,56 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } else { FileNameDisplayPreference::Remapped }; - p!(write( + write!( + self, "@{}", - // This may end up in stderr diagnostics but it may also be emitted - // into MIR. Hence we use the remapped path if available + // This may end up in stderr diagnostics but it may also be + // emitted into MIR. Hence we use the remapped path if + // available self.tcx().sess.source_map().span_to_string(span, preference) - )); + )?; } } else { - p!(write("@"), print_def_path(did, args)); + write!(self, "@")?; + self.print_def_path(did, args)?; } } } else { - p!(print_def_path(did, args)); - p!( - " closure_kind_ty=", - print(args.as_closure().kind_ty()), - " closure_sig_as_fn_ptr_ty=", - print(args.as_closure().sig_as_fn_ptr_ty()), - " upvar_tys=", - print(args.as_closure().tupled_upvars_ty()) - ); + self.print_def_path(did, args)?; + write!(self, " closure_kind_ty=")?; + args.as_closure().kind_ty().print(self)?; + write!(self, " closure_sig_as_fn_ptr_ty=")?; + args.as_closure().sig_as_fn_ptr_ty().print(self)?; + write!(self, " upvar_tys=")?; + args.as_closure().tupled_upvars_ty().print(self)?; } - p!("}}"); + write!(self, "}}")?; } ty::CoroutineClosure(did, args) => { - p!(write("{{")); + write!(self, "{{")?; if !self.should_print_verbose() { match self.tcx().coroutine_kind(self.tcx().coroutine_for_closure(did)).unwrap() { hir::CoroutineKind::Desugared( hir::CoroutineDesugaring::Async, hir::CoroutineSource::Closure, - ) => p!("async closure"), + ) => write!(self, "async closure")?, hir::CoroutineKind::Desugared( hir::CoroutineDesugaring::AsyncGen, hir::CoroutineSource::Closure, - ) => p!("async gen closure"), + ) => write!(self, "async gen closure")?, hir::CoroutineKind::Desugared( hir::CoroutineDesugaring::Gen, hir::CoroutineSource::Closure, - ) => p!("gen closure"), + ) => write!(self, "gen closure")?, _ => unreachable!( "coroutine from coroutine-closure should have CoroutineSource::Closure" ), } if let Some(did) = did.as_local() { if self.tcx().sess.opts.unstable_opts.span_free_formats { - p!("@", print_def_path(did.to_def_id(), args)); + write!(self, "@")?; + self.print_def_path(did.to_def_id(), args)?; } else { let span = self.tcx().def_span(did); let preference = if with_forced_trimmed_paths() { @@ -1015,35 +992,43 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } else { FileNameDisplayPreference::Remapped }; - p!(write( + write!( + self, "@{}", // This may end up in stderr diagnostics but it may also be emitted // into MIR. Hence we use the remapped path if available self.tcx().sess.source_map().span_to_string(span, preference) - )); + )?; } } else { - p!(write("@"), print_def_path(did, args)); + write!(self, "@")?; + self.print_def_path(did, args)?; } } else { - p!(print_def_path(did, args)); - p!( - " closure_kind_ty=", - print(args.as_coroutine_closure().kind_ty()), - " signature_parts_ty=", - print(args.as_coroutine_closure().signature_parts_ty()), - " upvar_tys=", - print(args.as_coroutine_closure().tupled_upvars_ty()), - " coroutine_captures_by_ref_ty=", - print(args.as_coroutine_closure().coroutine_captures_by_ref_ty()), - " coroutine_witness_ty=", - print(args.as_coroutine_closure().coroutine_witness_ty()) - ); + self.print_def_path(did, args)?; + write!(self, " closure_kind_ty=")?; + args.as_coroutine_closure().kind_ty().print(self)?; + write!(self, " signature_parts_ty=")?; + args.as_coroutine_closure().signature_parts_ty().print(self)?; + write!(self, " upvar_tys=")?; + args.as_coroutine_closure().tupled_upvars_ty().print(self)?; + write!(self, " coroutine_captures_by_ref_ty=")?; + args.as_coroutine_closure().coroutine_captures_by_ref_ty().print(self)?; } - p!("}}"); + write!(self, "}}")?; + } + ty::Array(ty, sz) => { + write!(self, "[")?; + ty.print(self)?; + write!(self, "; ")?; + sz.print(self)?; + write!(self, "]")?; + } + ty::Slice(ty) => { + write!(self, "[")?; + ty.print(self)?; + write!(self, "]")?; } - ty::Array(ty, sz) => p!("[", print(ty), "; ", print(sz), "]"), - ty::Slice(ty) => p!("[", print(ty), "]"), } Ok(()) @@ -1141,25 +1126,25 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { self.wrap_binder( &bound_args_and_self_ty, WrapBinderMode::ForAll, - |(args, _), cx| { - define_scoped_cx!(cx); - p!(write("{}", tcx.item_name(trait_def_id))); - p!("("); + |(args, _), p| { + write!(p, "{}", tcx.item_name(trait_def_id))?; + write!(p, "(")?; for (idx, ty) in args.iter().enumerate() { if idx > 0 { - p!(", "); + write!(p, ", ")?; } - p!(print(ty)); + ty.print(p)?; } - p!(")"); + write!(p, ")")?; if let Some(ty) = return_ty.skip_binder().as_type() { if !ty.is_unit() { - p!(" -> ", print(return_ty)); + write!(p, " -> ")?; + return_ty.print(p)?; } } - p!(write("{}", if paren_needed { ")" } else { "" })); + write!(p, "{}", if paren_needed { ")" } else { "" })?; first = false; Ok(()) @@ -1185,13 +1170,11 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { for (trait_pred, assoc_items) in traits { write!(self, "{}", if first { "" } else { " + " })?; - self.wrap_binder(&trait_pred, WrapBinderMode::ForAll, |trait_pred, cx| { - define_scoped_cx!(cx); - + self.wrap_binder(&trait_pred, WrapBinderMode::ForAll, |trait_pred, p| { if trait_pred.polarity == ty::PredicatePolarity::Negative { - p!("!"); + write!(p, "!")?; } - p!(print(trait_pred.trait_ref.print_only_trait_name())); + trait_pred.trait_ref.print_only_trait_name().print(p)?; let generics = tcx.generics_of(trait_pred.def_id()); let own_args = generics.own_args_no_defaults(tcx, trait_pred.trait_ref.args); @@ -1201,32 +1184,32 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { for ty in own_args { if first { - p!("<"); + write!(p, "<")?; first = false; } else { - p!(", "); + write!(p, ", ")?; } - p!(print(ty)); + ty.print(p)?; } for (assoc_item_def_id, term) in assoc_items { if first { - p!("<"); + write!(p, "<")?; first = false; } else { - p!(", "); + write!(p, ", ")?; } - p!(write("{} = ", tcx.associated_item(assoc_item_def_id).name())); + write!(p, "{} = ", tcx.associated_item(assoc_item_def_id).name())?; match term.skip_binder().kind() { - TermKind::Ty(ty) => p!(print(ty)), - TermKind::Const(c) => p!(print(c)), + TermKind::Ty(ty) => ty.print(p)?, + TermKind::Const(c) => c.print(p)?, }; } if !first { - p!(">"); + write!(p, ">")?; } } @@ -1326,9 +1309,9 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ) -> Result<(), PrintError> { let def_key = self.tcx().def_key(alias_ty.def_id); self.path_generic_args( - |cx| { - cx.path_append( - |cx| cx.path_qualified(alias_ty.self_ty(), None), + |p| { + p.path_append( + |p| p.path_qualified(alias_ty.self_ty(), None), &def_key.disambiguated_data, ) }, @@ -1392,23 +1375,22 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { let mut first = true; if let Some(bound_principal) = predicates.principal() { - self.wrap_binder(&bound_principal, WrapBinderMode::ForAll, |principal, cx| { - define_scoped_cx!(cx); - p!(print_def_path(principal.def_id, &[])); + self.wrap_binder(&bound_principal, WrapBinderMode::ForAll, |principal, p| { + p.print_def_path(principal.def_id, &[])?; let mut resugared = false; // Special-case `Fn(...) -> ...` and re-sugar it. - let fn_trait_kind = cx.tcx().fn_trait_kind_from_def_id(principal.def_id); - if !cx.should_print_verbose() && fn_trait_kind.is_some() { + let fn_trait_kind = p.tcx().fn_trait_kind_from_def_id(principal.def_id); + if !p.should_print_verbose() && fn_trait_kind.is_some() { if let ty::Tuple(tys) = principal.args.type_at(0).kind() { let mut projections = predicates.projection_bounds(); if let (Some(proj), None) = (projections.next(), projections.next()) { - p!(pretty_fn_sig( + p.pretty_fn_sig( tys, false, - proj.skip_binder().term.as_type().expect("Return type was a const") - )); + proj.skip_binder().term.as_type().expect("Return type was a const"), + )?; resugared = true; } } @@ -1418,18 +1400,18 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { // in order to place the projections inside the `<...>`. if !resugared { let principal_with_self = - principal.with_self_ty(cx.tcx(), cx.tcx().types.trait_object_dummy_self); + principal.with_self_ty(p.tcx(), p.tcx().types.trait_object_dummy_self); - let args = cx + let args = p .tcx() .generics_of(principal_with_self.def_id) - .own_args_no_defaults(cx.tcx(), principal_with_self.args); + .own_args_no_defaults(p.tcx(), principal_with_self.args); let bound_principal_with_self = bound_principal - .with_self_ty(cx.tcx(), cx.tcx().types.trait_object_dummy_self); + .with_self_ty(p.tcx(), p.tcx().types.trait_object_dummy_self); - let clause: ty::Clause<'tcx> = bound_principal_with_self.upcast(cx.tcx()); - let super_projections: Vec<_> = elaborate::elaborate(cx.tcx(), [clause]) + let clause: ty::Clause<'tcx> = bound_principal_with_self.upcast(p.tcx()); + let super_projections: Vec<_> = elaborate::elaborate(p.tcx(), [clause]) .filter_only_self() .filter_map(|clause| clause.as_projection_clause()) .collect(); @@ -1440,15 +1422,15 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { // Filter out projections that are implied by the super predicates. let proj_is_implied = super_projections.iter().any(|&super_proj| { let super_proj = super_proj.map_bound(|super_proj| { - ty::ExistentialProjection::erase_self_ty(cx.tcx(), super_proj) + ty::ExistentialProjection::erase_self_ty(p.tcx(), super_proj) }); // This function is sometimes called on types with erased and // anonymized regions, but the super projections can still // contain named regions. So we erase and anonymize everything // here to compare the types modulo regions below. - let proj = cx.tcx().erase_regions(proj); - let super_proj = cx.tcx().erase_regions(super_proj); + let proj = p.tcx().erase_regions(proj); + let super_proj = p.tcx().erase_regions(super_proj); proj == super_proj }); @@ -1462,16 +1444,16 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { .collect(); projections - .sort_by_cached_key(|proj| cx.tcx().item_name(proj.def_id).to_string()); + .sort_by_cached_key(|proj| p.tcx().item_name(proj.def_id).to_string()); if !args.is_empty() || !projections.is_empty() { - p!(generic_delimiters(|cx| { - cx.comma_sep(args.iter().copied())?; + p.generic_delimiters(|p| { + p.comma_sep(args.iter().copied())?; if !args.is_empty() && !projections.is_empty() { - write!(cx, ", ")?; + write!(p, ", ")?; } - cx.comma_sep(projections.iter().copied()) - })); + p.comma_sep(projections.iter().copied()) + })?; } } Ok(()) @@ -1480,11 +1462,9 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { first = false; } - define_scoped_cx!(self); - // Builtin bounds. // FIXME(eddyb) avoid printing twice (needed to ensure - // that the auto traits are sorted *and* printed via cx). + // that the auto traits are sorted *and* printed via p). let mut auto_traits: Vec<_> = predicates.auto_traits().collect(); // The auto traits come ordered by `DefPathHash`. While @@ -1498,11 +1478,11 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { for def_id in auto_traits { if !first { - p!(" + "); + write!(self, " + ")?; } first = false; - p!(print_def_path(def_id, &[])); + self.print_def_path(def_id, &[])?; } Ok(()) @@ -1514,18 +1494,18 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { c_variadic: bool, output: Ty<'tcx>, ) -> Result<(), PrintError> { - define_scoped_cx!(self); - - p!("(", comma_sep(inputs.iter().copied())); + write!(self, "(")?; + self.comma_sep(inputs.iter().copied())?; if c_variadic { if !inputs.is_empty() { - p!(", "); + write!(self, ", ")?; } - p!("..."); + write!(self, "...")?; } - p!(")"); + write!(self, ")")?; if !output.is_unit() { - p!(" -> ", print(output)); + write!(self, " -> ")?; + output.print(self)?; } Ok(()) @@ -1536,10 +1516,8 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ct: ty::Const<'tcx>, print_ty: bool, ) -> Result<(), PrintError> { - define_scoped_cx!(self); - if self.should_print_verbose() { - p!(write("{:?}", ct)); + write!(self, "{ct:?}")?; return Ok(()); } @@ -1547,25 +1525,28 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, args }) => { match self.tcx().def_kind(def) { DefKind::Const | DefKind::AssocConst => { - p!(print_value_path(def, args)) + self.print_value_path(def, args)?; } DefKind::AnonConst => { if def.is_local() && let span = self.tcx().def_span(def) && let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) { - p!(write("{}", snip)) + write!(self, "{snip}")?; } else { - // Do not call `print_value_path` as if a parent of this anon const is an impl it will - // attempt to print out the impl trait ref i.e. `<T as Trait>::{constant#0}`. This would - // cause printing to enter an infinite recursion if the anon const is in the self type i.e. - // `impl<T: Default> Default for [T; 32 - 1 - 1 - 1] {` - // where we would try to print `<[T; /* print `constant#0` again */] as Default>::{constant#0}` - p!(write( + // Do not call `print_value_path` as if a parent of this anon const is + // an impl it will attempt to print out the impl trait ref i.e. `<T as + // Trait>::{constant#0}`. This would cause printing to enter an + // infinite recursion if the anon const is in the self type i.e. + // `impl<T: Default> Default for [T; 32 - 1 - 1 - 1] {` where we would + // try to print + // `<[T; /* print constant#0 again */] as // Default>::{constant#0}`. + write!( + self, "{}::{}", self.tcx().crate_name(def.krate), self.tcx().def_path(def).to_string_no_crate_verbose() - )) + )?; } } defkind => bug!("`{:?}` has unexpected defkind {:?}", ct, defkind), @@ -1573,11 +1554,11 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } ty::ConstKind::Infer(infer_ct) => match infer_ct { ty::InferConst::Var(ct_vid) if let Some(name) = self.const_infer_name(ct_vid) => { - p!(write("{}", name)) + write!(self, "{name}")?; } _ => write!(self, "_")?, }, - ty::ConstKind::Param(ParamConst { name, .. }) => p!(write("{}", name)), + ty::ConstKind::Param(ParamConst { name, .. }) => write!(self, "{name}")?, ty::ConstKind::Value(cv) => { return self.pretty_print_const_valtree(cv, print_ty); } @@ -1585,11 +1566,11 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ty::ConstKind::Bound(debruijn, bound_var) => { rustc_type_ir::debug_bound_var(self, debruijn, bound_var)? } - ty::ConstKind::Placeholder(placeholder) => p!(write("{placeholder:?}")), + ty::ConstKind::Placeholder(placeholder) => write!(self, "{placeholder:?}")?, // FIXME(generic_const_exprs): // write out some legible representation of an abstract const? ty::ConstKind::Expr(expr) => self.pretty_print_const_expr(expr, print_ty)?, - ty::ConstKind::Error(_) => p!("{{const error}}"), + ty::ConstKind::Error(_) => write!(self, "{{const error}}")?, }; Ok(()) } @@ -1599,7 +1580,6 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { expr: Expr<'tcx>, print_ty: bool, ) -> Result<(), PrintError> { - define_scoped_cx!(self); match expr.kind { ty::ExprKind::Binop(op) => { let (_, _, c1, c2) = expr.binop_args(); @@ -1638,7 +1618,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { |this| this.pretty_print_const(c1, print_ty), lhs_parenthesized, )?; - p!(write(" {formatted_op} ")); + write!(self, " {formatted_op} ")?; self.maybe_parenthesized( |this| this.pretty_print_const(c2, print_ty), rhs_parenthesized, @@ -1661,7 +1641,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ty::ConstKind::Expr(_) => true, _ => false, }; - p!(write("{formatted_op}")); + write!(self, "{formatted_op}")?; self.maybe_parenthesized( |this| this.pretty_print_const(ct, print_ty), parenthesized, @@ -1672,7 +1652,9 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { write!(self, "(")?; self.pretty_print_const(fn_def, print_ty)?; - p!(")(", comma_sep(fn_args), ")"); + write!(self, ")(")?; + self.comma_sep(fn_args)?; + write!(self, ")")?; } ty::ExprKind::Cast(kind) => { let (_, value, to_ty) = expr.cast_args(); @@ -1722,8 +1704,6 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ptr: Pointer, ty: Ty<'tcx>, ) -> Result<(), PrintError> { - define_scoped_cx!(self); - let (prov, offset) = ptr.prov_and_relative_offset(); match ty.kind() { // Byte strings (&[u8; N]) @@ -1738,19 +1718,19 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { if let Ok(byte_str) = alloc.inner().get_bytes_strip_provenance(&self.tcx(), range) { - p!(pretty_print_byte_str(byte_str)) + self.pretty_print_byte_str(byte_str)?; } else { - p!("<too short allocation>") + write!(self, "<too short allocation>")?; } } // FIXME: for statics, vtables, and functions, we could in principle print more detail. Some(GlobalAlloc::Static(def_id)) => { - p!(write("<static({:?})>", def_id)) + write!(self, "<static({def_id:?})>")?; } - Some(GlobalAlloc::Function { .. }) => p!("<function>"), - Some(GlobalAlloc::VTable(..)) => p!("<vtable>"), - Some(GlobalAlloc::TypeId { .. }) => p!("<typeid>"), - None => p!("<dangling pointer>"), + Some(GlobalAlloc::Function { .. }) => write!(self, "<function>")?, + Some(GlobalAlloc::VTable(..)) => write!(self, "<vtable>")?, + Some(GlobalAlloc::TypeId { .. }) => write!(self, "<typeid>")?, + None => write!(self, "<dangling pointer>")?, } return Ok(()); } @@ -1782,40 +1762,38 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ty: Ty<'tcx>, print_ty: bool, ) -> Result<(), PrintError> { - define_scoped_cx!(self); - match ty.kind() { // Bool - ty::Bool if int == ScalarInt::FALSE => p!("false"), - ty::Bool if int == ScalarInt::TRUE => p!("true"), + ty::Bool if int == ScalarInt::FALSE => write!(self, "false")?, + ty::Bool if int == ScalarInt::TRUE => write!(self, "true")?, // Float ty::Float(fty) => match fty { ty::FloatTy::F16 => { let val = Half::try_from(int).unwrap(); - p!(write("{}{}f16", val, if val.is_finite() { "" } else { "_" })) + write!(self, "{}{}f16", val, if val.is_finite() { "" } else { "_" })?; } ty::FloatTy::F32 => { let val = Single::try_from(int).unwrap(); - p!(write("{}{}f32", val, if val.is_finite() { "" } else { "_" })) + write!(self, "{}{}f32", val, if val.is_finite() { "" } else { "_" })?; } ty::FloatTy::F64 => { let val = Double::try_from(int).unwrap(); - p!(write("{}{}f64", val, if val.is_finite() { "" } else { "_" })) + write!(self, "{}{}f64", val, if val.is_finite() { "" } else { "_" })?; } ty::FloatTy::F128 => { let val = Quad::try_from(int).unwrap(); - p!(write("{}{}f128", val, if val.is_finite() { "" } else { "_" })) + write!(self, "{}{}f128", val, if val.is_finite() { "" } else { "_" })?; } }, // Int ty::Uint(_) | ty::Int(_) => { let int = ConstInt::new(int, matches!(ty.kind(), ty::Int(_)), ty.is_ptr_sized_integral()); - if print_ty { p!(write("{:#?}", int)) } else { p!(write("{:?}", int)) } + if print_ty { write!(self, "{int:#?}")? } else { write!(self, "{int:?}")? } } // Char ty::Char if char::try_from(int).is_ok() => { - p!(write("{:?}", char::try_from(int).unwrap())) + write!(self, "{:?}", char::try_from(int).unwrap())?; } // Pointer types ty::Ref(..) | ty::RawPtr(_, _) | ty::FnPtr(..) => { @@ -1831,7 +1809,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } ty::Pat(base_ty, pat) if self.tcx().validate_scalar_in_layout(int, ty) => { self.pretty_print_const_scalar_int(int, *base_ty, print_ty)?; - p!(write(" is {pat:?}")); + write!(self, " is {pat:?}")?; } // Nontrivial types with scalar bit representation _ => { @@ -1880,10 +1858,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { cv: ty::Value<'tcx>, print_ty: bool, ) -> Result<(), PrintError> { - define_scoped_cx!(self); - if with_reduced_queries() || self.should_print_verbose() { - p!(write("ValTree({:?}: ", cv.valtree), print(cv.ty), ")"); + write!(self, "ValTree({:?}: ", cv.valtree)?; + cv.ty.print(self)?; + write!(self, ")")?; return Ok(()); } @@ -1904,13 +1882,13 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { let bytes = cv.try_to_raw_bytes(self.tcx()).unwrap_or_else(|| { bug!("expected to convert valtree to raw bytes for type {:?}", cv.ty) }); - p!(write("{:?}", String::from_utf8_lossy(bytes))); + write!(self, "{:?}", String::from_utf8_lossy(bytes))?; return Ok(()); } _ => { let cv = ty::Value { valtree: cv.valtree, ty: inner_ty }; - p!("&"); - p!(pretty_print_const_valtree(cv, print_ty)); + write!(self, "&")?; + self.pretty_print_const_valtree(cv, print_ty)?; return Ok(()); } }, @@ -1918,8 +1896,8 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { let bytes = cv.try_to_raw_bytes(self.tcx()).unwrap_or_else(|| { bug!("expected to convert valtree to raw bytes for type {:?}", t) }); - p!("*"); - p!(pretty_print_byte_str(bytes)); + write!(self, "*")?; + self.pretty_print_byte_str(bytes)?; return Ok(()); } // Aggregates, printed as array/tuple/struct/variant construction syntax. @@ -1932,14 +1910,17 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { let fields = contents.fields.iter().copied(); match *cv.ty.kind() { ty::Array(..) => { - p!("[", comma_sep(fields), "]"); + write!(self, "[")?; + self.comma_sep(fields)?; + write!(self, "]")?; } ty::Tuple(..) => { - p!("(", comma_sep(fields)); + write!(self, "(")?; + self.comma_sep(fields)?; if contents.fields.len() == 1 { - p!(","); + write!(self, ",")?; } - p!(")"); + write!(self, ")")?; } ty::Adt(def, _) if def.variants().is_empty() => { self.typed_value( @@ -1955,23 +1936,26 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { let variant_idx = contents.variant.expect("destructed const of adt without variant idx"); let variant_def = &def.variant(variant_idx); - p!(print_value_path(variant_def.def_id, args)); + self.print_value_path(variant_def.def_id, args)?; match variant_def.ctor_kind() { Some(CtorKind::Const) => {} Some(CtorKind::Fn) => { - p!("(", comma_sep(fields), ")"); + write!(self, "(")?; + self.comma_sep(fields)?; + write!(self, ")")?; } None => { - p!(" {{ "); + write!(self, " {{ ")?; let mut first = true; for (field_def, field) in iter::zip(&variant_def.fields, fields) { if !first { - p!(", "); + write!(self, ", ")?; } - p!(write("{}: ", field_def.name), print(field)); + write!(self, "{}: ", field_def.name)?; + field.print(self)?; first = false; } - p!(" }}"); + write!(self, " }}")?; } } } @@ -1980,7 +1964,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { return Ok(()); } (ty::ValTreeKind::Leaf(leaf), ty::Ref(_, inner_ty, _)) => { - p!(write("&")); + write!(self, "&")?; return self.pretty_print_const_scalar_int(*leaf, inner_ty, print_ty); } (ty::ValTreeKind::Leaf(leaf), _) => { @@ -1988,7 +1972,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } (_, ty::FnDef(def_id, args)) => { // Never allowed today, but we still encounter them in invalid const args. - p!(print_value_path(def_id, args)); + self.print_value_path(def_id, args)?; return Ok(()); } // FIXME(oli-obk): also pretty print arrays and other aggregate constants by reading @@ -1998,12 +1982,13 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { // fallback if cv.valtree.is_zst() { - p!(write("<ZST>")); + write!(self, "<ZST>")?; } else { - p!(write("{:?}", cv.valtree)); + write!(self, "{:?}", cv.valtree)?; } if print_ty { - p!(": ", print(cv.ty)); + write!(self, ": ")?; + cv.ty.print(self)?; } Ok(()) } @@ -2016,20 +2001,19 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { let kind = closure.kind_ty().to_opt_closure_kind().unwrap_or(ty::ClosureKind::Fn); write!(self, "impl ")?; - self.wrap_binder(&sig, WrapBinderMode::ForAll, |sig, cx| { - define_scoped_cx!(cx); - - p!(write("{kind}(")); + self.wrap_binder(&sig, WrapBinderMode::ForAll, |sig, p| { + write!(p, "{kind}(")?; for (i, arg) in sig.inputs()[0].tuple_fields().iter().enumerate() { if i > 0 { - p!(", "); + write!(p, ", ")?; } - p!(print(arg)); + arg.print(p)?; } - p!(")"); + write!(p, ")")?; if !sig.output().is_unit() { - p!(" -> ", print(sig.output())); + write!(p, " -> ")?; + sig.output().print(p)?; } Ok(()) @@ -2040,15 +2024,9 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { &mut self, constness: ty::BoundConstness, ) -> Result<(), PrintError> { - define_scoped_cx!(self); - match constness { - ty::BoundConstness::Const => { - p!("const "); - } - ty::BoundConstness::Maybe => { - p!("[const] "); - } + ty::BoundConstness::Const => write!(self, "const ")?, + ty::BoundConstness::Maybe => write!(self, "[const] ")?, } Ok(()) } @@ -2065,10 +2043,10 @@ pub(crate) fn pretty_print_const<'tcx>( ) -> fmt::Result { ty::tls::with(|tcx| { let literal = tcx.lift(c).unwrap(); - let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS); - cx.print_alloc_ids = true; - cx.pretty_print_const(literal, print_types)?; - fmt.write_str(&cx.into_buffer())?; + let mut p = FmtPrinter::new(tcx, Namespace::ValueNS); + p.print_alloc_ids = true; + p.pretty_print_const(literal, print_types)?; + fmt.write_str(&p.into_buffer())?; Ok(()) }) } @@ -2188,7 +2166,7 @@ impl<'t> TyCtxt<'t> { let ns = guess_def_namespace(self, def_id); debug!("def_path_str: def_id={:?}, ns={:?}", def_id, ns); - FmtPrinter::print_string(self, ns, |cx| cx.print_def_path(def_id, args)).unwrap() + FmtPrinter::print_string(self, ns, |p| p.print_def_path(def_id, args)).unwrap() } pub fn value_path_str_with_args( @@ -2200,7 +2178,7 @@ impl<'t> TyCtxt<'t> { let ns = guess_def_namespace(self, def_id); debug!("value_path_str: def_id={:?}, ns={:?}", def_id, ns); - FmtPrinter::print_string(self, ns, |cx| cx.print_value_path(def_id, args)).unwrap() + FmtPrinter::print_string(self, ns, |p| p.print_value_path(def_id, args)).unwrap() } } @@ -2362,15 +2340,14 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> { fn path_append_impl( &mut self, print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, - _disambiguated_data: &DisambiguatedDefPathData, self_ty: Ty<'tcx>, trait_ref: Option<ty::TraitRef<'tcx>>, ) -> Result<(), PrintError> { self.pretty_path_append_impl( - |cx| { - print_prefix(cx)?; - if !cx.empty_path { - write!(cx, "::")?; + |p| { + print_prefix(p)?; + if !p.empty_path { + write!(p, "::")?; } Ok(()) @@ -2424,7 +2401,7 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> { if self.in_value { write!(self, "::")?; } - self.generic_delimiters(|cx| cx.comma_sep(args.iter().copied())) + self.generic_delimiters(|p| p.comma_sep(args.iter().copied())) } else { Ok(()) } @@ -2460,7 +2437,7 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { where T: Print<'tcx, Self> + TypeFoldable<TyCtxt<'tcx>>, { - self.pretty_print_in_binder(value) + self.wrap_binder(value, WrapBinderMode::ForAll, |new_value, this| new_value.print(this)) } fn wrap_binder<T, C: FnOnce(&T, &mut Self) -> Result<(), PrintError>>( @@ -2472,7 +2449,12 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { where T: TypeFoldable<TyCtxt<'tcx>>, { - self.pretty_wrap_binder(value, mode, f) + let old_region_index = self.region_index; + let (new_value, _) = self.name_all_regions(value, mode)?; + f(&new_value, self)?; + self.region_index = old_region_index; + self.binder_depth -= 1; + Ok(()) } fn typed_value( @@ -2556,11 +2538,10 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { ty: Ty<'tcx>, ) -> Result<(), PrintError> { let print = |this: &mut Self| { - define_scoped_cx!(this); if this.print_alloc_ids { - p!(write("{:?}", p)); + write!(this, "{p:?}")?; } else { - p!("&_"); + write!(this, "&_")?; } Ok(()) }; @@ -2571,17 +2552,15 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { // HACK(eddyb) limited to `FmtPrinter` because of `region_highlight_mode`. impl<'tcx> FmtPrinter<'_, 'tcx> { pub fn pretty_print_region(&mut self, region: ty::Region<'tcx>) -> Result<(), fmt::Error> { - define_scoped_cx!(self); - // Watch out for region highlights. let highlight = self.region_highlight_mode; if let Some(n) = highlight.region_highlighted(region) { - p!(write("'{}", n)); + write!(self, "'{n}")?; return Ok(()); } if self.should_print_verbose() { - p!(write("{:?}", region)); + write!(self, "{region:?}")?; return Ok(()); } @@ -2593,12 +2572,12 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { // `explain_region()` or `note_and_explain_region()`. match region.kind() { ty::ReEarlyParam(data) => { - p!(write("{}", data.name)); + write!(self, "{}", data.name)?; return Ok(()); } ty::ReLateParam(ty::LateParamRegion { kind, .. }) => { if let Some(name) = kind.get_name(self.tcx) { - p!(write("{}", name)); + write!(self, "{name}")?; return Ok(()); } } @@ -2607,31 +2586,31 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { bound: ty::BoundRegion { kind: br, .. }, .. }) => { if let Some(name) = br.get_name(self.tcx) { - p!(write("{}", name)); + write!(self, "{name}")?; return Ok(()); } if let Some((region, counter)) = highlight.highlight_bound_region { if br == region { - p!(write("'{}", counter)); + write!(self, "'{counter}")?; return Ok(()); } } } ty::ReVar(region_vid) if identify_regions => { - p!(write("{:?}", region_vid)); + write!(self, "{region_vid:?}")?; return Ok(()); } ty::ReVar(_) => {} ty::ReErased => {} ty::ReError(_) => {} ty::ReStatic => { - p!("'static"); + write!(self, "'static")?; return Ok(()); } } - p!("'_"); + write!(self, "'_")?; Ok(()) } @@ -2749,17 +2728,17 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { debug!("self.used_region_names: {:?}", self.used_region_names); let mut empty = true; - let mut start_or_continue = |cx: &mut Self, start: &str, cont: &str| { + let mut start_or_continue = |p: &mut Self, start: &str, cont: &str| { let w = if empty { empty = false; start } else { cont }; - let _ = write!(cx, "{w}"); + let _ = write!(p, "{w}"); }; - let do_continue = |cx: &mut Self, cont: Symbol| { - let _ = write!(cx, "{cont}"); + let do_continue = |p: &mut Self, cont: Symbol| { + let _ = write!(p, "{cont}"); }; let possible_names = ('a'..='z').rev().map(|s| Symbol::intern(&format!("'{s}"))); @@ -2859,38 +2838,6 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { Ok((new_value, map)) } - pub fn pretty_print_in_binder<T>( - &mut self, - value: &ty::Binder<'tcx, T>, - ) -> Result<(), fmt::Error> - where - T: Print<'tcx, Self> + TypeFoldable<TyCtxt<'tcx>>, - { - let old_region_index = self.region_index; - let (new_value, _) = self.name_all_regions(value, WrapBinderMode::ForAll)?; - new_value.print(self)?; - self.region_index = old_region_index; - self.binder_depth -= 1; - Ok(()) - } - - pub fn pretty_wrap_binder<T, C: FnOnce(&T, &mut Self) -> Result<(), fmt::Error>>( - &mut self, - value: &ty::Binder<'tcx, T>, - mode: WrapBinderMode, - f: C, - ) -> Result<(), fmt::Error> - where - T: TypeFoldable<TyCtxt<'tcx>>, - { - let old_region_index = self.region_index; - let (new_value, _) = self.name_all_regions(value, mode)?; - f(&new_value, self)?; - self.region_index = old_region_index; - self.binder_depth -= 1; - Ok(()) - } - fn prepare_region_info<T>(&mut self, value: &ty::Binder<'tcx, T>) where T: TypeFoldable<TyCtxt<'tcx>>, @@ -2944,8 +2891,8 @@ impl<'tcx, T, P: PrettyPrinter<'tcx>> Print<'tcx, P> for ty::Binder<'tcx, T> where T: Print<'tcx, P> + TypeFoldable<TyCtxt<'tcx>>, { - fn print(&self, cx: &mut P) -> Result<(), PrintError> { - cx.print_in_binder(self) + fn print(&self, p: &mut P) -> Result<(), PrintError> { + p.print_in_binder(self) } } @@ -2953,9 +2900,10 @@ impl<'tcx, T, P: PrettyPrinter<'tcx>> Print<'tcx, P> for ty::OutlivesPredicate<' where T: Print<'tcx, P>, { - fn print(&self, cx: &mut P) -> Result<(), PrintError> { - define_scoped_cx!(cx); - p!(print(self.0), ": ", print(self.1)); + fn print(&self, p: &mut P) -> Result<(), PrintError> { + self.0.print(p)?; + write!(p, ": ")?; + self.1.print(p)?; Ok(()) } } @@ -3039,7 +2987,7 @@ impl<'tcx> ty::Binder<'tcx, ty::TraitRef<'tcx>> { } } -#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)] +#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift, Hash)] pub struct TraitPredPrintModifiersAndPath<'tcx>(ty::TraitPredicate<'tcx>); impl<'tcx> fmt::Debug for TraitPredPrintModifiersAndPath<'tcx> { @@ -3094,11 +3042,11 @@ macro_rules! forward_display_to_print { $(#[allow(unused_lifetimes)] impl<'tcx> fmt::Display for $ty { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ty::tls::with(|tcx| { - let mut cx = FmtPrinter::new(tcx, Namespace::TypeNS); + let mut p = FmtPrinter::new(tcx, Namespace::TypeNS); tcx.lift(*self) .expect("could not lift for printing") - .print(&mut cx)?; - f.write_str(&cx.into_buffer())?; + .print(&mut p)?; + f.write_str(&p.into_buffer())?; Ok(()) }) } @@ -3107,10 +3055,9 @@ macro_rules! forward_display_to_print { } macro_rules! define_print { - (($self:ident, $cx:ident): $($ty:ty $print:block)+) => { + (($self:ident, $p:ident): $($ty:ty $print:block)+) => { $(impl<'tcx, P: PrettyPrinter<'tcx>> Print<'tcx, P> for $ty { - fn print(&$self, $cx: &mut P) -> Result<(), PrintError> { - define_scoped_cx!($cx); + fn print(&$self, $p: &mut P) -> Result<(), PrintError> { let _: () = $print; Ok(()) } @@ -3119,8 +3066,8 @@ macro_rules! define_print { } macro_rules! define_print_and_forward_display { - (($self:ident, $cx:ident): $($ty:ty $print:block)+) => { - define_print!(($self, $cx): $($ty $print)*); + (($self:ident, $p:ident): $($ty:ty $print:block)+) => { + define_print!(($self, $p): $($ty $print)*); forward_display_to_print!($($ty),+); }; } @@ -3133,37 +3080,38 @@ forward_display_to_print! { } define_print! { - (self, cx): + (self, p): ty::FnSig<'tcx> { - p!(write("{}", self.safety.prefix_str())); + write!(p, "{}", self.safety.prefix_str())?; if self.abi != ExternAbi::Rust { - p!(write("extern {} ", self.abi)); + write!(p, "extern {} ", self.abi)?; } - p!("fn", pretty_fn_sig(self.inputs(), self.c_variadic, self.output())); + write!(p, "fn")?; + p.pretty_fn_sig(self.inputs(), self.c_variadic, self.output())?; } ty::TraitRef<'tcx> { - p!(write("<{} as {}>", self.self_ty(), self.print_only_trait_path())) + write!(p, "<{} as {}>", self.self_ty(), self.print_only_trait_path())?; } ty::AliasTy<'tcx> { let alias_term: ty::AliasTerm<'tcx> = (*self).into(); - p!(print(alias_term)) + alias_term.print(p)?; } ty::AliasTerm<'tcx> { - match self.kind(cx.tcx()) { - ty::AliasTermKind::InherentTy | ty::AliasTermKind::InherentConst => p!(pretty_print_inherent_projection(*self)), + match self.kind(p.tcx()) { + ty::AliasTermKind::InherentTy | ty::AliasTermKind::InherentConst => p.pretty_print_inherent_projection(*self)?, ty::AliasTermKind::ProjectionTy => { - if !(cx.should_print_verbose() || with_reduced_queries()) - && cx.tcx().is_impl_trait_in_trait(self.def_id) + if !(p.should_print_verbose() || with_reduced_queries()) + && p.tcx().is_impl_trait_in_trait(self.def_id) { - p!(pretty_print_rpitit(self.def_id, self.args)) + p.pretty_print_rpitit(self.def_id, self.args)?; } else { - p!(print_def_path(self.def_id, self.args)); + p.print_def_path(self.def_id, self.args)?; } } ty::AliasTermKind::FreeTy @@ -3171,17 +3119,18 @@ define_print! { | ty::AliasTermKind::OpaqueTy | ty::AliasTermKind::UnevaluatedConst | ty::AliasTermKind::ProjectionConst => { - p!(print_def_path(self.def_id, self.args)); + p.print_def_path(self.def_id, self.args)?; } } } ty::TraitPredicate<'tcx> { - p!(print(self.trait_ref.self_ty()), ": "); + self.trait_ref.self_ty().print(p)?; + write!(p, ": ")?; if let ty::PredicatePolarity::Negative = self.polarity { - p!("!"); + write!(p, "!")?; } - p!(print(self.trait_ref.print_trait_sugared())) + self.trait_ref.print_trait_sugared().print(p)?; } ty::HostEffectPredicate<'tcx> { @@ -3189,196 +3138,223 @@ define_print! { ty::BoundConstness::Const => { "const" } ty::BoundConstness::Maybe => { "[const]" } }; - p!(print(self.trait_ref.self_ty()), ": {constness} "); - p!(print(self.trait_ref.print_trait_sugared())) + self.trait_ref.self_ty().print(p)?; + write!(p, ": {constness} ")?; + self.trait_ref.print_trait_sugared().print(p)?; } ty::TypeAndMut<'tcx> { - p!(write("{}", self.mutbl.prefix_str()), print(self.ty)) + write!(p, "{}", self.mutbl.prefix_str())?; + self.ty.print(p)?; } ty::ClauseKind<'tcx> { match *self { - ty::ClauseKind::Trait(ref data) => { - p!(print(data)) - } - ty::ClauseKind::RegionOutlives(predicate) => p!(print(predicate)), - ty::ClauseKind::TypeOutlives(predicate) => p!(print(predicate)), - ty::ClauseKind::Projection(predicate) => p!(print(predicate)), - ty::ClauseKind::HostEffect(predicate) => p!(print(predicate)), + ty::ClauseKind::Trait(ref data) => data.print(p)?, + ty::ClauseKind::RegionOutlives(predicate) => predicate.print(p)?, + ty::ClauseKind::TypeOutlives(predicate) => predicate.print(p)?, + ty::ClauseKind::Projection(predicate) => predicate.print(p)?, + ty::ClauseKind::HostEffect(predicate) => predicate.print(p)?, ty::ClauseKind::ConstArgHasType(ct, ty) => { - p!("the constant `", print(ct), "` has type `", print(ty), "`") + write!(p, "the constant `")?; + ct.print(p)?; + write!(p, "` has type `")?; + ty.print(p)?; + write!(p, "`")?; }, - ty::ClauseKind::WellFormed(term) => p!(print(term), " well-formed"), + ty::ClauseKind::WellFormed(term) => { + term.print(p)?; + write!(p, " well-formed")?; + } ty::ClauseKind::ConstEvaluatable(ct) => { - p!("the constant `", print(ct), "` can be evaluated") + write!(p, "the constant `")?; + ct.print(p)?; + write!(p, "` can be evaluated")?; + } + ty::ClauseKind::UnstableFeature(symbol) => { + write!(p, "unstable feature: ")?; + write!(p, "`{symbol}`")?; } - ty::ClauseKind::UnstableFeature(symbol) => p!("unstable feature: ", write("`{}`", symbol)), } } ty::PredicateKind<'tcx> { match *self { - ty::PredicateKind::Clause(data) => { - p!(print(data)) - } - ty::PredicateKind::Subtype(predicate) => p!(print(predicate)), - ty::PredicateKind::Coerce(predicate) => p!(print(predicate)), + ty::PredicateKind::Clause(data) => data.print(p)?, + ty::PredicateKind::Subtype(predicate) => predicate.print(p)?, + ty::PredicateKind::Coerce(predicate) => predicate.print(p)?, ty::PredicateKind::DynCompatible(trait_def_id) => { - p!("the trait `", print_def_path(trait_def_id, &[]), "` is dyn-compatible") + write!(p, "the trait `")?; + p.print_def_path(trait_def_id, &[])?; + write!(p, "` is dyn-compatible")?; } ty::PredicateKind::ConstEquate(c1, c2) => { - p!("the constant `", print(c1), "` equals `", print(c2), "`") + write!(p, "the constant `")?; + c1.print(p)?; + write!(p, "` equals `")?; + c2.print(p)?; + write!(p, "`")?; + } + ty::PredicateKind::Ambiguous => write!(p, "ambiguous")?, + ty::PredicateKind::NormalizesTo(data) => data.print(p)?, + ty::PredicateKind::AliasRelate(t1, t2, dir) => { + t1.print(p)?; + write!(p, " {dir} ")?; + t2.print(p)?; } - ty::PredicateKind::Ambiguous => p!("ambiguous"), - ty::PredicateKind::NormalizesTo(data) => p!(print(data)), - ty::PredicateKind::AliasRelate(t1, t2, dir) => p!(print(t1), write(" {} ", dir), print(t2)), } } ty::ExistentialPredicate<'tcx> { match *self { - ty::ExistentialPredicate::Trait(x) => p!(print(x)), - ty::ExistentialPredicate::Projection(x) => p!(print(x)), - ty::ExistentialPredicate::AutoTrait(def_id) => { - p!(print_def_path(def_id, &[])); - } + ty::ExistentialPredicate::Trait(x) => x.print(p)?, + ty::ExistentialPredicate::Projection(x) => x.print(p)?, + ty::ExistentialPredicate::AutoTrait(def_id) => p.print_def_path(def_id, &[])?, } } ty::ExistentialTraitRef<'tcx> { // Use a type that can't appear in defaults of type parameters. - let dummy_self = Ty::new_fresh(cx.tcx(), 0); - let trait_ref = self.with_self_ty(cx.tcx(), dummy_self); - p!(print(trait_ref.print_only_trait_path())) + let dummy_self = Ty::new_fresh(p.tcx(), 0); + let trait_ref = self.with_self_ty(p.tcx(), dummy_self); + trait_ref.print_only_trait_path().print(p)?; } ty::ExistentialProjection<'tcx> { - let name = cx.tcx().associated_item(self.def_id).name(); + let name = p.tcx().associated_item(self.def_id).name(); // The args don't contain the self ty (as it has been erased) but the corresp. // generics do as the trait always has a self ty param. We need to offset. - let args = &self.args[cx.tcx().generics_of(self.def_id).parent_count - 1..]; - p!(path_generic_args(|cx| write!(cx, "{name}"), args), " = ", print(self.term)) + let args = &self.args[p.tcx().generics_of(self.def_id).parent_count - 1..]; + p.path_generic_args(|p| write!(p, "{name}"), args)?; + write!(p, " = ")?; + self.term.print(p)?; } ty::ProjectionPredicate<'tcx> { - p!(print(self.projection_term), " == "); - cx.reset_type_limit(); - p!(print(self.term)) + self.projection_term.print(p)?; + write!(p, " == ")?; + p.reset_type_limit(); + self.term.print(p)?; } ty::SubtypePredicate<'tcx> { - p!(print(self.a), " <: "); - cx.reset_type_limit(); - p!(print(self.b)) + self.a.print(p)?; + write!(p, " <: ")?; + p.reset_type_limit(); + self.b.print(p)?; } ty::CoercePredicate<'tcx> { - p!(print(self.a), " -> "); - cx.reset_type_limit(); - p!(print(self.b)) + self.a.print(p)?; + write!(p, " -> ")?; + p.reset_type_limit(); + self.b.print(p)?; } ty::NormalizesTo<'tcx> { - p!(print(self.alias), " normalizes-to "); - cx.reset_type_limit(); - p!(print(self.term)) + self.alias.print(p)?; + write!(p, " normalizes-to ")?; + p.reset_type_limit(); + self.term.print(p)?; } } define_print_and_forward_display! { - (self, cx): + (self, p): &'tcx ty::List<Ty<'tcx>> { - p!("{{", comma_sep(self.iter()), "}}") + write!(p, "{{")?; + p.comma_sep(self.iter())?; + write!(p, "}}")?; } TraitRefPrintOnlyTraitPath<'tcx> { - p!(print_def_path(self.0.def_id, self.0.args)); + p.print_def_path(self.0.def_id, self.0.args)?; } TraitRefPrintSugared<'tcx> { if !with_reduced_queries() - && cx.tcx().trait_def(self.0.def_id).paren_sugar + && p.tcx().trait_def(self.0.def_id).paren_sugar && let ty::Tuple(args) = self.0.args.type_at(1).kind() { - p!(write("{}", cx.tcx().item_name(self.0.def_id)), "("); + write!(p, "{}(", p.tcx().item_name(self.0.def_id))?; for (i, arg) in args.iter().enumerate() { if i > 0 { - p!(", "); + write!(p, ", ")?; } - p!(print(arg)); + arg.print(p)?; } - p!(")"); + write!(p, ")")?; } else { - p!(print_def_path(self.0.def_id, self.0.args)); + p.print_def_path(self.0.def_id, self.0.args)?; } } TraitRefPrintOnlyTraitName<'tcx> { - p!(print_def_path(self.0.def_id, &[])); + p.print_def_path(self.0.def_id, &[])?; } TraitPredPrintModifiersAndPath<'tcx> { if let ty::PredicatePolarity::Negative = self.0.polarity { - p!("!") + write!(p, "!")?; } - p!(print(self.0.trait_ref.print_trait_sugared())); + self.0.trait_ref.print_trait_sugared().print(p)?; } TraitPredPrintWithBoundConstness<'tcx> { - p!(print(self.0.trait_ref.self_ty()), ": "); + self.0.trait_ref.self_ty().print(p)?; + write!(p, ": ")?; if let Some(constness) = self.1 { - p!(pretty_print_bound_constness(constness)); + p.pretty_print_bound_constness(constness)?; } if let ty::PredicatePolarity::Negative = self.0.polarity { - p!("!"); + write!(p, "!")?; } - p!(print(self.0.trait_ref.print_trait_sugared())) + self.0.trait_ref.print_trait_sugared().print(p)?; } PrintClosureAsImpl<'tcx> { - p!(pretty_closure_as_impl(self.closure)) + p.pretty_closure_as_impl(self.closure)?; } ty::ParamTy { - p!(write("{}", self.name)) + write!(p, "{}", self.name)?; } ty::PlaceholderType { match self.bound.kind { - ty::BoundTyKind::Anon => p!(write("{self:?}")), - ty::BoundTyKind::Param(def_id) => match cx.should_print_verbose() { - true => p!(write("{self:?}")), - false => p!(write("{}", cx.tcx().item_name(def_id))), + ty::BoundTyKind::Anon => write!(p, "{self:?}")?, + ty::BoundTyKind::Param(def_id) => match p.should_print_verbose() { + true => write!(p, "{self:?}")?, + false => write!(p, "{}", p.tcx().item_name(def_id))?, }, } } ty::ParamConst { - p!(write("{}", self.name)) + write!(p, "{}", self.name)?; } ty::Term<'tcx> { match self.kind() { - ty::TermKind::Ty(ty) => p!(print(ty)), - ty::TermKind::Const(c) => p!(print(c)), + ty::TermKind::Ty(ty) => ty.print(p)?, + ty::TermKind::Const(c) => c.print(p)?, } } ty::Predicate<'tcx> { - p!(print(self.kind())) + self.kind().print(p)?; } ty::Clause<'tcx> { - p!(print(self.kind())) + self.kind().print(p)?; } GenericArg<'tcx> { match self.kind() { - GenericArgKind::Lifetime(lt) => p!(print(lt)), - GenericArgKind::Type(ty) => p!(print(ty)), - GenericArgKind::Const(ct) => p!(print(ct)), + GenericArgKind::Lifetime(lt) => lt.print(p)?, + GenericArgKind::Type(ty) => ty.print(p)?, + GenericArgKind::Const(ct) => ct.print(p)?, } } } diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs index 5cf96072177..3a7852dea06 100644 --- a/compiler/rustc_middle/src/ty/region.rs +++ b/compiler/rustc_middle/src/ty/region.rs @@ -324,6 +324,14 @@ pub struct EarlyParamRegion { pub name: Symbol, } +impl EarlyParamRegion { + /// Does this early bound region have a name? Early bound regions normally + /// always have names except when using anonymous lifetimes (`'_`). + pub fn is_named(&self) -> bool { + self.name != kw::UnderscoreLifetime + } +} + impl rustc_type_ir::inherent::ParamLike for EarlyParamRegion { fn index(self) -> u32 { self.index @@ -487,3 +495,15 @@ impl BoundRegionKind { } } } + +// Some types are used a lot. Make sure they don't unintentionally get bigger. +#[cfg(target_pointer_width = "64")] +mod size_asserts { + use rustc_data_structures::static_assert_size; + + use super::*; + // tidy-alphabetical-start + static_assert_size!(RegionKind<'_>, 20); + static_assert_size!(ty::WithCachedTypeInfo<RegionKind<'_>>, 48); + // tidy-alphabetical-end +} diff --git a/compiler/rustc_middle/src/ty/rvalue_scopes.rs b/compiler/rustc_middle/src/ty/rvalue_scopes.rs index 9bf6e3a7590..7dfe2d28051 100644 --- a/compiler/rustc_middle/src/ty/rvalue_scopes.rs +++ b/compiler/rustc_middle/src/ty/rvalue_scopes.rs @@ -44,7 +44,7 @@ impl RvalueScopes { debug!("temporary_scope({expr_id:?}) = {id:?} [enclosing]"); return (Some(id), backwards_incompatible); } - ScopeData::IfThenRescope => { + ScopeData::IfThenRescope | ScopeData::MatchGuard => { debug!("temporary_scope({expr_id:?}) = {p:?} [enclosing]"); return (Some(p), backwards_incompatible); } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index a5fdce93e4b..0e2aff6f9bd 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -25,8 +25,8 @@ impl fmt::Debug for ty::TraitDef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ty::tls::with(|tcx| { with_no_trimmed_paths!({ - let s = FmtPrinter::print_string(tcx, Namespace::TypeNS, |cx| { - cx.print_def_path(self.def_id, &[]) + let s = FmtPrinter::print_string(tcx, Namespace::TypeNS, |p| { + p.print_def_path(self.def_id, &[]) })?; f.write_str(&s) }) @@ -38,8 +38,8 @@ impl<'tcx> fmt::Debug for ty::AdtDef<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ty::tls::with(|tcx| { with_no_trimmed_paths!({ - let s = FmtPrinter::print_string(tcx, Namespace::TypeNS, |cx| { - cx.print_def_path(self.did(), &[]) + let s = FmtPrinter::print_string(tcx, Namespace::TypeNS, |p| { + p.print_def_path(self.did(), &[]) })?; f.write_str(&s) }) @@ -170,9 +170,9 @@ impl<'tcx> fmt::Debug for ty::Const<'tcx> { if let ConstKind::Value(cv) = self.kind() { return ty::tls::with(move |tcx| { let cv = tcx.lift(cv).unwrap(); - let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS); - cx.pretty_print_const_valtree(cv, /*print_ty*/ true)?; - f.write_str(&cx.into_buffer()) + let mut p = FmtPrinter::new(tcx, Namespace::ValueNS); + p.pretty_print_const_valtree(cv, /*print_ty*/ true)?; + f.write_str(&p.into_buffer()) }); } // Fall back to something verbose. @@ -232,6 +232,7 @@ TrivialLiftImpls! { crate::mir::Promoted, crate::mir::interpret::AllocId, crate::mir::interpret::Scalar, + crate::ty::ParamConst, rustc_abi::ExternAbi, rustc_abi::Size, rustc_hir::Safety, @@ -271,10 +272,6 @@ TrivialTypeTraversalImpls! { crate::ty::AssocItem, crate::ty::AssocKind, crate::ty::BoundRegion, - crate::ty::BoundVar, - crate::ty::InferConst, - crate::ty::Placeholder<crate::ty::BoundRegion>, - crate::ty::Placeholder<ty::BoundVar>, crate::ty::UserTypeAnnotationIndex, crate::ty::ValTree<'tcx>, crate::ty::abstract_const::NotConstEvaluatable, @@ -302,9 +299,8 @@ TrivialTypeTraversalImpls! { // interners). TrivialTypeTraversalAndLiftImpls! { // tidy-alphabetical-start - crate::ty::ParamConst, crate::ty::ParamTy, - crate::ty::Placeholder<crate::ty::BoundTy>, + crate::ty::PlaceholderType, crate::ty::instance::ReifyReason, rustc_hir::def_id::DefId, // tidy-alphabetical-end @@ -673,30 +669,30 @@ impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for ty::Const<'tcx> { folder: &mut F, ) -> Result<Self, F::Error> { let kind = match self.kind() { - ConstKind::Param(p) => ConstKind::Param(p.try_fold_with(folder)?), - ConstKind::Infer(i) => ConstKind::Infer(i.try_fold_with(folder)?), - ConstKind::Bound(d, b) => { - ConstKind::Bound(d.try_fold_with(folder)?, b.try_fold_with(folder)?) - } - ConstKind::Placeholder(p) => ConstKind::Placeholder(p.try_fold_with(folder)?), ConstKind::Unevaluated(uv) => ConstKind::Unevaluated(uv.try_fold_with(folder)?), ConstKind::Value(v) => ConstKind::Value(v.try_fold_with(folder)?), - ConstKind::Error(e) => ConstKind::Error(e.try_fold_with(folder)?), ConstKind::Expr(e) => ConstKind::Expr(e.try_fold_with(folder)?), + + ConstKind::Param(_) + | ConstKind::Infer(_) + | ConstKind::Bound(..) + | ConstKind::Placeholder(_) + | ConstKind::Error(_) => return Ok(self), }; if kind != self.kind() { Ok(folder.cx().mk_ct_from_kind(kind)) } else { Ok(self) } } fn super_fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self { let kind = match self.kind() { - ConstKind::Param(p) => ConstKind::Param(p.fold_with(folder)), - ConstKind::Infer(i) => ConstKind::Infer(i.fold_with(folder)), - ConstKind::Bound(d, b) => ConstKind::Bound(d.fold_with(folder), b.fold_with(folder)), - ConstKind::Placeholder(p) => ConstKind::Placeholder(p.fold_with(folder)), ConstKind::Unevaluated(uv) => ConstKind::Unevaluated(uv.fold_with(folder)), ConstKind::Value(v) => ConstKind::Value(v.fold_with(folder)), - ConstKind::Error(e) => ConstKind::Error(e.fold_with(folder)), ConstKind::Expr(e) => ConstKind::Expr(e.fold_with(folder)), + + ConstKind::Param(_) + | ConstKind::Infer(_) + | ConstKind::Bound(..) + | ConstKind::Placeholder(_) + | ConstKind::Error(_) => return self, }; if kind != self.kind() { folder.cx().mk_ct_from_kind(kind) } else { self } } @@ -705,17 +701,15 @@ impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for ty::Const<'tcx> { impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Const<'tcx> { fn super_visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result { match self.kind() { - ConstKind::Param(p) => p.visit_with(visitor), - ConstKind::Infer(i) => i.visit_with(visitor), - ConstKind::Bound(d, b) => { - try_visit!(d.visit_with(visitor)); - b.visit_with(visitor) - } - ConstKind::Placeholder(p) => p.visit_with(visitor), ConstKind::Unevaluated(uv) => uv.visit_with(visitor), ConstKind::Value(v) => v.visit_with(visitor), - ConstKind::Error(e) => e.visit_with(visitor), ConstKind::Expr(e) => e.visit_with(visitor), + ConstKind::Error(e) => e.visit_with(visitor), + + ConstKind::Param(_) + | ConstKind::Infer(_) + | ConstKind::Bound(..) + | ConstKind::Placeholder(_) => V::Result::output(), } } } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 4569596cfbe..72474a60566 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -403,12 +403,6 @@ pub enum BoundTyKind { Param(DefId), } -impl From<BoundVar> for BoundTy { - fn from(var: BoundVar) -> Self { - BoundTy { var, kind: BoundTyKind::Anon } - } -} - /// Constructors for `Ty` impl<'tcx> Ty<'tcx> { /// Avoid using this in favour of more specific `new_*` methods, where possible. @@ -1462,7 +1456,7 @@ impl<'tcx> Ty<'tcx> { } } - /// Returns the type and mutability of `*ty`. + /// Returns the type of `*ty`. /// /// The parameter `explicit` indicates if this is an *explicit* dereference. /// Some types -- notably raw ptrs -- can only be dereferenced explicitly. @@ -2040,7 +2034,7 @@ mod size_asserts { use super::*; // tidy-alphabetical-start - static_assert_size!(ty::RegionKind<'_>, 20); - static_assert_size!(ty::TyKind<'_>, 24); + static_assert_size!(TyKind<'_>, 24); + static_assert_size!(ty::WithCachedTypeInfo<TyKind<'_>>, 48); // tidy-alphabetical-end } diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 88583407d25..6b187c5325a 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -789,10 +789,10 @@ impl<'tcx> IsIdentity for CanonicalUserType<'tcx> { }, GenericArgKind::Lifetime(r) => match r.kind() { - ty::ReBound(debruijn, br) => { + ty::ReBound(debruijn, b) => { // We only allow a `ty::INNERMOST` index in generic parameters. assert_eq!(debruijn, ty::INNERMOST); - cvar == br.var + cvar == b.var } _ => false, }, @@ -801,7 +801,7 @@ impl<'tcx> IsIdentity for CanonicalUserType<'tcx> { ty::ConstKind::Bound(debruijn, b) => { // We only allow a `ty::INNERMOST` index in generic parameters. assert_eq!(debruijn, ty::INNERMOST); - cvar == b + cvar == b.var } _ => false, }, diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 174892c6f4d..a7d07adf78f 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -32,7 +32,7 @@ use crate::ty::{ #[derive(Copy, Clone, Debug)] pub struct Discr<'tcx> { - /// Bit representation of the discriminant (e.g., `-128i8` is `0xFF_u128`). + /// Bit representation of the discriminant (e.g., `-1i8` is `0xFF_u128`). pub val: u128, pub ty: Ty<'tcx>, } diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml index c4c2d8a7ac8..f756f0a19ee 100644 --- a/compiler/rustc_mir_build/Cargo.toml +++ b/compiler/rustc_mir_build/Cargo.toml @@ -6,12 +6,10 @@ edition = "2024" [dependencies] # tidy-alphabetical-start itertools = "0.12" - rustc_abi = { path = "../rustc_abi" } rustc_apfloat = "0.2.0" rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } -rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index abfe8eb66dd..83fbcb30dd9 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -87,7 +87,7 @@ mir_build_confused = missing patterns are not covered because `{$variable}` is i mir_build_const_continue_bad_const = could not determine the target branch for this `#[const_continue]` .label = this value is too generic -mir_build_const_continue_missing_value = a `#[const_continue]` must break to a label with a value +mir_build_const_continue_missing_label_or_value = a `#[const_continue]` must break to a label with a value mir_build_const_continue_not_const = could not determine the target branch for this `#[const_continue]` .help = try extracting the expression into a `const` item @@ -121,8 +121,6 @@ mir_build_deref_raw_pointer_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = .note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior .label = dereference of raw pointer -mir_build_exceeds_mcdc_condition_limit = number of conditions in decision ({$num_conditions}) exceeds limit ({$max_conditions}), so MC/DC analysis will not count this expression - mir_build_extern_static_requires_unsafe = use of extern static is unsafe and requires unsafe block .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior diff --git a/compiler/rustc_mir_build/src/builder/block.rs b/compiler/rustc_mir_build/src/builder/block.rs index a71196f79d7..566d89f4269 100644 --- a/compiler/rustc_mir_build/src/builder/block.rs +++ b/compiler/rustc_mir_build/src/builder/block.rs @@ -6,7 +6,7 @@ use rustc_span::Span; use tracing::debug; use crate::builder::ForGuard::OutsideGuard; -use crate::builder::matches::{DeclareLetBindings, EmitStorageLive, ScheduleDrops}; +use crate::builder::matches::{DeclareLetBindings, ScheduleDrops}; use crate::builder::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; impl<'a, 'tcx> Builder<'a, 'tcx> { @@ -199,15 +199,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None, Some((Some(&destination), initializer_span)), ); - this.visit_primary_bindings(pattern, &mut |this, node, span| { - this.storage_live_binding( - block, - node, - span, - OutsideGuard, - ScheduleDrops::Yes, - ); - }); let else_block_span = this.thir[*else_block].span; let (matching, failure) = this.in_if_then_scope(last_remainder_scope, else_block_span, |this| { @@ -218,7 +209,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None, initializer_span, DeclareLetBindings::No, - EmitStorageLive::No, ) }); matching.and(failure) diff --git a/compiler/rustc_mir_build/src/builder/coverageinfo.rs b/compiler/rustc_mir_build/src/builder/coverageinfo.rs index aa43b273cff..14199c20921 100644 --- a/compiler/rustc_mir_build/src/builder/coverageinfo.rs +++ b/compiler/rustc_mir_build/src/builder/coverageinfo.rs @@ -8,11 +8,8 @@ use rustc_middle::thir::{ExprId, ExprKind, Pat, Thir}; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::LocalDefId; -use crate::builder::coverageinfo::mcdc::MCDCInfoBuilder; use crate::builder::{Builder, CFG}; -mod mcdc; - /// Collects coverage-related information during MIR building, to eventually be /// turned into a function's [`CoverageInfoHi`] when MIR building is complete. pub(crate) struct CoverageInfoBuilder { @@ -23,8 +20,6 @@ pub(crate) struct CoverageInfoBuilder { /// Present if branch coverage is enabled. branch_info: Option<BranchInfo>, - /// Present if MC/DC coverage is enabled. - mcdc_info: Option<MCDCInfoBuilder>, } #[derive(Default)] @@ -83,7 +78,6 @@ impl CoverageInfoBuilder { nots: FxHashMap::default(), markers: BlockMarkerGen::default(), branch_info: tcx.sess.instrument_coverage_branch().then(BranchInfo::default), - mcdc_info: tcx.sess.instrument_coverage_mcdc().then(MCDCInfoBuilder::new), }) } @@ -135,26 +129,11 @@ impl CoverageInfoBuilder { fn register_two_way_branch<'tcx>( &mut self, - tcx: TyCtxt<'tcx>, cfg: &mut CFG<'tcx>, source_info: SourceInfo, true_block: BasicBlock, false_block: BasicBlock, ) { - // Separate path for handling branches when MC/DC is enabled. - if let Some(mcdc_info) = self.mcdc_info.as_mut() { - let inject_block_marker = - |source_info, block| self.markers.inject_block_marker(cfg, source_info, block); - mcdc_info.visit_evaluated_condition( - tcx, - source_info, - true_block, - false_block, - inject_block_marker, - ); - return; - } - // Bail out if branch coverage is not enabled. let Some(branch_info) = self.branch_info.as_mut() else { return }; @@ -169,23 +148,14 @@ impl CoverageInfoBuilder { } pub(crate) fn into_done(self) -> Box<CoverageInfoHi> { - let Self { nots: _, markers: BlockMarkerGen { num_block_markers }, branch_info, mcdc_info } = - self; + let Self { nots: _, markers: BlockMarkerGen { num_block_markers }, branch_info } = self; let branch_spans = branch_info.map(|branch_info| branch_info.branch_spans).unwrap_or_default(); - let (mcdc_spans, mcdc_degraded_branch_spans) = - mcdc_info.map(MCDCInfoBuilder::into_done).unwrap_or_default(); - // For simplicity, always return an info struct (without Option), even // if there's nothing interesting in it. - Box::new(CoverageInfoHi { - num_block_markers, - branch_spans, - mcdc_degraded_branch_spans, - mcdc_spans, - }) + Box::new(CoverageInfoHi { num_block_markers, branch_spans }) } } @@ -238,14 +208,7 @@ impl<'tcx> Builder<'_, 'tcx> { mir::TerminatorKind::if_(mir::Operand::Copy(place), true_block, false_block), ); - // Separate path for handling branches when MC/DC is enabled. - coverage_info.register_two_way_branch( - self.tcx, - &mut self.cfg, - source_info, - true_block, - false_block, - ); + coverage_info.register_two_way_branch(&mut self.cfg, source_info, true_block, false_block); let join_block = self.cfg.start_new_block(); self.cfg.goto(true_block, source_info, join_block); @@ -276,13 +239,7 @@ impl<'tcx> Builder<'_, 'tcx> { let source_info = SourceInfo { span: self.thir[expr_id].span, scope: self.source_scope }; - coverage_info.register_two_way_branch( - self.tcx, - &mut self.cfg, - source_info, - then_block, - else_block, - ); + coverage_info.register_two_way_branch(&mut self.cfg, source_info, then_block, else_block); } /// If branch coverage is enabled, inject marker statements into `true_block` @@ -299,12 +256,6 @@ impl<'tcx> Builder<'_, 'tcx> { let Some(coverage_info) = self.coverage_info.as_mut() else { return }; let source_info = SourceInfo { span: pattern.span, scope: self.source_scope }; - coverage_info.register_two_way_branch( - self.tcx, - &mut self.cfg, - source_info, - true_block, - false_block, - ); + coverage_info.register_two_way_branch(&mut self.cfg, source_info, true_block, false_block); } } diff --git a/compiler/rustc_mir_build/src/builder/coverageinfo/mcdc.rs b/compiler/rustc_mir_build/src/builder/coverageinfo/mcdc.rs deleted file mode 100644 index 6b4871dc1fc..00000000000 --- a/compiler/rustc_mir_build/src/builder/coverageinfo/mcdc.rs +++ /dev/null @@ -1,295 +0,0 @@ -use std::collections::VecDeque; - -use rustc_middle::bug; -use rustc_middle::mir::coverage::{ - BlockMarkerId, ConditionId, ConditionInfo, MCDCBranchSpan, MCDCDecisionSpan, -}; -use rustc_middle::mir::{BasicBlock, SourceInfo}; -use rustc_middle::thir::LogicalOp; -use rustc_middle::ty::TyCtxt; -use rustc_span::Span; - -use crate::builder::Builder; -use crate::errors::MCDCExceedsConditionLimit; - -/// LLVM uses `i16` to represent condition id. Hence `i16::MAX` is the hard limit for number of -/// conditions in a decision. -const MAX_CONDITIONS_IN_DECISION: usize = i16::MAX as usize; - -#[derive(Default)] -struct MCDCDecisionCtx { - /// To construct condition evaluation tree. - decision_stack: VecDeque<ConditionInfo>, - processing_decision: Option<MCDCDecisionSpan>, - conditions: Vec<MCDCBranchSpan>, -} - -struct MCDCState { - decision_ctx_stack: Vec<MCDCDecisionCtx>, -} - -impl MCDCState { - fn new() -> Self { - Self { decision_ctx_stack: vec![MCDCDecisionCtx::default()] } - } - - /// Decision depth is given as a u16 to reduce the size of the `CoverageKind`, - /// as it is very unlikely that the depth ever reaches 2^16. - #[inline] - fn decision_depth(&self) -> u16 { - match u16::try_from(self.decision_ctx_stack.len()) - .expect( - "decision depth did not fit in u16, this is likely to be an instrumentation error", - ) - .checked_sub(1) - { - Some(d) => d, - None => bug!("Unexpected empty decision stack"), - } - } - - // At first we assign ConditionIds for each sub expression. - // If the sub expression is composite, re-assign its ConditionId to its LHS and generate a new ConditionId for its RHS. - // - // Example: "x = (A && B) || (C && D) || (D && F)" - // - // Visit Depth1: - // (A && B) || (C && D) || (D && F) - // ^-------LHS--------^ ^-RHS--^ - // ID=1 ID=2 - // - // Visit LHS-Depth2: - // (A && B) || (C && D) - // ^-LHS--^ ^-RHS--^ - // ID=1 ID=3 - // - // Visit LHS-Depth3: - // (A && B) - // LHS RHS - // ID=1 ID=4 - // - // Visit RHS-Depth3: - // (C && D) - // LHS RHS - // ID=3 ID=5 - // - // Visit RHS-Depth2: (D && F) - // LHS RHS - // ID=2 ID=6 - // - // Visit Depth1: - // (A && B) || (C && D) || (D && F) - // ID=1 ID=4 ID=3 ID=5 ID=2 ID=6 - // - // A node ID of '0' always means MC/DC isn't being tracked. - // - // If a "next" node ID is '0', it means it's the end of the test vector. - // - // As the compiler tracks expression in pre-order, we can ensure that condition info of parents are always properly assigned when their children are visited. - // - If the op is AND, the "false_next" of LHS and RHS should be the parent's "false_next". While "true_next" of the LHS is the RHS, the "true next" of RHS is the parent's "true_next". - // - If the op is OR, the "true_next" of LHS and RHS should be the parent's "true_next". While "false_next" of the LHS is the RHS, the "false next" of RHS is the parent's "false_next". - fn record_conditions(&mut self, op: LogicalOp, span: Span) { - let decision_depth = self.decision_depth(); - let Some(decision_ctx) = self.decision_ctx_stack.last_mut() else { - bug!("Unexpected empty decision_ctx_stack") - }; - let decision = match decision_ctx.processing_decision.as_mut() { - Some(decision) => { - decision.span = decision.span.to(span); - decision - } - None => decision_ctx.processing_decision.insert(MCDCDecisionSpan { - span, - num_conditions: 0, - end_markers: vec![], - decision_depth, - }), - }; - - let parent_condition = decision_ctx.decision_stack.pop_back().unwrap_or_else(|| { - assert_eq!( - decision.num_conditions, 0, - "decision stack must be empty only for empty decision" - ); - decision.num_conditions += 1; - ConditionInfo { - condition_id: ConditionId::START, - true_next_id: None, - false_next_id: None, - } - }); - let lhs_id = parent_condition.condition_id; - - let rhs_condition_id = ConditionId::from(decision.num_conditions); - decision.num_conditions += 1; - let (lhs, rhs) = match op { - LogicalOp::And => { - let lhs = ConditionInfo { - condition_id: lhs_id, - true_next_id: Some(rhs_condition_id), - false_next_id: parent_condition.false_next_id, - }; - let rhs = ConditionInfo { - condition_id: rhs_condition_id, - true_next_id: parent_condition.true_next_id, - false_next_id: parent_condition.false_next_id, - }; - (lhs, rhs) - } - LogicalOp::Or => { - let lhs = ConditionInfo { - condition_id: lhs_id, - true_next_id: parent_condition.true_next_id, - false_next_id: Some(rhs_condition_id), - }; - let rhs = ConditionInfo { - condition_id: rhs_condition_id, - true_next_id: parent_condition.true_next_id, - false_next_id: parent_condition.false_next_id, - }; - (lhs, rhs) - } - }; - // We visit expressions tree in pre-order, so place the left-hand side on the top. - decision_ctx.decision_stack.push_back(rhs); - decision_ctx.decision_stack.push_back(lhs); - } - - fn try_finish_decision( - &mut self, - span: Span, - true_marker: BlockMarkerId, - false_marker: BlockMarkerId, - degraded_branches: &mut Vec<MCDCBranchSpan>, - ) -> Option<(MCDCDecisionSpan, Vec<MCDCBranchSpan>)> { - let Some(decision_ctx) = self.decision_ctx_stack.last_mut() else { - bug!("Unexpected empty decision_ctx_stack") - }; - let Some(condition_info) = decision_ctx.decision_stack.pop_back() else { - let branch = MCDCBranchSpan { - span, - condition_info: ConditionInfo { - condition_id: ConditionId::START, - true_next_id: None, - false_next_id: None, - }, - true_marker, - false_marker, - }; - degraded_branches.push(branch); - return None; - }; - let Some(decision) = decision_ctx.processing_decision.as_mut() else { - bug!("Processing decision should have been created before any conditions are taken"); - }; - if condition_info.true_next_id.is_none() { - decision.end_markers.push(true_marker); - } - if condition_info.false_next_id.is_none() { - decision.end_markers.push(false_marker); - } - decision_ctx.conditions.push(MCDCBranchSpan { - span, - condition_info, - true_marker, - false_marker, - }); - - if decision_ctx.decision_stack.is_empty() { - let conditions = std::mem::take(&mut decision_ctx.conditions); - decision_ctx.processing_decision.take().map(|decision| (decision, conditions)) - } else { - None - } - } -} - -pub(crate) struct MCDCInfoBuilder { - degraded_spans: Vec<MCDCBranchSpan>, - mcdc_spans: Vec<(MCDCDecisionSpan, Vec<MCDCBranchSpan>)>, - state: MCDCState, -} - -impl MCDCInfoBuilder { - pub(crate) fn new() -> Self { - Self { degraded_spans: vec![], mcdc_spans: vec![], state: MCDCState::new() } - } - - pub(crate) fn visit_evaluated_condition( - &mut self, - tcx: TyCtxt<'_>, - source_info: SourceInfo, - true_block: BasicBlock, - false_block: BasicBlock, - mut inject_block_marker: impl FnMut(SourceInfo, BasicBlock) -> BlockMarkerId, - ) { - let true_marker = inject_block_marker(source_info, true_block); - let false_marker = inject_block_marker(source_info, false_block); - - // take_condition() returns Some for decision_result when the decision stack - // is empty, i.e. when all the conditions of the decision were instrumented, - // and the decision is "complete". - if let Some((decision, conditions)) = self.state.try_finish_decision( - source_info.span, - true_marker, - false_marker, - &mut self.degraded_spans, - ) { - let num_conditions = conditions.len(); - assert_eq!( - num_conditions, decision.num_conditions, - "final number of conditions is not correct" - ); - match num_conditions { - 0 => { - unreachable!("Decision with no condition is not expected"); - } - 1..=MAX_CONDITIONS_IN_DECISION => { - self.mcdc_spans.push((decision, conditions)); - } - _ => { - self.degraded_spans.extend(conditions); - - tcx.dcx().emit_warn(MCDCExceedsConditionLimit { - span: decision.span, - num_conditions, - max_conditions: MAX_CONDITIONS_IN_DECISION, - }); - } - } - } - } - - pub(crate) fn into_done( - self, - ) -> (Vec<(MCDCDecisionSpan, Vec<MCDCBranchSpan>)>, Vec<MCDCBranchSpan>) { - (self.mcdc_spans, self.degraded_spans) - } -} - -impl Builder<'_, '_> { - pub(crate) fn visit_coverage_branch_operation(&mut self, logical_op: LogicalOp, span: Span) { - if let Some(coverage_info) = self.coverage_info.as_mut() - && let Some(mcdc_info) = coverage_info.mcdc_info.as_mut() - { - mcdc_info.state.record_conditions(logical_op, span); - } - } - - pub(crate) fn mcdc_increment_depth_if_enabled(&mut self) { - if let Some(coverage_info) = self.coverage_info.as_mut() - && let Some(mcdc_info) = coverage_info.mcdc_info.as_mut() - { - mcdc_info.state.decision_ctx_stack.push(MCDCDecisionCtx::default()); - }; - } - - pub(crate) fn mcdc_decrement_depth_if_enabled(&mut self) { - if let Some(coverage_info) = self.coverage_info.as_mut() - && let Some(mcdc_info) = coverage_info.mcdc_info.as_mut() - && mcdc_info.state.decision_ctx_stack.pop().is_none() - { - bug!("Unexpected empty decision stack"); - }; - } -} diff --git a/compiler/rustc_mir_build/src/builder/expr/as_operand.rs b/compiler/rustc_mir_build/src/builder/expr/as_operand.rs index 982e7aa8246..6a422223990 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_operand.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_operand.rs @@ -57,7 +57,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// ``` /// #![feature(unsized_fn_params)] /// # use core::fmt::Debug; - /// fn foo(_p: dyn Debug) { /* ... */ } + /// fn foo(_p: dyn Debug) { + /// /* ... */ + /// } /// /// fn bar(box_p: Box<dyn Debug>) { foo(*box_p); } /// ``` diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs index 82b883a99a1..eb99c184bd2 100644 --- a/compiler/rustc_mir_build/src/builder/expr/into.rs +++ b/compiler/rustc_mir_build/src/builder/expr/into.rs @@ -159,8 +159,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let condition_scope = this.local_scope(); let source_info = this.source_info(expr.span); - this.visit_coverage_branch_operation(op, expr.span); - // We first evaluate the left-hand side of the predicate ... let (then_block, else_block) = this.in_if_then_scope(condition_scope, expr.span, |this| { diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs index 3a7854a5e11..7a848536d0e 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -124,9 +124,19 @@ impl<'tcx> MatchPairTree<'tcx> { let test_case = match pattern.kind { PatKind::Missing | PatKind::Wild | PatKind::Error(_) => None, - PatKind::Or { ref pats } => Some(TestCase::Or { - pats: pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect(), - }), + PatKind::Or { ref pats } => { + let pats: Box<[FlatPat<'tcx>]> = + pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect(); + if !pats[0].extra_data.bindings.is_empty() { + // Hold a place for any bindings established in (possibly-nested) or-patterns. + // By only holding a place when bindings are present, we skip over any + // or-patterns that will be simplified by `merge_trivial_subcandidates`. In + // other words, we can assume this expands into subcandidates. + // FIXME(@dianne): this needs updating/removing if we always merge or-patterns + extra_data.bindings.push(super::SubpatternBindings::FromOrPattern); + } + Some(TestCase::Or { pats }) + } PatKind::Range(ref range) => { if range.is_full_range(cx.tcx) == Some(true) { @@ -194,12 +204,12 @@ impl<'tcx> MatchPairTree<'tcx> { // Then push this binding, after any bindings in the subpattern. if let Some(source) = place { - extra_data.bindings.push(super::Binding { + extra_data.bindings.push(super::SubpatternBindings::One(super::Binding { span: pattern.span, source, var_id: var, binding_mode: mode, - }); + })); } None diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 2c29b862841..94ae5dadd8a 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -5,11 +5,11 @@ //! This also includes code for pattern bindings in `let` statements and //! function parameters. -use std::assert_matches::assert_matches; use std::borrow::Borrow; use std::mem; use std::sync::Arc; +use itertools::{Itertools, Position}; use rustc_abi::VariantIdx; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -69,18 +69,6 @@ pub(crate) enum DeclareLetBindings { LetNotPermitted, } -/// Used by [`Builder::bind_matched_candidate_for_arm_body`] to determine -/// whether or not to call [`Builder::storage_live_binding`] to emit -/// [`StatementKind::StorageLive`]. -#[derive(Clone, Copy)] -pub(crate) enum EmitStorageLive { - /// Yes, emit `StorageLive` as normal. - Yes, - /// No, don't emit `StorageLive`. The caller has taken responsibility for - /// emitting `StorageLive` as appropriate. - No, -} - /// Used by [`Builder::storage_live_binding`] and [`Builder::bind_matched_candidate_for_arm_body`] /// to decide whether to schedule drops. #[derive(Clone, Copy, Debug)] @@ -125,15 +113,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let expr_span = expr.span; match expr.kind { - ExprKind::LogicalOp { op: op @ LogicalOp::And, lhs, rhs } => { - this.visit_coverage_branch_operation(op, expr_span); + ExprKind::LogicalOp { op: LogicalOp::And, lhs, rhs } => { let lhs_then_block = this.then_else_break_inner(block, lhs, args).into_block(); let rhs_then_block = this.then_else_break_inner(lhs_then_block, rhs, args).into_block(); rhs_then_block.unit() } - ExprKind::LogicalOp { op: op @ LogicalOp::Or, lhs, rhs } => { - this.visit_coverage_branch_operation(op, expr_span); + ExprKind::LogicalOp { op: LogicalOp::Or, lhs, rhs } => { let local_scope = this.local_scope(); let (lhs_success_block, failure_block) = this.in_if_then_scope(local_scope, expr_span, |this| { @@ -207,16 +193,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Some(args.variable_source_info.scope), args.variable_source_info.span, args.declare_let_bindings, - EmitStorageLive::Yes, ), _ => { let mut block = block; let temp_scope = args.temp_scope_override.unwrap_or_else(|| this.local_scope()); let mutability = Mutability::Mut; - // Increment the decision depth, in case we encounter boolean expressions - // further down. - this.mcdc_increment_depth_if_enabled(); let place = unpack!( block = this.as_temp( block, @@ -228,7 +210,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { mutability ) ); - this.mcdc_decrement_depth_if_enabled(); let operand = Operand::Move(Place::from(place)); @@ -447,48 +428,53 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let arm_source_info = self.source_info(arm.span); let arm_scope = (arm.scope, arm_source_info); let match_scope = self.local_scope(); + let guard_scope = arm + .guard + .map(|_| region::Scope { data: region::ScopeData::MatchGuard, ..arm.scope }); self.in_scope(arm_scope, arm.lint_level, |this| { - let old_dedup_scope = - mem::replace(&mut this.fixed_temps_scope, Some(arm.scope)); - - // `try_to_place` may fail if it is unable to resolve the given - // `PlaceBuilder` inside a closure. In this case, we don't want to include - // a scrutinee place. `scrutinee_place_builder` will fail to be resolved - // if the only match arm is a wildcard (`_`). - // Example: - // ``` - // let foo = (0, 1); - // let c = || { - // match foo { _ => () }; - // }; - // ``` - let scrutinee_place = scrutinee_place_builder.try_to_place(this); - let opt_scrutinee_place = - scrutinee_place.as_ref().map(|place| (Some(place), scrutinee_span)); - let scope = this.declare_bindings( - None, - arm.span, - &arm.pattern, - arm.guard, - opt_scrutinee_place, - ); + this.opt_in_scope(guard_scope.map(|scope| (scope, arm_source_info)), |this| { + // `if let` guard temps needing deduplicating will be in the guard scope. + let old_dedup_scope = + mem::replace(&mut this.fixed_temps_scope, guard_scope); + + // `try_to_place` may fail if it is unable to resolve the given + // `PlaceBuilder` inside a closure. In this case, we don't want to include + // a scrutinee place. `scrutinee_place_builder` will fail to be resolved + // if the only match arm is a wildcard (`_`). + // Example: + // ``` + // let foo = (0, 1); + // let c = || { + // match foo { _ => () }; + // }; + // ``` + let scrutinee_place = scrutinee_place_builder.try_to_place(this); + let opt_scrutinee_place = + scrutinee_place.as_ref().map(|place| (Some(place), scrutinee_span)); + let scope = this.declare_bindings( + None, + arm.span, + &arm.pattern, + arm.guard, + opt_scrutinee_place, + ); - let arm_block = this.bind_pattern( - outer_source_info, - branch, - &built_match_tree.fake_borrow_temps, - scrutinee_span, - Some((arm, match_scope)), - EmitStorageLive::Yes, - ); + let arm_block = this.bind_pattern( + outer_source_info, + branch, + &built_match_tree.fake_borrow_temps, + scrutinee_span, + Some((arm, match_scope)), + ); - this.fixed_temps_scope = old_dedup_scope; + this.fixed_temps_scope = old_dedup_scope; - if let Some(source_scope) = scope { - this.source_scope = source_scope; - } + if let Some(source_scope) = scope { + this.source_scope = source_scope; + } - this.expr_into_dest(destination, arm_block, arm.body) + this.expr_into_dest(destination, arm_block, arm.body) + }) }) .into_block() }) @@ -533,7 +519,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fake_borrow_temps: &[(Place<'tcx>, Local, FakeBorrowKind)], scrutinee_span: Span, arm_match_scope: Option<(&Arm<'tcx>, region::Scope)>, - emit_storage_live: EmitStorageLive, ) -> BasicBlock { if branch.sub_branches.len() == 1 { let [sub_branch] = branch.sub_branches.try_into().unwrap(); @@ -544,7 +529,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { scrutinee_span, arm_match_scope, ScheduleDrops::Yes, - emit_storage_live, ) } else { // It's helpful to avoid scheduling drops multiple times to save @@ -561,27 +545,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // return: it isn't bound by move until right before enter the arm. // To handle this we instead unschedule it's drop after each time // we lower the guard. + // As a result, we end up with the drop order of the last sub-branch we lower. To use + // the drop order for the first sub-branch, we lower sub-branches in reverse (#142163). let target_block = self.cfg.start_new_block(); - let mut schedule_drops = ScheduleDrops::Yes; - let arm = arm_match_scope.unzip().0; - // We keep a stack of all of the bindings and type ascriptions - // from the parent candidates that we visit, that also need to - // be bound for each candidate. - for sub_branch in branch.sub_branches { - if let Some(arm) = arm { - self.clear_top_scope(arm.scope); - } + for (pos, sub_branch) in branch.sub_branches.into_iter().rev().with_position() { + debug_assert!(pos != Position::Only); + let schedule_drops = + if pos == Position::Last { ScheduleDrops::Yes } else { ScheduleDrops::No }; let binding_end = self.bind_and_guard_matched_candidate( sub_branch, fake_borrow_temps, scrutinee_span, arm_match_scope, schedule_drops, - emit_storage_live, ); - if arm.is_none() { - schedule_drops = ScheduleDrops::No; - } self.cfg.goto(binding_end, outer_source_info, target_block); } @@ -741,7 +718,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &[], irrefutable_pat.span, None, - EmitStorageLive::Yes, ) .unit() } @@ -996,7 +972,7 @@ struct PatternExtraData<'tcx> { span: Span, /// Bindings that must be established. - bindings: Vec<Binding<'tcx>>, + bindings: Vec<SubpatternBindings<'tcx>>, /// Types that must be asserted. ascriptions: Vec<Ascription<'tcx>>, @@ -1011,6 +987,15 @@ impl<'tcx> PatternExtraData<'tcx> { } } +#[derive(Debug, Clone)] +enum SubpatternBindings<'tcx> { + /// A single binding. + One(Binding<'tcx>), + /// Holds the place for an or-pattern's bindings. This ensures their drops are scheduled in the + /// order the primary bindings appear. See rust-lang/rust#142163 for more information. + FromOrPattern, +} + /// A pattern in a form suitable for lowering the match tree, with all irrefutable /// patterns simplified away. /// @@ -1226,7 +1211,7 @@ fn traverse_candidate<'tcx, C, T, I>( } } -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug)] struct Binding<'tcx> { span: Span, source: Place<'tcx>, @@ -1452,12 +1437,7 @@ impl<'tcx> MatchTreeSubBranch<'tcx> { span: candidate.extra_data.span, success_block: candidate.pre_binding_block.unwrap(), otherwise_block: candidate.otherwise_block.unwrap(), - bindings: parent_data - .iter() - .flat_map(|d| &d.bindings) - .chain(&candidate.extra_data.bindings) - .cloned() - .collect(), + bindings: sub_branch_bindings(parent_data, &candidate.extra_data.bindings), ascriptions: parent_data .iter() .flat_map(|d| &d.ascriptions) @@ -1490,6 +1470,68 @@ impl<'tcx> MatchTreeBranch<'tcx> { } } +/// Collects the bindings for a [`MatchTreeSubBranch`], preserving the order they appear in the +/// pattern, as though the or-alternatives chosen in this sub-branch were inlined. +fn sub_branch_bindings<'tcx>( + parents: &[PatternExtraData<'tcx>], + leaf_bindings: &[SubpatternBindings<'tcx>], +) -> Vec<Binding<'tcx>> { + // In the common case, all bindings will be in leaves. Allocate to fit the leaf's bindings. + let mut all_bindings = Vec::with_capacity(leaf_bindings.len()); + let mut remainder = parents + .iter() + .map(|parent| parent.bindings.as_slice()) + .chain([leaf_bindings]) + // Skip over unsimplified or-patterns without bindings. + .filter(|bindings| !bindings.is_empty()); + if let Some(candidate_bindings) = remainder.next() { + push_sub_branch_bindings(&mut all_bindings, candidate_bindings, &mut remainder); + } + // Make sure we've included all bindings. For ill-formed patterns like `(x, _ | y)`, we may not + // have collected all bindings yet, since we only check the first alternative when determining + // whether to inline subcandidates' bindings. + // FIXME(@dianne): prevent ill-formed patterns from getting here + while let Some(candidate_bindings) = remainder.next() { + ty::tls::with(|tcx| { + tcx.dcx().delayed_bug("mismatched or-pattern bindings but no error emitted") + }); + // To recover, we collect the rest in an arbitrary order. + push_sub_branch_bindings(&mut all_bindings, candidate_bindings, &mut remainder); + } + all_bindings +} + +/// Helper for [`sub_branch_bindings`]. Collects bindings from `candidate_bindings` into +/// `flattened`. Bindings in or-patterns are collected recursively from `remainder`. +fn push_sub_branch_bindings<'c, 'tcx: 'c>( + flattened: &mut Vec<Binding<'tcx>>, + candidate_bindings: &'c [SubpatternBindings<'tcx>], + remainder: &mut impl Iterator<Item = &'c [SubpatternBindings<'tcx>]>, +) { + for subpat_bindings in candidate_bindings { + match subpat_bindings { + SubpatternBindings::One(binding) => flattened.push(*binding), + SubpatternBindings::FromOrPattern => { + // Inline bindings from an or-pattern. By construction, this always + // corresponds to a subcandidate and its closest descendants (i.e. those + // from nested or-patterns, but not adjacent or-patterns). To handle + // adjacent or-patterns, e.g. `(x | x, y | y)`, we update the `remainder` to + // point to the first descendant candidate from outside this or-pattern. + if let Some(subcandidate_bindings) = remainder.next() { + push_sub_branch_bindings(flattened, subcandidate_bindings, remainder); + } else { + // For ill-formed patterns like `x | _`, we may not have any subcandidates left + // to inline bindings from. + // FIXME(@dianne): prevent ill-formed patterns from getting here + ty::tls::with(|tcx| { + tcx.dcx().delayed_bug("mismatched or-pattern bindings but no error emitted") + }); + }; + } + } + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(crate) enum HasMatchGuard { Yes, @@ -2364,7 +2406,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { source_scope: Option<SourceScope>, scope_span: Span, declare_let_bindings: DeclareLetBindings, - emit_storage_live: EmitStorageLive, ) -> BlockAnd<()> { let expr_span = self.thir[expr_id].span; let scrutinee = unpack!(block = self.lower_scrutinee(block, expr_id, expr_span)); @@ -2398,14 +2439,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - let success = self.bind_pattern( - self.source_info(pat.span), - branch, - &[], - expr_span, - None, - emit_storage_live, - ); + let success = self.bind_pattern(self.source_info(pat.span), branch, &[], expr_span, None); // If branch coverage is enabled, record this branch. self.visit_coverage_conditional_let(pat, success, built_tree.otherwise_block); @@ -2428,7 +2462,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { scrutinee_span: Span, arm_match_scope: Option<(&Arm<'tcx>, region::Scope)>, schedule_drops: ScheduleDrops, - emit_storage_live: EmitStorageLive, ) -> BasicBlock { debug!("bind_and_guard_matched_candidate(subbranch={:?})", sub_branch); @@ -2453,11 +2486,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Bindings for guards require some extra handling to automatically // insert implicit references/dereferences. - self.bind_matched_candidate_for_guard( - block, - schedule_drops, - sub_branch.bindings.iter(), - ); + // This always schedules storage drops, so we may need to unschedule them below. + self.bind_matched_candidate_for_guard(block, sub_branch.bindings.iter()); let guard_frame = GuardFrame { locals: sub_branch .bindings @@ -2489,6 +2519,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) }); + // If this isn't the final sub-branch being lowered, we need to unschedule drops of + // bindings and temporaries created for and by the guard. As a result, the drop order + // for the arm will correspond to the binding order of the final sub-branch lowered. + if matches!(schedule_drops, ScheduleDrops::No) { + self.clear_match_arm_and_guard_scopes(arm.scope); + } + let source_info = self.source_info(guard_span); let guard_end = self.source_info(tcx.sess.source_map().end_point(guard_span)); let guard_frame = self.guard_context.pop().unwrap(); @@ -2538,16 +2575,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let cause = FakeReadCause::ForGuardBinding; self.cfg.push_fake_read(post_guard_block, guard_end, cause, Place::from(local_id)); } - assert_matches!( - schedule_drops, - ScheduleDrops::Yes, - "patterns with guards must schedule drops" - ); + // Only schedule drops for the last sub-branch we lower. self.bind_matched_candidate_for_arm_body( post_guard_block, - ScheduleDrops::Yes, + schedule_drops, by_value_bindings, - emit_storage_live, ); post_guard_block @@ -2559,7 +2591,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, schedule_drops, sub_branch.bindings.iter(), - emit_storage_live, ); block } @@ -2671,7 +2702,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn bind_matched_candidate_for_guard<'b>( &mut self, block: BasicBlock, - schedule_drops: ScheduleDrops, bindings: impl IntoIterator<Item = &'b Binding<'tcx>>, ) where 'tcx: 'b, @@ -2690,12 +2720,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // a reference R: &T pointing to the location matched by // the pattern, and every occurrence of P within a guard // denotes *R. + // Drops must be scheduled to emit `StorageDead` on the guard's failure/break branches. let ref_for_guard = self.storage_live_binding( block, binding.var_id, binding.span, RefWithinGuard, - schedule_drops, + ScheduleDrops::Yes, ); match binding.binding_mode.0 { ByRef::No => { @@ -2705,13 +2736,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.push_assign(block, source_info, ref_for_guard, rvalue); } ByRef::Yes(mutbl) => { - // The arm binding will be by reference, so eagerly create it now. + // The arm binding will be by reference, so eagerly create it now. Drops must + // be scheduled to emit `StorageDead` on the guard's failure/break branches. let value_for_arm = self.storage_live_binding( block, binding.var_id, binding.span, OutsideGuard, - schedule_drops, + ScheduleDrops::Yes, ); let rvalue = @@ -2730,7 +2762,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block: BasicBlock, schedule_drops: ScheduleDrops, bindings: impl IntoIterator<Item = &'b Binding<'tcx>>, - emit_storage_live: EmitStorageLive, ) where 'tcx: 'b, { @@ -2740,19 +2771,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Assign each of the bindings. This may trigger moves out of the candidate. for binding in bindings { let source_info = self.source_info(binding.span); - let local = match emit_storage_live { - // Here storages are already alive, probably because this is a binding - // from let-else. - // We just need to schedule drop for the value. - EmitStorageLive::No => self.var_local_id(binding.var_id, OutsideGuard).into(), - EmitStorageLive::Yes => self.storage_live_binding( - block, - binding.var_id, - binding.span, - OutsideGuard, - schedule_drops, - ), - }; + let local = self.storage_live_binding( + block, + binding.var_id, + binding.span, + OutsideGuard, + schedule_drops, + ); if matches!(schedule_drops, ScheduleDrops::Yes) { self.schedule_drop_for_binding(binding.var_id, binding.span, OutsideGuard); } diff --git a/compiler/rustc_mir_build/src/builder/matches/util.rs b/compiler/rustc_mir_build/src/builder/matches/util.rs index 589e350a03f..2c8ad95b6af 100644 --- a/compiler/rustc_mir_build/src/builder/matches/util.rs +++ b/compiler/rustc_mir_build/src/builder/matches/util.rs @@ -138,7 +138,9 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> { fn visit_candidate(&mut self, candidate: &Candidate<'tcx>) { for binding in &candidate.extra_data.bindings { - self.visit_binding(binding); + if let super::SubpatternBindings::One(binding) = binding { + self.visit_binding(binding); + } } for match_pair in &candidate.match_pairs { self.visit_match_pair(match_pair); @@ -147,7 +149,9 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> { fn visit_flat_pat(&mut self, flat_pat: &FlatPat<'tcx>) { for binding in &flat_pat.extra_data.bindings { - self.visit_binding(binding); + if let super::SubpatternBindings::One(binding) = binding { + self.visit_binding(binding); + } } for match_pair in &flat_pat.match_pairs { self.visit_match_pair(match_pair); diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs index 1240b34cf9d..96659873622 100644 --- a/compiler/rustc_mir_build/src/builder/scope.rs +++ b/compiler/rustc_mir_build/src/builder/scope.rs @@ -697,6 +697,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.and(rv) } + /// Convenience wrapper that executes `f` either within the current scope or a new scope. + /// Used for pattern matching, which introduces an additional scope for patterns with guards. + pub(crate) fn opt_in_scope<R>( + &mut self, + opt_region_scope: Option<(region::Scope, SourceInfo)>, + f: impl FnOnce(&mut Builder<'a, 'tcx>) -> BlockAnd<R>, + ) -> BlockAnd<R> { + if let Some(region_scope) = opt_region_scope { + self.in_scope(region_scope, LintLevel::Inherited, f) + } else { + f(self) + } + } + /// Push a scope onto the stack. You can then build code in this /// scope and call `pop_scope` afterwards. Note that these two /// calls must be paired; using `in_scope` as a convenience @@ -1750,17 +1764,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { success_block } - /// Unschedules any drops in the top scope. + /// Unschedules any drops in the top two scopes. /// - /// This is only needed for `match` arm scopes, because they have one - /// entrance per pattern, but only one exit. - pub(crate) fn clear_top_scope(&mut self, region_scope: region::Scope) { - let top_scope = self.scopes.scopes.last_mut().unwrap(); + /// This is only needed for pattern-matches combining guards and or-patterns: or-patterns lead + /// to guards being lowered multiple times before lowering the arm body, so we unschedle drops + /// for guards' temporaries and bindings between lowering each instance of an match arm's guard. + pub(crate) fn clear_match_arm_and_guard_scopes(&mut self, region_scope: region::Scope) { + let [.., arm_scope, guard_scope] = &mut *self.scopes.scopes else { + bug!("matches with guards should introduce separate scopes for the pattern and guard"); + }; - assert_eq!(top_scope.region_scope, region_scope); + assert_eq!(arm_scope.region_scope, region_scope); + assert_eq!(guard_scope.region_scope.data, region::ScopeData::MatchGuard); + assert_eq!(guard_scope.region_scope.local_id, region_scope.local_id); - top_scope.drops.clear(); - top_scope.invalidate_cache(); + arm_scope.drops.clear(); + arm_scope.invalidate_cache(); + guard_scope.drops.clear(); + guard_scope.invalidate_cache(); } } diff --git a/compiler/rustc_mir_build/src/check_tail_calls.rs b/compiler/rustc_mir_build/src/check_tail_calls.rs index 18db8c1debb..3ecccb422c4 100644 --- a/compiler/rustc_mir_build/src/check_tail_calls.rs +++ b/compiler/rustc_mir_build/src/check_tail_calls.rs @@ -60,9 +60,13 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> { let BodyTy::Fn(caller_sig) = self.thir.body_type else { span_bug!( call.span, - "`become` outside of functions should have been disallowed by hit_typeck" + "`become` outside of functions should have been disallowed by hir_typeck" ) }; + // While the `caller_sig` does have its regions erased, it does not have its + // binders anonymized. We call `erase_regions` once again to anonymize any binders + // within the signature, such as in function pointer or `dyn Trait` args. + let caller_sig = self.tcx.erase_regions(caller_sig); let ExprKind::Scope { value, .. } = call.kind else { span_bug!(call.span, "expected scope, found: {call:?}") @@ -89,22 +93,39 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> { self.report_op(ty, args, fn_span, expr); } - // Closures in thir look something akin to - // `for<'a> extern "rust-call" fn(&'a [closure@...], ()) -> <[closure@...] as FnOnce<()>>::Output {<[closure@...] as Fn<()>>::call}` - // So we have to check for them in this weird way... if let &ty::FnDef(did, args) = ty.kind() { + // Closures in thir look something akin to + // `for<'a> extern "rust-call" fn(&'a [closure@...], ()) -> <[closure@...] as FnOnce<()>>::Output {<[closure@...] as Fn<()>>::call}` + // So we have to check for them in this weird way... let parent = self.tcx.parent(did); if self.tcx.fn_trait_kind_from_def_id(parent).is_some() - && args.first().and_then(|arg| arg.as_type()).is_some_and(Ty::is_closure) + && let Some(this) = args.first() + && let Some(this) = this.as_type() { - self.report_calling_closure(&self.thir[fun], args[1].as_type().unwrap(), expr); + if this.is_closure() { + self.report_calling_closure(&self.thir[fun], args[1].as_type().unwrap(), expr); + } else { + // This can happen when tail calling `Box` that wraps a function + self.report_nonfn_callee(fn_span, self.thir[fun].span, this); + } // Tail calling is likely to cause unrelated errors (ABI, argument mismatches), // skip them, producing an error about calling a closure is enough. return; }; + + if self.tcx.intrinsic(did).is_some() { + self.report_calling_intrinsic(expr); + } } + let (ty::FnDef(..) | ty::FnPtr(..)) = ty.kind() else { + self.report_nonfn_callee(fn_span, self.thir[fun].span, ty); + + // `fn_sig` below panics otherwise + return; + }; + // Erase regions since tail calls don't care about lifetimes let callee_sig = self.tcx.normalize_erasing_late_bound_regions(self.typing_env, ty.fn_sig(self.tcx)); @@ -280,6 +301,50 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> { self.found_errors = Err(err); } + fn report_calling_intrinsic(&mut self, expr: &Expr<'_>) { + let err = self + .tcx + .dcx() + .struct_span_err(expr.span, "tail calling intrinsics is not allowed") + .emit(); + + self.found_errors = Err(err); + } + + fn report_nonfn_callee(&mut self, call_sp: Span, fun_sp: Span, ty: Ty<'_>) { + let mut err = self + .tcx + .dcx() + .struct_span_err( + call_sp, + "tail calls can only be performed with function definitions or pointers", + ) + .with_note(format!("callee has type `{ty}`")); + + let mut ty = ty; + let mut refs = 0; + while ty.is_box() || ty.is_ref() { + ty = ty.builtin_deref(false).unwrap(); + refs += 1; + } + + if refs > 0 && ty.is_fn() { + let thing = if ty.is_fn_ptr() { "pointer" } else { "definition" }; + + let derefs = + std::iter::once('(').chain(std::iter::repeat_n('*', refs)).collect::<String>(); + + err.multipart_suggestion( + format!("consider dereferencing the expression to get a function {thing}"), + vec![(fun_sp.shrink_to_lo(), derefs), (fun_sp.shrink_to_hi(), ")".to_owned())], + Applicability::MachineApplicable, + ); + } + + let err = err.emit(); + self.found_errors = Err(err); + } + fn report_abi_mismatch(&mut self, sp: Span, caller_abi: ExternAbi, callee_abi: ExternAbi) { let err = self .tcx diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index f1fbd5c4a49..58c3de4a8b5 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -976,15 +976,6 @@ pub(crate) struct NonEmptyNeverPattern<'tcx> { } #[derive(Diagnostic)] -#[diag(mir_build_exceeds_mcdc_condition_limit)] -pub(crate) struct MCDCExceedsConditionLimit { - #[primary_span] - pub(crate) span: Span, - pub(crate) num_conditions: usize, - pub(crate) max_conditions: usize, -} - -#[derive(Diagnostic)] #[diag(mir_build_pattern_not_covered, code = E0005)] pub(crate) struct PatternNotCovered<'s, 'tcx> { #[primary_span] @@ -1254,8 +1245,8 @@ pub(crate) struct ConstContinueBadConst { } #[derive(Diagnostic)] -#[diag(mir_build_const_continue_missing_value)] -pub(crate) struct ConstContinueMissingValue { +#[diag(mir_build_const_continue_missing_label_or_value)] +pub(crate) struct ConstContinueMissingLabelOrValue { #[primary_span] pub span: Span, } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 33bf4e3e29f..81b0e21a5f5 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -1,10 +1,11 @@ use itertools::Itertools; use rustc_abi::{FIRST_VARIANT, FieldIdx}; use rustc_ast::UnsafeBinderCastKind; -use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; +use rustc_hir::find_attr; use rustc_index::Idx; use rustc_middle::hir::place::{ Place as HirPlace, PlaceBase as HirPlaceBase, ProjectionKind as HirProjectionKind, @@ -851,9 +852,9 @@ impl<'tcx> ThirBuildCx<'tcx> { if find_attr!(self.tcx.hir_attrs(expr.hir_id), AttributeKind::ConstContinue(_)) { match dest.target_id { Ok(target_id) => { - let Some(value) = value else { + let (Some(value), Some(_)) = (value, dest.label) else { let span = expr.span; - self.tcx.dcx().emit_fatal(ConstContinueMissingValue { span }) + self.tcx.dcx().emit_fatal(ConstContinueMissingLabelOrValue { span }) }; ExprKind::ConstContinue { @@ -955,9 +956,13 @@ impl<'tcx> ThirBuildCx<'tcx> { dcx.emit_fatal(LoopMatchBadRhs { span: block_body_expr.span }) }; - fn local(expr: &rustc_hir::Expr<'_>) -> Option<hir::HirId> { + fn local( + cx: &mut ThirBuildCx<'_>, + expr: &rustc_hir::Expr<'_>, + ) -> Option<hir::HirId> { if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = expr.kind && let Res::Local(hir_id) = path.res + && !cx.is_upvar(hir_id) { return Some(hir_id); } @@ -965,11 +970,11 @@ impl<'tcx> ThirBuildCx<'tcx> { None } - let Some(scrutinee_hir_id) = local(scrutinee) else { + let Some(scrutinee_hir_id) = local(self, scrutinee) else { dcx.emit_fatal(LoopMatchInvalidMatch { span: scrutinee.span }) }; - if local(state) != Some(scrutinee_hir_id) { + if local(self, state) != Some(scrutinee_hir_id) { dcx.emit_fatal(LoopMatchInvalidUpdate { scrutinee: scrutinee.span, lhs: state.span, @@ -1260,10 +1265,7 @@ impl<'tcx> ThirBuildCx<'tcx> { fn convert_var(&mut self, var_hir_id: hir::HirId) -> ExprKind<'tcx> { // We want upvars here not captures. // Captures will be handled in MIR. - let is_upvar = self - .tcx - .upvars_mentioned(self.body_owner) - .is_some_and(|upvars| upvars.contains_key(&var_hir_id)); + let is_upvar = self.is_upvar(var_hir_id); debug!( "convert_var({:?}): is_upvar={}, body_owner={:?}", @@ -1443,6 +1445,12 @@ impl<'tcx> ThirBuildCx<'tcx> { } } + fn is_upvar(&mut self, var_hir_id: hir::HirId) -> bool { + self.tcx + .upvars_mentioned(self.body_owner) + .is_some_and(|upvars| upvars.contains_key(&var_hir_id)) + } + /// Converts a list of named fields (i.e., for struct-like struct/enum ADTs) into FieldExpr. fn field_refs(&mut self, fields: &'tcx [hir::ExprField<'tcx>]) -> Box<[FieldExpr]> { fields diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 91fcbb9390f..a501cdf88c2 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -2,10 +2,11 @@ use core::ops::ControlFlow; use rustc_abi::{FieldIdx, VariantIdx}; use rustc_apfloat::Float; -use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Diag; use rustc_hir as hir; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::find_attr; use rustc_index::Idx; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::Obligation; diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index a7d5422a3d7..f86a15a8f92 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -800,6 +800,7 @@ where let re = regex!("\t?\u{001f}([+-])"); let raw_diff = format!("{:#?}", DebugDiffWithAdapter { new, old, ctxt }); + let raw_diff = dot::escape_html(&raw_diff); // Replace newlines in the `Debug` output with `<br/>` let raw_diff = raw_diff.replace('\n', r#"<br align="left"/>"#); diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs index 117525eb777..5937d68f389 100644 --- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs +++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs @@ -108,6 +108,7 @@ impl<'tcx> MaybePlacesSwitchIntData<'tcx> { /// /// ```rust /// struct S; +/// #[rustfmt::skip] /// fn foo(pred: bool) { // maybe-init: /// // {} /// let a = S; let mut b = S; let c; let d; // {a, b} @@ -197,6 +198,7 @@ impl<'a, 'tcx> HasMoveData<'tcx> for MaybeInitializedPlaces<'a, 'tcx> { /// /// ```rust /// struct S; +/// #[rustfmt::skip] /// fn foo(pred: bool) { // maybe-uninit: /// // {a, b, c, d} /// let a = S; let mut b = S; let c; let d; // { c, d} @@ -289,6 +291,7 @@ impl<'tcx> HasMoveData<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { /// /// ```rust /// struct S; +/// #[rustfmt::skip] /// fn foo(pred: bool) { // ever-init: /// // { } /// let a = S; let mut b = S; let c; let d; // {a, b } diff --git a/compiler/rustc_mir_transform/Cargo.toml b/compiler/rustc_mir_transform/Cargo.toml index a7d0b3acbe4..08c43a4648c 100644 --- a/compiler/rustc_mir_transform/Cargo.toml +++ b/compiler/rustc_mir_transform/Cargo.toml @@ -10,7 +10,6 @@ itertools = "0.12" rustc_abi = { path = "../rustc_abi" } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } -rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_const_eval = { path = "../rustc_const_eval" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_mir_transform/messages.ftl b/compiler/rustc_mir_transform/messages.ftl index ae3062f07de..2e08f50e8a9 100644 --- a/compiler/rustc_mir_transform/messages.ftl +++ b/compiler/rustc_mir_transform/messages.ftl @@ -9,8 +9,6 @@ mir_transform_const_mut_borrow = taking a mutable reference to a `const` item .note2 = the mutable reference will refer to this temporary, not the original `const` item .note3 = mutable reference created due to call to this method -mir_transform_exceeds_mcdc_test_vector_limit = number of total test vectors in one function will exceed limit ({$max_num_test_vectors}) if this decision is instrumented, so MC/DC analysis ignores it - mir_transform_ffi_unwind_call = call to {$foreign -> [true] foreign function *[false] function pointer diff --git a/compiler/rustc_mir_transform/src/check_inline.rs b/compiler/rustc_mir_transform/src/check_inline.rs index 14d9532894f..8d28cb3ca00 100644 --- a/compiler/rustc_mir_transform/src/check_inline.rs +++ b/compiler/rustc_mir_transform/src/check_inline.rs @@ -1,7 +1,7 @@ //! Check that a body annotated with `#[rustc_force_inline]` will not fail to inline based on its //! definition alone (irrespective of any specific caller). -use rustc_attr_data_structures::InlineAttr; +use rustc_hir::attrs::InlineAttr; use rustc_hir::def_id::DefId; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::{Body, TerminatorKind}; @@ -45,12 +45,6 @@ pub(super) fn is_inline_valid_on_fn<'tcx>( return Err("#[rustc_no_mir_inline]"); } - // FIXME(#127234): Coverage instrumentation currently doesn't handle inlined - // MIR correctly when Modified Condition/Decision Coverage is enabled. - if tcx.sess.instrument_coverage_mcdc() { - return Err("incompatible with MC/DC coverage"); - } - let ty = tcx.type_of(def_id); if match ty.instantiate_identity().kind() { ty::FnDef(..) => tcx.fn_sig(def_id).instantiate_identity().c_variadic(), diff --git a/compiler/rustc_mir_transform/src/coverage/hir_info.rs b/compiler/rustc_mir_transform/src/coverage/hir_info.rs new file mode 100644 index 00000000000..28fdc52b06c --- /dev/null +++ b/compiler/rustc_mir_transform/src/coverage/hir_info.rs @@ -0,0 +1,128 @@ +use rustc_hir as hir; +use rustc_hir::intravisit::{Visitor, walk_expr}; +use rustc_middle::hir::nested_filter; +use rustc_middle::ty::TyCtxt; +use rustc_span::Span; +use rustc_span::def_id::LocalDefId; + +/// Function information extracted from HIR by the coverage instrumentor. +#[derive(Debug)] +pub(crate) struct ExtractedHirInfo { + pub(crate) function_source_hash: u64, + pub(crate) is_async_fn: bool, + /// The span of the function's signature, if available. + /// Must have the same context and filename as the body span. + pub(crate) fn_sig_span: Option<Span>, + pub(crate) body_span: Span, + /// "Holes" are regions within the function body (or its expansions) that + /// should not be included in coverage spans for this function + /// (e.g. closures and nested items). + pub(crate) hole_spans: Vec<Span>, +} + +pub(crate) fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHirInfo { + // FIXME(#79625): Consider improving MIR to provide the information needed, to avoid going back + // to HIR for it. + + // HACK: For synthetic MIR bodies (async closures), use the def id of the HIR body. + if tcx.is_synthetic_mir(def_id) { + return extract_hir_info(tcx, tcx.local_parent(def_id)); + } + + let hir_node = tcx.hir_node_by_def_id(def_id); + let fn_body_id = hir_node.body_id().expect("HIR node is a function with body"); + let hir_body = tcx.hir_body(fn_body_id); + + let maybe_fn_sig = hir_node.fn_sig(); + let is_async_fn = maybe_fn_sig.is_some_and(|fn_sig| fn_sig.header.is_async()); + + let mut body_span = hir_body.value.span; + + use hir::{Closure, Expr, ExprKind, Node}; + // Unexpand a closure's body span back to the context of its declaration. + // This helps with closure bodies that consist of just a single bang-macro, + // and also with closure bodies produced by async desugaring. + if let Node::Expr(&Expr { kind: ExprKind::Closure(&Closure { fn_decl_span, .. }), .. }) = + hir_node + { + body_span = body_span.find_ancestor_in_same_ctxt(fn_decl_span).unwrap_or(body_span); + } + + // The actual signature span is only used if it has the same context and + // filename as the body, and precedes the body. + let fn_sig_span = maybe_fn_sig.map(|fn_sig| fn_sig.span).filter(|&fn_sig_span| { + let source_map = tcx.sess.source_map(); + let file_idx = |span: Span| source_map.lookup_source_file_idx(span.lo()); + + fn_sig_span.eq_ctxt(body_span) + && fn_sig_span.hi() <= body_span.lo() + && file_idx(fn_sig_span) == file_idx(body_span) + }); + + let function_source_hash = hash_mir_source(tcx, hir_body); + + let hole_spans = extract_hole_spans_from_hir(tcx, hir_body); + + ExtractedHirInfo { function_source_hash, is_async_fn, fn_sig_span, body_span, hole_spans } +} + +fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx hir::Body<'tcx>) -> u64 { + let owner = hir_body.id().hir_id.owner; + tcx.hir_owner_nodes(owner) + .opt_hash_including_bodies + .expect("hash should be present when coverage instrumentation is enabled") + .to_smaller_hash() + .as_u64() +} + +fn extract_hole_spans_from_hir<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &hir::Body<'tcx>) -> Vec<Span> { + struct HolesVisitor<'tcx> { + tcx: TyCtxt<'tcx>, + hole_spans: Vec<Span>, + } + + impl<'tcx> Visitor<'tcx> for HolesVisitor<'tcx> { + /// We have special handling for nested items, but we still want to + /// traverse into nested bodies of things that are not considered items, + /// such as "anon consts" (e.g. array lengths). + type NestedFilter = nested_filter::OnlyBodies; + + fn maybe_tcx(&mut self) -> TyCtxt<'tcx> { + self.tcx + } + + /// We override `visit_nested_item` instead of `visit_item` because we + /// only need the item's span, not the item itself. + fn visit_nested_item(&mut self, id: hir::ItemId) -> Self::Result { + let span = self.tcx.def_span(id.owner_id.def_id); + self.visit_hole_span(span); + // Having visited this item, we don't care about its children, + // so don't call `walk_item`. + } + + // We override `visit_expr` instead of the more specific expression + // visitors, so that we have direct access to the expression span. + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { + match expr.kind { + hir::ExprKind::Closure(_) | hir::ExprKind::ConstBlock(_) => { + self.visit_hole_span(expr.span); + // Having visited this expression, we don't care about its + // children, so don't call `walk_expr`. + } + + // For other expressions, recursively visit as normal. + _ => walk_expr(self, expr), + } + } + } + impl HolesVisitor<'_> { + fn visit_hole_span(&mut self, hole_span: Span) { + self.hole_spans.push(hole_span); + } + } + + let mut visitor = HolesVisitor { tcx, hole_spans: vec![] }; + + visitor.visit_body(hir_body); + visitor.hole_spans +} diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs index b4b4d0416fb..46fe7c40826 100644 --- a/compiler/rustc_mir_transform/src/coverage/mappings.rs +++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs @@ -1,19 +1,13 @@ -use std::collections::BTreeSet; - -use rustc_data_structures::fx::FxIndexMap; use rustc_index::IndexVec; -use rustc_middle::mir::coverage::{ - BlockMarkerId, BranchSpan, ConditionId, ConditionInfo, CoverageInfoHi, CoverageKind, -}; +use rustc_middle::mir::coverage::{BlockMarkerId, BranchSpan, CoverageInfoHi, CoverageKind}; use rustc_middle::mir::{self, BasicBlock, StatementKind}; use rustc_middle::ty::TyCtxt; use rustc_span::Span; -use crate::coverage::ExtractedHirInfo; -use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, START_BCB}; +use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph}; +use crate::coverage::hir_info::ExtractedHirInfo; use crate::coverage::spans::extract_refined_covspans; use crate::coverage::unexpand::unexpand_into_body_span; -use crate::errors::MCDCExceedsTestVectorLimit; /// Associates an ordinary executable code span with its corresponding BCB. #[derive(Debug)] @@ -22,9 +16,6 @@ pub(super) struct CodeMapping { pub(super) bcb: BasicCoverageBlock, } -/// This is separate from [`MCDCBranch`] to help prepare for larger changes -/// that will be needed for improved branch coverage in the future. -/// (See <https://github.com/rust-lang/rust/pull/124217>.) #[derive(Debug)] pub(super) struct BranchPair { pub(super) span: Span, @@ -32,40 +23,10 @@ pub(super) struct BranchPair { pub(super) false_bcb: BasicCoverageBlock, } -/// Associates an MC/DC branch span with condition info besides fields for normal branch. -#[derive(Debug)] -pub(super) struct MCDCBranch { - pub(super) span: Span, - pub(super) true_bcb: BasicCoverageBlock, - pub(super) false_bcb: BasicCoverageBlock, - pub(super) condition_info: ConditionInfo, - // Offset added to test vector idx if this branch is evaluated to true. - pub(super) true_index: usize, - // Offset added to test vector idx if this branch is evaluated to false. - pub(super) false_index: usize, -} - -/// Associates an MC/DC decision with its join BCBs. -#[derive(Debug)] -pub(super) struct MCDCDecision { - pub(super) span: Span, - pub(super) end_bcbs: BTreeSet<BasicCoverageBlock>, - pub(super) bitmap_idx: usize, - pub(super) num_test_vectors: usize, - pub(super) decision_depth: u16, -} - -// LLVM uses `i32` to index the bitmap. Thus `i32::MAX` is the hard limit for number of all test vectors -// in a function. -const MCDC_MAX_BITMAP_SIZE: usize = i32::MAX as usize; - #[derive(Default)] pub(super) struct ExtractedMappings { pub(super) code_mappings: Vec<CodeMapping>, pub(super) branch_pairs: Vec<BranchPair>, - pub(super) mcdc_bitmap_bits: usize, - pub(super) mcdc_degraded_branches: Vec<MCDCBranch>, - pub(super) mcdc_mappings: Vec<(MCDCDecision, Vec<MCDCBranch>)>, } /// Extracts coverage-relevant spans from MIR, and associates them with @@ -78,46 +39,13 @@ pub(super) fn extract_all_mapping_info_from_mir<'tcx>( ) -> ExtractedMappings { let mut code_mappings = vec![]; let mut branch_pairs = vec![]; - let mut mcdc_bitmap_bits = 0; - let mut mcdc_degraded_branches = vec![]; - let mut mcdc_mappings = vec![]; - if hir_info.is_async_fn || tcx.sess.coverage_no_mir_spans() { - // An async function desugars into a function that returns a future, - // with the user code wrapped in a closure. Any spans in the desugared - // outer function will be unhelpful, so just keep the signature span - // and ignore all of the spans in the MIR body. - // - // When debugging flag `-Zcoverage-options=no-mir-spans` is set, we need - // to give the same treatment to _all_ functions, because `llvm-cov` - // seems to ignore functions that don't have any ordinary code spans. - if let Some(span) = hir_info.fn_sig_span { - code_mappings.push(CodeMapping { span, bcb: START_BCB }); - } - } else { - // Extract coverage spans from MIR statements/terminators as normal. - extract_refined_covspans(tcx, mir_body, hir_info, graph, &mut code_mappings); - } + // Extract ordinary code mappings from MIR statement/terminator spans. + extract_refined_covspans(tcx, mir_body, hir_info, graph, &mut code_mappings); branch_pairs.extend(extract_branch_pairs(mir_body, hir_info, graph)); - extract_mcdc_mappings( - mir_body, - tcx, - hir_info.body_span, - graph, - &mut mcdc_bitmap_bits, - &mut mcdc_degraded_branches, - &mut mcdc_mappings, - ); - - ExtractedMappings { - code_mappings, - branch_pairs, - mcdc_bitmap_bits, - mcdc_degraded_branches, - mcdc_mappings, - } + ExtractedMappings { code_mappings, branch_pairs } } fn resolve_block_markers( @@ -141,12 +69,6 @@ fn resolve_block_markers( block_markers } -// FIXME: There is currently a lot of redundancy between -// `extract_branch_pairs` and `extract_mcdc_mappings`. This is needed so -// that they can each be modified without interfering with the other, but in -// the long term we should try to bring them together again when branch coverage -// and MC/DC coverage support are more mature. - pub(super) fn extract_branch_pairs( mir_body: &mir::Body<'_>, hir_info: &ExtractedHirInfo, @@ -176,175 +98,3 @@ pub(super) fn extract_branch_pairs( }) .collect::<Vec<_>>() } - -pub(super) fn extract_mcdc_mappings( - mir_body: &mir::Body<'_>, - tcx: TyCtxt<'_>, - body_span: Span, - graph: &CoverageGraph, - mcdc_bitmap_bits: &mut usize, - mcdc_degraded_branches: &mut impl Extend<MCDCBranch>, - mcdc_mappings: &mut impl Extend<(MCDCDecision, Vec<MCDCBranch>)>, -) { - let Some(coverage_info_hi) = mir_body.coverage_info_hi.as_deref() else { return }; - - let block_markers = resolve_block_markers(coverage_info_hi, mir_body); - - let bcb_from_marker = |marker: BlockMarkerId| graph.bcb_from_bb(block_markers[marker]?); - - let check_branch_bcb = - |raw_span: Span, true_marker: BlockMarkerId, false_marker: BlockMarkerId| { - // For now, ignore any branch span that was introduced by - // expansion. This makes things like assert macros less noisy. - if !raw_span.ctxt().outer_expn_data().is_root() { - return None; - } - let span = unexpand_into_body_span(raw_span, body_span)?; - - let true_bcb = bcb_from_marker(true_marker)?; - let false_bcb = bcb_from_marker(false_marker)?; - Some((span, true_bcb, false_bcb)) - }; - - let to_mcdc_branch = |&mir::coverage::MCDCBranchSpan { - span: raw_span, - condition_info, - true_marker, - false_marker, - }| { - let (span, true_bcb, false_bcb) = check_branch_bcb(raw_span, true_marker, false_marker)?; - Some(MCDCBranch { - span, - true_bcb, - false_bcb, - condition_info, - true_index: usize::MAX, - false_index: usize::MAX, - }) - }; - - let mut get_bitmap_idx = |num_test_vectors: usize| -> Option<usize> { - let bitmap_idx = *mcdc_bitmap_bits; - let next_bitmap_bits = bitmap_idx.saturating_add(num_test_vectors); - (next_bitmap_bits <= MCDC_MAX_BITMAP_SIZE).then(|| { - *mcdc_bitmap_bits = next_bitmap_bits; - bitmap_idx - }) - }; - mcdc_degraded_branches - .extend(coverage_info_hi.mcdc_degraded_branch_spans.iter().filter_map(to_mcdc_branch)); - - mcdc_mappings.extend(coverage_info_hi.mcdc_spans.iter().filter_map(|(decision, branches)| { - if branches.len() == 0 { - return None; - } - let decision_span = unexpand_into_body_span(decision.span, body_span)?; - - let end_bcbs = decision - .end_markers - .iter() - .map(|&marker| bcb_from_marker(marker)) - .collect::<Option<_>>()?; - let mut branch_mappings: Vec<_> = branches.into_iter().filter_map(to_mcdc_branch).collect(); - if branch_mappings.len() != branches.len() { - mcdc_degraded_branches.extend(branch_mappings); - return None; - } - let num_test_vectors = calc_test_vectors_index(&mut branch_mappings); - let Some(bitmap_idx) = get_bitmap_idx(num_test_vectors) else { - tcx.dcx().emit_warn(MCDCExceedsTestVectorLimit { - span: decision_span, - max_num_test_vectors: MCDC_MAX_BITMAP_SIZE, - }); - mcdc_degraded_branches.extend(branch_mappings); - return None; - }; - // LLVM requires span of the decision contains all spans of its conditions. - // Usually the decision span meets the requirement well but in cases like macros it may not. - let span = branch_mappings - .iter() - .map(|branch| branch.span) - .reduce(|lhs, rhs| lhs.to(rhs)) - .map( - |joint_span| { - if decision_span.contains(joint_span) { decision_span } else { joint_span } - }, - ) - .expect("branch mappings are ensured to be non-empty as checked above"); - Some(( - MCDCDecision { - span, - end_bcbs, - bitmap_idx, - num_test_vectors, - decision_depth: decision.decision_depth, - }, - branch_mappings, - )) - })); -} - -// LLVM checks the executed test vector by accumulating indices of tested branches. -// We calculate number of all possible test vectors of the decision and assign indices -// to branches here. -// See [the rfc](https://discourse.llvm.org/t/rfc-coverage-new-algorithm-and-file-format-for-mc-dc/76798/) -// for more details about the algorithm. -// This function is mostly like [`TVIdxBuilder::TvIdxBuilder`](https://github.com/llvm/llvm-project/blob/d594d9f7f4dc6eb748b3261917db689fdc348b96/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp#L226) -fn calc_test_vectors_index(conditions: &mut Vec<MCDCBranch>) -> usize { - let mut indegree_stats = IndexVec::<ConditionId, usize>::from_elem_n(0, conditions.len()); - // `num_paths` is `width` described at the llvm rfc, which indicates how many paths reaching the condition node. - let mut num_paths_stats = IndexVec::<ConditionId, usize>::from_elem_n(0, conditions.len()); - let mut next_conditions = conditions - .iter_mut() - .map(|branch| { - let ConditionInfo { condition_id, true_next_id, false_next_id } = branch.condition_info; - [true_next_id, false_next_id] - .into_iter() - .flatten() - .for_each(|next_id| indegree_stats[next_id] += 1); - (condition_id, branch) - }) - .collect::<FxIndexMap<_, _>>(); - - let mut queue = - std::collections::VecDeque::from_iter(next_conditions.swap_remove(&ConditionId::START)); - num_paths_stats[ConditionId::START] = 1; - let mut decision_end_nodes = Vec::new(); - while let Some(branch) = queue.pop_front() { - let ConditionInfo { condition_id, true_next_id, false_next_id } = branch.condition_info; - let (false_index, true_index) = (&mut branch.false_index, &mut branch.true_index); - let this_paths_count = num_paths_stats[condition_id]; - // Note. First check the false next to ensure conditions are touched in same order with llvm-cov. - for (next, index) in [(false_next_id, false_index), (true_next_id, true_index)] { - if let Some(next_id) = next { - let next_paths_count = &mut num_paths_stats[next_id]; - *index = *next_paths_count; - *next_paths_count = next_paths_count.saturating_add(this_paths_count); - let next_indegree = &mut indegree_stats[next_id]; - *next_indegree -= 1; - if *next_indegree == 0 { - queue.push_back(next_conditions.swap_remove(&next_id).expect( - "conditions with non-zero indegree before must be in next_conditions", - )); - } - } else { - decision_end_nodes.push((this_paths_count, condition_id, index)); - } - } - } - assert!(next_conditions.is_empty(), "the decision tree has untouched nodes"); - let mut cur_idx = 0; - // LLVM hopes the end nodes are sorted in descending order by `num_paths` so that it can - // optimize bitmap size for decisions in tree form such as `a && b && c && d && ...`. - decision_end_nodes.sort_by_key(|(num_paths, _, _)| usize::MAX - *num_paths); - for (num_paths, condition_id, index) in decision_end_nodes { - assert_eq!( - num_paths, num_paths_stats[condition_id], - "end nodes should not be updated since they were visited" - ); - assert_eq!(*index, usize::MAX, "end nodes should not be assigned index before"); - *index = cur_idx; - cur_idx += num_paths; - } - cur_idx -} diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index f253d1662ca..47a87a2e94d 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -1,5 +1,15 @@ +use rustc_middle::mir::coverage::{CoverageKind, FunctionCoverageInfo, Mapping, MappingKind}; +use rustc_middle::mir::{self, BasicBlock, Statement, StatementKind, TerminatorKind}; +use rustc_middle::ty::TyCtxt; +use tracing::{debug, debug_span, trace}; + +use crate::coverage::counters::BcbCountersData; +use crate::coverage::graph::CoverageGraph; +use crate::coverage::mappings::ExtractedMappings; + mod counters; mod graph; +mod hir_info; mod mappings; pub(super) mod query; mod spans; @@ -7,22 +17,6 @@ mod spans; mod tests; mod unexpand; -use rustc_hir as hir; -use rustc_hir::intravisit::{Visitor, walk_expr}; -use rustc_middle::hir::nested_filter; -use rustc_middle::mir::coverage::{ - CoverageKind, DecisionInfo, FunctionCoverageInfo, Mapping, MappingKind, -}; -use rustc_middle::mir::{self, BasicBlock, Statement, StatementKind, TerminatorKind}; -use rustc_middle::ty::TyCtxt; -use rustc_span::Span; -use rustc_span::def_id::LocalDefId; -use tracing::{debug, debug_span, trace}; - -use crate::coverage::counters::BcbCountersData; -use crate::coverage::graph::CoverageGraph; -use crate::coverage::mappings::ExtractedMappings; - /// Inserts `StatementKind::Coverage` statements that either instrument the binary with injected /// counters, via intrinsic `llvm.instrprof.increment`, and/or inject metadata used during codegen /// to construct the coverage map. @@ -69,7 +63,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: let def_id = mir_body.source.def_id(); let _span = debug_span!("instrument_function_for_coverage", ?def_id).entered(); - let hir_info = extract_hir_info(tcx, def_id.expect_local()); + let hir_info = hir_info::extract_hir_info(tcx, def_id.expect_local()); // Build the coverage graph, which is a simplified view of the MIR control-flow // graph that ignores some details not relevant to coverage instrumentation. @@ -95,14 +89,6 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: // Inject coverage statements into MIR. inject_coverage_statements(mir_body, &graph); - inject_mcdc_statements(mir_body, &graph, &extracted_mappings); - - let mcdc_num_condition_bitmaps = extracted_mappings - .mcdc_mappings - .iter() - .map(|&(mappings::MCDCDecision { decision_depth, .. }, _)| decision_depth) - .max() - .map_or(0, |max| usize::from(max) + 1); mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo { function_source_hash: hir_info.function_source_hash, @@ -111,9 +97,6 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: priority_list, mappings, - - mcdc_bitmap_bits: extracted_mappings.mcdc_bitmap_bits, - mcdc_num_condition_bitmaps, })); } @@ -124,13 +107,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: /// function can potentially be simplified even further. fn create_mappings(extracted_mappings: &ExtractedMappings) -> Vec<Mapping> { // Fully destructure the mappings struct to make sure we don't miss any kinds. - let ExtractedMappings { - code_mappings, - branch_pairs, - mcdc_bitmap_bits: _, - mcdc_degraded_branches, - mcdc_mappings, - } = extracted_mappings; + let ExtractedMappings { code_mappings, branch_pairs } = extracted_mappings; let mut mappings = Vec::new(); mappings.extend(code_mappings.iter().map( @@ -148,57 +125,6 @@ fn create_mappings(extracted_mappings: &ExtractedMappings) -> Vec<Mapping> { }, )); - // MCDC branch mappings are appended with their decisions in case decisions were ignored. - mappings.extend(mcdc_degraded_branches.iter().map( - |&mappings::MCDCBranch { - span, - true_bcb, - false_bcb, - condition_info: _, - true_index: _, - false_index: _, - }| { Mapping { kind: MappingKind::Branch { true_bcb, false_bcb }, span } }, - )); - - for (decision, branches) in mcdc_mappings { - // FIXME(#134497): Previously it was possible for some of these branch - // conversions to fail, in which case the remaining branches in the - // decision would be degraded to plain `MappingKind::Branch`. - // The changes in #134497 made that failure impossible, because the - // fallible step was deferred to codegen. But the corresponding code - // in codegen wasn't updated to detect the need for a degrade step. - let conditions = branches - .into_iter() - .map( - |&mappings::MCDCBranch { - span, - true_bcb, - false_bcb, - condition_info, - true_index: _, - false_index: _, - }| { - Mapping { - kind: MappingKind::MCDCBranch { - true_bcb, - false_bcb, - mcdc_params: condition_info, - }, - span, - } - }, - ) - .collect::<Vec<_>>(); - - // LLVM requires end index for counter mapping regions. - let kind = MappingKind::MCDCDecision(DecisionInfo { - bitmap_idx: (decision.bitmap_idx + decision.num_test_vectors) as u32, - num_conditions: u16::try_from(conditions.len()).unwrap(), - }); - let span = decision.span; - mappings.extend(std::iter::once(Mapping { kind, span }).chain(conditions.into_iter())); - } - mappings } @@ -210,51 +136,6 @@ fn inject_coverage_statements<'tcx>(mir_body: &mut mir::Body<'tcx>, graph: &Cove } } -/// For each conditions inject statements to update condition bitmap after it has been evaluated. -/// For each decision inject statements to update test vector bitmap after it has been evaluated. -fn inject_mcdc_statements<'tcx>( - mir_body: &mut mir::Body<'tcx>, - graph: &CoverageGraph, - extracted_mappings: &ExtractedMappings, -) { - for (decision, conditions) in &extracted_mappings.mcdc_mappings { - // Inject test vector update first because `inject_statement` always insert new statement at head. - for &end in &decision.end_bcbs { - let end_bb = graph[end].leader_bb(); - inject_statement( - mir_body, - CoverageKind::TestVectorBitmapUpdate { - bitmap_idx: decision.bitmap_idx as u32, - decision_depth: decision.decision_depth, - }, - end_bb, - ); - } - - for &mappings::MCDCBranch { - span: _, - true_bcb, - false_bcb, - condition_info: _, - true_index, - false_index, - } in conditions - { - for (index, bcb) in [(false_index, false_bcb), (true_index, true_bcb)] { - let bb = graph[bcb].leader_bb(); - inject_statement( - mir_body, - CoverageKind::CondBitmapUpdate { - index: index as u32, - decision_depth: decision.decision_depth, - }, - bb, - ); - } - } - } -} - fn inject_statement(mir_body: &mut mir::Body<'_>, counter_kind: CoverageKind, bb: BasicBlock) { debug!(" injecting statement {counter_kind:?} for {bb:?}"); let data = &mut mir_body[bb]; @@ -262,122 +143,3 @@ fn inject_statement(mir_body: &mut mir::Body<'_>, counter_kind: CoverageKind, bb let statement = Statement::new(source_info, StatementKind::Coverage(counter_kind)); data.statements.insert(0, statement); } - -/// Function information extracted from HIR by the coverage instrumentor. -#[derive(Debug)] -struct ExtractedHirInfo { - function_source_hash: u64, - is_async_fn: bool, - /// The span of the function's signature, if available. - /// Must have the same context and filename as the body span. - fn_sig_span: Option<Span>, - body_span: Span, - /// "Holes" are regions within the function body (or its expansions) that - /// should not be included in coverage spans for this function - /// (e.g. closures and nested items). - hole_spans: Vec<Span>, -} - -fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHirInfo { - // FIXME(#79625): Consider improving MIR to provide the information needed, to avoid going back - // to HIR for it. - - // HACK: For synthetic MIR bodies (async closures), use the def id of the HIR body. - if tcx.is_synthetic_mir(def_id) { - return extract_hir_info(tcx, tcx.local_parent(def_id)); - } - - let hir_node = tcx.hir_node_by_def_id(def_id); - let fn_body_id = hir_node.body_id().expect("HIR node is a function with body"); - let hir_body = tcx.hir_body(fn_body_id); - - let maybe_fn_sig = hir_node.fn_sig(); - let is_async_fn = maybe_fn_sig.is_some_and(|fn_sig| fn_sig.header.is_async()); - - let mut body_span = hir_body.value.span; - - use hir::{Closure, Expr, ExprKind, Node}; - // Unexpand a closure's body span back to the context of its declaration. - // This helps with closure bodies that consist of just a single bang-macro, - // and also with closure bodies produced by async desugaring. - if let Node::Expr(&Expr { kind: ExprKind::Closure(&Closure { fn_decl_span, .. }), .. }) = - hir_node - { - body_span = body_span.find_ancestor_in_same_ctxt(fn_decl_span).unwrap_or(body_span); - } - - // The actual signature span is only used if it has the same context and - // filename as the body, and precedes the body. - let fn_sig_span = maybe_fn_sig.map(|fn_sig| fn_sig.span).filter(|&fn_sig_span| { - let source_map = tcx.sess.source_map(); - let file_idx = |span: Span| source_map.lookup_source_file_idx(span.lo()); - - fn_sig_span.eq_ctxt(body_span) - && fn_sig_span.hi() <= body_span.lo() - && file_idx(fn_sig_span) == file_idx(body_span) - }); - - let function_source_hash = hash_mir_source(tcx, hir_body); - - let hole_spans = extract_hole_spans_from_hir(tcx, hir_body); - - ExtractedHirInfo { function_source_hash, is_async_fn, fn_sig_span, body_span, hole_spans } -} - -fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx hir::Body<'tcx>) -> u64 { - // FIXME(cjgillot) Stop hashing HIR manually here. - let owner = hir_body.id().hir_id.owner; - tcx.hir_owner_nodes(owner).opt_hash_including_bodies.unwrap().to_smaller_hash().as_u64() -} - -fn extract_hole_spans_from_hir<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &hir::Body<'tcx>) -> Vec<Span> { - struct HolesVisitor<'tcx> { - tcx: TyCtxt<'tcx>, - hole_spans: Vec<Span>, - } - - impl<'tcx> Visitor<'tcx> for HolesVisitor<'tcx> { - /// We have special handling for nested items, but we still want to - /// traverse into nested bodies of things that are not considered items, - /// such as "anon consts" (e.g. array lengths). - type NestedFilter = nested_filter::OnlyBodies; - - fn maybe_tcx(&mut self) -> TyCtxt<'tcx> { - self.tcx - } - - /// We override `visit_nested_item` instead of `visit_item` because we - /// only need the item's span, not the item itself. - fn visit_nested_item(&mut self, id: hir::ItemId) -> Self::Result { - let span = self.tcx.def_span(id.owner_id.def_id); - self.visit_hole_span(span); - // Having visited this item, we don't care about its children, - // so don't call `walk_item`. - } - - // We override `visit_expr` instead of the more specific expression - // visitors, so that we have direct access to the expression span. - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { - match expr.kind { - hir::ExprKind::Closure(_) | hir::ExprKind::ConstBlock(_) => { - self.visit_hole_span(expr.span); - // Having visited this expression, we don't care about its - // children, so don't call `walk_expr`. - } - - // For other expressions, recursively visit as normal. - _ => walk_expr(self, expr), - } - } - } - impl HolesVisitor<'_> { - fn visit_hole_span(&mut self, hole_span: Span) { - self.hole_spans.push(hole_span); - } - } - - let mut visitor = HolesVisitor { tcx, hole_spans: vec![] }; - - visitor.visit_body(hir_body); - visitor.hole_spans -} diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs index 551f720c869..63c550c27fe 100644 --- a/compiler/rustc_mir_transform/src/coverage/query.rs +++ b/compiler/rustc_mir_transform/src/coverage/query.rs @@ -1,4 +1,5 @@ -use rustc_attr_data_structures::{AttributeKind, CoverageStatus, find_attr}; +use rustc_hir::attrs::{AttributeKind, CoverageAttrKind}; +use rustc_hir::find_attr; use rustc_index::bit_set::DenseBitSet; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::coverage::{BasicCoverageBlock, CoverageIdsInfo, CoverageKind, MappingKind}; @@ -32,16 +33,6 @@ fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { return false; } - // Don't instrument functions with `#[automatically_derived]` on their - // enclosing impl block, on the assumption that most users won't care about - // coverage for derived impls. - if let Some(impl_of) = tcx.impl_of_assoc(def_id.to_def_id()) - && tcx.is_automatically_derived(impl_of) - { - trace!("InstrumentCoverage skipped for {def_id:?} (automatically derived)"); - return false; - } - if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NAKED) { trace!("InstrumentCoverage skipped for {def_id:?} (`#[naked]`)"); return false; @@ -57,20 +48,32 @@ fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { /// Query implementation for `coverage_attr_on`. fn coverage_attr_on(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { - // Check for annotations directly on this def. - if let Some(coverage_status) = - find_attr!(tcx.get_all_attrs(def_id), AttributeKind::Coverage(_, status) => status) + // Check for a `#[coverage(..)]` attribute on this def. + if let Some(kind) = + find_attr!(tcx.get_all_attrs(def_id), AttributeKind::Coverage(_sp, kind) => kind) { - *coverage_status == CoverageStatus::On - } else { - match tcx.opt_local_parent(def_id) { - // Check the parent def (and so on recursively) until we find an - // enclosing attribute or reach the crate root. - Some(parent) => tcx.coverage_attr_on(parent), - // We reached the crate root without seeing a coverage attribute, so - // allow coverage instrumentation by default. - None => true, + match kind { + CoverageAttrKind::On => return true, + CoverageAttrKind::Off => return false, } + }; + + // Treat `#[automatically_derived]` as an implied `#[coverage(off)]`, on + // the assumption that most users won't want coverage for derived impls. + // + // This affects not just the associated items of an impl block, but also + // any closures and other nested functions within those associated items. + if tcx.is_automatically_derived(def_id.to_def_id()) { + return false; + } + + // Check the parent def (and so on recursively) until we find an + // enclosing attribute or reach the crate root. + match tcx.opt_local_parent(def_id) { + Some(parent) => tcx.coverage_attr_on(parent), + // We reached the crate root without seeing a coverage attribute, so + // allow coverage instrumentation by default. + None => true, } } @@ -108,11 +111,6 @@ fn coverage_ids_info<'tcx>( bcb_needs_counter.insert(true_bcb); bcb_needs_counter.insert(false_bcb); } - MappingKind::MCDCBranch { true_bcb, false_bcb, mcdc_params: _ } => { - bcb_needs_counter.insert(true_bcb); - bcb_needs_counter.insert(false_bcb); - } - MappingKind::MCDCDecision(_) => {} } } diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index ec76076020e..ae9459dee84 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -1,12 +1,15 @@ use rustc_data_structures::fx::FxHashSet; use rustc_middle::mir; +use rustc_middle::mir::coverage::START_BCB; use rustc_middle::ty::TyCtxt; -use rustc_span::{DesugaringKind, ExpnKind, MacroKind, Span}; +use rustc_span::source_map::SourceMap; +use rustc_span::{BytePos, DesugaringKind, ExpnKind, MacroKind, Span}; use tracing::instrument; use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph}; +use crate::coverage::hir_info::ExtractedHirInfo; use crate::coverage::spans::from_mir::{Hole, RawSpanFromMir, SpanFromMir}; -use crate::coverage::{ExtractedHirInfo, mappings, unexpand}; +use crate::coverage::{mappings, unexpand}; mod from_mir; @@ -15,8 +18,19 @@ pub(super) fn extract_refined_covspans<'tcx>( mir_body: &mir::Body<'tcx>, hir_info: &ExtractedHirInfo, graph: &CoverageGraph, - code_mappings: &mut impl Extend<mappings::CodeMapping>, + code_mappings: &mut Vec<mappings::CodeMapping>, ) { + if hir_info.is_async_fn { + // An async function desugars into a function that returns a future, + // with the user code wrapped in a closure. Any spans in the desugared + // outer function will be unhelpful, so just keep the signature span + // and ignore all of the spans in the MIR body. + if let Some(span) = hir_info.fn_sig_span { + code_mappings.push(mappings::CodeMapping { span, bcb: START_BCB }); + } + return; + } + let &ExtractedHirInfo { body_span, .. } = hir_info; let raw_spans = from_mir::extract_raw_spans_from_mir(mir_body, graph); @@ -83,8 +97,18 @@ pub(super) fn extract_refined_covspans<'tcx>( // Discard any span that overlaps with a hole. discard_spans_overlapping_holes(&mut covspans, &holes); - // Perform more refinement steps after holes have been dealt with. + // Discard spans that overlap in unwanted ways. let mut covspans = remove_unwanted_overlapping_spans(covspans); + + // For all empty spans, either enlarge them to be non-empty, or discard them. + let source_map = tcx.sess.source_map(); + covspans.retain_mut(|covspan| { + let Some(span) = ensure_non_empty_span(source_map, covspan.span) else { return false }; + covspan.span = span; + true + }); + + // Merge covspans that can be merged. covspans.dedup_by(|b, a| a.merge_if_eligible(b)); code_mappings.extend(covspans.into_iter().map(|Covspan { span, bcb }| { @@ -230,3 +254,26 @@ fn compare_spans(a: Span, b: Span) -> std::cmp::Ordering { // - Both have the same start and span A extends further right .then_with(|| Ord::cmp(&a.hi(), &b.hi()).reverse()) } + +fn ensure_non_empty_span(source_map: &SourceMap, span: Span) -> Option<Span> { + if !span.is_empty() { + return Some(span); + } + + // The span is empty, so try to enlarge it to cover an adjacent '{' or '}'. + source_map + .span_to_source(span, |src, start, end| try { + // Adjusting span endpoints by `BytePos(1)` is normally a bug, + // but in this case we have specifically checked that the character + // we're skipping over is one of two specific ASCII characters, so + // adjusting by exactly 1 byte is correct. + if src.as_bytes().get(end).copied() == Some(b'{') { + Some(span.with_hi(span.hi() + BytePos(1))) + } else if start > 0 && src.as_bytes()[start - 1] == b'}' { + Some(span.with_lo(span.lo() - BytePos(1))) + } else { + None + } + }) + .ok()? +} diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs index 804cd8ab3f7..7985e1c0798 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -101,11 +101,7 @@ fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span> { StatementKind::Coverage(CoverageKind::BlockMarker { .. }) => None, // These coverage statements should not exist prior to coverage instrumentation. - StatementKind::Coverage( - CoverageKind::VirtualCounter { .. } - | CoverageKind::CondBitmapUpdate { .. } - | CoverageKind::TestVectorBitmapUpdate { .. }, - ) => bug!( + StatementKind::Coverage(CoverageKind::VirtualCounter { .. }) => bug!( "Unexpected coverage statement found during coverage instrumentation: {statement:?}" ), } diff --git a/compiler/rustc_mir_transform/src/cross_crate_inline.rs b/compiler/rustc_mir_transform/src/cross_crate_inline.rs index 6d7b7e10ef6..b186c2bd775 100644 --- a/compiler/rustc_mir_transform/src/cross_crate_inline.rs +++ b/compiler/rustc_mir_transform/src/cross_crate_inline.rs @@ -1,4 +1,4 @@ -use rustc_attr_data_structures::InlineAttr; +use rustc_hir::attrs::InlineAttr; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_middle::mir::visit::Visitor; diff --git a/compiler/rustc_mir_transform/src/ctfe_limit.rs b/compiler/rustc_mir_transform/src/ctfe_limit.rs index fb17cca30f4..ac46336b834 100644 --- a/compiler/rustc_mir_transform/src/ctfe_limit.rs +++ b/compiler/rustc_mir_transform/src/ctfe_limit.rs @@ -18,7 +18,7 @@ impl<'tcx> crate::MirPass<'tcx> for CtfeLimit { .basic_blocks .iter_enumerated() .filter_map(|(node, node_data)| { - if matches!(node_data.terminator().kind, TerminatorKind::Call { .. }) + if matches!(node_data.terminator().kind, TerminatorKind::Call { .. } | TerminatorKind::TailCall { .. }) // Back edges in a CFG indicate loops || has_back_edge(doms, node, node_data) { diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs index de96b1f255a..4f3c53d761f 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drop.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs @@ -611,6 +611,7 @@ where /// /// For example, with 3 fields, the drop ladder is /// + /// ```text /// .d0: /// ELAB(drop location.0 [target=.d1, unwind=.c1]) /// .d1: @@ -621,8 +622,10 @@ where /// ELAB(drop location.1 [target=.c2]) /// .c2: /// ELAB(drop location.2 [target=`self.unwind`]) + /// ``` /// /// For possible-async drops in coroutines we also need dropline ladder + /// ```text /// .d0 (mainline): /// ELAB(drop location.0 [target=.d1, unwind=.c1, drop=.e1]) /// .d1 (mainline): @@ -637,6 +640,7 @@ where /// ELAB(drop location.1 [target=.e2, unwind=.c2]) /// .e2 (dropline): /// ELAB(drop location.2 [target=`self.drop`, unwind=`self.unwind`]) + /// ``` /// /// NOTE: this does not clear the master drop flag, so you need /// to point succ/unwind on a `drop_ladder_bottom`. @@ -761,24 +765,37 @@ where let skip_contents = adt.is_union() || adt.is_manually_drop(); let contents_drop = if skip_contents { + if adt.has_dtor(self.tcx()) && self.elaborator.get_drop_flag(self.path).is_some() { + // the top-level drop flag is usually cleared by open_drop_for_adt_contents + // types with destructors would still need an empty drop ladder to clear it + + // however, these types are only open dropped in `DropShimElaborator` + // which does not have drop flags + // a future box-like "DerefMove" trait would allow for this case to happen + span_bug!(self.source_info.span, "open dropping partially moved union"); + } + (self.succ, self.unwind, self.dropline) } else { self.open_drop_for_adt_contents(adt, args) }; - if adt.is_box() { - // we need to drop the inside of the box before running the destructor - let succ = self.destructor_call_block_sync((contents_drop.0, contents_drop.1)); - let unwind = contents_drop - .1 - .map(|unwind| self.destructor_call_block_sync((unwind, Unwind::InCleanup))); - let dropline = contents_drop - .2 - .map(|dropline| self.destructor_call_block_sync((dropline, contents_drop.1))); - - self.open_drop_for_box_contents(adt, args, succ, unwind, dropline) - } else if adt.has_dtor(self.tcx()) { - self.destructor_call_block(contents_drop) + if adt.has_dtor(self.tcx()) { + let destructor_block = if adt.is_box() { + // we need to drop the inside of the box before running the destructor + let succ = self.destructor_call_block_sync((contents_drop.0, contents_drop.1)); + let unwind = contents_drop + .1 + .map(|unwind| self.destructor_call_block_sync((unwind, Unwind::InCleanup))); + let dropline = contents_drop + .2 + .map(|dropline| self.destructor_call_block_sync((dropline, contents_drop.1))); + self.open_drop_for_box_contents(adt, args, succ, unwind, dropline) + } else { + self.destructor_call_block(contents_drop) + }; + + self.drop_flag_test_block(destructor_block, contents_drop.0, contents_drop.1) } else { contents_drop.0 } @@ -982,12 +999,7 @@ where unwind.is_cleanup(), ); - let destructor_block = self.elaborator.patch().new_block(result); - - let block_start = Location { block: destructor_block, statement_index: 0 }; - self.elaborator.clear_drop_flag(block_start, self.path, DropFlagMode::Shallow); - - self.drop_flag_test_block(destructor_block, succ, unwind) + self.elaborator.patch().new_block(result) } fn destructor_call_block( @@ -1002,13 +1014,7 @@ where && !unwind.is_cleanup() && ty.is_async_drop(self.tcx(), self.elaborator.typing_env()) { - let destructor_block = - self.build_async_drop(self.place, ty, None, succ, unwind, dropline, true); - - let block_start = Location { block: destructor_block, statement_index: 0 }; - self.elaborator.clear_drop_flag(block_start, self.path, DropFlagMode::Shallow); - - self.drop_flag_test_block(destructor_block, succ, unwind) + self.build_async_drop(self.place, ty, None, succ, unwind, dropline, true) } else { self.destructor_call_block_sync((succ, unwind)) } diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index cffa0183fa7..ad9635aae33 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -117,14 +117,6 @@ pub(crate) struct FnItemRef { pub ident: Ident, } -#[derive(Diagnostic)] -#[diag(mir_transform_exceeds_mcdc_test_vector_limit)] -pub(crate) struct MCDCExceedsTestVectorLimit { - #[primary_span] - pub(crate) span: Span, - pub(crate) max_num_test_vectors: usize, -} - pub(crate) struct MustNotSupend<'a, 'tcx> { pub tcx: TyCtxt<'tcx>, pub yield_sp: Span, diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index dc99b67a1e8..952da2cdf72 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -756,7 +756,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { && let Some(v) = self.simplify_place_value(&mut pointee, location) { value = v; - place_ref = pointee.project_deeper(&place.projection[index..], self.tcx).as_ref(); + // `pointee` holds a `Place`, so `ProjectionElem::Index` holds a `Local`. + // That local is SSA, but we otherwise have no guarantee on that local's value at + // the current location compared to its value where `pointee` was borrowed. + if pointee.projection.iter().all(|elem| !matches!(elem, ProjectionElem::Index(_))) { + place_ref = + pointee.project_deeper(&place.projection[index..], self.tcx).as_ref(); + } } if let Some(local) = self.try_as_local(value, location) { // Both `local` and `Place { local: place.local, projection: projection[..index] }` @@ -774,7 +780,12 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { && let Some(v) = self.simplify_place_value(&mut pointee, location) { value = v; - place_ref = pointee.project_deeper(&[], self.tcx).as_ref(); + // `pointee` holds a `Place`, so `ProjectionElem::Index` holds a `Local`. + // That local is SSA, but we otherwise have no guarantee on that local's value at + // the current location compared to its value where `pointee` was borrowed. + if pointee.projection.iter().all(|elem| !matches!(elem, ProjectionElem::Index(_))) { + place_ref = pointee.project_deeper(&[], self.tcx).as_ref(); + } } if let Some(new_local) = self.try_as_local(value, location) { place_ref = PlaceRef { local: new_local, projection: &[] }; diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 1c0fc774867..3d49eb4e8ef 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -5,7 +5,7 @@ use std::iter; use std::ops::{Range, RangeFrom}; use rustc_abi::{ExternAbi, FieldIdx}; -use rustc_attr_data_structures::{InlineAttr, OptimizeAttr}; +use rustc_hir::attrs::{InlineAttr, OptimizeAttr}; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_index::Idx; diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index dbcaed20953..c83bd25c663 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -55,6 +55,7 @@ impl<'tcx> crate::MirPass<'tcx> for InstSimplify { let terminator = block.terminator.as_mut().unwrap(); ctx.simplify_primitive_clone(terminator, &mut block.statements); + ctx.simplify_align_of_slice_val(terminator, &mut block.statements); ctx.simplify_intrinsic_assert(terminator); ctx.simplify_nounwind_call(terminator); simplify_duplicate_switch_targets(terminator); @@ -252,6 +253,36 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> { terminator.kind = TerminatorKind::Goto { target: *destination_block }; } + // Convert `align_of_val::<[T]>(ptr)` to `align_of::<T>()`, since the + // alignment of a slice doesn't actually depend on metadata at all + // and the element type is always `Sized`. + // + // This is here so it can run after inlining, where it's more useful. + // (LowerIntrinsics is done in cleanup, before the optimization passes.) + fn simplify_align_of_slice_val( + &self, + terminator: &mut Terminator<'tcx>, + statements: &mut Vec<Statement<'tcx>>, + ) { + if let TerminatorKind::Call { + func, args, destination, target: Some(destination_block), .. + } = &terminator.kind + && args.len() == 1 + && let Some((fn_def_id, generics)) = func.const_fn_def() + && self.tcx.is_intrinsic(fn_def_id, sym::align_of_val) + && let ty::Slice(elem_ty) = *generics.type_at(0).kind() + { + statements.push(Statement::new( + terminator.source_info, + StatementKind::Assign(Box::new(( + *destination, + Rvalue::NullaryOp(NullOp::AlignOf, elem_ty), + ))), + )); + terminator.kind = TerminatorKind::Goto { target: *destination_block }; + } + } + fn simplify_nounwind_call(&self, terminator: &mut Terminator<'tcx>) { let TerminatorKind::Call { ref func, ref mut unwind, .. } = terminator.kind else { return; diff --git a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs index 43f80508e4a..6c2dfc59da2 100644 --- a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs +++ b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs @@ -4,7 +4,13 @@ //! useful because (unlike MIR building) it runs after type checking, so it can make use of //! `TypingMode::PostAnalysis` to provide more precise type information, especially about opaque //! types. +//! +//! When we're optimizing, we also remove calls to `drop_in_place<T>` when `T` isn't `needs_drop`, +//! as those are essentially equivalent to `Drop` terminators. While the compiler doesn't insert +//! them automatically, preferring the built-in instead, they're common in generic code (such as +//! `Vec::truncate`) so removing them from things like inlined `Vec<u8>` is helpful. +use rustc_hir::LangItem; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; use tracing::{debug, trace}; @@ -21,15 +27,26 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveUnneededDrops { let mut should_simplify = false; for block in body.basic_blocks.as_mut() { let terminator = block.terminator_mut(); - if let TerminatorKind::Drop { place, target, .. } = terminator.kind { - let ty = place.ty(&body.local_decls, tcx); - if ty.ty.needs_drop(tcx, typing_env) { - continue; + let (ty, target) = match terminator.kind { + TerminatorKind::Drop { place, target, .. } => { + (place.ty(&body.local_decls, tcx).ty, target) + } + TerminatorKind::Call { ref func, target: Some(target), .. } + if tcx.sess.mir_opt_level() > 0 + && let Some((def_id, generics)) = func.const_fn_def() + && tcx.is_lang_item(def_id, LangItem::DropInPlace) => + { + (generics.type_at(0), target) } - debug!("SUCCESS: replacing `drop` with goto({:?})", target); - terminator.kind = TerminatorKind::Goto { target }; - should_simplify = true; + _ => continue, + }; + + if ty.needs_drop(tcx, typing_env) { + continue; } + debug!("SUCCESS: replacing `drop` with goto({:?})", target); + terminator.kind = TerminatorKind::Goto { target }; + should_simplify = true; } // if we applied optimizations, we potentially have some cfg to cleanup to diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index db933da6413..468ef742dfb 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -225,6 +225,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { current = target; } let last = current; + *changed |= *start != last; *start = last; while let Some((current, mut terminator)) = terminators.pop() { let Terminator { kind: TerminatorKind::Goto { ref mut target }, .. } = terminator diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs index 80c4b58a574..38769885f36 100644 --- a/compiler/rustc_mir_transform/src/sroa.rs +++ b/compiler/rustc_mir_transform/src/sroa.rs @@ -72,8 +72,12 @@ fn escaping_locals<'tcx>( return true; } if let ty::Adt(def, _args) = ty.kind() - && tcx.is_lang_item(def.did(), LangItem::DynMetadata) + && (def.repr().simd() || tcx.is_lang_item(def.did(), LangItem::DynMetadata)) { + // Exclude #[repr(simd)] types so that they are not de-optimized into an array + // (MCP#838 banned projections into SIMD types, but if the value is unused + // this pass sees "all the uses are of the fields" and expands it.) + // codegen wants to see the `DynMetadata<T>`, // not the inner reference-to-opaque-type. return true; diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 98d12bf0a38..99e4782e470 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -1,9 +1,9 @@ //! Validates the MIR to ensure that invariants are upheld. use rustc_abi::{ExternAbi, FIRST_VARIANT, Size}; -use rustc_attr_data_structures::InlineAttr; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::LangItem; +use rustc_hir::attrs::InlineAttr; use rustc_index::IndexVec; use rustc_index::bit_set::DenseBitSet; use rustc_infer::infer::TyCtxtInferExt; diff --git a/compiler/rustc_monomorphize/Cargo.toml b/compiler/rustc_monomorphize/Cargo.toml index 063fc8f1c74..0ed5b4fc0d0 100644 --- a/compiler/rustc_monomorphize/Cargo.toml +++ b/compiler/rustc_monomorphize/Cargo.toml @@ -7,7 +7,6 @@ edition = "2024" # tidy-alphabetical-start rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } -rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } diff --git a/compiler/rustc_monomorphize/messages.ftl b/compiler/rustc_monomorphize/messages.ftl index 2bd19e81b01..9595a5b5ac7 100644 --- a/compiler/rustc_monomorphize/messages.ftl +++ b/compiler/rustc_monomorphize/messages.ftl @@ -40,7 +40,10 @@ monomorphize_couldnt_dump_mono_stats = unexpected error occurred while dumping monomorphization stats: {$error} monomorphize_encountered_error_while_instantiating = - the above error was encountered while instantiating `{$formatted_item}` + the above error was encountered while instantiating `{$kind} {$instance}` + +monomorphize_encountered_error_while_instantiating_global_asm = + the above error was encountered while instantiating `global_asm` monomorphize_large_assignments = moving {$size} bytes @@ -52,12 +55,10 @@ monomorphize_no_optimized_mir = .note = missing optimized MIR for this item (was the crate `{$crate_name}` compiled with `--emit=metadata`?) monomorphize_recursion_limit = - reached the recursion limit while instantiating `{$shrunk}` + reached the recursion limit while instantiating `{$instance}` .note = `{$def_path_str}` defined here monomorphize_start_not_found = using `fn main` requires the standard library .help = use `#![no_main]` to bypass the Rust generated entrypoint and declare a platform specific entrypoint yourself, usually with `#[no_mangle]` monomorphize_symbol_already_defined = symbol `{$symbol}` is already defined - -monomorphize_written_to_path = the full type name has been written to '{$path}' diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 1bfd83d97ac..26ca8518434 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -206,13 +206,12 @@ //! regardless of whether it is actually needed or not. use std::cell::OnceCell; -use std::path::PathBuf; -use rustc_attr_data_structures::InlineAttr; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::{MTLock, par_for_each_in}; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_hir as hir; +use rustc_hir::attrs::InlineAttr; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; use rustc_hir::lang_items::LangItem; @@ -224,7 +223,6 @@ use rustc_middle::mir::{self, Location, MentionedItem, traversal}; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCoercion}; use rustc_middle::ty::layout::ValidityRequirement; -use rustc_middle::ty::print::{shrunk_instance_name, with_no_trimmed_paths}; use rustc_middle::ty::{ self, GenericArgs, GenericParamDefKind, Instance, InstanceKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, VtblEntry, @@ -237,7 +235,10 @@ use rustc_span::source_map::{Spanned, dummy_spanned, respan}; use rustc_span::{DUMMY_SP, Span}; use tracing::{debug, instrument, trace}; -use crate::errors::{self, EncounteredErrorWhileInstantiating, NoOptimizedMir, RecursionLimit}; +use crate::errors::{ + self, EncounteredErrorWhileInstantiating, EncounteredErrorWhileInstantiatingGlobalAsm, + NoOptimizedMir, RecursionLimit, +}; #[derive(PartialEq)] pub(crate) enum MonoItemCollectionStrategy { @@ -525,11 +526,23 @@ fn collect_items_rec<'tcx>( && starting_item.node.is_generic_fn() && starting_item.node.is_user_defined() { - let formatted_item = with_no_trimmed_paths!(starting_item.node.to_string()); - tcx.dcx().emit_note(EncounteredErrorWhileInstantiating { - span: starting_item.span, - formatted_item, - }); + match starting_item.node { + MonoItem::Fn(instance) => tcx.dcx().emit_note(EncounteredErrorWhileInstantiating { + span: starting_item.span, + kind: "fn", + instance, + }), + MonoItem::Static(def_id) => tcx.dcx().emit_note(EncounteredErrorWhileInstantiating { + span: starting_item.span, + kind: "static", + instance: Instance::new_raw(def_id, GenericArgs::empty()), + }), + MonoItem::GlobalAsm(_) => { + tcx.dcx().emit_note(EncounteredErrorWhileInstantiatingGlobalAsm { + span: starting_item.span, + }) + } + } } // Only updating `usage_map` for used items as otherwise we may be inserting the same item // multiple times (if it is first 'mentioned' and then later actually used), and the usage map @@ -612,22 +625,7 @@ fn check_recursion_limit<'tcx>( if !recursion_limit.value_within_limit(adjusted_recursion_depth) { let def_span = tcx.def_span(def_id); let def_path_str = tcx.def_path_str(def_id); - let (shrunk, written_to_path) = shrunk_instance_name(tcx, instance); - let mut path = PathBuf::new(); - let was_written = if let Some(written_to_path) = written_to_path { - path = written_to_path; - true - } else { - false - }; - tcx.dcx().emit_fatal(RecursionLimit { - span, - shrunk, - def_span, - def_path_str, - was_written, - path, - }); + tcx.dcx().emit_fatal(RecursionLimit { span, instance, def_span, def_path_str }); } recursion_depths.insert(def_id, recursion_depth + 1); diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs index 938c427b56c..89a78897dea 100644 --- a/compiler/rustc_monomorphize/src/errors.rs +++ b/compiler/rustc_monomorphize/src/errors.rs @@ -1,21 +1,16 @@ -use std::path::PathBuf; - use rustc_macros::{Diagnostic, LintDiagnostic}; -use rustc_middle::ty::Ty; +use rustc_middle::ty::{Instance, Ty}; use rustc_span::{Span, Symbol}; #[derive(Diagnostic)] #[diag(monomorphize_recursion_limit)] -pub(crate) struct RecursionLimit { +pub(crate) struct RecursionLimit<'tcx> { #[primary_span] pub span: Span, - pub shrunk: String, + pub instance: Instance<'tcx>, #[note] pub def_span: Span, pub def_path_str: String, - #[note(monomorphize_written_to_path)] - pub was_written: bool, - pub path: PathBuf, } #[derive(Diagnostic)] @@ -53,10 +48,18 @@ pub(crate) struct CouldntDumpMonoStats { #[derive(Diagnostic)] #[diag(monomorphize_encountered_error_while_instantiating)] -pub(crate) struct EncounteredErrorWhileInstantiating { +pub(crate) struct EncounteredErrorWhileInstantiating<'tcx> { + #[primary_span] + pub span: Span, + pub kind: &'static str, + pub instance: Instance<'tcx>, +} + +#[derive(Diagnostic)] +#[diag(monomorphize_encountered_error_while_instantiating_global_asm)] +pub(crate) struct EncounteredErrorWhileInstantiatingGlobalAsm { #[primary_span] pub span: Span, - pub formatted_item: String, } #[derive(Diagnostic)] diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index cee15e0f696..d76b27d9970 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -100,11 +100,11 @@ use std::fs::{self, File}; use std::io::Write; use std::path::{Path, PathBuf}; -use rustc_attr_data_structures::InlineAttr; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::sync; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_hir::LangItem; +use rustc_hir::attrs::InlineAttr; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdSet, LOCAL_CRATE}; use rustc_hir::definitions::DefPathDataName; diff --git a/compiler/rustc_next_trait_solver/Cargo.toml b/compiler/rustc_next_trait_solver/Cargo.toml index 36d53901d9e..05bcabad02f 100644 --- a/compiler/rustc_next_trait_solver/Cargo.toml +++ b/compiler/rustc_next_trait_solver/Cargo.toml @@ -15,6 +15,7 @@ tracing = "0.1" # tidy-alphabetical-end [features] +# tidy-alphabetical-start default = ["nightly"] nightly = [ "dep:rustc_data_structures", @@ -22,3 +23,4 @@ nightly = [ "rustc_index/nightly", "rustc_type_ir/nightly", ] +# tidy-alphabetical-end diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index a418aa82100..1bc35e599c7 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -19,6 +19,20 @@ const NEEDS_CANONICAL: TypeFlags = TypeFlags::from_bits( ) .unwrap(); +#[derive(Debug, Clone, Copy)] +enum CanonicalizeInputKind { + /// When canonicalizing the `param_env`, we keep `'static` as merging + /// trait candidates relies on it when deciding whether a where-bound + /// is trivial. + ParamEnv, + /// When canonicalizing predicates, we don't keep `'static`. If we're + /// currently outside of the trait solver and canonicalize the root goal + /// during HIR typeck, we replace each occurance of a region with a + /// unique region variable. See the comment on `InferCtxt::in_hir_typeck` + /// for more details. + Predicate { is_hir_typeck_root_goal: bool }, +} + /// Whether we're canonicalizing a query input or the query response. /// /// When canonicalizing an input we're in the context of the caller @@ -26,10 +40,7 @@ const NEEDS_CANONICAL: TypeFlags = TypeFlags::from_bits( /// query. #[derive(Debug, Clone, Copy)] enum CanonicalizeMode { - /// When canonicalizing the `param_env`, we keep `'static` as merging - /// trait candidates relies on it when deciding whether a where-bound - /// is trivial. - Input { keep_static: bool }, + Input(CanonicalizeInputKind), /// FIXME: We currently return region constraints referring to /// placeholders and inference variables from a binder instantiated /// inside of the query. @@ -122,7 +133,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> { let mut variables = Vec::new(); let mut env_canonicalizer = Canonicalizer { delegate, - canonicalize_mode: CanonicalizeMode::Input { keep_static: true }, + canonicalize_mode: CanonicalizeMode::Input(CanonicalizeInputKind::ParamEnv), variables: &mut variables, variable_lookup_table: Default::default(), @@ -154,7 +165,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> { } else { let mut env_canonicalizer = Canonicalizer { delegate, - canonicalize_mode: CanonicalizeMode::Input { keep_static: true }, + canonicalize_mode: CanonicalizeMode::Input(CanonicalizeInputKind::ParamEnv), variables, variable_lookup_table: Default::default(), @@ -180,6 +191,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> { pub fn canonicalize_input<P: TypeFoldable<I>>( delegate: &'a D, variables: &'a mut Vec<I::GenericArg>, + is_hir_typeck_root_goal: bool, input: QueryInput<I, P>, ) -> ty::Canonical<I, QueryInput<I, P>> { // First canonicalize the `param_env` while keeping `'static` @@ -189,7 +201,9 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> { // while *mostly* reusing the canonicalizer from above. let mut rest_canonicalizer = Canonicalizer { delegate, - canonicalize_mode: CanonicalizeMode::Input { keep_static: false }, + canonicalize_mode: CanonicalizeMode::Input(CanonicalizeInputKind::Predicate { + is_hir_typeck_root_goal, + }), variables, variable_lookup_table, @@ -296,7 +310,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> { } } - fn cached_fold_ty(&mut self, t: I::Ty) -> I::Ty { + fn inner_fold_ty(&mut self, t: I::Ty) -> I::Ty { let kind = match t.kind() { ty::Infer(i) => match i { ty::TyVar(vid) => { @@ -413,10 +427,10 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz // We don't canonicalize `ReStatic` in the `param_env` as we use it // when checking whether a `ParamEnv` candidate is global. ty::ReStatic => match self.canonicalize_mode { - CanonicalizeMode::Input { keep_static: false } => { + CanonicalizeMode::Input(CanonicalizeInputKind::Predicate { .. }) => { CanonicalVarKind::Region(ty::UniverseIndex::ROOT) } - CanonicalizeMode::Input { keep_static: true } + CanonicalizeMode::Input(CanonicalizeInputKind::ParamEnv) | CanonicalizeMode::Response { .. } => return r, }, @@ -428,12 +442,12 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz // `ReErased`. We may be able to short-circuit registering region // obligations if we encounter a `ReErased` on one side, for example. ty::ReErased | ty::ReError(_) => match self.canonicalize_mode { - CanonicalizeMode::Input { .. } => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), + CanonicalizeMode::Input(_) => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), CanonicalizeMode::Response { .. } => return r, }, ty::ReEarlyParam(_) | ty::ReLateParam(_) => match self.canonicalize_mode { - CanonicalizeMode::Input { .. } => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), + CanonicalizeMode::Input(_) => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), CanonicalizeMode::Response { .. } => { panic!("unexpected region in response: {r:?}") } @@ -441,7 +455,7 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz ty::RePlaceholder(placeholder) => match self.canonicalize_mode { // We canonicalize placeholder regions as existentials in query inputs. - CanonicalizeMode::Input { .. } => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), + CanonicalizeMode::Input(_) => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), CanonicalizeMode::Response { max_input_universe } => { // If we have a placeholder region inside of a query, it must be from // a new universe. @@ -459,9 +473,7 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz "region vid should have been resolved fully before canonicalization" ); match self.canonicalize_mode { - CanonicalizeMode::Input { keep_static: _ } => { - CanonicalVarKind::Region(ty::UniverseIndex::ROOT) - } + CanonicalizeMode::Input(_) => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), CanonicalizeMode::Response { .. } => { CanonicalVarKind::Region(self.delegate.universe_of_lt(vid).unwrap()) } @@ -469,16 +481,34 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz } }; - let var = self.get_or_insert_bound_var(r, kind); + let var = if let CanonicalizeMode::Input(CanonicalizeInputKind::Predicate { + is_hir_typeck_root_goal: true, + }) = self.canonicalize_mode + { + let var = ty::BoundVar::from(self.variables.len()); + self.variables.push(r.into()); + self.var_kinds.push(kind); + var + } else { + self.get_or_insert_bound_var(r, kind) + }; Region::new_anon_bound(self.cx(), self.binder_index, var) } fn fold_ty(&mut self, t: I::Ty) -> I::Ty { - if let Some(&ty) = self.cache.get(&(self.binder_index, t)) { + if let CanonicalizeMode::Input(CanonicalizeInputKind::Predicate { + is_hir_typeck_root_goal: true, + }) = self.canonicalize_mode + { + // If we're canonicalizing a root goal during HIR typeck, we + // must not use the `cache` as we want to map each occurrence + // of a region to a unique existential variable. + self.inner_fold_ty(t) + } else if let Some(&ty) = self.cache.get(&(self.binder_index, t)) { ty } else { - let res = self.cached_fold_ty(t); + let res = self.inner_fold_ty(t); let old = self.cache.insert((self.binder_index, t), res); assert_eq!(old, None); res @@ -541,9 +571,9 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz fn fold_clauses(&mut self, c: I::Clauses) -> I::Clauses { match self.canonicalize_mode { - CanonicalizeMode::Input { keep_static: true } + CanonicalizeMode::Input(CanonicalizeInputKind::ParamEnv) | CanonicalizeMode::Response { max_input_universe: _ } => {} - CanonicalizeMode::Input { keep_static: false } => { + CanonicalizeMode::Input(CanonicalizeInputKind::Predicate { .. }) => { panic!("erasing 'static in env") } } diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index b2d40146348..5e08c3a03d8 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -21,7 +21,7 @@ use crate::delegate::SolverDelegate; use crate::solve::inspect::ProbeKind; use crate::solve::{ BuiltinImplSource, CandidateSource, CanonicalResponse, Certainty, EvalCtxt, Goal, GoalSource, - MaybeCause, NoSolution, ParamEnvSource, QueryResult, + MaybeCause, NoSolution, ParamEnvSource, QueryResult, has_no_inference_or_external_constraints, }; enum AliasBoundKind { @@ -50,7 +50,7 @@ where fn trait_ref(self, cx: I) -> ty::TraitRef<I>; - fn with_self_ty(self, cx: I, self_ty: I::Ty) -> Self; + fn with_replaced_self_ty(self, cx: I, self_ty: I::Ty) -> Self; fn trait_def_id(self, cx: I) -> I::DefId; @@ -376,8 +376,8 @@ where return self.forced_ambiguity(MaybeCause::Ambiguity).into_iter().collect(); } - let goal: Goal<I, G> = - goal.with(self.cx(), goal.predicate.with_self_ty(self.cx(), normalized_self_ty)); + let goal: Goal<I, G> = goal + .with(self.cx(), goal.predicate.with_replaced_self_ty(self.cx(), normalized_self_ty)); // Vars that show up in the rest of the goal substs may have been constrained by // normalizing the self type as well, since type variables are not uniquified. let goal = self.resolve_vars_if_possible(goal); @@ -395,9 +395,30 @@ where match assemble_from { AssembleCandidatesFrom::All => { - self.assemble_impl_candidates(goal, &mut candidates); self.assemble_builtin_impl_candidates(goal, &mut candidates); - self.assemble_object_bound_candidates(goal, &mut candidates); + // For performance we only assemble impls if there are no candidates + // which would shadow them. This is necessary to avoid hangs in rayon, + // see trait-system-refactor-initiative#109 for more details. + // + // We always assemble builtin impls as trivial builtin impls have a higher + // priority than where-clauses. + // + // We only do this if any such candidate applies without any constraints + // as we may want to weaken inference guidance in the future and don't want + // to worry about causing major performance regressions when doing so. + // See trait-system-refactor-initiative#226 for some ideas here. + if TypingMode::Coherence == self.typing_mode() + || !candidates.iter().any(|c| { + matches!( + c.source, + CandidateSource::ParamEnv(ParamEnvSource::NonGlobal) + | CandidateSource::AliasBound + ) && has_no_inference_or_external_constraints(c.result) + }) + { + self.assemble_impl_candidates(goal, &mut candidates); + self.assemble_object_bound_candidates(goal, &mut candidates); + } } AssembleCandidatesFrom::EnvAndBounds => {} } @@ -938,36 +959,23 @@ where // Even when a trait bound has been proven using a where-bound, we // still need to consider alias-bounds for normalization, see // `tests/ui/next-solver/alias-bound-shadowed-by-env.rs`. - let candidates_from_env_and_bounds: Vec<_> = self + let mut candidates: Vec<_> = self .assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::EnvAndBounds); // We still need to prefer where-bounds over alias-bounds however. // See `tests/ui/winnowing/norm-where-bound-gt-alias-bound.rs`. - let mut considered_candidates: Vec<_> = if candidates_from_env_and_bounds - .iter() - .any(|c| matches!(c.source, CandidateSource::ParamEnv(_))) - { - candidates_from_env_and_bounds - .into_iter() - .filter(|c| matches!(c.source, CandidateSource::ParamEnv(_))) - .map(|c| c.result) - .collect() - } else { - candidates_from_env_and_bounds.into_iter().map(|c| c.result).collect() - }; - - // If the trait goal has been proven by using the environment, we want to treat - // aliases as rigid if there are no applicable projection bounds in the environment. - if considered_candidates.is_empty() { - if let Ok(response) = inject_normalize_to_rigid_candidate(self) { - considered_candidates.push(response); - } + if candidates.iter().any(|c| matches!(c.source, CandidateSource::ParamEnv(_))) { + candidates.retain(|c| matches!(c.source, CandidateSource::ParamEnv(_))); + } else if candidates.is_empty() { + // If the trait goal has been proven by using the environment, we want to treat + // aliases as rigid if there are no applicable projection bounds in the environment. + return inject_normalize_to_rigid_candidate(self); } - if let Some(response) = self.try_merge_responses(&considered_candidates) { + if let Some(response) = self.try_merge_candidates(&candidates) { Ok(response) } else { - self.flounder(&considered_candidates) + self.flounder(&candidates) } } TraitGoalProvenVia::Misc => { @@ -977,11 +985,9 @@ where // Prefer "orphaned" param-env normalization predicates, which are used // (for example, and ideally only) when proving item bounds for an impl. let candidates_from_env: Vec<_> = candidates - .iter() - .filter(|c| matches!(c.source, CandidateSource::ParamEnv(_))) - .map(|c| c.result) + .extract_if(.., |c| matches!(c.source, CandidateSource::ParamEnv(_))) .collect(); - if let Some(response) = self.try_merge_responses(&candidates_from_env) { + if let Some(response) = self.try_merge_candidates(&candidates_from_env) { return Ok(response); } @@ -991,12 +997,10 @@ where // means we can just ignore inference constraints and don't have to special-case // constraining the normalized-to `term`. self.filter_specialized_impls(AllowInferenceConstraints::Yes, &mut candidates); - - let responses: Vec<_> = candidates.iter().map(|c| c.result).collect(); - if let Some(response) = self.try_merge_responses(&responses) { + if let Some(response) = self.try_merge_candidates(&candidates) { Ok(response) } else { - self.flounder(&responses) + self.flounder(&candidates) } } } diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index c0bebdf6fb6..faa86734d08 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -75,9 +75,16 @@ where Ok(ty::Binder::dummy(vec![args.as_coroutine_closure().tupled_upvars_ty()])) } - ty::Coroutine(_, args) => { + ty::Coroutine(def_id, args) => { let coroutine_args = args.as_coroutine(); - Ok(ty::Binder::dummy(vec![coroutine_args.tupled_upvars_ty(), coroutine_args.witness()])) + Ok(ty::Binder::dummy(vec![ + coroutine_args.tupled_upvars_ty(), + Ty::new_coroutine_witness( + ecx.cx(), + def_id, + ecx.cx().mk_args(coroutine_args.parent_args().as_slice()), + ), + ])) } ty::CoroutineWitness(def_id, args) => Ok(ecx @@ -245,7 +252,14 @@ where Movability::Movable => { if ecx.cx().features().coroutine_clone() { let coroutine = args.as_coroutine(); - Ok(ty::Binder::dummy(vec![coroutine.tupled_upvars_ty(), coroutine.witness()])) + Ok(ty::Binder::dummy(vec![ + coroutine.tupled_upvars_ty(), + Ty::new_coroutine_witness( + ecx.cx(), + def_id, + ecx.cx().mk_args(coroutine.parent_args().as_slice()), + ), + ])) } else { Err(NoSolution) } diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index 61f3f9367f0..9a22bf58c03 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -29,8 +29,8 @@ where self.trait_ref } - fn with_self_ty(self, cx: I, self_ty: I::Ty) -> Self { - self.with_self_ty(cx, self_ty) + fn with_replaced_self_ty(self, cx: I, self_ty: I::Ty) -> Self { + self.with_replaced_self_ty(cx, self_ty) } fn trait_def_id(self, _: I) -> I::DefId { diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs index 5ed316aa6b1..74c5b49ea92 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs @@ -53,20 +53,19 @@ where { /// Canonicalizes the goal remembering the original values /// for each bound variable. + /// + /// This expects `goal` and `opaque_types` to be eager resolved. pub(super) fn canonicalize_goal( &self, + is_hir_typeck_root_goal: bool, goal: Goal<I, I::Predicate>, + opaque_types: Vec<(ty::OpaqueTypeKey<I>, I::Ty)>, ) -> (Vec<I::GenericArg>, CanonicalInput<I, I::Predicate>) { - // We only care about one entry per `OpaqueTypeKey` here, - // so we only canonicalize the lookup table and ignore - // duplicate entries. - let opaque_types = self.delegate.clone_opaque_types_lookup_table(); - let (goal, opaque_types) = eager_resolve_vars(self.delegate, (goal, opaque_types)); - let mut orig_values = Default::default(); let canonical = Canonicalizer::canonicalize_input( self.delegate, &mut orig_values, + is_hir_typeck_root_goal, QueryInput { goal, predefined_opaques_in_body: self diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index ce9b794d40d..8671cc7c3d3 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -20,6 +20,7 @@ use super::has_only_region_constraints; use crate::coherence; use crate::delegate::SolverDelegate; use crate::placeholder::BoundVarReplacer; +use crate::resolve::eager_resolve_vars; use crate::solve::inspect::{self, ProofTreeBuilder}; use crate::solve::search_graph::SearchGraph; use crate::solve::ty::may_use_unstable_feature; @@ -440,6 +441,7 @@ where return Ok(( NestedNormalizationGoals::empty(), GoalEvaluation { + goal, certainty: Certainty::Maybe(stalled_on.stalled_cause), has_changed: HasChanged::No, stalled_on: Some(stalled_on), @@ -447,7 +449,16 @@ where )); } - let (orig_values, canonical_goal) = self.canonicalize_goal(goal); + // We only care about one entry per `OpaqueTypeKey` here, + // so we only canonicalize the lookup table and ignore + // duplicate entries. + let opaque_types = self.delegate.clone_opaque_types_lookup_table(); + let (goal, opaque_types) = eager_resolve_vars(self.delegate, (goal, opaque_types)); + + let is_hir_typeck_root_goal = matches!(goal_evaluation_kind, GoalEvaluationKind::Root) + && self.delegate.in_hir_typeck(); + let (orig_values, canonical_goal) = + self.canonicalize_goal(is_hir_typeck_root_goal, goal, opaque_types); let mut goal_evaluation = self.inspect.new_goal_evaluation(goal, &orig_values, goal_evaluation_kind); let canonical_result = self.search_graph.evaluate_goal( @@ -525,7 +536,10 @@ where }, }; - Ok((normalization_nested_goals, GoalEvaluation { certainty, has_changed, stalled_on })) + Ok(( + normalization_nested_goals, + GoalEvaluation { goal, certainty, has_changed, stalled_on }, + )) } pub(super) fn compute_goal(&mut self, goal: Goal<I, I::Predicate>) -> QueryResult<I> { @@ -661,7 +675,7 @@ where let ( NestedNormalizationGoals(nested_goals), - GoalEvaluation { certainty, stalled_on, has_changed: _ }, + GoalEvaluation { goal, certainty, stalled_on, has_changed: _ }, ) = self.evaluate_goal_raw( GoalEvaluationKind::Nested, source, @@ -699,7 +713,15 @@ where // FIXME: Do we need to eagerly resolve here? Or should we check // if the cache key has any changed vars? let with_resolved_vars = self.resolve_vars_if_possible(goal); - if pred.alias != goal.predicate.as_normalizes_to().unwrap().skip_binder().alias { + if pred.alias + != with_resolved_vars + .predicate + .as_normalizes_to() + .unwrap() + .no_bound_vars() + .unwrap() + .alias + { unchanged_certainty = None; } @@ -711,7 +733,7 @@ where } } } else { - let GoalEvaluation { certainty, has_changed, stalled_on } = + let GoalEvaluation { goal, certainty, has_changed, stalled_on } = self.evaluate_goal(GoalEvaluationKind::Nested, source, goal, stalled_on)?; if has_changed == HasChanged::Yes { unchanged_certainty = None; diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 5ea3f0d1061..2feebe270a6 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -29,6 +29,7 @@ use tracing::instrument; pub use self::eval_ctxt::{EvalCtxt, GenerateProofTree, SolverDelegateEvalExt}; use crate::delegate::SolverDelegate; +use crate::solve::assembly::Candidate; /// How many fixpoint iterations we should attempt inside of the solver before bailing /// with overflow. @@ -244,52 +245,51 @@ where /// /// In this case we tend to flounder and return ambiguity by calling `[EvalCtxt::flounder]`. #[instrument(level = "trace", skip(self), ret)] - fn try_merge_responses( + fn try_merge_candidates( &mut self, - responses: &[CanonicalResponse<I>], + candidates: &[Candidate<I>], ) -> Option<CanonicalResponse<I>> { - if responses.is_empty() { + if candidates.is_empty() { return None; } - // FIXME(-Znext-solver): Add support to merge region constraints in - // responses to deal with trait-system-refactor-initiative#27. - let one = responses[0]; - if responses[1..].iter().all(|&resp| resp == one) { + let one: CanonicalResponse<I> = candidates[0].result; + if candidates[1..].iter().all(|candidate| candidate.result == one) { return Some(one); } - responses + candidates .iter() - .find(|response| { - response.value.certainty == Certainty::Yes - && has_no_inference_or_external_constraints(**response) + .find(|candidate| { + candidate.result.value.certainty == Certainty::Yes + && has_no_inference_or_external_constraints(candidate.result) }) - .copied() + .map(|candidate| candidate.result) } - fn bail_with_ambiguity(&mut self, responses: &[CanonicalResponse<I>]) -> CanonicalResponse<I> { - debug_assert!(responses.len() > 1); - let maybe_cause = responses.iter().fold(MaybeCause::Ambiguity, |maybe_cause, response| { - // Pull down the certainty of `Certainty::Yes` to ambiguity when combining - // these responses, b/c we're combining more than one response and this we - // don't know which one applies. - let candidate = match response.value.certainty { - Certainty::Yes => MaybeCause::Ambiguity, - Certainty::Maybe(candidate) => candidate, - }; - maybe_cause.or(candidate) - }); + fn bail_with_ambiguity(&mut self, candidates: &[Candidate<I>]) -> CanonicalResponse<I> { + debug_assert!(candidates.len() > 1); + let maybe_cause = + candidates.iter().fold(MaybeCause::Ambiguity, |maybe_cause, candidates| { + // Pull down the certainty of `Certainty::Yes` to ambiguity when combining + // these responses, b/c we're combining more than one response and this we + // don't know which one applies. + let candidate = match candidates.result.value.certainty { + Certainty::Yes => MaybeCause::Ambiguity, + Certainty::Maybe(candidate) => candidate, + }; + maybe_cause.or(candidate) + }); self.make_ambiguous_response_no_constraints(maybe_cause) } /// If we fail to merge responses we flounder and return overflow or ambiguity. #[instrument(level = "trace", skip(self), ret)] - fn flounder(&mut self, responses: &[CanonicalResponse<I>]) -> QueryResult<I> { - if responses.is_empty() { + fn flounder(&mut self, candidates: &[Candidate<I>]) -> QueryResult<I> { + if candidates.is_empty() { return Err(NoSolution); } else { - Ok(self.bail_with_ambiguity(responses)) + Ok(self.bail_with_ambiguity(candidates)) } } @@ -388,6 +388,23 @@ fn response_no_constraints_raw<I: Interner>( /// The result of evaluating a goal. pub struct GoalEvaluation<I: Interner> { + /// The goal we've evaluated. This is the input goal, but potentially with its + /// inference variables resolved. This never applies any inference constraints + /// from evaluating the goal. + /// + /// We rely on this to check whether root goals in HIR typeck had an unresolved + /// type inference variable in the input. We must not resolve this after evaluating + /// the goal as even if the inference variable has been resolved by evaluating the + /// goal itself, this goal may still end up failing due to region uniquification + /// later on. + /// + /// This is used as a minor optimization to avoid re-resolving inference variables + /// when reevaluating ambiguous goals. E.g. if we've got a goal `?x: Trait` with `?x` + /// already being constrained to `Vec<?y>`, then the first evaluation resolves it to + /// `Vec<?y>: Trait`. If this goal is still ambiguous and we later resolve `?y` to `u32`, + /// then reevaluating this goal now only needs to resolve `?y` while it would otherwise + /// have to resolve both `?x` and `?y`, + pub goal: Goal<I, I::Predicate>, pub certainty: Certainty, pub has_changed: HasChanged, /// If the [`Certainty`] was `Maybe`, then keep track of whether the goal has changed diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index 1e0a90eb2ee..93434dce79f 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -99,8 +99,8 @@ where self.alias.trait_ref(cx) } - fn with_self_ty(self, cx: I, self_ty: I::Ty) -> Self { - self.with_self_ty(cx, self_ty) + fn with_replaced_self_ty(self, cx: I, self_ty: I::Ty) -> Self { + self.with_replaced_self_ty(cx, self_ty) } fn trait_def_id(self, cx: I) -> I::DefId { diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 650b85d99d2..60bae738e61 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -33,8 +33,8 @@ where self.trait_ref } - fn with_self_ty(self, cx: I, self_ty: I::Ty) -> Self { - self.with_self_ty(cx, self_ty) + fn with_replaced_self_ty(self, cx: I, self_ty: I::Ty) -> Self { + self.with_replaced_self_ty(cx, self_ty) } fn trait_def_id(self, _: I) -> I::DefId { @@ -229,7 +229,7 @@ where } // We need to make sure to stall any coroutines we are inferring to avoid query cycles. - if let Some(cand) = ecx.try_stall_coroutine_witness(goal.predicate.self_ty()) { + if let Some(cand) = ecx.try_stall_coroutine(goal.predicate.self_ty()) { return cand; } @@ -294,7 +294,7 @@ where } // We need to make sure to stall any coroutines we are inferring to avoid query cycles. - if let Some(cand) = ecx.try_stall_coroutine_witness(goal.predicate.self_ty()) { + if let Some(cand) = ecx.try_stall_coroutine(goal.predicate.self_ty()) { return cand; } @@ -1263,7 +1263,9 @@ where let goals = ecx.enter_forall(constituent_tys(ecx, goal.predicate.self_ty())?, |ecx, tys| { tys.into_iter() - .map(|ty| goal.with(ecx.cx(), goal.predicate.with_self_ty(ecx.cx(), ty))) + .map(|ty| { + goal.with(ecx.cx(), goal.predicate.with_replaced_self_ty(ecx.cx(), ty)) + }) .collect::<Vec<_>>() }); ecx.add_goals(GoalSource::ImplWhereBound, goals); @@ -1344,11 +1346,10 @@ where mut candidates: Vec<Candidate<I>>, ) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> { if let TypingMode::Coherence = self.typing_mode() { - let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect(); - return if let Some(response) = self.try_merge_responses(&all_candidates) { + return if let Some(response) = self.try_merge_candidates(&candidates) { Ok((response, Some(TraitGoalProvenVia::Misc))) } else { - self.flounder(&all_candidates).map(|r| (r, None)) + self.flounder(&candidates).map(|r| (r, None)) }; } @@ -1373,11 +1374,9 @@ where .any(|c| matches!(c.source, CandidateSource::ParamEnv(ParamEnvSource::NonGlobal))); if has_non_global_where_bounds { let where_bounds: Vec<_> = candidates - .iter() - .filter(|c| matches!(c.source, CandidateSource::ParamEnv(_))) - .map(|c| c.result) + .extract_if(.., |c| matches!(c.source, CandidateSource::ParamEnv(_))) .collect(); - return if let Some(response) = self.try_merge_responses(&where_bounds) { + return if let Some(response) = self.try_merge_candidates(&where_bounds) { Ok((response, Some(TraitGoalProvenVia::ParamEnv))) } else { Ok((self.bail_with_ambiguity(&where_bounds), None)) @@ -1386,11 +1385,9 @@ where if candidates.iter().any(|c| matches!(c.source, CandidateSource::AliasBound)) { let alias_bounds: Vec<_> = candidates - .iter() - .filter(|c| matches!(c.source, CandidateSource::AliasBound)) - .map(|c| c.result) + .extract_if(.., |c| matches!(c.source, CandidateSource::AliasBound)) .collect(); - return if let Some(response) = self.try_merge_responses(&alias_bounds) { + return if let Some(response) = self.try_merge_candidates(&alias_bounds) { Ok((response, Some(TraitGoalProvenVia::AliasBound))) } else { Ok((self.bail_with_ambiguity(&alias_bounds), None)) @@ -1415,11 +1412,10 @@ where TraitGoalProvenVia::Misc }; - let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect(); - if let Some(response) = self.try_merge_responses(&all_candidates) { + if let Some(response) = self.try_merge_candidates(&candidates) { Ok((response, Some(proven_via))) } else { - self.flounder(&all_candidates).map(|r| (r, None)) + self.flounder(&candidates).map(|r| (r, None)) } } @@ -1432,11 +1428,8 @@ where self.merge_trait_candidates(candidates) } - fn try_stall_coroutine_witness( - &mut self, - self_ty: I::Ty, - ) -> Option<Result<Candidate<I>, NoSolution>> { - if let ty::CoroutineWitness(def_id, _) = self_ty.kind() { + fn try_stall_coroutine(&mut self, self_ty: I::Ty) -> Option<Result<Candidate<I>, NoSolution>> { + if let ty::Coroutine(def_id, _) = self_ty.kind() { match self.typing_mode() { TypingMode::Analysis { defining_opaque_types_and_generators: stalled_generators, diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml index 88f93782de1..0ae0b613fa2 100644 --- a/compiler/rustc_parse/Cargo.toml +++ b/compiler/rustc_parse/Cargo.toml @@ -26,5 +26,8 @@ unicode-width = "0.2.0" # tidy-alphabetical-end [dev-dependencies] +# tidy-alphabetical-start termcolor = "1.2" +# tidy-alphabetical-end + diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 859118a4ade..aaf1b6c05bf 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -71,6 +71,17 @@ parse_attr_without_generics = attribute without generic parameters parse_attribute_on_param_type = attributes cannot be applied to a function parameter's type .label = attributes are not allowed here +parse_attribute_on_type = attributes cannot be applied to types + .label = attributes are not allowed here + .suggestion = remove attribute from here + +parse_attribute_on_generic_arg = attributes cannot be applied to generic arguments + .label = attributes are not allowed here + .suggestion = remove attribute from here + +parse_attribute_on_empty_type = attributes cannot be applied here + .label = attributes are not allowed here + parse_bad_assoc_type_bounds = bounds on associated types do not belong here .label = belongs in `where` clause @@ -631,7 +642,7 @@ parse_missing_for_in_trait_impl = missing `for` in a trait impl .suggestion = add `for` here parse_missing_in_in_for_loop = missing `in` in `for` loop - .use_in_not_of = try using `in` here instead + .use_in = try using `in` here instead .add_in = try adding `in` here parse_missing_let_before_mut = missing keyword diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 4aaaba01fae..ddb2c545c78 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -585,14 +585,13 @@ pub(crate) struct MissingInInForLoop { #[derive(Subdiagnostic)] pub(crate) enum MissingInInForLoopSub { + // User wrote `for pat of expr {}` // Has been misleading, at least in the past (closed Issue #48492), thus maybe-incorrect - #[suggestion( - parse_use_in_not_of, - style = "verbose", - applicability = "maybe-incorrect", - code = "in" - )] + #[suggestion(parse_use_in, style = "verbose", applicability = "maybe-incorrect", code = "in")] InNotOf(#[primary_span] Span), + // User wrote `for pat = expr {}` + #[suggestion(parse_use_in, style = "verbose", applicability = "maybe-incorrect", code = "in")] + InNotEq(#[primary_span] Span), #[suggestion(parse_add_in, style = "verbose", applicability = "maybe-incorrect", code = " in ")] AddIn(#[primary_span] Span), } @@ -1490,6 +1489,34 @@ pub(crate) struct AttributeOnParamType { } #[derive(Diagnostic)] +#[diag(parse_attribute_on_type)] +pub(crate) struct AttributeOnType { + #[primary_span] + #[label] + pub span: Span, + #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")] + pub fix_span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_attribute_on_generic_arg)] +pub(crate) struct AttributeOnGenericArg { + #[primary_span] + #[label] + pub span: Span, + #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")] + pub fix_span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_attribute_on_empty_type)] +pub(crate) struct AttributeOnEmptyType { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(Diagnostic)] #[diag(parse_pattern_method_param_without_body, code = E0642)] pub(crate) struct PatternMethodParamWithoutBody { #[primary_span] diff --git a/compiler/rustc_parse/src/parser/asm.rs b/compiler/rustc_parse/src/parser/asm.rs index d4d0612a317..41c3b0f0b67 100644 --- a/compiler/rustc_parse/src/parser/asm.rs +++ b/compiler/rustc_parse/src/parser/asm.rs @@ -1,4 +1,3 @@ -use rustc_ast::ptr::P; use rustc_ast::{self as ast, AsmMacro}; use rustc_span::{Span, Symbol, kw}; @@ -14,7 +13,7 @@ pub struct AsmArg { } pub enum AsmArgKind { - Template(P<ast::Expr>), + Template(Box<ast::Expr>), Operand(Option<Symbol>, ast::InlineAsmOperand), Options(Vec<AsmOption>), ClobberAbi(Vec<(Symbol, Span)>), diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index e0f810d8c1e..a32cd33a260 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -3,7 +3,6 @@ use std::ops::{Deref, DerefMut}; use ast::token::IdentIsRaw; use rustc_ast as ast; -use rustc_ast::ptr::P; use rustc_ast::token::{self, Lit, LitKind, Token, TokenKind}; use rustc_ast::util::parser::AssocOp; use rustc_ast::{ @@ -50,7 +49,7 @@ use crate::{exp, fluent_generated as fluent}; /// Creates a placeholder argument. pub(super) fn dummy_arg(ident: Ident, guar: ErrorGuaranteed) -> Param { - let pat = P(Pat { + let pat = Box::new(Pat { id: ast::DUMMY_NODE_ID, kind: PatKind::Ident(BindingMode::NONE, ident, None), span: ident.span, @@ -62,23 +61,23 @@ pub(super) fn dummy_arg(ident: Ident, guar: ErrorGuaranteed) -> Param { id: ast::DUMMY_NODE_ID, pat, span: ident.span, - ty: P(ty), + ty: Box::new(ty), is_placeholder: false, } } pub(super) trait RecoverQPath: Sized + 'static { const PATH_STYLE: PathStyle = PathStyle::Expr; - fn to_ty(&self) -> Option<P<Ty>>; - fn recovered(qself: Option<P<QSelf>>, path: ast::Path) -> Self; + fn to_ty(&self) -> Option<Box<Ty>>; + fn recovered(qself: Option<Box<QSelf>>, path: ast::Path) -> Self; } impl RecoverQPath for Ty { const PATH_STYLE: PathStyle = PathStyle::Type; - fn to_ty(&self) -> Option<P<Ty>> { - Some(P(self.clone())) + fn to_ty(&self) -> Option<Box<Ty>> { + Some(Box::new(self.clone())) } - fn recovered(qself: Option<P<QSelf>>, path: ast::Path) -> Self { + fn recovered(qself: Option<Box<QSelf>>, path: ast::Path) -> Self { Self { span: path.span, kind: TyKind::Path(qself, path), @@ -90,10 +89,10 @@ impl RecoverQPath for Ty { impl RecoverQPath for Pat { const PATH_STYLE: PathStyle = PathStyle::Pat; - fn to_ty(&self) -> Option<P<Ty>> { + fn to_ty(&self) -> Option<Box<Ty>> { self.to_ty() } - fn recovered(qself: Option<P<QSelf>>, path: ast::Path) -> Self { + fn recovered(qself: Option<Box<QSelf>>, path: ast::Path) -> Self { Self { span: path.span, kind: PatKind::Path(qself, path), @@ -104,10 +103,10 @@ impl RecoverQPath for Pat { } impl RecoverQPath for Expr { - fn to_ty(&self) -> Option<P<Ty>> { + fn to_ty(&self) -> Option<Box<Ty>> { self.to_ty() } - fn recovered(qself: Option<P<QSelf>>, path: ast::Path) -> Self { + fn recovered(qself: Option<Box<QSelf>>, path: ast::Path) -> Self { Self { span: path.span, kind: ExprKind::Path(qself, path), @@ -977,7 +976,7 @@ impl<'a> Parser<'a> { lo: Span, s: BlockCheckMode, maybe_struct_name: token::Token, - ) -> Option<PResult<'a, P<Block>>> { + ) -> Option<PResult<'a, Box<Block>>> { if self.token.is_ident() && self.look_ahead(1, |t| t == &token::Colon) { // We might be having a struct literal where people forgot to include the path: // fn foo() -> Foo { @@ -1042,7 +1041,7 @@ impl<'a> Parser<'a> { token: token::Token, lo: Span, decl_hi: Span, - ) -> PResult<'a, P<Expr>> { + ) -> PResult<'a, Box<Expr>> { err.span_label(lo.to(decl_hi), "while parsing the body of this closure"); let guar = match before.kind { token::OpenBrace if token.kind != token::OpenBrace => { @@ -1260,7 +1259,7 @@ impl<'a> Parser<'a> { pub(super) fn check_mistyped_turbofish_with_multiple_type_params( &mut self, mut e: Diag<'a>, - expr: &mut P<Expr>, + expr: &mut Box<Expr>, ) -> PResult<'a, ErrorGuaranteed> { if let ExprKind::Binary(binop, _, _) = &expr.kind && let ast::BinOpKind::Lt = binop.node @@ -1443,7 +1442,7 @@ impl<'a> Parser<'a> { &mut self, inner_op: &Expr, outer_op: &Spanned<AssocOp>, - ) -> PResult<'a, Option<P<Expr>>> { + ) -> PResult<'a, Option<Box<Expr>>> { debug_assert!( outer_op.node.is_comparison(), "check_no_chained_comparison: {:?} is not comparison", @@ -1595,7 +1594,7 @@ impl<'a> Parser<'a> { } /// Swift lets users write `Ty?` to mean `Option<Ty>`. Parse the construct and recover from it. - pub(super) fn maybe_recover_from_question_mark(&mut self, ty: P<Ty>) -> P<Ty> { + pub(super) fn maybe_recover_from_question_mark(&mut self, ty: Box<Ty>) -> Box<Ty> { if self.token == token::Question { self.bump(); let guar = self.dcx().emit_err(QuestionMarkInType { @@ -1690,10 +1689,10 @@ impl<'a> Parser<'a> { pub(super) fn recover_from_prefix_increment( &mut self, - operand_expr: P<Expr>, + operand_expr: Box<Expr>, op_span: Span, start_stmt: bool, - ) -> PResult<'a, P<Expr>> { + ) -> PResult<'a, Box<Expr>> { let standalone = if start_stmt { IsStandalone::Standalone } else { IsStandalone::Subexpr }; let kind = IncDecRecovery { standalone, op: IncOrDec::Inc, fixity: UnaryFixity::Pre }; self.recover_from_inc_dec(operand_expr, kind, op_span) @@ -1701,10 +1700,10 @@ impl<'a> Parser<'a> { pub(super) fn recover_from_postfix_increment( &mut self, - operand_expr: P<Expr>, + operand_expr: Box<Expr>, op_span: Span, start_stmt: bool, - ) -> PResult<'a, P<Expr>> { + ) -> PResult<'a, Box<Expr>> { let kind = IncDecRecovery { standalone: if start_stmt { IsStandalone::Standalone } else { IsStandalone::Subexpr }, op: IncOrDec::Inc, @@ -1715,10 +1714,10 @@ impl<'a> Parser<'a> { pub(super) fn recover_from_postfix_decrement( &mut self, - operand_expr: P<Expr>, + operand_expr: Box<Expr>, op_span: Span, start_stmt: bool, - ) -> PResult<'a, P<Expr>> { + ) -> PResult<'a, Box<Expr>> { let kind = IncDecRecovery { standalone: if start_stmt { IsStandalone::Standalone } else { IsStandalone::Subexpr }, op: IncOrDec::Dec, @@ -1729,10 +1728,10 @@ impl<'a> Parser<'a> { fn recover_from_inc_dec( &mut self, - base: P<Expr>, + base: Box<Expr>, kind: IncDecRecovery, op_span: Span, - ) -> PResult<'a, P<Expr>> { + ) -> PResult<'a, Box<Expr>> { let mut err = self.dcx().struct_span_err( op_span, format!("Rust has no {} {} operator", kind.fixity, kind.op.name()), @@ -1833,8 +1832,8 @@ impl<'a> Parser<'a> { /// tail, and combines them into a `<Ty>::AssocItem` expression/pattern/type. pub(super) fn maybe_recover_from_bad_qpath<T: RecoverQPath>( &mut self, - base: P<T>, - ) -> PResult<'a, P<T>> { + base: Box<T>, + ) -> PResult<'a, Box<T>> { if !self.may_recover() { return Ok(base); } @@ -1853,8 +1852,8 @@ impl<'a> Parser<'a> { pub(super) fn maybe_recover_from_bad_qpath_stage_2<T: RecoverQPath>( &mut self, ty_span: Span, - ty: P<Ty>, - ) -> PResult<'a, P<T>> { + ty: Box<Ty>, + ) -> PResult<'a, Box<T>> { self.expect(exp!(PathSep))?; let mut path = ast::Path { segments: ThinVec::new(), span: DUMMY_SP, tokens: None }; @@ -1867,7 +1866,7 @@ impl<'a> Parser<'a> { }); let path_span = ty_span.shrink_to_hi(); // Use an empty path since `position == 0`. - Ok(P(T::recovered(Some(P(QSelf { ty, path_span, position: 0 })), path))) + Ok(Box::new(T::recovered(Some(Box::new(QSelf { ty, path_span, position: 0 })), path))) } /// This function gets called in places where a semicolon is NOT expected and if there's a @@ -1970,7 +1969,7 @@ impl<'a> Parser<'a> { pub(super) fn recover_incorrect_await_syntax( &mut self, await_sp: Span, - ) -> PResult<'a, P<Expr>> { + ) -> PResult<'a, Box<Expr>> { let (hi, expr, is_question) = if self.token == token::Bang { // Handle `await!(<expr>)`. self.recover_await_macro()? @@ -1982,7 +1981,7 @@ impl<'a> Parser<'a> { self.maybe_recover_from_bad_qpath(expr) } - fn recover_await_macro(&mut self) -> PResult<'a, (Span, P<Expr>, bool)> { + fn recover_await_macro(&mut self) -> PResult<'a, (Span, Box<Expr>, bool)> { self.expect(exp!(Bang))?; self.expect(exp!(OpenParen))?; let expr = self.parse_expr()?; @@ -1990,7 +1989,7 @@ impl<'a> Parser<'a> { Ok((self.prev_token.span, expr, false)) } - fn recover_await_prefix(&mut self, await_sp: Span) -> PResult<'a, (Span, P<Expr>, bool)> { + fn recover_await_prefix(&mut self, await_sp: Span) -> PResult<'a, (Span, Box<Expr>, bool)> { let is_question = self.eat(exp!(Question)); // Handle `await? <expr>`. let expr = if self.token == token::OpenBrace { // Handle `await { <expr> }`. @@ -2052,7 +2051,7 @@ impl<'a> Parser<'a> { } } - pub(super) fn try_macro_suggestion(&mut self) -> PResult<'a, P<Expr>> { + pub(super) fn try_macro_suggestion(&mut self) -> PResult<'a, Box<Expr>> { let is_try = self.token.is_keyword(kw::Try); let is_questionmark = self.look_ahead(1, |t| t == &token::Bang); //check for ! let is_open = self.look_ahead(2, |t| t == &token::OpenParen); //check for ( @@ -2124,7 +2123,7 @@ impl<'a> Parser<'a> { close: ExpTokenPair<'_>, lo: Span, err: Diag<'a>, - ) -> P<Expr> { + ) -> Box<Expr> { let guar = err.emit(); // Recover from parse error, callers expect the closing delim to be consumed. self.consume_block(open, close, ConsumeClosingDelim::Yes); @@ -2244,7 +2243,7 @@ impl<'a> Parser<'a> { pub(super) fn parameter_without_type( &mut self, err: &mut Diag<'_>, - pat: P<ast::Pat>, + pat: Box<ast::Pat>, require_name: bool, first_param: bool, ) -> Option<Ident> { @@ -2346,7 +2345,7 @@ impl<'a> Parser<'a> { None } - pub(super) fn recover_arg_parse(&mut self) -> PResult<'a, (P<ast::Pat>, P<ast::Ty>)> { + pub(super) fn recover_arg_parse(&mut self) -> PResult<'a, (Box<ast::Pat>, Box<ast::Ty>)> { let pat = self.parse_pat_no_top_alt(Some(Expected::ArgumentName), None)?; self.expect(exp!(Colon))?; let ty = self.parse_ty()?; @@ -2354,8 +2353,12 @@ impl<'a> Parser<'a> { self.dcx().emit_err(PatternMethodParamWithoutBody { span: pat.span }); // Pretend the pattern is `_`, to avoid duplicate errors from AST validation. - let pat = - P(Pat { kind: PatKind::Wild, span: pat.span, id: ast::DUMMY_NODE_ID, tokens: None }); + let pat = Box::new(Pat { + kind: PatKind::Wild, + span: pat.span, + id: ast::DUMMY_NODE_ID, + tokens: None, + }); Ok((pat, ty)) } @@ -2506,7 +2509,7 @@ impl<'a> Parser<'a> { /// - Single-segment paths (i.e. standalone generic const parameters). /// All other expressions that can be parsed will emit an error suggesting the expression be /// wrapped in braces. - pub(super) fn handle_unambiguous_unbraced_const_arg(&mut self) -> PResult<'a, P<Expr>> { + pub(super) fn handle_unambiguous_unbraced_const_arg(&mut self) -> PResult<'a, Box<Expr>> { let start = self.token.span; let attrs = self.parse_outer_attributes()?; let (expr, _) = @@ -2688,7 +2691,7 @@ impl<'a> Parser<'a> { pub(crate) fn recover_unbraced_const_arg_that_can_begin_ty( &mut self, mut snapshot: SnapshotParser<'a>, - ) -> Option<P<ast::Expr>> { + ) -> Option<Box<ast::Expr>> { match (|| { let attrs = self.parse_outer_attributes()?; snapshot.parse_expr_res(Restrictions::CONST_EXPR, attrs) @@ -2724,9 +2727,9 @@ impl<'a> Parser<'a> { /// `for` loop, `let`, &c. (in contrast to subpatterns within such). pub(crate) fn maybe_recover_colon_colon_in_pat_typo( &mut self, - mut first_pat: P<Pat>, + mut first_pat: Box<Pat>, expected: Option<Expected>, - ) -> P<Pat> { + ) -> Box<Pat> { if token::Colon != self.token.kind { return first_pat; } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 3d89530f914..d0604f76317 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -6,7 +6,6 @@ use core::ops::{Bound, ControlFlow}; use ast::mut_visit::{self, MutVisitor}; use ast::token::IdentIsRaw; use ast::{CoroutineKind, ForLoopKind, GenBlockKind, MatchKind, Pat, Path, PathSegment, Recovered}; -use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, InvisibleOrigin, MetaVarKind, Token, TokenKind}; use rustc_ast::tokenstream::TokenTree; use rustc_ast::util::case::Case; @@ -56,7 +55,7 @@ pub(super) enum DestructuredFloat { impl<'a> Parser<'a> { /// Parses an expression. #[inline] - pub fn parse_expr(&mut self) -> PResult<'a, P<Expr>> { + pub fn parse_expr(&mut self) -> PResult<'a, Box<Expr>> { self.current_closure.take(); let attrs = self.parse_outer_attributes()?; @@ -64,7 +63,7 @@ impl<'a> Parser<'a> { } /// Parses an expression, forcing tokens to be collected. - pub fn parse_expr_force_collect(&mut self) -> PResult<'a, P<Expr>> { + pub fn parse_expr_force_collect(&mut self) -> PResult<'a, Box<Expr>> { self.current_closure.take(); // If the expression is associative (e.g. `1 + 2`), then any preceding @@ -90,7 +89,10 @@ impl<'a> Parser<'a> { self.parse_expr().map(|value| AnonConst { id: DUMMY_NODE_ID, value }) } - fn parse_expr_catch_underscore(&mut self, restrictions: Restrictions) -> PResult<'a, P<Expr>> { + fn parse_expr_catch_underscore( + &mut self, + restrictions: Restrictions, + ) -> PResult<'a, Box<Expr>> { let attrs = self.parse_outer_attributes()?; match self.parse_expr_res(restrictions, attrs) { Ok((expr, _)) => Ok(expr), @@ -109,7 +111,7 @@ impl<'a> Parser<'a> { } /// Parses a sequence of expressions delimited by parentheses. - fn parse_expr_paren_seq(&mut self) -> PResult<'a, ThinVec<P<Expr>>> { + fn parse_expr_paren_seq(&mut self) -> PResult<'a, ThinVec<Box<Expr>>> { self.parse_paren_comma_seq(|p| p.parse_expr_catch_underscore(Restrictions::empty())) .map(|(r, _)| r) } @@ -120,7 +122,7 @@ impl<'a> Parser<'a> { &mut self, r: Restrictions, attrs: AttrWrapper, - ) -> PResult<'a, (P<Expr>, bool)> { + ) -> PResult<'a, (Box<Expr>, bool)> { self.with_res(r, |this| this.parse_expr_assoc_with(Bound::Unbounded, attrs)) } @@ -131,7 +133,7 @@ impl<'a> Parser<'a> { &mut self, min_prec: Bound<ExprPrecedence>, attrs: AttrWrapper, - ) -> PResult<'a, (P<Expr>, bool)> { + ) -> PResult<'a, (Box<Expr>, bool)> { let lhs = if self.token.is_range_separator() { return self.parse_expr_prefix_range(attrs).map(|res| (res, false)); } else { @@ -147,8 +149,8 @@ impl<'a> Parser<'a> { &mut self, min_prec: Bound<ExprPrecedence>, starts_stmt: bool, - mut lhs: P<Expr>, - ) -> PResult<'a, (P<Expr>, bool)> { + mut lhs: Box<Expr>, + ) -> PResult<'a, (Box<Expr>, bool)> { let mut parsed_something = false; if !self.should_continue_as_assoc_expr(&lhs) { return Ok((lhs, parsed_something)); @@ -263,10 +265,11 @@ impl<'a> Parser<'a> { continue; } + let op_span = op.span; let op = op.node; // Special cases: if op == AssocOp::Cast { - lhs = self.parse_assoc_op_cast(lhs, lhs_span, ExprKind::Cast)?; + lhs = self.parse_assoc_op_cast(lhs, lhs_span, op_span, ExprKind::Cast)?; continue; } else if let AssocOp::Range(limits) = op { // If we didn't have to handle `x..`/`x..=`, it would be pretty easy to @@ -284,7 +287,7 @@ impl<'a> Parser<'a> { this.parse_expr_assoc_with(min_prec, attrs) })?; - let span = self.mk_expr_sp(&lhs, lhs_span, rhs.span); + let span = self.mk_expr_sp(&lhs, lhs_span, op_span, rhs.span); lhs = match op { AssocOp::Binary(ast_op) => { let binary = self.mk_binary(source_map::respan(cur_op_span, ast_op), lhs, rhs); @@ -413,10 +416,10 @@ impl<'a> Parser<'a> { fn parse_expr_range( &mut self, prec: ExprPrecedence, - lhs: P<Expr>, + lhs: Box<Expr>, limits: RangeLimits, cur_op_span: Span, - ) -> PResult<'a, P<Expr>> { + ) -> PResult<'a, Box<Expr>> { let rhs = if self.is_at_start_of_range_notation_rhs() { let maybe_lt = self.token; let attrs = self.parse_outer_attributes()?; @@ -429,7 +432,7 @@ impl<'a> Parser<'a> { None }; let rhs_span = rhs.as_ref().map_or(cur_op_span, |x| x.span); - let span = self.mk_expr_sp(&lhs, lhs.span, rhs_span); + let span = self.mk_expr_sp(&lhs, lhs.span, cur_op_span, rhs_span); let range = self.mk_range(Some(lhs), rhs, limits); Ok(self.mk_expr(span, range)) } @@ -447,7 +450,7 @@ impl<'a> Parser<'a> { } /// Parses prefix-forms of range notation: `..expr`, `..`, `..=expr`. - fn parse_expr_prefix_range(&mut self, attrs: AttrWrapper) -> PResult<'a, P<Expr>> { + fn parse_expr_prefix_range(&mut self, attrs: AttrWrapper) -> PResult<'a, Box<Expr>> { if !attrs.is_empty() { let err = errors::DotDotRangeAttribute { span: self.token.span }; self.dcx().emit_err(err); @@ -489,7 +492,7 @@ impl<'a> Parser<'a> { } /// Parses a prefix-unary-operator expr. - fn parse_expr_prefix(&mut self, attrs: AttrWrapper) -> PResult<'a, P<Expr>> { + fn parse_expr_prefix(&mut self, attrs: AttrWrapper) -> PResult<'a, Box<Expr>> { let lo = self.token.span; macro_rules! make_it { @@ -563,7 +566,7 @@ impl<'a> Parser<'a> { } } - fn parse_expr_prefix_common(&mut self, lo: Span) -> PResult<'a, (Span, P<Expr>)> { + fn parse_expr_prefix_common(&mut self, lo: Span) -> PResult<'a, (Span, Box<Expr>)> { self.bump(); let attrs = self.parse_outer_attributes()?; let expr = if self.token.is_range_separator() { @@ -652,12 +655,13 @@ impl<'a> Parser<'a> { fn parse_assoc_op_cast( &mut self, - lhs: P<Expr>, + lhs: Box<Expr>, lhs_span: Span, - expr_kind: fn(P<Expr>, P<Ty>) -> ExprKind, - ) -> PResult<'a, P<Expr>> { - let mk_expr = |this: &mut Self, lhs: P<Expr>, rhs: P<Ty>| { - this.mk_expr(this.mk_expr_sp(&lhs, lhs_span, rhs.span), expr_kind(lhs, rhs)) + op_span: Span, + expr_kind: fn(Box<Expr>, Box<Ty>) -> ExprKind, + ) -> PResult<'a, Box<Expr>> { + let mk_expr = |this: &mut Self, lhs: Box<Expr>, rhs: Box<Ty>| { + this.mk_expr(this.mk_expr_sp(&lhs, lhs_span, op_span, rhs.span), expr_kind(lhs, rhs)) }; // Save the state of the parser before parsing type normally, in case there is a @@ -785,9 +789,13 @@ impl<'a> Parser<'a> { ExprKind::Call(_, _) => "a function call", ExprKind::Await(_, _) => "`.await`", ExprKind::Use(_, _) => "`.use`", + ExprKind::Yield(YieldKind::Postfix(_)) => "`.yield`", ExprKind::Match(_, _, MatchKind::Postfix) => "a postfix match", ExprKind::Err(_) => return Ok(with_postfix), - _ => unreachable!("parse_dot_or_call_expr_with_ shouldn't produce this"), + _ => unreachable!( + "did not expect {:?} as an illegal postfix operator following cast", + with_postfix.kind + ), } ); let mut err = self.dcx().struct_span_err(span, msg); @@ -867,7 +875,7 @@ impl<'a> Parser<'a> { } /// Parses `a.b` or `a(13)` or `a[4]` or just `a`. - fn parse_expr_dot_or_call(&mut self, attrs: AttrWrapper) -> PResult<'a, P<Expr>> { + fn parse_expr_dot_or_call(&mut self, attrs: AttrWrapper) -> PResult<'a, Box<Expr>> { self.collect_tokens_for_expr(attrs, |this, attrs| { let base = this.parse_expr_bottom()?; let span = this.interpolated_or_expr_span(&base); @@ -878,9 +886,9 @@ impl<'a> Parser<'a> { pub(super) fn parse_expr_dot_or_call_with( &mut self, mut attrs: ast::AttrVec, - mut e: P<Expr>, + mut e: Box<Expr>, lo: Span, - ) -> PResult<'a, P<Expr>> { + ) -> PResult<'a, Box<Expr>> { let mut res = ensure_sufficient_stack(|| { loop { let has_question = @@ -939,8 +947,8 @@ impl<'a> Parser<'a> { pub(super) fn parse_dot_suffix_expr( &mut self, lo: Span, - base: P<Expr>, - ) -> PResult<'a, P<Expr>> { + base: Box<Expr>, + ) -> PResult<'a, Box<Expr>> { // At this point we've consumed something like `expr.` and `self.token` holds the token // after the dot. match self.token.uninterpolate().kind { @@ -1226,10 +1234,10 @@ impl<'a> Parser<'a> { &self, lo: Span, ident_span: Span, - base: P<Expr>, + base: Box<Expr>, field: Symbol, suffix: Option<Symbol>, - ) -> P<Expr> { + ) -> Box<Expr> { if let Some(suffix) = suffix { self.expect_no_tuple_index_suffix(ident_span, suffix); } @@ -1237,7 +1245,7 @@ impl<'a> Parser<'a> { } /// Parse a function call expression, `expr(...)`. - fn parse_expr_fn_call(&mut self, lo: Span, fun: P<Expr>) -> P<Expr> { + fn parse_expr_fn_call(&mut self, lo: Span, fun: Box<Expr>) -> Box<Expr> { let snapshot = if self.token == token::OpenParen { Some((self.create_snapshot_for_diagnostic(), fun.kind.clone())) } else { @@ -1261,9 +1269,9 @@ impl<'a> Parser<'a> { &mut self, lo: Span, open_paren: Span, - seq: PResult<'a, P<Expr>>, + seq: PResult<'a, Box<Expr>>, snapshot: Option<(SnapshotParser<'a>, ExprKind)>, - ) -> PResult<'a, P<Expr>> { + ) -> PResult<'a, Box<Expr>> { match (self.may_recover(), seq, snapshot) { (true, Err(err), Some((mut snapshot, ExprKind::Path(None, path)))) => { snapshot.bump(); // `(` @@ -1319,7 +1327,7 @@ impl<'a> Parser<'a> { } /// Parse an indexing expression `expr[...]`. - fn parse_expr_index(&mut self, lo: Span, base: P<Expr>) -> PResult<'a, P<Expr>> { + fn parse_expr_index(&mut self, lo: Span, base: Box<Expr>) -> PResult<'a, Box<Expr>> { let prev_span = self.prev_token.span; let open_delim_span = self.token.span; self.bump(); // `[` @@ -1333,7 +1341,7 @@ impl<'a> Parser<'a> { } /// Assuming we have just parsed `.`, continue parsing into an expression. - fn parse_dot_suffix(&mut self, self_arg: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> { + fn parse_dot_suffix(&mut self, self_arg: Box<Expr>, lo: Span) -> PResult<'a, Box<Expr>> { if self.token_uninterpolated_span().at_least_rust_2018() && self.eat_keyword(exp!(Await)) { return Ok(self.mk_await_expr(self_arg, lo)); } @@ -1398,7 +1406,7 @@ impl<'a> Parser<'a> { /// /// N.B., this does not parse outer attributes, and is private because it only works /// correctly if called from `parse_expr_dot_or_call`. - fn parse_expr_bottom(&mut self) -> PResult<'a, P<Expr>> { + fn parse_expr_bottom(&mut self) -> PResult<'a, Box<Expr>> { maybe_recover_from_interpolated_ty_qpath!(self, true); let span = self.token.span; @@ -1550,7 +1558,7 @@ impl<'a> Parser<'a> { }) } - fn parse_expr_lit(&mut self) -> PResult<'a, P<Expr>> { + fn parse_expr_lit(&mut self) -> PResult<'a, Box<Expr>> { let lo = self.token.span; match self.parse_opt_token_lit() { Some((token_lit, _)) => { @@ -1561,7 +1569,7 @@ impl<'a> Parser<'a> { } } - fn parse_expr_tuple_parens(&mut self, restrictions: Restrictions) -> PResult<'a, P<Expr>> { + fn parse_expr_tuple_parens(&mut self, restrictions: Restrictions) -> PResult<'a, Box<Expr>> { let lo = self.token.span; self.expect(exp!(OpenParen))?; let (es, trailing_comma) = match self.parse_seq_to_end( @@ -1590,7 +1598,7 @@ impl<'a> Parser<'a> { self.maybe_recover_from_bad_qpath(expr) } - fn parse_expr_array_or_repeat(&mut self, close: ExpTokenPair<'_>) -> PResult<'a, P<Expr>> { + fn parse_expr_array_or_repeat(&mut self, close: ExpTokenPair<'_>) -> PResult<'a, Box<Expr>> { let lo = self.token.span; self.bump(); // `[` or other open delim @@ -1621,7 +1629,7 @@ impl<'a> Parser<'a> { self.maybe_recover_from_bad_qpath(expr) } - fn parse_expr_path_start(&mut self) -> PResult<'a, P<Expr>> { + fn parse_expr_path_start(&mut self) -> PResult<'a, Box<Expr>> { let maybe_eq_tok = self.prev_token; let (qself, path) = if self.eat_lt() { let lt_span = self.prev_token.span; @@ -1647,7 +1655,7 @@ impl<'a> Parser<'a> { self.dcx().emit_err(errors::MacroInvocationWithQualifiedPath(path.span)); } let lo = path.span; - let mac = P(MacCall { path, args: self.parse_delim_args()? }); + let mac = Box::new(MacCall { path, args: self.parse_delim_args()? }); (lo.to(self.prev_token.span), ExprKind::MacCall(mac)) } else if self.check(exp!(OpenBrace)) && let Some(expr) = self.maybe_parse_struct_expr(&qself, &path) @@ -1669,7 +1677,7 @@ impl<'a> Parser<'a> { &mut self, label_: Label, mut consume_colon: bool, - ) -> PResult<'a, P<Expr>> { + ) -> PResult<'a, Box<Expr>> { let lo = label_.ident.span; let label = Some(label_); let ate_colon = self.eat(exp!(Colon)); @@ -1804,7 +1812,7 @@ impl<'a> Parser<'a> { } /// Recover on the syntax `do catch { ... }` suggesting `try { ... }` instead. - fn recover_do_catch(&mut self) -> PResult<'a, P<Expr>> { + fn recover_do_catch(&mut self) -> PResult<'a, Box<Expr>> { let lo = self.token.span; self.bump(); // `do` @@ -1817,12 +1825,12 @@ impl<'a> Parser<'a> { } /// Parse an expression if the token can begin one. - fn parse_expr_opt(&mut self) -> PResult<'a, Option<P<Expr>>> { + fn parse_expr_opt(&mut self) -> PResult<'a, Option<Box<Expr>>> { Ok(if self.token.can_begin_expr() { Some(self.parse_expr()?) } else { None }) } /// Parse `"return" expr?`. - fn parse_expr_return(&mut self) -> PResult<'a, P<Expr>> { + fn parse_expr_return(&mut self) -> PResult<'a, Box<Expr>> { let lo = self.prev_token.span; let kind = ExprKind::Ret(self.parse_expr_opt()?); let expr = self.mk_expr(lo.to(self.prev_token.span), kind); @@ -1830,7 +1838,7 @@ impl<'a> Parser<'a> { } /// Parse `"do" "yeet" expr?`. - fn parse_expr_yeet(&mut self) -> PResult<'a, P<Expr>> { + fn parse_expr_yeet(&mut self) -> PResult<'a, Box<Expr>> { let lo = self.token.span; self.bump(); // `do` @@ -1845,7 +1853,7 @@ impl<'a> Parser<'a> { } /// Parse `"become" expr`, with `"become"` token already eaten. - fn parse_expr_become(&mut self) -> PResult<'a, P<Expr>> { + fn parse_expr_become(&mut self) -> PResult<'a, Box<Expr>> { let lo = self.prev_token.span; let kind = ExprKind::Become(self.parse_expr()?); let span = lo.to(self.prev_token.span); @@ -1862,7 +1870,7 @@ impl<'a> Parser<'a> { /// `break 'lbl: loop {}`); a labeled break with an unlabeled loop as its value /// expression only gets a warning for compatibility reasons; and a labeled break /// with a labeled loop does not even get a warning because there is no ambiguity. - fn parse_expr_break(&mut self) -> PResult<'a, P<Expr>> { + fn parse_expr_break(&mut self) -> PResult<'a, Box<Expr>> { let lo = self.prev_token.span; let mut label = self.eat_label(); let kind = if self.token == token::Colon @@ -1924,7 +1932,7 @@ impl<'a> Parser<'a> { } /// Parse `"continue" label?`. - fn parse_expr_continue(&mut self, lo: Span) -> PResult<'a, P<Expr>> { + fn parse_expr_continue(&mut self, lo: Span) -> PResult<'a, Box<Expr>> { let mut label = self.eat_label(); // Recover `continue label` -> `continue 'label` @@ -1941,7 +1949,7 @@ impl<'a> Parser<'a> { } /// Parse `"yield" expr?`. - fn parse_expr_yield(&mut self) -> PResult<'a, P<Expr>> { + fn parse_expr_yield(&mut self) -> PResult<'a, Box<Expr>> { let lo = self.prev_token.span; let kind = ExprKind::Yield(YieldKind::Prefix(self.parse_expr_opt()?)); let span = lo.to(self.prev_token.span); @@ -1951,7 +1959,7 @@ impl<'a> Parser<'a> { } /// Parse `builtin # ident(args,*)`. - fn parse_expr_builtin(&mut self) -> PResult<'a, P<Expr>> { + fn parse_expr_builtin(&mut self) -> PResult<'a, Box<Expr>> { self.parse_builtin(|this, lo, ident| { Ok(match ident.name { sym::offset_of => Some(this.parse_expr_offset_of(lo)?), @@ -1999,7 +2007,7 @@ impl<'a> Parser<'a> { } /// Built-in macro for `offset_of!` expressions. - pub(crate) fn parse_expr_offset_of(&mut self, lo: Span) -> PResult<'a, P<Expr>> { + pub(crate) fn parse_expr_offset_of(&mut self, lo: Span) -> PResult<'a, Box<Expr>> { let container = self.parse_ty()?; self.expect(exp!(Comma))?; @@ -2027,7 +2035,7 @@ impl<'a> Parser<'a> { } /// Built-in macro for type ascription expressions. - pub(crate) fn parse_expr_type_ascribe(&mut self, lo: Span) -> PResult<'a, P<Expr>> { + pub(crate) fn parse_expr_type_ascribe(&mut self, lo: Span) -> PResult<'a, Box<Expr>> { let expr = self.parse_expr()?; self.expect(exp!(Comma))?; let ty = self.parse_ty()?; @@ -2039,7 +2047,7 @@ impl<'a> Parser<'a> { &mut self, lo: Span, kind: UnsafeBinderCastKind, - ) -> PResult<'a, P<Expr>> { + ) -> PResult<'a, Box<Expr>> { let expr = self.parse_expr()?; let ty = if self.eat(exp!(Comma)) { Some(self.parse_ty()?) } else { None }; let span = lo.to(self.token.span); @@ -2149,7 +2157,7 @@ impl<'a> Parser<'a> { /// Keep this in sync with `Token::can_begin_literal_maybe_minus` and /// `Lit::from_token` (excluding unary negation). fn eat_token_lit(&mut self) -> Option<token::Lit> { - let check_expr = |expr: P<Expr>| { + let check_expr = |expr: Box<Expr>| { if let ast::ExprKind::Lit(token_lit) = expr.kind { Some(token_lit) } else if let ast::ExprKind::Unary(UnOp::Neg, inner) = &expr.kind @@ -2237,7 +2245,7 @@ impl<'a> Parser<'a> { /// Matches `'-' lit | lit` (cf. `ast_validation::AstValidator::check_expr_within_pat`). /// Keep this in sync with `Token::can_begin_literal_maybe_minus`. - pub fn parse_literal_maybe_minus(&mut self) -> PResult<'a, P<Expr>> { + pub fn parse_literal_maybe_minus(&mut self) -> PResult<'a, Box<Expr>> { if let Some(expr) = self.eat_metavar_seq_with_matcher( |mv_kind| matches!(mv_kind, MetaVarKind::Expr { .. }), |this| { @@ -2284,7 +2292,7 @@ impl<'a> Parser<'a> { /// Emits a suggestion if it looks like the user meant an array but /// accidentally used braces, causing the code to be interpreted as a block /// expression. - fn maybe_suggest_brackets_instead_of_braces(&mut self, lo: Span) -> Option<P<Expr>> { + fn maybe_suggest_brackets_instead_of_braces(&mut self, lo: Span) -> Option<Box<Expr>> { let mut snapshot = self.create_snapshot_for_diagnostic(); match snapshot.parse_expr_array_or_repeat(exp!(CloseBrace)) { Ok(arr) => { @@ -2354,7 +2362,7 @@ impl<'a> Parser<'a> { opt_label: Option<Label>, lo: Span, blk_mode: BlockCheckMode, - ) -> PResult<'a, P<Expr>> { + ) -> PResult<'a, Box<Expr>> { if self.may_recover() && self.is_array_like_block() { if let Some(arr) = self.maybe_suggest_brackets_instead_of_braces(lo) { return Ok(arr); @@ -2377,13 +2385,13 @@ impl<'a> Parser<'a> { } /// Parse a block which takes no attributes and has no label - fn parse_simple_block(&mut self) -> PResult<'a, P<Expr>> { + fn parse_simple_block(&mut self) -> PResult<'a, Box<Expr>> { let blk = self.parse_block()?; Ok(self.mk_expr(blk.span, ExprKind::Block(blk, None))) } /// Parses a closure expression (e.g., `move |args| expr`). - fn parse_expr_closure(&mut self) -> PResult<'a, P<Expr>> { + fn parse_expr_closure(&mut self) -> PResult<'a, Box<Expr>> { let lo = self.token.span; let before = self.prev_token; @@ -2488,7 +2496,7 @@ impl<'a> Parser<'a> { } /// If an explicit return type is given, require a block to appear (RFC 968). - fn parse_closure_block_body(&mut self, ret_span: Span) -> PResult<'a, P<Expr>> { + fn parse_closure_block_body(&mut self, ret_span: Span) -> PResult<'a, Box<Expr>> { if self.may_recover() && self.token.can_begin_expr() && self.token.kind != TokenKind::OpenBrace @@ -2559,7 +2567,7 @@ impl<'a> Parser<'a> { } /// Parses the `|arg, arg|` header of a closure. - fn parse_fn_block_decl(&mut self) -> PResult<'a, (P<FnDecl>, Span)> { + fn parse_fn_block_decl(&mut self) -> PResult<'a, (Box<FnDecl>, Span)> { let arg_start = self.token.span.lo(); let inputs = if self.eat(exp!(OrOr)) { @@ -2581,7 +2589,7 @@ impl<'a> Parser<'a> { let output = self.parse_ret_ty(AllowPlus::Yes, RecoverQPath::Yes, RecoverReturnSign::Yes)?; - Ok((P(FnDecl { inputs, output }), arg_span)) + Ok((Box::new(FnDecl { inputs, output }), arg_span)) } /// Parses a parameter in a closure header (e.g., `|arg, arg|`). @@ -2612,7 +2620,7 @@ impl<'a> Parser<'a> { } /// Parses an `if` expression (`if` token already eaten). - fn parse_expr_if(&mut self) -> PResult<'a, P<Expr>> { + fn parse_expr_if(&mut self) -> PResult<'a, Box<Expr>> { let lo = self.prev_token.span; // Scoping code checks the top level edition of the `if`; let's match it here. // The `CondChecker` also checks the edition of the `let` itself, just to make sure. @@ -2621,7 +2629,7 @@ impl<'a> Parser<'a> { self.parse_if_after_cond(lo, cond) } - fn parse_if_after_cond(&mut self, lo: Span, mut cond: P<Expr>) -> PResult<'a, P<Expr>> { + fn parse_if_after_cond(&mut self, lo: Span, mut cond: Box<Expr>) -> PResult<'a, Box<Expr>> { let cond_span = cond.span; // Tries to interpret `cond` as either a missing expression if it's a block, // or as an unfinished expression if it's a binop and the RHS is a block. @@ -2731,7 +2739,10 @@ impl<'a> Parser<'a> { /// i.e. the same span we use to later decide whether the drop behaviour should be that of /// edition `..=2021` or that of `2024..`. // Public because it is used in rustfmt forks such as https://github.com/tucant/rustfmt/blob/30c83df9e1db10007bdd16dafce8a86b404329b2/src/parse/macros/html.rs#L57 for custom if expressions. - pub fn parse_expr_cond(&mut self, let_chains_policy: LetChainsPolicy) -> PResult<'a, P<Expr>> { + pub fn parse_expr_cond( + &mut self, + let_chains_policy: LetChainsPolicy, + ) -> PResult<'a, Box<Expr>> { let attrs = self.parse_outer_attributes()?; let (mut cond, _) = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET, attrs)?; @@ -2742,7 +2753,7 @@ impl<'a> Parser<'a> { } /// Parses a `let $pat = $expr` pseudo-expression. - fn parse_expr_let(&mut self, restrictions: Restrictions) -> PResult<'a, P<Expr>> { + fn parse_expr_let(&mut self, restrictions: Restrictions) -> PResult<'a, Box<Expr>> { let recovered = if !restrictions.contains(Restrictions::ALLOW_LET) { let err = errors::ExpectedExpressionFoundLet { span: self.token.span, @@ -2784,7 +2795,7 @@ impl<'a> Parser<'a> { } /// Parses an `else { ... }` expression (`else` token already eaten). - fn parse_expr_else(&mut self) -> PResult<'a, P<Expr>> { + fn parse_expr_else(&mut self) -> PResult<'a, Box<Expr>> { let else_span = self.prev_token.span; // `else` let attrs = self.parse_outer_attributes()?; // For recovery. let expr = if self.eat_keyword(exp!(If)) { @@ -2882,7 +2893,7 @@ impl<'a> Parser<'a> { } } - fn error_on_extra_if(&mut self, cond: &P<Expr>) -> PResult<'a, ()> { + fn error_on_extra_if(&mut self, cond: &Box<Expr>) -> PResult<'a, ()> { if let ExprKind::Binary(Spanned { span: binop_span, node: binop }, _, right) = &cond.kind && let BinOpKind::And = binop && let ExprKind::If(cond, ..) = &right.kind @@ -2895,7 +2906,7 @@ impl<'a> Parser<'a> { } } - fn parse_for_head(&mut self) -> PResult<'a, (P<Pat>, P<Expr>)> { + fn parse_for_head(&mut self) -> PResult<'a, (Box<Pat>, Box<Expr>)> { let begin_paren = if self.token == token::OpenParen { // Record whether we are about to parse `for (`. // This is used below for recovery in case of `for ( $stuff ) $block` @@ -2961,7 +2972,7 @@ impl<'a> Parser<'a> { } /// Parses `for await? <src_pat> in <src_expr> <src_loop_block>` (`for` token already eaten). - fn parse_expr_for(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, P<Expr>> { + fn parse_expr_for(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, Box<Expr>> { let is_await = self.token_uninterpolated_span().at_least_rust_2018() && self.eat_keyword(exp!(Await)); @@ -3022,6 +3033,8 @@ impl<'a> Parser<'a> { let span = self.token.span; self.bump(); (span, errors::MissingInInForLoopSub::InNotOf) + } else if self.eat(exp!(Eq)) { + (self.prev_token.span, errors::MissingInInForLoopSub::InNotEq) } else { (self.prev_token.span.between(self.token.span), errors::MissingInInForLoopSub::AddIn) }; @@ -3030,7 +3043,7 @@ impl<'a> Parser<'a> { } /// Parses a `while` or `while let` expression (`while` token already eaten). - fn parse_expr_while(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, P<Expr>> { + fn parse_expr_while(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, Box<Expr>> { let policy = LetChainsPolicy::EditionDependent { current_edition: lo.edition() }; let cond = self.parse_expr_cond(policy).map_err(|mut err| { err.span_label(lo, "while parsing the condition of this `while` expression"); @@ -3058,7 +3071,7 @@ impl<'a> Parser<'a> { } /// Parses `loop { ... }` (`loop` token already eaten). - fn parse_expr_loop(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, P<Expr>> { + fn parse_expr_loop(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, Box<Expr>> { let loop_span = self.prev_token.span; let (attrs, body) = self.parse_inner_attrs_and_block( // Only suggest moving erroneous block label to the loop header @@ -3088,7 +3101,7 @@ impl<'a> Parser<'a> { } /// Parses a `match ... { ... }` expression (`match` token already eaten). - fn parse_expr_match(&mut self) -> PResult<'a, P<Expr>> { + fn parse_expr_match(&mut self) -> PResult<'a, Box<Expr>> { let match_span = self.prev_token.span; let attrs = self.parse_outer_attributes()?; let (scrutinee, _) = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, attrs)?; @@ -3102,9 +3115,9 @@ impl<'a> Parser<'a> { &mut self, lo: Span, match_span: Span, - scrutinee: P<Expr>, + scrutinee: Box<Expr>, match_kind: MatchKind, - ) -> PResult<'a, P<Expr>> { + ) -> PResult<'a, Box<Expr>> { if let Err(mut e) = self.expect(exp!(OpenBrace)) { if self.token == token::Semi { e.span_suggestion_short( @@ -3161,7 +3174,7 @@ impl<'a> Parser<'a> { /// Attempt to recover from match arm body with statements and no surrounding braces. fn parse_arm_body_missing_braces( &mut self, - first_expr: &P<Expr>, + first_expr: &Box<Expr>, arrow_span: Span, ) -> Option<(Span, ErrorGuaranteed)> { if self.token != token::Semi { @@ -3433,7 +3446,7 @@ impl<'a> Parser<'a> { }) } - fn parse_match_arm_guard(&mut self) -> PResult<'a, Option<P<Expr>>> { + fn parse_match_arm_guard(&mut self) -> PResult<'a, Option<Box<Expr>>> { // Used to check the `if_let_guard` feature mostly by scanning // `&&` tokens. fn has_let_expr(expr: &Expr) -> bool { @@ -3464,7 +3477,7 @@ impl<'a> Parser<'a> { Ok(Some(cond)) } - fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (P<Pat>, Option<P<Expr>>)> { + fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (Box<Pat>, Option<Box<Expr>>)> { if self.token == token::OpenParen { let left = self.token.span; let pat = self.parse_pat_no_top_guard( @@ -3504,7 +3517,7 @@ impl<'a> Parser<'a> { } } - fn parse_match_guard_condition(&mut self) -> PResult<'a, P<Expr>> { + fn parse_match_guard_condition(&mut self) -> PResult<'a, Box<Expr>> { let attrs = self.parse_outer_attributes()?; match self.parse_expr_res(Restrictions::ALLOW_LET | Restrictions::IN_IF_GUARD, attrs) { Ok((expr, _)) => Ok(expr), @@ -3538,7 +3551,7 @@ impl<'a> Parser<'a> { } /// Parses a `try {...}` expression (`try` token already eaten). - fn parse_try_block(&mut self, span_lo: Span) -> PResult<'a, P<Expr>> { + fn parse_try_block(&mut self, span_lo: Span) -> PResult<'a, Box<Expr>> { let (attrs, body) = self.parse_inner_attrs_and_block(None)?; if self.eat_keyword(exp!(Catch)) { Err(self.dcx().create_err(errors::CatchAfterTry { span: self.prev_token.span })) @@ -3567,7 +3580,7 @@ impl<'a> Parser<'a> { } /// Parses an `async move? {...}` or `gen move? {...}` expression. - fn parse_gen_block(&mut self) -> PResult<'a, P<Expr>> { + fn parse_gen_block(&mut self) -> PResult<'a, Box<Expr>> { let lo = self.token.span; let kind = if self.eat_keyword(exp!(Async)) { if self.eat_keyword(exp!(Gen)) { GenBlockKind::AsyncGen } else { GenBlockKind::Async } @@ -3616,9 +3629,9 @@ impl<'a> Parser<'a> { fn maybe_parse_struct_expr( &mut self, - qself: &Option<P<ast::QSelf>>, + qself: &Option<Box<ast::QSelf>>, path: &ast::Path, - ) -> Option<PResult<'a, P<Expr>>> { + ) -> Option<PResult<'a, Box<Expr>>> { let struct_allowed = !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL); if struct_allowed || self.is_certainly_not_a_block() { if let Err(err) = self.expect(exp!(OpenBrace)) { @@ -3812,10 +3825,10 @@ impl<'a> Parser<'a> { /// Precondition: already parsed the '{'. pub(super) fn parse_expr_struct( &mut self, - qself: Option<P<ast::QSelf>>, + qself: Option<Box<ast::QSelf>>, pth: ast::Path, recover: bool, - ) -> PResult<'a, P<Expr>> { + ) -> PResult<'a, Box<Expr>> { let lo = pth.span; let (fields, base, recovered_async) = self.parse_struct_fields(pth.clone(), recover, exp!(CloseBrace))?; @@ -3824,7 +3837,7 @@ impl<'a> Parser<'a> { let expr = if let Some(guar) = recovered_async { ExprKind::Err(guar) } else { - ExprKind::Struct(P(ast::StructExpr { qself, path: pth, fields, rest: base })) + ExprKind::Struct(Box::new(ast::StructExpr { qself, path: pth, fields, rest: base })) }; Ok(self.mk_expr(span, expr)) } @@ -3939,14 +3952,14 @@ impl<'a> Parser<'a> { self.dcx().emit_err(errors::LeftArrowOperator { span }); } - fn mk_assign_op(&self, assign_op: AssignOp, lhs: P<Expr>, rhs: P<Expr>) -> ExprKind { + fn mk_assign_op(&self, assign_op: AssignOp, lhs: Box<Expr>, rhs: Box<Expr>) -> ExprKind { ExprKind::AssignOp(assign_op, lhs, rhs) } fn mk_range( &mut self, - start: Option<P<Expr>>, - end: Option<P<Expr>>, + start: Option<Box<Expr>>, + end: Option<Box<Expr>>, limits: RangeLimits, ) -> ExprKind { if end.is_none() && limits == RangeLimits::Closed { @@ -3957,63 +3970,69 @@ impl<'a> Parser<'a> { } } - fn mk_unary(&self, unop: UnOp, expr: P<Expr>) -> ExprKind { + fn mk_unary(&self, unop: UnOp, expr: Box<Expr>) -> ExprKind { ExprKind::Unary(unop, expr) } - fn mk_binary(&self, binop: BinOp, lhs: P<Expr>, rhs: P<Expr>) -> ExprKind { + fn mk_binary(&self, binop: BinOp, lhs: Box<Expr>, rhs: Box<Expr>) -> ExprKind { ExprKind::Binary(binop, lhs, rhs) } - fn mk_index(&self, expr: P<Expr>, idx: P<Expr>, brackets_span: Span) -> ExprKind { + fn mk_index(&self, expr: Box<Expr>, idx: Box<Expr>, brackets_span: Span) -> ExprKind { ExprKind::Index(expr, idx, brackets_span) } - fn mk_call(&self, f: P<Expr>, args: ThinVec<P<Expr>>) -> ExprKind { + fn mk_call(&self, f: Box<Expr>, args: ThinVec<Box<Expr>>) -> ExprKind { ExprKind::Call(f, args) } - fn mk_await_expr(&mut self, self_arg: P<Expr>, lo: Span) -> P<Expr> { + fn mk_await_expr(&mut self, self_arg: Box<Expr>, lo: Span) -> Box<Expr> { let span = lo.to(self.prev_token.span); let await_expr = self.mk_expr(span, ExprKind::Await(self_arg, self.prev_token.span)); self.recover_from_await_method_call(); await_expr } - fn mk_use_expr(&mut self, self_arg: P<Expr>, lo: Span) -> P<Expr> { + fn mk_use_expr(&mut self, self_arg: Box<Expr>, lo: Span) -> Box<Expr> { let span = lo.to(self.prev_token.span); let use_expr = self.mk_expr(span, ExprKind::Use(self_arg, self.prev_token.span)); self.recover_from_use(); use_expr } - pub(crate) fn mk_expr_with_attrs(&self, span: Span, kind: ExprKind, attrs: AttrVec) -> P<Expr> { - P(Expr { kind, span, attrs, id: DUMMY_NODE_ID, tokens: None }) + pub(crate) fn mk_expr_with_attrs( + &self, + span: Span, + kind: ExprKind, + attrs: AttrVec, + ) -> Box<Expr> { + Box::new(Expr { kind, span, attrs, id: DUMMY_NODE_ID, tokens: None }) } - pub(crate) fn mk_expr(&self, span: Span, kind: ExprKind) -> P<Expr> { + pub(crate) fn mk_expr(&self, span: Span, kind: ExprKind) -> Box<Expr> { self.mk_expr_with_attrs(span, kind, AttrVec::new()) } - pub(super) fn mk_expr_err(&self, span: Span, guar: ErrorGuaranteed) -> P<Expr> { + pub(super) fn mk_expr_err(&self, span: Span, guar: ErrorGuaranteed) -> Box<Expr> { self.mk_expr(span, ExprKind::Err(guar)) } /// Create expression span ensuring the span of the parent node /// is larger than the span of lhs and rhs, including the attributes. - fn mk_expr_sp(&self, lhs: &P<Expr>, lhs_span: Span, rhs_span: Span) -> Span { + fn mk_expr_sp(&self, lhs: &Box<Expr>, lhs_span: Span, op_span: Span, rhs_span: Span) -> Span { lhs.attrs .iter() .find(|a| a.style == AttrStyle::Outer) .map_or(lhs_span, |a| a.span) + .to(op_span) .to(rhs_span) } fn collect_tokens_for_expr( &mut self, attrs: AttrWrapper, - f: impl FnOnce(&mut Self, ast::AttrVec) -> PResult<'a, P<Expr>>, - ) -> PResult<'a, P<Expr>> { + f: impl FnOnce(&mut Self, ast::AttrVec) -> PResult<'a, Box<Expr>>, + ) -> PResult<'a, Box<Expr>> { self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| { let res = f(this, attrs)?; let trailing = Trailing::from( diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index 86326341a75..4a8530a2b38 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -308,9 +308,7 @@ impl<'a> Parser<'a> { /// Parses an experimental fn contract /// (`contract_requires(WWW) contract_ensures(ZZZ)`) - pub(super) fn parse_contract( - &mut self, - ) -> PResult<'a, Option<rustc_ast::ptr::P<ast::FnContract>>> { + pub(super) fn parse_contract(&mut self) -> PResult<'a, Option<Box<ast::FnContract>>> { let requires = if self.eat_keyword_noexpect(exp!(ContractRequires).kw) { self.psess.gated_spans.gate(sym::contracts_internals, self.prev_token.span); let precond = self.parse_expr()?; @@ -328,7 +326,7 @@ impl<'a> Parser<'a> { if requires.is_none() && ensures.is_none() { Ok(None) } else { - Ok(Some(rustc_ast::ptr::P(ast::FnContract { requires, ensures }))) + Ok(Some(Box::new(ast::FnContract { requires, ensures }))) } } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 65d84b3e3d9..14a90e74049 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -3,7 +3,6 @@ use std::mem; use ast::token::IdentIsRaw; use rustc_ast::ast::*; -use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, InvisibleOrigin, MetaVarKind, TokenKind}; use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree}; use rustc_ast::util::case::Case; @@ -56,12 +55,12 @@ impl<'a> Parser<'a> { pub fn parse_mod( &mut self, term: ExpTokenPair<'_>, - ) -> PResult<'a, (AttrVec, ThinVec<P<Item>>, ModSpans)> { + ) -> PResult<'a, (AttrVec, ThinVec<Box<Item>>, ModSpans)> { let lo = self.token.span; let attrs = self.parse_inner_attributes()?; let post_attr_lo = self.token.span; - let mut items: ThinVec<P<_>> = ThinVec::new(); + let mut items: ThinVec<Box<_>> = ThinVec::new(); // There shouldn't be any stray semicolons before or after items. // `parse_item` consumes the appropriate semicolons so any leftover is an error. @@ -116,9 +115,9 @@ impl<'a> Parser<'a> { } impl<'a> Parser<'a> { - pub fn parse_item(&mut self, force_collect: ForceCollect) -> PResult<'a, Option<P<Item>>> { + pub fn parse_item(&mut self, force_collect: ForceCollect) -> PResult<'a, Option<Box<Item>>> { let fn_parse_mode = FnParseMode { req_name: |_| true, req_body: true }; - self.parse_item_(fn_parse_mode, force_collect).map(|i| i.map(P)) + self.parse_item_(fn_parse_mode, force_collect).map(|i| i.map(Box::new)) } fn parse_item_( @@ -327,7 +326,7 @@ impl<'a> Parser<'a> { self.recover_missing_kw_before_item()?; } // MACRO INVOCATION ITEM - ItemKind::MacCall(P(self.parse_item_macro(vis)?)) + ItemKind::MacCall(Box::new(self.parse_item_macro(vis)?)) } else { return Ok(None); }; @@ -885,6 +884,9 @@ impl<'a> Parser<'a> { /// Parses `unsafe? auto? trait Foo { ... }` or `trait Foo = Bar;`. fn parse_item_trait(&mut self, attrs: &mut AttrVec, lo: Span) -> PResult<'a, ItemKind> { let constness = self.parse_constness(Case::Sensitive); + if let Const::Yes(span) = constness { + self.psess.gated_spans.gate(sym::const_trait_impl, span); + } let safety = self.parse_safety(Case::Sensitive); // Parse optional `auto` prefix. let is_auto = if self.eat_keyword(exp!(Auto)) { @@ -948,7 +950,7 @@ impl<'a> Parser<'a> { pub fn parse_impl_item( &mut self, force_collect: ForceCollect, - ) -> PResult<'a, Option<Option<P<AssocItem>>>> { + ) -> PResult<'a, Option<Option<Box<AssocItem>>>> { let fn_parse_mode = FnParseMode { req_name: |_| true, req_body: true }; self.parse_assoc_item(fn_parse_mode, force_collect) } @@ -956,7 +958,7 @@ impl<'a> Parser<'a> { pub fn parse_trait_item( &mut self, force_collect: ForceCollect, - ) -> PResult<'a, Option<Option<P<AssocItem>>>> { + ) -> PResult<'a, Option<Option<Box<AssocItem>>>> { let fn_parse_mode = FnParseMode { req_name: |edition| edition >= Edition::Edition2018, req_body: false }; self.parse_assoc_item(fn_parse_mode, force_collect) @@ -967,7 +969,7 @@ impl<'a> Parser<'a> { &mut self, fn_parse_mode: FnParseMode, force_collect: ForceCollect, - ) -> PResult<'a, Option<Option<P<AssocItem>>>> { + ) -> PResult<'a, Option<Option<Box<AssocItem>>>> { Ok(self.parse_item_(fn_parse_mode, force_collect)?.map( |Item { attrs, id, span, vis, kind, tokens }| { let kind = match AssocItemKind::try_from(kind) { @@ -994,7 +996,7 @@ impl<'a> Parser<'a> { _ => return self.error_bad_item_kind(span, &kind, "`trait`s or `impl`s"), }, }; - Some(P(Item { attrs, id, span, vis, kind, tokens })) + Some(Box::new(Item { attrs, id, span, vis, kind, tokens })) }, )) } @@ -1234,7 +1236,7 @@ impl<'a> Parser<'a> { pub fn parse_foreign_item( &mut self, force_collect: ForceCollect, - ) -> PResult<'a, Option<Option<P<ForeignItem>>>> { + ) -> PResult<'a, Option<Option<Box<ForeignItem>>>> { let fn_parse_mode = FnParseMode { req_name: |_| true, req_body: false }; Ok(self.parse_item_(fn_parse_mode, force_collect)?.map( |Item { attrs, id, span, vis, kind, tokens }| { @@ -1260,7 +1262,7 @@ impl<'a> Parser<'a> { _ => return self.error_bad_item_kind(span, &kind, "`extern` blocks"), }, }; - Some(P(Item { attrs, id, span, vis, kind, tokens })) + Some(Box::new(Item { attrs, id, span, vis, kind, tokens })) }, )) } @@ -1421,7 +1423,9 @@ impl<'a> Parser<'a> { /// ```ebnf /// Const = "const" ($ident | "_") Generics ":" $ty (= $expr)? WhereClause ";" ; /// ``` - fn parse_const_item(&mut self) -> PResult<'a, (Ident, Generics, P<Ty>, Option<P<ast::Expr>>)> { + fn parse_const_item( + &mut self, + ) -> PResult<'a, (Ident, Generics, Box<Ty>, Option<Box<ast::Expr>>)> { let ident = self.parse_ident_or_underscore()?; let mut generics = self.parse_generics()?; @@ -1514,7 +1518,7 @@ impl<'a> Parser<'a> { &mut self, colon_present: bool, m: Option<Mutability>, - ) -> P<Ty> { + ) -> Box<Ty> { // Construct the error and stash it away with the hope // that typeck will later enrich the error with a type. let kind = match m { @@ -1534,7 +1538,7 @@ impl<'a> Parser<'a> { // The user intended that the type be inferred, // so treat this as if the user wrote e.g. `const A: _ = expr;`. - P(Ty { kind: TyKind::Infer, span, id: ast::DUMMY_NODE_ID, tokens: None }) + Box::new(Ty { kind: TyKind::Infer, span, id: ast::DUMMY_NODE_ID, tokens: None }) } /// Parses an enum declaration. @@ -2204,7 +2208,7 @@ impl<'a> Parser<'a> { let arrow = TokenTree::token_alone(token::FatArrow, pspan.between(bspan)); // `=>` let tokens = TokenStream::new(vec![params, arrow, body]); let dspan = DelimSpan::from_pair(pspan.shrink_to_lo(), bspan.shrink_to_hi()); - P(DelimArgs { dspan, delim: Delimiter::Brace, tokens }) + Box::new(DelimArgs { dspan, delim: Delimiter::Brace, tokens }) } else { self.unexpected_any()? }; @@ -2406,7 +2410,7 @@ impl<'a> Parser<'a> { sig_lo: Span, vis: &Visibility, case: Case, - ) -> PResult<'a, (Ident, FnSig, Generics, Option<P<FnContract>>, Option<P<Block>>)> { + ) -> PResult<'a, (Ident, FnSig, Generics, Option<Box<FnContract>>, Option<Box<Block>>)> { let fn_span = self.token.span; let header = self.parse_fn_front_matter(vis, case, FrontMatterParsingMode::Function)?; // `const ... fn` let ident = self.parse_ident()?; // `foo` @@ -2536,7 +2540,7 @@ impl<'a> Parser<'a> { sig_hi: &mut Span, req_body: bool, fn_params_end: Option<Span>, - ) -> PResult<'a, Option<P<Block>>> { + ) -> PResult<'a, Option<Box<Block>>> { let has_semi = if req_body { self.token == TokenKind::Semi } else { @@ -2936,8 +2940,8 @@ impl<'a> Parser<'a> { req_name: ReqName, ret_allow_plus: AllowPlus, recover_return_sign: RecoverReturnSign, - ) -> PResult<'a, P<FnDecl>> { - Ok(P(FnDecl { + ) -> PResult<'a, Box<FnDecl>> { + Ok(Box::new(FnDecl { inputs: self.parse_fn_params(req_name)?, output: self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes, recover_return_sign)?, })) diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 90491e53249..0a8a0203013 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -25,7 +25,6 @@ pub(crate) use expr::ForbiddenLetReason; pub(crate) use item::FnParseMode; pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma}; use path::PathStyle; -use rustc_ast::ptr::P; use rustc_ast::token::{ self, IdentIsRaw, InvisibleOrigin, MetaVarKind, NtExprKind, NtPatKind, Token, TokenKind, }; @@ -1286,7 +1285,7 @@ impl<'a> Parser<'a> { } /// Parses inline const expressions. - fn parse_const_block(&mut self, span: Span, pat: bool) -> PResult<'a, P<Expr>> { + fn parse_const_block(&mut self, span: Span, pat: bool) -> PResult<'a, Box<Expr>> { self.expect_keyword(exp!(Const))?; let (attrs, blk) = self.parse_inner_attrs_and_block(None)?; let anon_const = AnonConst { @@ -1343,9 +1342,9 @@ impl<'a> Parser<'a> { } } - fn parse_delim_args(&mut self) -> PResult<'a, P<DelimArgs>> { + fn parse_delim_args(&mut self) -> PResult<'a, Box<DelimArgs>> { if let Some(args) = self.parse_delim_args_inner() { - Ok(P(args)) + Ok(Box::new(args)) } else { self.unexpected_any() } @@ -1470,7 +1469,7 @@ impl<'a> Parser<'a> { let path = self.parse_path(PathStyle::Mod)?; // `path` self.expect(exp!(CloseParen))?; // `)` let vis = VisibilityKind::Restricted { - path: P(path), + path: Box::new(path), id: ast::DUMMY_NODE_ID, shorthand: false, }; @@ -1487,7 +1486,7 @@ impl<'a> Parser<'a> { let path = self.parse_path(PathStyle::Mod)?; // `crate`/`super`/`self` self.expect(exp!(CloseParen))?; // `)` let vis = VisibilityKind::Restricted { - path: P(path), + path: Box::new(path), id: ast::DUMMY_NODE_ID, shorthand: true, }; @@ -1652,14 +1651,14 @@ pub enum ParseNtResult { Tt(TokenTree), Ident(Ident, IdentIsRaw), Lifetime(Ident, IdentIsRaw), - Item(P<ast::Item>), - Block(P<ast::Block>), - Stmt(P<ast::Stmt>), - Pat(P<ast::Pat>, NtPatKind), - Expr(P<ast::Expr>, NtExprKind), - Literal(P<ast::Expr>), - Ty(P<ast::Ty>), - Meta(P<ast::AttrItem>), - Path(P<ast::Path>), - Vis(P<ast::Visibility>), + Item(Box<ast::Item>), + Block(Box<ast::Block>), + Stmt(Box<ast::Stmt>), + Pat(Box<ast::Pat>, NtPatKind), + Expr(Box<ast::Expr>, NtExprKind), + Literal(Box<ast::Expr>), + Ty(Box<ast::Ty>), + Meta(Box<ast::AttrItem>), + Path(Box<ast::Path>), + Vis(Box<ast::Visibility>), } diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 7c83e96c160..42eb07858c2 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -1,4 +1,3 @@ -use rustc_ast::ptr::P; use rustc_ast::token::NtExprKind::*; use rustc_ast::token::NtPatKind::*; use rustc_ast::token::{self, InvisibleOrigin, MetaVarKind, NonterminalKind, Token}; @@ -129,7 +128,7 @@ impl<'a> Parser<'a> { Ok(ParseNtResult::Block(self.collect_tokens_no_attrs(|this| this.parse_block())?)) } NonterminalKind::Stmt => match self.parse_stmt(ForceCollect::Yes)? { - Some(stmt) => Ok(ParseNtResult::Stmt(P(stmt))), + Some(stmt) => Ok(ParseNtResult::Stmt(Box::new(stmt))), None => { Err(self.dcx().create_err(UnexpectedNonterminal::Statement(self.token.span))) } @@ -170,16 +169,15 @@ impl<'a> Parser<'a> { })) } } - NonterminalKind::Path => Ok(ParseNtResult::Path(P( - self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))? + NonterminalKind::Path => Ok(ParseNtResult::Path(Box::new( + self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))?, ))), NonterminalKind::Meta => { - Ok(ParseNtResult::Meta(P(self.parse_attr_item(ForceCollect::Yes)?))) - } - NonterminalKind::Vis => { - Ok(ParseNtResult::Vis(P(self - .collect_tokens_no_attrs(|this| this.parse_visibility(FollowedByType::Yes))?))) + Ok(ParseNtResult::Meta(Box::new(self.parse_attr_item(ForceCollect::Yes)?))) } + NonterminalKind::Vis => Ok(ParseNtResult::Vis(Box::new( + self.collect_tokens_no_attrs(|this| this.parse_visibility(FollowedByType::Yes))?, + ))), NonterminalKind::Lifetime => { // We want to keep `'keyword` parsing, just like `keyword` is still // an ident for nonterminal purposes. diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 64653ee2a04..a415849b915 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -1,7 +1,6 @@ use std::ops::Bound; use rustc_ast::mut_visit::{self, MutVisitor}; -use rustc_ast::ptr::P; use rustc_ast::token::NtPatKind::*; use rustc_ast::token::{self, IdentIsRaw, MetaVarKind, Token}; use rustc_ast::util::parser::ExprPrecedence; @@ -108,7 +107,7 @@ impl<'a> Parser<'a> { rc: RecoverComma, ra: RecoverColon, rt: CommaRecoveryMode, - ) -> PResult<'a, P<Pat>> { + ) -> PResult<'a, Box<Pat>> { let pat = self.parse_pat_no_top_guard(expected, rc, ra, rt)?; if self.eat_keyword(exp!(If)) { @@ -131,7 +130,7 @@ impl<'a> Parser<'a> { &mut self, expected: Option<Expected>, syntax_loc: Option<PatternLocation>, - ) -> PResult<'a, P<Pat>> { + ) -> PResult<'a, Box<Pat>> { self.parse_pat_with_range_pat(true, expected, syntax_loc) } @@ -150,7 +149,7 @@ impl<'a> Parser<'a> { rc: RecoverComma, ra: RecoverColon, rt: CommaRecoveryMode, - ) -> PResult<'a, P<Pat>> { + ) -> PResult<'a, Box<Pat>> { self.parse_pat_no_top_guard_inner(expected, rc, ra, rt, None).map(|(pat, _)| pat) } @@ -163,7 +162,7 @@ impl<'a> Parser<'a> { ra: RecoverColon, rt: CommaRecoveryMode, syntax_loc: Option<PatternLocation>, - ) -> PResult<'a, (P<Pat>, bool)> { + ) -> PResult<'a, (Box<Pat>, bool)> { // Keep track of whether we recovered from a trailing vert so that we can avoid duplicated // suggestions (which bothers rustfix). // @@ -253,7 +252,7 @@ impl<'a> Parser<'a> { expected: Option<Expected>, rc: RecoverComma, syntax_loc: PatternLocation, - ) -> PResult<'a, (P<Pat>, bool)> { + ) -> PResult<'a, (Box<Pat>, bool)> { // We use `parse_pat_allow_top_alt` regardless of whether we actually want top-level // or-patterns so that we can detect when a user tries to use it. This allows us to print a // better error message. @@ -301,7 +300,7 @@ impl<'a> Parser<'a> { /// /// The return value represents the parsed pattern and `true` if a `Colon` was parsed (`false` /// otherwise). - pub(super) fn parse_fn_param_pat_colon(&mut self) -> PResult<'a, (P<Pat>, bool)> { + pub(super) fn parse_fn_param_pat_colon(&mut self) -> PResult<'a, (Box<Pat>, bool)> { // In order to get good UX, we first recover in the case of a leading vert for an illegal // top-level or-pat. Normally, this means recovering both `|` and `||`, but in this case, // a leading `||` probably doesn't indicate an or-pattern attempt, so we handle that @@ -685,7 +684,7 @@ impl<'a> Parser<'a> { PatVisitor { parser: self, stmt, arm: None, field: None }.visit_stmt(stmt); } - fn eat_metavar_pat(&mut self) -> Option<P<Pat>> { + fn eat_metavar_pat(&mut self) -> Option<Box<Pat>> { // Must try both kinds of pattern nonterminals. if let Some(pat) = self.eat_metavar_seq_with_matcher( |mv_kind| matches!(mv_kind, MetaVarKind::Pat(PatParam { .. })), @@ -713,7 +712,7 @@ impl<'a> Parser<'a> { allow_range_pat: bool, expected: Option<Expected>, syntax_loc: Option<PatternLocation>, - ) -> PResult<'a, P<Pat>> { + ) -> PResult<'a, Box<Pat>> { maybe_recover_from_interpolated_ty_qpath!(self, true); if let Some(pat) = self.eat_metavar_pat() { @@ -909,7 +908,7 @@ impl<'a> Parser<'a> { /// e.g. [F#][and] where they are called AND-patterns. /// /// [and]: https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/pattern-matching - fn recover_intersection_pat(&mut self, lhs: P<Pat>) -> PResult<'a, P<Pat>> { + fn recover_intersection_pat(&mut self, lhs: Box<Pat>) -> PResult<'a, Box<Pat>> { if self.token != token::At { // Next token is not `@` so it's not going to be an intersection pattern. return Ok(lhs); @@ -1091,7 +1090,7 @@ impl<'a> Parser<'a> { /// Turn all by-value immutable bindings in a pattern into mutable bindings. /// Returns `true` if any change was made. - fn make_all_value_bindings_mutable(pat: &mut P<Pat>) -> bool { + fn make_all_value_bindings_mutable(pat: &mut Box<Pat>) -> bool { struct AddMut(bool); impl MutVisitor for AddMut { fn visit_pat(&mut self, pat: &mut Pat) { @@ -1139,7 +1138,7 @@ impl<'a> Parser<'a> { fn parse_pat_mac_invoc(&mut self, path: Path) -> PResult<'a, PatKind> { self.bump(); let args = self.parse_delim_args()?; - let mac = P(MacCall { path, args }); + let mac = Box::new(MacCall { path, args }); Ok(PatKind::MacCall(mac)) } @@ -1147,7 +1146,7 @@ impl<'a> Parser<'a> { &mut self, err: Diag<'a>, expected: Option<Expected>, - ) -> PResult<'a, P<Pat>> { + ) -> PResult<'a, Box<Pat>> { err.cancel(); let expected = Expected::to_string_or_fallback(expected); @@ -1182,7 +1181,7 @@ impl<'a> Parser<'a> { /// `$begin $form` has already been parsed. fn parse_pat_range_begin_with( &mut self, - begin: P<Expr>, + begin: Box<Expr>, re: Spanned<RangeEnd>, ) -> PResult<'a, PatKind> { let end = if self.is_pat_range_end_start(0) { @@ -1262,7 +1261,7 @@ impl<'a> Parser<'a> { } /// Parse a range pattern end bound - fn parse_pat_range_end(&mut self) -> PResult<'a, P<Expr>> { + fn parse_pat_range_end(&mut self) -> PResult<'a, Box<Expr>> { // recover leading `(` let open_paren = (self.may_recover() && self.eat_noexpect(&token::OpenParen)) .then_some(self.prev_token.span); @@ -1380,7 +1379,7 @@ impl<'a> Parser<'a> { } /// Parse a struct ("record") pattern (e.g. `Foo { ... }` or `Foo::Bar { ... }`). - fn parse_pat_struct(&mut self, qself: Option<P<QSelf>>, path: Path) -> PResult<'a, PatKind> { + fn parse_pat_struct(&mut self, qself: Option<Box<QSelf>>, path: Path) -> PResult<'a, PatKind> { if qself.is_some() { // Feature gate the use of qualified paths in patterns self.psess.gated_spans.gate(sym::more_qualified_paths, path.span); @@ -1400,7 +1399,7 @@ impl<'a> Parser<'a> { /// Parse tuple struct or tuple variant pattern (e.g. `Foo(...)` or `Foo::Bar(...)`). fn parse_pat_tuple_struct( &mut self, - qself: Option<P<QSelf>>, + qself: Option<Box<QSelf>>, path: Path, ) -> PResult<'a, PatKind> { let (fields, _) = self.parse_paren_comma_seq(|p| { @@ -1749,11 +1748,11 @@ impl<'a> Parser<'a> { }) } - pub(super) fn mk_pat_ident(&self, span: Span, ann: BindingMode, ident: Ident) -> P<Pat> { + pub(super) fn mk_pat_ident(&self, span: Span, ann: BindingMode, ident: Ident) -> Box<Pat> { self.mk_pat(span, PatKind::Ident(ann, ident, None)) } - pub(super) fn mk_pat(&self, span: Span, kind: PatKind) -> P<Pat> { - P(Pat { kind, span, id: ast::DUMMY_NODE_ID, tokens: None }) + pub(super) fn mk_pat(&self, span: Span, kind: PatKind) -> Box<Pat> { + Box::new(Pat { kind, span, id: ast::DUMMY_NODE_ID, tokens: None }) } } diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 1f4049f197f..a6ec3ea4245 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -1,7 +1,6 @@ use std::mem; use ast::token::IdentIsRaw; -use rustc_ast::ptr::P; use rustc_ast::token::{self, MetaVarKind, Token, TokenKind}; use rustc_ast::{ self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocItemConstraint, @@ -17,11 +16,11 @@ use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{Parser, Restrictions, TokenType}; use crate::ast::{PatKind, TyKind}; use crate::errors::{ - self, FnPathFoundNamedParams, PathFoundAttributeInParams, PathFoundCVariadicParams, - PathSingleColon, PathTripleColon, + self, AttributeOnEmptyType, AttributeOnGenericArg, FnPathFoundNamedParams, + PathFoundAttributeInParams, PathFoundCVariadicParams, PathSingleColon, PathTripleColon, }; use crate::exp; -use crate::parser::{CommaRecoveryMode, RecoverColon, RecoverComma}; +use crate::parser::{CommaRecoveryMode, ExprKind, RecoverColon, RecoverComma}; /// Specifies how to parse a path. #[derive(Copy, Clone, PartialEq)] @@ -75,7 +74,7 @@ impl<'a> Parser<'a> { /// `<T as U>::a` /// `<T as U>::F::a<S>` (without disambiguator) /// `<T as U>::F::a::<S>` (with disambiguator) - pub(super) fn parse_qpath(&mut self, style: PathStyle) -> PResult<'a, (P<QSelf>, Path)> { + pub(super) fn parse_qpath(&mut self, style: PathStyle) -> PResult<'a, (Box<QSelf>, Path)> { let lo = self.prev_token.span; let ty = self.parse_ty()?; @@ -105,7 +104,7 @@ impl<'a> Parser<'a> { self.expect(exp!(PathSep))?; } - let qself = P(QSelf { ty, path_span, position: path.segments.len() }); + let qself = Box::new(QSelf { ty, path_span, position: path.segments.len() }); if !is_import_coupler { self.parse_path_segments(&mut path.segments, style, None)?; } @@ -380,7 +379,7 @@ impl<'a> Parser<'a> { .emit_err(errors::BadReturnTypeNotationOutput { span, suggestion }); } - P(ast::GenericArgs::ParenthesizedElided(span)) + Box::new(ast::GenericArgs::ParenthesizedElided(span)) } else { // `(T, U) -> R` @@ -842,7 +841,7 @@ impl<'a> Parser<'a> { /// - A literal. /// - A numeric literal prefixed by `-`. /// - A single-segment path. - pub(super) fn expr_is_valid_const_arg(&self, expr: &P<rustc_ast::Expr>) -> bool { + pub(super) fn expr_is_valid_const_arg(&self, expr: &Box<rustc_ast::Expr>) -> bool { match &expr.kind { ast::ExprKind::Block(_, _) | ast::ExprKind::Lit(_) @@ -880,6 +879,12 @@ impl<'a> Parser<'a> { &mut self, ty_generics: Option<&Generics>, ) -> PResult<'a, Option<GenericArg>> { + let mut attr_span: Option<Span> = None; + if self.token == token::Pound && self.look_ahead(1, |t| *t == token::OpenBracket) { + let attrs_wrapper = self.parse_outer_attributes()?; + let raw_attrs = attrs_wrapper.take_for_recovery(self.psess); + attr_span = Some(raw_attrs[0].span.to(raw_attrs.last().unwrap().span)); + } let start = self.token.span; let arg = if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) { // Parse lifetime argument. @@ -934,6 +939,9 @@ impl<'a> Parser<'a> { } } else if self.token.is_keyword(kw::Const) { return self.recover_const_param_declaration(ty_generics); + } else if let Some(attr_span) = attr_span { + let diag = self.dcx().create_err(AttributeOnEmptyType { span: attr_span }); + return Err(diag); } else { // Fall back by trying to parse a const-expr expression. If we successfully do so, // then we should report an error that it needs to be wrapped in braces. @@ -953,6 +961,22 @@ impl<'a> Parser<'a> { } } }; + + if let Some(attr_span) = attr_span { + let guar = self.dcx().emit_err(AttributeOnGenericArg { + span: attr_span, + fix_span: attr_span.until(arg.span()), + }); + return Ok(Some(match arg { + GenericArg::Type(_) => GenericArg::Type(self.mk_ty(attr_span, TyKind::Err(guar))), + GenericArg::Const(_) => { + let error_expr = self.mk_expr(attr_span, ExprKind::Err(guar)); + GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value: error_expr }) + } + GenericArg::Lifetime(lt) => GenericArg::Lifetime(lt), + })); + } + Ok(Some(arg)) } diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 2fa6520f2a4..7aacb674253 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -4,7 +4,6 @@ use std::ops::Bound; use ast::Label; use rustc_ast as ast; -use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, InvisibleOrigin, MetaVarKind, TokenKind}; use rustc_ast::util::classify::{self, TrailingBrace}; use rustc_ast::{ @@ -157,7 +156,7 @@ impl<'a> Parser<'a> { FnParseMode { req_name: |_| true, req_body: true }, force_collect, )? { - self.mk_stmt(lo.to(item.span), StmtKind::Item(P(item))) + self.mk_stmt(lo.to(item.span), StmtKind::Item(Box::new(item))) } else if self.eat(exp!(Semi)) { // Do not attempt to parse an expression if we're done here. self.error_outer_attrs(attrs); @@ -246,7 +245,7 @@ impl<'a> Parser<'a> { _ => MacStmtStyle::NoBraces, }; - let mac = P(MacCall { path, args }); + let mac = Box::new(MacCall { path, args }); let kind = if (style == MacStmtStyle::Braces && !matches!(self.token.kind, token::Dot | token::Question)) @@ -256,7 +255,7 @@ impl<'a> Parser<'a> { | token::Eof | token::CloseInvisible(InvisibleOrigin::MetaVar(MetaVarKind::Stmt)) ) { - StmtKind::MacCall(P(MacCallStmt { mac, style, attrs, tokens: None })) + StmtKind::MacCall(Box::new(MacCallStmt { mac, style, attrs, tokens: None })) } else { // Since none of the above applied, this is an expression statement macro. let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac)); @@ -307,7 +306,7 @@ impl<'a> Parser<'a> { } /// Parses a local variable declaration. - fn parse_local(&mut self, super_: Option<Span>, attrs: AttrVec) -> PResult<'a, P<Local>> { + fn parse_local(&mut self, super_: Option<Span>, attrs: AttrVec) -> PResult<'a, Box<Local>> { let lo = super_.unwrap_or(self.prev_token.span); if self.token.is_keyword(kw::Const) && self.look_ahead(1, |t| t.is_ident()) { @@ -409,7 +408,7 @@ impl<'a> Parser<'a> { } }; let hi = if self.token == token::Semi { self.token.span } else { self.prev_token.span }; - Ok(P(ast::Local { + Ok(Box::new(ast::Local { super_, ty, pat, @@ -463,7 +462,7 @@ impl<'a> Parser<'a> { } /// Parses the RHS of a local variable declaration (e.g., `= 14;`). - fn parse_initializer(&mut self, eq_optional: bool) -> PResult<'a, Option<P<Expr>>> { + fn parse_initializer(&mut self, eq_optional: bool) -> PResult<'a, Option<Box<Expr>>> { let eq_consumed = match self.token.kind { token::PlusEq | token::MinusEq @@ -494,7 +493,7 @@ impl<'a> Parser<'a> { } /// Parses a block. No inner attributes are allowed. - pub fn parse_block(&mut self) -> PResult<'a, P<Block>> { + pub fn parse_block(&mut self) -> PResult<'a, Box<Block>> { let (attrs, block) = self.parse_inner_attrs_and_block(None)?; if let [.., last] = &*attrs { let suggest_to_outer = match &last.kind { @@ -679,7 +678,7 @@ impl<'a> Parser<'a> { pub(super) fn parse_inner_attrs_and_block( &mut self, loop_header: Option<Span>, - ) -> PResult<'a, (AttrVec, P<Block>)> { + ) -> PResult<'a, (AttrVec, Box<Block>)> { self.parse_block_common(self.token.span, BlockCheckMode::Default, loop_header) } @@ -692,7 +691,7 @@ impl<'a> Parser<'a> { lo: Span, blk_mode: BlockCheckMode, loop_header: Option<Span>, - ) -> PResult<'a, (AttrVec, P<Block>)> { + ) -> PResult<'a, (AttrVec, Box<Block>)> { if let Some(block) = self.eat_metavar_seq(MetaVarKind::Block, |this| this.parse_block()) { return Ok((AttrVec::new(), block)); } @@ -718,7 +717,7 @@ impl<'a> Parser<'a> { lo: Span, s: BlockCheckMode, recover: AttemptLocalParseRecovery, - ) -> PResult<'a, P<Block>> { + ) -> PResult<'a, Box<Block>> { let mut stmts = ThinVec::new(); let mut snapshot = None; while !self.eat(exp!(CloseBrace)) { @@ -1050,8 +1049,8 @@ impl<'a> Parser<'a> { stmts: ThinVec<Stmt>, rules: BlockCheckMode, span: Span, - ) -> P<Block> { - P(Block { stmts, id: DUMMY_NODE_ID, rules, span, tokens: None }) + ) -> Box<Block> { + Box::new(Block { stmts, id: DUMMY_NODE_ID, rules, span, tokens: None }) } pub(super) fn mk_stmt(&self, span: Span, kind: StmtKind) -> Stmt { @@ -1062,7 +1061,7 @@ impl<'a> Parser<'a> { self.mk_stmt(span, StmtKind::Expr(self.mk_expr_err(span, guar))) } - pub(super) fn mk_block_err(&self, span: Span, guar: ErrorGuaranteed) -> P<Block> { + pub(super) fn mk_block_err(&self, span: Span, guar: ErrorGuaranteed) -> Box<Block> { self.mk_block(thin_vec![self.mk_stmt_err(span, guar)], BlockCheckMode::Default, span) } } diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs index 15679d23bc5..a6e7266e71b 100644 --- a/compiler/rustc_parse/src/parser/tests.rs +++ b/compiler/rustc_parse/src/parser/tests.rs @@ -8,7 +8,6 @@ use std::sync::{Arc, Mutex}; use std::{io, str}; use ast::token::IdentIsRaw; -use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, Token}; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; use rustc_ast::{self as ast, PatKind, visit}; @@ -2114,15 +2113,15 @@ fn foo() { error: foo --> test.rs:3:6 | -3 | X0 Y0 Z0 + 3 | X0 Y0 Z0 | _______^ -4 | | X1 Y1 Z1 + 4 | | X1 Y1 Z1 | | ____^____- | ||____| | | `X` is a good letter -5 | | 1 -6 | | 2 -7 | | 3 + 5 | | 1 + 6 | | 2 + 7 | | 3 ... | 15 | | X2 Y2 Z2 16 | | X3 Y3 Z3 @@ -2133,15 +2132,15 @@ error: foo error: foo ╭▸ test.rs:3:6 │ -3 │ X0 Y0 Z0 + 3 │ X0 Y0 Z0 │ ┏━━━━━━━┛ -4 │ ┃ X1 Y1 Z1 + 4 │ ┃ X1 Y1 Z1 │ ┃┌────╿────┘ │ ┗│━━━━┥ │ │ `X` is a good letter -5 │ │ 1 -6 │ │ 2 -7 │ │ 3 + 5 │ │ 1 + 6 │ │ 2 + 7 │ │ 3 ‡ │ 15 │ │ X2 Y2 Z2 16 │ │ X3 Y3 Z3 @@ -2189,15 +2188,15 @@ fn foo() { error: foo --> test.rs:3:6 | -3 | X0 Y0 Z0 + 3 | X0 Y0 Z0 | _______^ -4 | | 1 -5 | | 2 -6 | | 3 -7 | | X1 Y1 Z1 + 4 | | 1 + 5 | | 2 + 6 | | 3 + 7 | | X1 Y1 Z1 | | _________- -8 | || 4 -9 | || 5 + 8 | || 4 + 9 | || 5 10 | || 6 11 | || X2 Y2 Z2 | ||__________- `Z` is a good letter too @@ -2211,15 +2210,15 @@ error: foo error: foo ╭▸ test.rs:3:6 │ -3 │ X0 Y0 Z0 + 3 │ X0 Y0 Z0 │ ┏━━━━━━━┛ -4 │ ┃ 1 -5 │ ┃ 2 -6 │ ┃ 3 -7 │ ┃ X1 Y1 Z1 + 4 │ ┃ 1 + 5 │ ┃ 2 + 6 │ ┃ 3 + 7 │ ┃ X1 Y1 Z1 │ ┃┌─────────┘ -8 │ ┃│ 4 -9 │ ┃│ 5 + 8 │ ┃│ 4 + 9 │ ┃│ 5 10 │ ┃│ 6 11 │ ┃│ X2 Y2 Z2 │ ┃└──────────┘ `Z` is a good letter too @@ -2240,7 +2239,7 @@ fn parse_item_from_source_str( name: FileName, source: String, psess: &ParseSess, -) -> PResult<'_, Option<P<ast::Item>>> { +) -> PResult<'_, Option<Box<ast::Item>>> { unwrap_or_emit_fatal(new_parser_from_source_str(psess, name, source)) .parse_item(ForceCollect::No) } @@ -2251,12 +2250,12 @@ fn sp(a: u32, b: u32) -> Span { } /// Parses a string, return an expression. -fn string_to_expr(source_str: String) -> P<ast::Expr> { +fn string_to_expr(source_str: String) -> Box<ast::Expr> { with_error_checking_parse(source_str, &psess(), |p| p.parse_expr()) } /// Parses a string, returns an item. -fn string_to_item(source_str: String) -> Option<P<ast::Item>> { +fn string_to_item(source_str: String) -> Option<Box<ast::Item>> { with_error_checking_parse(source_str, &psess(), |p| p.parse_item(ForceCollect::No)) } @@ -2520,7 +2519,7 @@ fn ttdelim_span() { name: FileName, source: String, psess: &ParseSess, - ) -> PResult<'_, P<ast::Expr>> { + ) -> PResult<'_, Box<ast::Expr>> { unwrap_or_emit_fatal(new_parser_from_source_str(psess, name, source)).parse_expr() } diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 740dd10ea8b..0d479731e73 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -1,4 +1,3 @@ -use rustc_ast::ptr::P; use rustc_ast::token::{self, IdentIsRaw, MetaVarKind, Token, TokenKind}; use rustc_ast::util::case::Case; use rustc_ast::{ @@ -14,10 +13,10 @@ use thin_vec::{ThinVec, thin_vec}; use super::{Parser, PathStyle, SeqSep, TokenType, Trailing}; use crate::errors::{ - self, DynAfterMut, ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType, - FnPtrWithGenerics, FnPtrWithGenericsSugg, HelpUseLatestEdition, InvalidDynKeyword, - LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime, NestedCVariadicType, - ReturnTypesUseThinArrow, + self, AttributeOnEmptyType, AttributeOnType, DynAfterMut, ExpectedFnPathFoundFnKeyword, + ExpectedMutOrConstInRawPointerType, FnPtrWithGenerics, FnPtrWithGenericsSugg, + HelpUseLatestEdition, InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime, + NestedCVariadicType, ReturnTypesUseThinArrow, }; use crate::parser::item::FrontMatterParsingMode; use crate::{exp, maybe_recover_from_interpolated_ty_qpath}; @@ -105,7 +104,7 @@ fn can_begin_dyn_bound_in_edition_2015(t: &Token) -> bool { impl<'a> Parser<'a> { /// Parses a type. - pub fn parse_ty(&mut self) -> PResult<'a, P<Ty>> { + pub fn parse_ty(&mut self) -> PResult<'a, Box<Ty>> { // Make sure deeply nested types don't overflow the stack. ensure_sufficient_stack(|| { self.parse_ty_common( @@ -122,7 +121,7 @@ impl<'a> Parser<'a> { pub(super) fn parse_ty_with_generics_recovery( &mut self, ty_params: &Generics, - ) -> PResult<'a, P<Ty>> { + ) -> PResult<'a, Box<Ty>> { self.parse_ty_common( AllowPlus::Yes, AllowCVariadic::No, @@ -136,7 +135,7 @@ impl<'a> Parser<'a> { /// Parse a type suitable for a function or function pointer parameter. /// The difference from `parse_ty` is that this version allows `...` /// (`CVarArgs`) at the top level of the type. - pub(super) fn parse_ty_for_param(&mut self) -> PResult<'a, P<Ty>> { + pub(super) fn parse_ty_for_param(&mut self) -> PResult<'a, Box<Ty>> { self.parse_ty_common( AllowPlus::Yes, AllowCVariadic::Yes, @@ -153,7 +152,7 @@ impl<'a> Parser<'a> { /// `+` is prohibited to maintain operator priority (P(+) < P(&)). /// Example 2: `value1 as TYPE + value2` /// `+` is prohibited to avoid interactions with expression grammar. - pub(super) fn parse_ty_no_plus(&mut self) -> PResult<'a, P<Ty>> { + pub(super) fn parse_ty_no_plus(&mut self) -> PResult<'a, Box<Ty>> { self.parse_ty_common( AllowPlus::No, AllowCVariadic::No, @@ -166,7 +165,7 @@ impl<'a> Parser<'a> { /// Parses a type following an `as` cast. Similar to `parse_ty_no_plus`, but signaling origin /// for better diagnostics involving `?`. - pub(super) fn parse_as_cast_ty(&mut self) -> PResult<'a, P<Ty>> { + pub(super) fn parse_as_cast_ty(&mut self) -> PResult<'a, Box<Ty>> { self.parse_ty_common( AllowPlus::No, AllowCVariadic::No, @@ -177,7 +176,7 @@ impl<'a> Parser<'a> { ) } - pub(super) fn parse_ty_no_question_mark_recover(&mut self) -> PResult<'a, P<Ty>> { + pub(super) fn parse_ty_no_question_mark_recover(&mut self) -> PResult<'a, Box<Ty>> { self.parse_ty_common( AllowPlus::Yes, AllowCVariadic::No, @@ -190,7 +189,7 @@ impl<'a> Parser<'a> { /// Parse a type without recovering `:` as `->` to avoid breaking code such /// as `where fn() : for<'a>`. - pub(super) fn parse_ty_for_where_clause(&mut self) -> PResult<'a, P<Ty>> { + pub(super) fn parse_ty_for_where_clause(&mut self) -> PResult<'a, Box<Ty>> { self.parse_ty_common( AllowPlus::Yes, AllowCVariadic::No, @@ -250,10 +249,30 @@ impl<'a> Parser<'a> { recover_return_sign: RecoverReturnSign, ty_generics: Option<&Generics>, recover_question_mark: RecoverQuestionMark, - ) -> PResult<'a, P<Ty>> { + ) -> PResult<'a, Box<Ty>> { let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes; maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery); + if self.token == token::Pound && self.look_ahead(1, |t| *t == token::OpenBracket) { + let attrs_wrapper = self.parse_outer_attributes()?; + let raw_attrs = attrs_wrapper.take_for_recovery(self.psess); + let attr_span = raw_attrs[0].span.to(raw_attrs.last().unwrap().span); + let (full_span, guar) = match self.parse_ty() { + Ok(ty) => { + let full_span = attr_span.until(ty.span); + let guar = self + .dcx() + .emit_err(AttributeOnType { span: attr_span, fix_span: full_span }); + (attr_span, guar) + } + Err(err) => { + err.cancel(); + let guar = self.dcx().emit_err(AttributeOnEmptyType { span: attr_span }); + (attr_span, guar) + } + }; + return Ok(self.mk_ty(full_span, TyKind::Err(guar))); + } if let Some(ty) = self.eat_metavar_seq_with_matcher( |mv_kind| matches!(mv_kind, MetaVarKind::Ty { .. }), |this| this.parse_ty_no_question_mark_recover(), @@ -405,7 +424,7 @@ impl<'a> Parser<'a> { let span = lo.to(self.prev_token.span); self.psess.gated_spans.gate(sym::unsafe_binders, span); - Ok(TyKind::UnsafeBinder(P(UnsafeBinderTy { generic_params, inner_ty }))) + Ok(TyKind::UnsafeBinder(Box::new(UnsafeBinderTy { generic_params, inner_ty }))) } /// Parses either: @@ -590,7 +609,7 @@ impl<'a> Parser<'a> { /// - `[u8, 5]` → suggests using `;`, return a Array type /// - `[u8 5]` → suggests using `;`, return a Array type /// Consider to add more cases in the future. - fn maybe_recover_array_ty_without_semi(&mut self, elt_ty: P<Ty>) -> PResult<'a, TyKind> { + fn maybe_recover_array_ty_without_semi(&mut self, elt_ty: Box<Ty>) -> PResult<'a, TyKind> { let span = self.token.span; let token_descr = super::token_descr(&self.token); let mut err = @@ -753,7 +772,13 @@ impl<'a> Parser<'a> { let decl = self.parse_fn_decl(|_| false, AllowPlus::No, recover_return_sign)?; let decl_span = span_start.to(self.prev_token.span); - Ok(TyKind::FnPtr(P(FnPtrTy { ext, safety, generic_params: params, decl, decl_span }))) + Ok(TyKind::FnPtr(Box::new(FnPtrTy { + ext, + safety, + generic_params: params, + decl, + decl_span, + }))) } /// Recover from function pointer types with a generic parameter list (e.g. `fn<'a>(&'a str)`). @@ -895,7 +920,7 @@ impl<'a> Parser<'a> { let path = self.parse_path_inner(PathStyle::Type, ty_generics)?; if self.eat(exp!(Bang)) { // Macro invocation in type position - Ok(TyKind::MacCall(P(MacCall { path, args: self.parse_delim_args()? }))) + Ok(TyKind::MacCall(Box::new(MacCall { path, args: self.parse_delim_args()? }))) } else if allow_plus == AllowPlus::Yes && self.check_plus() { // `Trait1 + Trait2 + 'a` self.parse_remaining_bounds_path(ThinVec::new(), path, lo, true, ast::Parens::No) @@ -995,7 +1020,7 @@ impl<'a> Parser<'a> { let bound = GenericBound::Outlives(lt); if let ast::Parens::Yes = parens { // FIXME(Centril): Consider not erroring here and accepting `('lt)` instead, - // possibly introducing `GenericBound::Paren(P<GenericBound>)`? + // possibly introducing `GenericBound::Paren(Box<GenericBound>)`? self.recover_paren_lifetime(lo)?; } Ok(bound) @@ -1297,12 +1322,14 @@ impl<'a> Parser<'a> { segments: thin_vec![ast::PathSegment { ident: Ident::new(sym::Fn, fn_token_span), id: DUMMY_NODE_ID, - args: Some(P(ast::GenericArgs::Parenthesized(ast::ParenthesizedArgs { - span: args_lo.to(self.prev_token.span), - inputs: decl.inputs.iter().map(|a| a.ty.clone()).collect(), - inputs_span: args_lo.until(decl.output.span()), - output: decl.output.clone(), - }))), + args: Some(Box::new(ast::GenericArgs::Parenthesized( + ast::ParenthesizedArgs { + span: args_lo.to(self.prev_token.span), + inputs: decl.inputs.iter().map(|a| a.ty.clone()).collect(), + inputs_span: args_lo.until(decl.output.span()), + output: decl.output.clone(), + } + ))), }], tokens: None, }) @@ -1444,7 +1471,7 @@ impl<'a> Parser<'a> { } } - pub(super) fn mk_ty(&self, span: Span, kind: TyKind) -> P<Ty> { - P(Ty { kind, span, id: ast::DUMMY_NODE_ID, tokens: None }) + pub(super) fn mk_ty(&self, span: Span, kind: TyKind) -> Box<Ty> { + Box::new(Ty { kind, span, id: ast::DUMMY_NODE_ID, tokens: None }) } } diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index bc4c605afad..a7f8d3b9139 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -106,7 +106,7 @@ pub fn parse_meta<'a>(psess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Met res } else { // Example cases: - // - `#[foo = 1+1]`: results in `ast::ExprKind::BinOp`. + // - `#[foo = 1+1]`: results in `ast::ExprKind::Binary`. // - `#[foo = include_str!("nonexistent-file.rs")]`: // results in `ast::ExprKind::Err`. In that case we delay // the error because an earlier error will have already diff --git a/compiler/rustc_passes/Cargo.toml b/compiler/rustc_passes/Cargo.toml index 503fc98da76..ba81ef3103b 100644 --- a/compiler/rustc_passes/Cargo.toml +++ b/compiler/rustc_passes/Cargo.toml @@ -9,7 +9,6 @@ rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_lowering = { path = "../rustc_ast_lowering" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } -rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 0b329cc38b0..10c532b436a 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -11,10 +11,6 @@ use std::slice; use rustc_abi::{Align, ExternAbi, Size}; use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, ast, join_path_syms}; -use rustc_attr_data_structures::{ - AttributeKind, InlineAttr, PartialConstStability, ReprAttr, Stability, StabilityLevel, - find_attr, -}; use rustc_attr_parsing::{AttributeParser, Late}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey}; @@ -22,12 +18,14 @@ use rustc_feature::{ ACCEPTED_LANG_FEATURES, AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, }; +use rustc_hir::attrs::{AttributeKind, InlineAttr, ReprAttr}; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalModDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{ - self as hir, self, Attribute, CRATE_HIR_ID, CRATE_OWNER_ID, FnSig, ForeignItem, HirId, Item, - ItemKind, MethodKind, Safety, Target, TraitItem, + self as hir, Attribute, CRATE_HIR_ID, CRATE_OWNER_ID, FnSig, ForeignItem, HirId, Item, + ItemKind, MethodKind, PartialConstStability, Safety, Stability, StabilityLevel, Target, + TraitItem, find_attr, }; use rustc_macros::LintDiagnostic; use rustc_middle::hir::nested_filter; @@ -291,8 +289,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::MacroTransparency(_) | AttributeKind::Pointee(..) | AttributeKind::Dummy - | AttributeKind::RustcBuiltinMacro { .. } - | AttributeKind::OmitGdbPrettyPrinterSection, + | AttributeKind::RustcBuiltinMacro { .. }, ) => { /* do nothing */ } Attribute::Parsed(AttributeKind::AsPtr(attr_span)) => { self.check_applied_to_fn_or_method(hir_id, *attr_span, span, target) @@ -318,6 +315,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::Used { span: attr_span, .. }) => { self.check_used(*attr_span, target, span); } + Attribute::Parsed(AttributeKind::ShouldPanic { span: attr_span, .. }) => self + .check_generic_attr(hir_id, sym::should_panic, *attr_span, target, Target::Fn), &Attribute::Parsed(AttributeKind::PassByValue(attr_span)) => { self.check_pass_by_value(attr_span, span, target) } @@ -327,6 +326,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { &Attribute::Parsed(AttributeKind::Coverage(attr_span, _)) => { self.check_coverage(attr_span, span, target) } + &Attribute::Parsed(AttributeKind::Coroutine(attr_span)) => { + self.check_coroutine(attr_span, target) + } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); match attr.path().as_slice() { @@ -387,15 +389,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::link, ..] => self.check_link(hir_id, attr, span, target), [sym::path, ..] => self.check_generic_attr_unparsed(hir_id, attr, target, Target::Mod), [sym::macro_export, ..] => self.check_macro_export(hir_id, attr, target), - [sym::should_panic, ..] => { - self.check_generic_attr_unparsed(hir_id, attr, target, Target::Fn) - } [sym::autodiff_forward, ..] | [sym::autodiff_reverse, ..] => { self.check_autodiff(hir_id, attr, span, target) } - [sym::coroutine, ..] => { - self.check_coroutine(attr, target); - } [sym::linkage, ..] => self.check_linkage(attr, span, target), [ // ok @@ -2654,11 +2650,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_coroutine(&self, attr: &Attribute, target: Target) { + fn check_coroutine(&self, attr_span: Span, target: Target) { match target { Target::Closure => return, _ => { - self.dcx().emit_err(errors::CoroutineOnNonClosure { span: attr.span() }); + self.dcx().emit_err(errors::CoroutineOnNonClosure { span: attr_span }); } } } diff --git a/compiler/rustc_passes/src/check_export.rs b/compiler/rustc_passes/src/check_export.rs index b1f4584c2a8..6eded3a9eb9 100644 --- a/compiler/rustc_passes/src/check_export.rs +++ b/compiler/rustc_passes/src/check_export.rs @@ -2,11 +2,12 @@ use std::iter; use std::ops::ControlFlow; use rustc_abi::ExternAbi; -use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_hir as hir; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::find_attr; use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::hir::nested_filter; use rustc_middle::middle::privacy::{EffectiveVisibility, Level}; diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index a90d1af87ca..fa9d0c7b1b7 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -5,7 +5,6 @@ use std::mem; -use hir::ItemKind; use hir::def_id::{LocalDefIdMap, LocalDefIdSet}; use rustc_abi::FieldIdx; use rustc_data_structures::fx::FxIndexSet; @@ -14,7 +13,7 @@ use rustc_errors::MultiSpan; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{self as hir, ImplItem, ImplItemKind, Node, PatKind, QPath, TyKind}; +use rustc_hir::{self as hir, Node, PatKind, QPath}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::privacy::Level; use rustc_middle::query::Providers; @@ -28,37 +27,43 @@ use crate::errors::{ ChangeFields, IgnoredDerivedImpls, MultipleDeadCodes, ParentInfo, UselessAssignment, }; -// Any local node that may call something in its body block should be -// explored. For example, if it's a live Node::Item that is a -// function, then we should explore its block to check for codes that -// may need to be marked as live. +/// Any local definition that may call something in its body block should be explored. For example, +/// if it's a live function, then we should explore its block to check for codes that may need to +/// be marked as live. fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { - matches!( - tcx.hir_node_by_def_id(def_id), - Node::Item(..) - | Node::ImplItem(..) - | Node::ForeignItem(..) - | Node::TraitItem(..) - | Node::Variant(..) - | Node::AnonConst(..) - | Node::OpaqueTy(..) - ) -} - -/// Returns the local def id of the ADT if the given ty refers to a local one. -fn local_adt_def_of_ty<'tcx>(ty: &hir::Ty<'tcx>) -> Option<LocalDefId> { - match ty.kind { - TyKind::Path(QPath::Resolved(_, path)) => { - if let Res::Def(def_kind, def_id) = path.res - && let Some(local_def_id) = def_id.as_local() - && matches!(def_kind, DefKind::Struct | DefKind::Enum | DefKind::Union) - { - Some(local_def_id) - } else { - None - } - } - _ => None, + match tcx.def_kind(def_id) { + DefKind::Mod + | DefKind::Struct + | DefKind::Union + | DefKind::Enum + | DefKind::Variant + | DefKind::Trait + | DefKind::TyAlias + | DefKind::ForeignTy + | DefKind::TraitAlias + | DefKind::AssocTy + | DefKind::Fn + | DefKind::Const + | DefKind::Static { .. } + | DefKind::AssocFn + | DefKind::AssocConst + | DefKind::Macro(_) + | DefKind::GlobalAsm + | DefKind::Impl { .. } + | DefKind::OpaqueTy + | DefKind::AnonConst + | DefKind::InlineConst + | DefKind::ExternCrate + | DefKind::Use + | DefKind::Ctor(..) + | DefKind::ForeignMod => true, + + DefKind::TyParam + | DefKind::ConstParam + | DefKind::Field + | DefKind::LifetimeParam + | DefKind::Closure + | DefKind::SyntheticCoroutineBody => false, } } @@ -74,17 +79,16 @@ struct MarkSymbolVisitor<'tcx> { worklist: Vec<(LocalDefId, ComesFromAllowExpect)>, tcx: TyCtxt<'tcx>, maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>, + scanned: UnordSet<(LocalDefId, ComesFromAllowExpect)>, live_symbols: LocalDefIdSet, repr_unconditionally_treats_fields_as_live: bool, repr_has_repr_simd: bool, in_pat: bool, ignore_variant_stack: Vec<DefId>, - // maps from tuple struct constructors to tuple struct items - struct_constructors: LocalDefIdMap<LocalDefId>, // maps from ADTs to ignored derived traits (e.g. Debug and Clone) // and the span of their respective impl (i.e., part of the derive // macro) - ignored_derived_traits: LocalDefIdMap<FxIndexSet<(DefId, DefId)>>, + ignored_derived_traits: LocalDefIdMap<FxIndexSet<DefId>>, } impl<'tcx> MarkSymbolVisitor<'tcx> { @@ -99,7 +103,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { fn check_def_id(&mut self, def_id: DefId) { if let Some(def_id) = def_id.as_local() { - if should_explore(self.tcx, def_id) || self.struct_constructors.contains_key(&def_id) { + if should_explore(self.tcx, def_id) { self.worklist.push((def_id, ComesFromAllowExpect::No)); } self.live_symbols.insert(def_id); @@ -318,13 +322,12 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { } fn mark_live_symbols(&mut self) { - let mut scanned = UnordSet::default(); while let Some(work) = self.worklist.pop() { - if !scanned.insert(work) { + if !self.scanned.insert(work) { continue; } - let (id, comes_from_allow_expect) = work; + let (mut id, comes_from_allow_expect) = work; // Avoid accessing the HIR for the synthesized associated type generated for RPITITs. if self.tcx.is_impl_trait_in_trait(id.to_def_id()) { @@ -332,9 +335,11 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { continue; } - // in the case of tuple struct constructors we want to check the item, not the generated - // tuple struct constructor function - let id = self.struct_constructors.get(&id).copied().unwrap_or(id); + // in the case of tuple struct constructors we want to check the item, + // not the generated tuple struct constructor function + if let DefKind::Ctor(..) = self.tcx.def_kind(id) { + id = self.tcx.local_parent(id); + } // When using `#[allow]` or `#[expect]` of `dead_code`, we do a QOL improvement // by declaring fn calls, statics, ... within said items as live, as well as @@ -380,10 +385,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { if let ty::Adt(adt_def, _) = trait_ref.self_ty().kind() && let Some(adt_def_id) = adt_def.did().as_local() { - self.ignored_derived_traits - .entry(adt_def_id) - .or_default() - .insert((trait_of, impl_of)); + self.ignored_derived_traits.entry(adt_def_id).or_default().insert(trait_of); } return true; } @@ -478,24 +480,24 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { /// `local_def_id` points to an impl or an impl item, /// both impl and impl item that may be passed to this function are of a trait, /// and added into the unsolved_items during `create_and_seed_worklist` - fn check_impl_or_impl_item_live( - &mut self, - impl_id: hir::ItemId, - local_def_id: LocalDefId, - ) -> bool { - let trait_def_id = match self.tcx.def_kind(local_def_id) { + fn check_impl_or_impl_item_live(&mut self, local_def_id: LocalDefId) -> bool { + let (impl_block_id, trait_def_id) = match self.tcx.def_kind(local_def_id) { // assoc impl items of traits are live if the corresponding trait items are live - DefKind::AssocConst | DefKind::AssocTy | DefKind::AssocFn => self - .tcx - .associated_item(local_def_id) - .trait_item_def_id - .and_then(|def_id| def_id.as_local()), + DefKind::AssocConst | DefKind::AssocTy | DefKind::AssocFn => ( + self.tcx.local_parent(local_def_id), + self.tcx + .associated_item(local_def_id) + .trait_item_def_id + .and_then(|def_id| def_id.as_local()), + ), // impl items are live if the corresponding traits are live - DefKind::Impl { of_trait: true } => self - .tcx - .impl_trait_ref(impl_id.owner_id.def_id) - .and_then(|trait_ref| trait_ref.skip_binder().def_id.as_local()), - _ => None, + DefKind::Impl { of_trait: true } => ( + local_def_id, + self.tcx + .impl_trait_ref(local_def_id) + .and_then(|trait_ref| trait_ref.skip_binder().def_id.as_local()), + ), + _ => bug!(), }; if let Some(trait_def_id) = trait_def_id @@ -505,9 +507,9 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { } // The impl or impl item is used if the corresponding trait or trait item is used and the ty is used. - if let Some(local_def_id) = - local_adt_def_of_ty(self.tcx.hir_item(impl_id).expect_impl().self_ty) - && !self.live_symbols.contains(&local_def_id) + if let ty::Adt(adt, _) = self.tcx.type_of(impl_block_id).instantiate_identity().kind() + && let Some(adt_def_id) = adt.did().as_local() + && !self.live_symbols.contains(&adt_def_id) { return false; } @@ -714,139 +716,86 @@ fn has_allow_dead_code_or_lang_attr( } } -// These check_* functions seeds items that -// 1) We want to explicitly consider as live: -// * Item annotated with #[allow(dead_code)] -// - This is done so that if we want to suppress warnings for a -// group of dead functions, we only have to annotate the "root". -// For example, if both `f` and `g` are dead and `f` calls `g`, -// then annotating `f` with `#[allow(dead_code)]` will suppress -// warning for both `f` and `g`. -// * Item annotated with #[lang=".."] -// - This is because lang items are always callable from elsewhere. -// or -// 2) We are not sure to be live or not -// * Implementations of traits and trait methods -fn check_item<'tcx>( +/// Examine the given definition and record it in the worklist if it should be considered live. +/// +/// We want to explicitly consider as live: +/// * Item annotated with #[allow(dead_code)] +/// This is done so that if we want to suppress warnings for a +/// group of dead functions, we only have to annotate the "root". +/// For example, if both `f` and `g` are dead and `f` calls `g`, +/// then annotating `f` with `#[allow(dead_code)]` will suppress +/// warning for both `f` and `g`. +/// +/// * Item annotated with #[lang=".."] +/// Lang items are always callable from elsewhere. +/// +/// For trait methods and implementations of traits, we are not certain that the definitions are +/// live at this stage. We record them in `unsolved_items` for later examination. +fn maybe_record_as_seed<'tcx>( tcx: TyCtxt<'tcx>, + owner_id: hir::OwnerId, worklist: &mut Vec<(LocalDefId, ComesFromAllowExpect)>, - struct_constructors: &mut LocalDefIdMap<LocalDefId>, - unsolved_items: &mut Vec<(hir::ItemId, LocalDefId)>, - id: hir::ItemId, + unsolved_items: &mut Vec<LocalDefId>, ) { - let allow_dead_code = has_allow_dead_code_or_lang_attr(tcx, id.owner_id.def_id); + let allow_dead_code = has_allow_dead_code_or_lang_attr(tcx, owner_id.def_id); if let Some(comes_from_allow) = allow_dead_code { - worklist.push((id.owner_id.def_id, comes_from_allow)); + worklist.push((owner_id.def_id, comes_from_allow)); } - match tcx.def_kind(id.owner_id) { + match tcx.def_kind(owner_id) { DefKind::Enum => { - let item = tcx.hir_item(id); - if let hir::ItemKind::Enum(_, _, ref enum_def) = item.kind { - if let Some(comes_from_allow) = allow_dead_code { - worklist.extend( - enum_def.variants.iter().map(|variant| (variant.def_id, comes_from_allow)), - ); - } - - for variant in enum_def.variants { - if let Some(ctor_def_id) = variant.data.ctor_def_id() { - struct_constructors.insert(ctor_def_id, variant.def_id); - } - } + if let Some(comes_from_allow) = allow_dead_code { + let adt = tcx.adt_def(owner_id); + worklist.extend( + adt.variants() + .iter() + .map(|variant| (variant.def_id.expect_local(), comes_from_allow)), + ); } } - DefKind::Impl { of_trait } => { - if let Some(comes_from_allow) = - has_allow_dead_code_or_lang_attr(tcx, id.owner_id.def_id) - { - worklist.push((id.owner_id.def_id, comes_from_allow)); - } else if of_trait { - unsolved_items.push((id, id.owner_id.def_id)); - } - - for def_id in tcx.associated_item_def_ids(id.owner_id) { - let local_def_id = def_id.expect_local(); - - if let Some(comes_from_allow) = has_allow_dead_code_or_lang_attr(tcx, local_def_id) - { - worklist.push((local_def_id, comes_from_allow)); - } else if of_trait { - // We only care about associated items of traits, - // because they cannot be visited directly, - // so we later mark them as live if their corresponding traits - // or trait items and self types are both live, - // but inherent associated items can be visited and marked directly. - unsolved_items.push((id, local_def_id)); + DefKind::AssocFn | DefKind::AssocConst | DefKind::AssocTy => { + if allow_dead_code.is_none() { + let parent = tcx.local_parent(owner_id.def_id); + match tcx.def_kind(parent) { + DefKind::Impl { of_trait: false } | DefKind::Trait => {} + DefKind::Impl { of_trait: true } => { + // We only care about associated items of traits, + // because they cannot be visited directly, + // so we later mark them as live if their corresponding traits + // or trait items and self types are both live, + // but inherent associated items can be visited and marked directly. + unsolved_items.push(owner_id.def_id); + } + _ => bug!(), } } } - DefKind::Struct => { - let item = tcx.hir_item(id); - if let hir::ItemKind::Struct(_, _, ref variant_data) = item.kind - && let Some(ctor_def_id) = variant_data.ctor_def_id() - { - struct_constructors.insert(ctor_def_id, item.owner_id.def_id); + DefKind::Impl { of_trait: true } => { + if allow_dead_code.is_none() { + unsolved_items.push(owner_id.def_id); } } DefKind::GlobalAsm => { // global_asm! is always live. - worklist.push((id.owner_id.def_id, ComesFromAllowExpect::No)); + worklist.push((owner_id.def_id, ComesFromAllowExpect::No)); } DefKind::Const => { - let item = tcx.hir_item(id); - if let hir::ItemKind::Const(ident, ..) = item.kind - && ident.name == kw::Underscore - { + if tcx.item_name(owner_id.def_id) == kw::Underscore { // `const _` is always live, as that syntax only exists for the side effects // of type checking and evaluating the constant expression, and marking them // as dead code would defeat that purpose. - worklist.push((id.owner_id.def_id, ComesFromAllowExpect::No)); + worklist.push((owner_id.def_id, ComesFromAllowExpect::No)); } } _ => {} } } -fn check_trait_item( - tcx: TyCtxt<'_>, - worklist: &mut Vec<(LocalDefId, ComesFromAllowExpect)>, - id: hir::TraitItemId, -) { - use hir::TraitItemKind::{Const, Fn, Type}; - - let trait_item = tcx.hir_trait_item(id); - if matches!(trait_item.kind, Const(_, Some(_)) | Type(_, Some(_)) | Fn(..)) - && let Some(comes_from_allow) = - has_allow_dead_code_or_lang_attr(tcx, trait_item.owner_id.def_id) - { - worklist.push((trait_item.owner_id.def_id, comes_from_allow)); - } -} - -fn check_foreign_item( - tcx: TyCtxt<'_>, - worklist: &mut Vec<(LocalDefId, ComesFromAllowExpect)>, - id: hir::ForeignItemId, -) { - if matches!(tcx.def_kind(id.owner_id), DefKind::Static { .. } | DefKind::Fn) - && let Some(comes_from_allow) = has_allow_dead_code_or_lang_attr(tcx, id.owner_id.def_id) - { - worklist.push((id.owner_id.def_id, comes_from_allow)); - } -} - fn create_and_seed_worklist( tcx: TyCtxt<'_>, -) -> ( - Vec<(LocalDefId, ComesFromAllowExpect)>, - LocalDefIdMap<LocalDefId>, - Vec<(hir::ItemId, LocalDefId)>, -) { +) -> (Vec<(LocalDefId, ComesFromAllowExpect)>, Vec<LocalDefId>) { let effective_visibilities = &tcx.effective_visibilities(()); - // see `MarkSymbolVisitor::struct_constructors` let mut unsolved_impl_item = Vec::new(); - let mut struct_constructors = Default::default(); let mut worklist = effective_visibilities .iter() .filter_map(|(&id, effective_vis)| { @@ -863,54 +812,49 @@ fn create_and_seed_worklist( .collect::<Vec<_>>(); let crate_items = tcx.hir_crate_items(()); - for id in crate_items.free_items() { - check_item(tcx, &mut worklist, &mut struct_constructors, &mut unsolved_impl_item, id); - } - - for id in crate_items.trait_items() { - check_trait_item(tcx, &mut worklist, id); - } - - for id in crate_items.foreign_items() { - check_foreign_item(tcx, &mut worklist, id); + for id in crate_items.owners() { + maybe_record_as_seed(tcx, id, &mut worklist, &mut unsolved_impl_item); } - (worklist, struct_constructors, unsolved_impl_item) + (worklist, unsolved_impl_item) } fn live_symbols_and_ignored_derived_traits( tcx: TyCtxt<'_>, (): (), -) -> (LocalDefIdSet, LocalDefIdMap<FxIndexSet<(DefId, DefId)>>) { - let (worklist, struct_constructors, mut unsolved_items) = create_and_seed_worklist(tcx); +) -> (LocalDefIdSet, LocalDefIdMap<FxIndexSet<DefId>>) { + let (worklist, mut unsolved_items) = create_and_seed_worklist(tcx); let mut symbol_visitor = MarkSymbolVisitor { worklist, tcx, maybe_typeck_results: None, + scanned: Default::default(), live_symbols: Default::default(), repr_unconditionally_treats_fields_as_live: false, repr_has_repr_simd: false, in_pat: false, ignore_variant_stack: vec![], - struct_constructors, ignored_derived_traits: Default::default(), }; symbol_visitor.mark_live_symbols(); - let mut items_to_check; - (items_to_check, unsolved_items) = - unsolved_items.into_iter().partition(|&(impl_id, local_def_id)| { - symbol_visitor.check_impl_or_impl_item_live(impl_id, local_def_id) - }); + + // We have marked the primary seeds as live. We now need to process unsolved items from traits + // and trait impls: add them to the work list if the trait or the implemented type is live. + let mut items_to_check: Vec<_> = unsolved_items + .extract_if(.., |&mut local_def_id| { + symbol_visitor.check_impl_or_impl_item_live(local_def_id) + }) + .collect(); while !items_to_check.is_empty() { - symbol_visitor.worklist = - items_to_check.into_iter().map(|(_, id)| (id, ComesFromAllowExpect::No)).collect(); + symbol_visitor + .worklist + .extend(items_to_check.drain(..).map(|id| (id, ComesFromAllowExpect::No))); symbol_visitor.mark_live_symbols(); - (items_to_check, unsolved_items) = - unsolved_items.into_iter().partition(|&(impl_id, local_def_id)| { - symbol_visitor.check_impl_or_impl_item_live(impl_id, local_def_id) - }); + items_to_check.extend(unsolved_items.extract_if(.., |&mut local_def_id| { + symbol_visitor.check_impl_or_impl_item_live(local_def_id) + })); } (symbol_visitor.live_symbols, symbol_visitor.ignored_derived_traits) @@ -925,7 +869,7 @@ struct DeadItem { struct DeadVisitor<'tcx> { tcx: TyCtxt<'tcx>, live_symbols: &'tcx LocalDefIdSet, - ignored_derived_traits: &'tcx LocalDefIdMap<FxIndexSet<(DefId, DefId)>>, + ignored_derived_traits: &'tcx LocalDefIdMap<FxIndexSet<DefId>>, } enum ShouldWarnAboutField { @@ -984,25 +928,7 @@ impl<'tcx> DeadVisitor<'tcx> { parent_item: Option<LocalDefId>, report_on: ReportOn, ) { - fn get_parent_if_enum_variant<'tcx>( - tcx: TyCtxt<'tcx>, - may_variant: LocalDefId, - ) -> LocalDefId { - if let Node::Variant(_) = tcx.hir_node_by_def_id(may_variant) - && let Some(enum_did) = tcx.opt_parent(may_variant.to_def_id()) - && let Some(enum_local_id) = enum_did.as_local() - && let Node::Item(item) = tcx.hir_node_by_def_id(enum_local_id) - && let ItemKind::Enum(..) = item.kind - { - enum_local_id - } else { - may_variant - } - } - - let Some(&first_item) = dead_codes.first() else { - return; - }; + let Some(&first_item) = dead_codes.first() else { return }; let tcx = self.tcx; let first_lint_level = first_item.level; @@ -1011,81 +937,54 @@ impl<'tcx> DeadVisitor<'tcx> { let names: Vec<_> = dead_codes.iter().map(|item| item.name).collect(); let spans: Vec<_> = dead_codes .iter() - .map(|item| match tcx.def_ident_span(item.def_id) { - Some(s) => s.with_ctxt(tcx.def_span(item.def_id).ctxt()), - None => tcx.def_span(item.def_id), + .map(|item| { + let span = tcx.def_span(item.def_id); + let ident_span = tcx.def_ident_span(item.def_id); + // FIXME(cjgillot) this SyntaxContext manipulation does not make any sense. + ident_span.map(|s| s.with_ctxt(span.ctxt())).unwrap_or(span) }) .collect(); - let descr = tcx.def_descr(first_item.def_id.to_def_id()); + let mut descr = tcx.def_descr(first_item.def_id.to_def_id()); // `impl` blocks are "batched" and (unlike other batching) might // contain different kinds of associated items. - let descr = if dead_codes.iter().any(|item| tcx.def_descr(item.def_id.to_def_id()) != descr) - { - "associated item" - } else { - descr - }; + if dead_codes.iter().any(|item| tcx.def_descr(item.def_id.to_def_id()) != descr) { + descr = "associated item" + } + let num = dead_codes.len(); let multiple = num > 6; let name_list = names.into(); - let parent_info = if let Some(parent_item) = parent_item { + let parent_info = parent_item.map(|parent_item| { let parent_descr = tcx.def_descr(parent_item.to_def_id()); let span = if let DefKind::Impl { .. } = tcx.def_kind(parent_item) { tcx.def_span(parent_item) } else { tcx.def_ident_span(parent_item).unwrap() }; - Some(ParentInfo { num, descr, parent_descr, span }) - } else { - None - }; + ParentInfo { num, descr, parent_descr, span } + }); - let encl_def_id = parent_item.unwrap_or(first_item.def_id); - // If parent of encl_def_id is an enum, use the parent ID instead. - let encl_def_id = get_parent_if_enum_variant(tcx, encl_def_id); + let mut encl_def_id = parent_item.unwrap_or(first_item.def_id); + // `ignored_derived_traits` is computed for the enum, not for the variants. + if let DefKind::Variant = tcx.def_kind(encl_def_id) { + encl_def_id = tcx.local_parent(encl_def_id); + } let ignored_derived_impls = - if let Some(ign_traits) = self.ignored_derived_traits.get(&encl_def_id) { + self.ignored_derived_traits.get(&encl_def_id).map(|ign_traits| { let trait_list = ign_traits .iter() - .map(|(trait_id, _)| self.tcx.item_name(*trait_id)) + .map(|trait_id| self.tcx.item_name(*trait_id)) .collect::<Vec<_>>(); let trait_list_len = trait_list.len(); - Some(IgnoredDerivedImpls { + IgnoredDerivedImpls { name: self.tcx.item_name(encl_def_id.to_def_id()), trait_list: trait_list.into(), trait_list_len, - }) - } else { - None - }; - - let enum_variants_with_same_name = dead_codes - .iter() - .filter_map(|dead_item| { - if let Node::ImplItem(ImplItem { - kind: ImplItemKind::Fn(..) | ImplItemKind::Const(..), - .. - }) = tcx.hir_node_by_def_id(dead_item.def_id) - && let Some(impl_did) = tcx.opt_parent(dead_item.def_id.to_def_id()) - && let DefKind::Impl { of_trait: false } = tcx.def_kind(impl_did) - && let ty::Adt(maybe_enum, _) = tcx.type_of(impl_did).skip_binder().kind() - && maybe_enum.is_enum() - && let Some(variant) = - maybe_enum.variants().iter().find(|i| i.name == dead_item.name) - { - Some(crate::errors::EnumVariantSameName { - dead_descr: tcx.def_descr(dead_item.def_id.to_def_id()), - dead_name: dead_item.name, - variant_span: tcx.def_span(variant.def_id), - }) - } else { - None } - }) - .collect(); + }); let diag = match report_on { ReportOn::TupleField => { @@ -1132,16 +1031,42 @@ impl<'tcx> DeadVisitor<'tcx> { ignored_derived_impls, } } - ReportOn::NamedField => MultipleDeadCodes::DeadCodes { - multiple, - num, - descr, - participle, - name_list, - parent_info, - ignored_derived_impls, - enum_variants_with_same_name, - }, + ReportOn::NamedField => { + let enum_variants_with_same_name = dead_codes + .iter() + .filter_map(|dead_item| { + if let DefKind::AssocFn | DefKind::AssocConst = + tcx.def_kind(dead_item.def_id) + && let impl_did = tcx.local_parent(dead_item.def_id) + && let DefKind::Impl { of_trait: false } = tcx.def_kind(impl_did) + && let ty::Adt(maybe_enum, _) = + tcx.type_of(impl_did).instantiate_identity().kind() + && maybe_enum.is_enum() + && let Some(variant) = + maybe_enum.variants().iter().find(|i| i.name == dead_item.name) + { + Some(crate::errors::EnumVariantSameName { + dead_descr: tcx.def_descr(dead_item.def_id.to_def_id()), + dead_name: dead_item.name, + variant_span: tcx.def_span(variant.def_id), + }) + } else { + None + } + }) + .collect(); + + MultipleDeadCodes::DeadCodes { + multiple, + num, + descr, + participle, + name_list, + parent_info, + ignored_derived_impls, + enum_variants_with_same_name, + } + } }; let hir_id = tcx.local_def_id_to_hir_id(first_item.def_id); diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs index 6ee325dce03..c83610da1aa 100644 --- a/compiler/rustc_passes/src/input_stats.rs +++ b/compiler/rustc_passes/src/input_stats.rs @@ -44,11 +44,11 @@ impl Node { /// For example, `ast::Visitor` has `visit_ident`, but `Ident`s are always /// stored inline within other AST nodes, so we don't implement `visit_ident` /// here. In contrast, we do implement `visit_expr` because `ast::Expr` is -/// always stored as `P<ast::Expr>`, and every such expression should be +/// always stored as `Box<ast::Expr>`, and every such expression should be /// measured separately. /// /// In general, a `visit_foo` method should be implemented here if the -/// corresponding `Foo` type is always stored on its own, e.g.: `P<Foo>`, +/// corresponding `Foo` type is always stored on its own, e.g.: `Box<Foo>`, /// `Box<Foo>`, `Vec<Foo>`, `Box<[Foo]>`. /// /// There are some types in the AST and HIR tree that the visitors do not have diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index af7ecf0830c..2ad0b5ff60e 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -8,6 +8,7 @@ #![allow(internal_features)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] +#![feature(if_let_guard)] #![feature(map_try_insert)] #![feature(rustdoc_internals)] // tidy-alphabetical-end diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs index 35d2a655991..8d0ef88610a 100644 --- a/compiler/rustc_passes/src/lib_features.rs +++ b/compiler/rustc_passes/src/lib_features.rs @@ -4,9 +4,9 @@ //! but are not declared in one single location (unlike lang features), which means we need to //! collect them instead. -use rustc_attr_data_structures::{AttributeKind, StabilityLevel, StableSince}; -use rustc_hir::Attribute; +use rustc_hir::attrs::AttributeKind; use rustc_hir::intravisit::Visitor; +use rustc_hir::{Attribute, StabilityLevel, StableSince}; use rustc_middle::hir::nested_filter; use rustc_middle::middle::lib_features::{FeatureStability, LibFeatures}; use rustc_middle::query::{LocalCrate, Providers}; diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 7350c6a5a82..801a533c943 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -85,13 +85,13 @@ use std::io; use std::io::prelude::*; use std::rc::Rc; -use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fx::FxIndexMap; use rustc_hir as hir; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::*; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{Expr, HirId, HirIdMap, HirIdSet}; +use rustc_hir::{Expr, HirId, HirIdMap, HirIdSet, find_attr}; use rustc_index::IndexVec; use rustc_middle::query::Providers; use rustc_middle::span_bug; diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index abc1821e76d..e2f223325df 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -4,17 +4,18 @@ use std::num::NonZero; use rustc_ast_lowering::stability::extern_abi_stability; -use rustc_attr_data_structures::{ - self as attrs, AttributeKind, ConstStability, DefaultBodyStability, DeprecatedSince, Stability, - StabilityLevel, StableSince, UnstableReason, VERSION_PLACEHOLDER, find_attr, -}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet}; use rustc_feature::{EnabledLangFeature, EnabledLibFeature}; +use rustc_hir::attrs::{AttributeKind, DeprecatedSince}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId, LocalModDefId}; use rustc_hir::intravisit::{self, Visitor, VisitorExt}; -use rustc_hir::{self as hir, AmbigArg, FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant}; +use rustc_hir::{ + self as hir, AmbigArg, ConstStability, DefaultBodyStability, FieldDef, Item, ItemKind, + Stability, StabilityLevel, StableSince, TraitRef, Ty, TyKind, UnstableReason, + VERSION_PLACEHOLDER, Variant, find_attr, +}; use rustc_middle::hir::nested_filter; use rustc_middle::middle::lib_features::{FeatureStability, LibFeatures}; use rustc_middle::middle::privacy::EffectiveVisibilities; @@ -96,7 +97,7 @@ fn annotation_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> AnnotationKind { fn lookup_deprecation_entry(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<DeprecationEntry> { let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id)); - let depr = attrs::find_attr!(attrs, + let depr = find_attr!(attrs, AttributeKind::Deprecation { deprecation, span: _ } => *deprecation ); @@ -128,7 +129,7 @@ fn inherit_stability(def_kind: DefKind) -> bool { /// while maintaining the invariant that all sysroot crates are unstable /// by default and are unable to be used. const FORCE_UNSTABLE: Stability = Stability { - level: attrs::StabilityLevel::Unstable { + level: StabilityLevel::Unstable { reason: UnstableReason::Default, issue: NonZero::new(27812), is_soft: false, @@ -161,8 +162,7 @@ fn lookup_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<Stability> { // # Regular stability let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id)); - let stab = - attrs::find_attr!(attrs, AttributeKind::Stability { stability, span: _ } => *stability); + let stab = find_attr!(attrs, AttributeKind::Stability { stability, span: _ } => *stability); if let Some(stab) = stab { return Some(stab); @@ -197,7 +197,7 @@ fn lookup_default_body_stability( let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id)); // FIXME: check that this item can have body stability - attrs::find_attr!(attrs, AttributeKind::BodyStability { stability, .. } => *stability) + find_attr!(attrs, AttributeKind::BodyStability { stability, .. } => *stability) } #[instrument(level = "debug", skip(tcx))] @@ -224,7 +224,8 @@ fn lookup_const_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ConstSt let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id)); let const_stability_indirect = find_attr!(attrs, AttributeKind::ConstStabilityIndirect); - let const_stab = attrs::find_attr!(attrs, AttributeKind::ConstStability { stability, span: _ } => *stability); + let const_stab = + find_attr!(attrs, AttributeKind::ConstStability { stability, span: _ } => *stability); // After checking the immediate attributes, get rid of the span and compute implied // const stability: inherit feature gate from regular stability. @@ -334,7 +335,7 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { macro_rules! find_attr_span { ($name:ident) => {{ let attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id)); - attrs::find_attr!(attrs, AttributeKind::$name { span, .. } => *span) + find_attr!(attrs, AttributeKind::$name { span, .. } => *span) }} } @@ -361,7 +362,7 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { // this is *almost surely* an accident. if let Some(depr) = depr && let DeprecatedSince::RustcVersion(dep_since) = depr.attr.since - && let attrs::StabilityLevel::Stable { since: stab_since, .. } = stab.level + && let StabilityLevel::Stable { since: stab_since, .. } = stab.level && let Some(span) = find_attr_span!(Stability) { let item_sp = self.tcx.def_span(def_id); @@ -595,10 +596,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { let features = self.tcx.features(); if features.staged_api() { let attrs = self.tcx.hir_attrs(item.hir_id()); - let stab = attrs::find_attr!(attrs, AttributeKind::Stability{stability, span} => (*stability, *span)); + let stab = find_attr!(attrs, AttributeKind::Stability{stability, span} => (*stability, *span)); // FIXME(jdonszelmann): make it impossible to miss the or_else in the typesystem - let const_stab = attrs::find_attr!(attrs, AttributeKind::ConstStability{stability, ..} => *stability); + let const_stab = find_attr!(attrs, AttributeKind::ConstStability{stability, ..} => *stability); let unstable_feature_stab = find_attr!(attrs, AttributeKind::UnstableFeatureBound(i) => i) @@ -621,7 +622,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { // impl Foo for Bar {} // ``` if let Some(( - Stability { level: attrs::StabilityLevel::Unstable { .. }, feature }, + Stability { level: StabilityLevel::Unstable { .. }, feature }, span, )) = stab { diff --git a/compiler/rustc_pattern_analysis/Cargo.toml b/compiler/rustc_pattern_analysis/Cargo.toml index 40d549630ac..a59f7bbeb9e 100644 --- a/compiler/rustc_pattern_analysis/Cargo.toml +++ b/compiler/rustc_pattern_analysis/Cargo.toml @@ -6,7 +6,6 @@ edition = "2024" [dependencies] # tidy-alphabetical-start rustc-hash = "2.0.0" - rustc_abi = { path = "../rustc_abi", optional = true } rustc_apfloat = "0.2.0" rustc_arena = { path = "../rustc_arena", optional = true } @@ -24,10 +23,13 @@ tracing = "0.1" # tidy-alphabetical-end [dev-dependencies] +# tidy-alphabetical-start tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "ansi"] } tracing-tree = "0.3.0" +# tidy-alphabetical-end [features] +# tidy-alphabetical-start default = ["rustc"] rustc = [ "dep:rustc_abi", @@ -43,3 +45,4 @@ rustc = [ "smallvec/may_dangle", "rustc_index/nightly", ] +# tidy-alphabetical-end diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs index 9a9e0db964c..12f653a1337 100644 --- a/compiler/rustc_pattern_analysis/src/constructor.rs +++ b/compiler/rustc_pattern_analysis/src/constructor.rs @@ -1130,16 +1130,16 @@ impl<Cx: PatCx> ConstructorSet<Cx> { seen_false = true; } } - if seen_false { - present.push(Bool(false)); - } else { - missing.push(Bool(false)); - } if seen_true { present.push(Bool(true)); } else { missing.push(Bool(true)); } + if seen_false { + present.push(Bool(false)); + } else { + missing.push(Bool(false)); + } } ConstructorSet::Integers { range_1, range_2 } => { let seen_ranges: Vec<_> = diff --git a/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs b/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs index 14ca0d057f0..4ad64f81560 100644 --- a/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs +++ b/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs @@ -176,6 +176,9 @@ fn test_witnesses() { ), vec!["Enum::Variant1(_)", "Enum::Variant2(_)", "_"], ); + + // Assert we put `true` before `false`. + assert_witnesses(AllOfThem, Ty::Bool, Vec::new(), vec!["true", "false"]); } #[test] diff --git a/compiler/rustc_privacy/Cargo.toml b/compiler/rustc_privacy/Cargo.toml index 109a7bf49fe..c8bfdb91304 100644 --- a/compiler/rustc_privacy/Cargo.toml +++ b/compiler/rustc_privacy/Cargo.toml @@ -6,7 +6,6 @@ edition = "2024" [dependencies] # tidy-alphabetical-start rustc_ast = { path = "../rustc_ast" } -rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index b4fa11a8eb3..5d02c02b23c 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -23,10 +23,12 @@ use rustc_ast::visit::{VisitorResult, try_visit}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::intern::Interned; use rustc_errors::{MultiSpan, listify}; +use rustc_hir as hir; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId, LocalModDefId}; +use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::intravisit::{self, InferKind, Visitor}; -use rustc_hir::{AmbigArg, ForeignItemId, ItemId, PatKind}; +use rustc_hir::{AmbigArg, ForeignItemId, ItemId, OwnerId, PatKind, find_attr}; use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility, Level}; use rustc_middle::query::Providers; use rustc_middle::ty::print::PrintTraitRefExt as _; @@ -39,7 +41,6 @@ use rustc_session::lint; use rustc_span::hygiene::Transparency; use rustc_span::{Ident, Span, Symbol, sym}; use tracing::debug; -use {rustc_attr_data_structures as attrs, rustc_hir as hir}; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } @@ -495,7 +496,7 @@ impl<'tcx> EmbargoVisitor<'tcx> { let hir_id = self.tcx.local_def_id_to_hir_id(local_def_id); let attrs = self.tcx.hir_attrs(hir_id); - if attrs::find_attr!(attrs, attrs::AttributeKind::MacroTransparency(x) => *x) + if find_attr!(attrs, AttributeKind::MacroTransparency(x) => *x) .unwrap_or(Transparency::fallback(md.macro_rules)) != Transparency::Opaque { @@ -598,7 +599,7 @@ impl<'tcx> EmbargoVisitor<'tcx> { DefKind::Struct | DefKind::Union => { // While structs and unions have type privacy, their fields do not. let struct_def = self.tcx.adt_def(def_id); - for field in struct_def.non_enum_variant().fields.iter() { + for field in &struct_def.non_enum_variant().fields { let def_id = field.did.expect_local(); let field_vis = self.tcx.local_visibility(def_id); if field_vis.is_accessible_from(module, self.tcx) { @@ -636,45 +637,49 @@ impl<'tcx> EmbargoVisitor<'tcx> { } } -impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { - fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { +impl<'tcx> EmbargoVisitor<'tcx> { + fn check_def_id(&mut self, owner_id: OwnerId) { // Update levels of nested things and mark all items // in interfaces of reachable items as reachable. - let item_ev = self.get(item.owner_id.def_id); - match item.kind { + let item_ev = self.get(owner_id.def_id); + match self.tcx.def_kind(owner_id) { // The interface is empty, and no nested items. - hir::ItemKind::Use(..) - | hir::ItemKind::ExternCrate(..) - | hir::ItemKind::GlobalAsm { .. } => {} - // The interface is empty, and all nested items are processed by `visit_item`. - hir::ItemKind::Mod(..) => {} - hir::ItemKind::Macro(_, macro_def, _) => { + DefKind::Use | DefKind::ExternCrate | DefKind::GlobalAsm => {} + // The interface is empty, and all nested items are processed by `check_def_id`. + DefKind::Mod => {} + DefKind::Macro { .. } => { if let Some(item_ev) = item_ev { - self.update_reachability_from_macro(item.owner_id.def_id, macro_def, item_ev); + let (_, macro_def, _) = + self.tcx.hir_expect_item(owner_id.def_id).expect_macro(); + self.update_reachability_from_macro(owner_id.def_id, macro_def, item_ev); } } - hir::ItemKind::Const(..) - | hir::ItemKind::Static(..) - | hir::ItemKind::Fn { .. } - | hir::ItemKind::TyAlias(..) => { + DefKind::ForeignTy + | DefKind::Const + | DefKind::Static { .. } + | DefKind::Fn + | DefKind::TyAlias => { if let Some(item_ev) = item_ev { - self.reach(item.owner_id.def_id, item_ev).generics().predicates().ty(); + self.reach(owner_id.def_id, item_ev).generics().predicates().ty(); } } - hir::ItemKind::Trait(.., trait_item_refs) => { + DefKind::Trait => { if let Some(item_ev) = item_ev { - self.reach(item.owner_id.def_id, item_ev).generics().predicates(); + self.reach(owner_id.def_id, item_ev).generics().predicates(); - for trait_item_ref in trait_item_refs { - self.update(trait_item_ref.owner_id.def_id, item_ev, Level::Reachable); + for assoc_item in self.tcx.associated_items(owner_id).in_definition_order() { + if assoc_item.is_impl_trait_in_trait() { + continue; + } + + let def_id = assoc_item.def_id.expect_local(); + self.update(def_id, item_ev, Level::Reachable); let tcx = self.tcx; - let mut reach = self.reach(trait_item_ref.owner_id.def_id, item_ev); + let mut reach = self.reach(def_id, item_ev); reach.generics().predicates(); - if let DefKind::AssocTy = tcx.def_kind(trait_item_ref.owner_id) - && !tcx.defaultness(trait_item_ref.owner_id).has_value() - { + if assoc_item.is_type() && !assoc_item.defaultness(tcx).has_value() { // No type to visit. } else { reach.ty(); @@ -682,12 +687,12 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { } } } - hir::ItemKind::TraitAlias(..) => { + DefKind::TraitAlias => { if let Some(item_ev) = item_ev { - self.reach(item.owner_id.def_id, item_ev).generics().predicates(); + self.reach(owner_id.def_id, item_ev).generics().predicates(); } } - hir::ItemKind::Impl(impl_) => { + DefKind::Impl { of_trait } => { // Type inference is very smart sometimes. It can make an impl reachable even some // components of its type or trait are unreachable. E.g. methods of // `impl ReachableTrait<UnreachableTy> for ReachableTy<UnreachableTy> { ... }` @@ -699,19 +704,23 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { // without knowing both "shallow" version of its self type and "shallow" version of // its trait if it exists (which require reaching the `DefId`s in them). let item_ev = EffectiveVisibility::of_impl::<true>( - item.owner_id.def_id, + owner_id.def_id, self.tcx, &self.effective_visibilities, ); - self.update_eff_vis(item.owner_id.def_id, item_ev, None, Level::Direct); + self.update_eff_vis(owner_id.def_id, item_ev, None, Level::Direct); + + self.reach(owner_id.def_id, item_ev).generics().predicates().ty().trait_ref(); - self.reach(item.owner_id.def_id, item_ev).generics().predicates().ty().trait_ref(); + for assoc_item in self.tcx.associated_items(owner_id).in_definition_order() { + if assoc_item.is_impl_trait_in_trait() { + continue; + } - for impl_item_ref in impl_.items { - let def_id = impl_item_ref.owner_id.def_id; + let def_id = assoc_item.def_id.expect_local(); let max_vis = - impl_.of_trait.is_none().then(|| self.tcx.local_visibility(def_id)); + if of_trait { None } else { Some(self.tcx.local_visibility(def_id)) }; self.update_eff_vis(def_id, item_ev, max_vis, Level::Direct); if let Some(impl_item_ev) = self.get(def_id) { @@ -719,65 +728,76 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { } } } - hir::ItemKind::Enum(_, _, ref def) => { + DefKind::Enum => { if let Some(item_ev) = item_ev { - self.reach(item.owner_id.def_id, item_ev).generics().predicates(); + self.reach(owner_id.def_id, item_ev).generics().predicates(); } - for variant in def.variants { + let def = self.tcx.adt_def(owner_id); + for variant in def.variants() { if let Some(item_ev) = item_ev { - self.update(variant.def_id, item_ev, Level::Reachable); + self.update(variant.def_id.expect_local(), item_ev, Level::Reachable); } - if let Some(variant_ev) = self.get(variant.def_id) { - if let Some(ctor_def_id) = variant.data.ctor_def_id() { - self.update(ctor_def_id, variant_ev, Level::Reachable); + if let Some(variant_ev) = self.get(variant.def_id.expect_local()) { + if let Some(ctor_def_id) = variant.ctor_def_id() { + self.update(ctor_def_id.expect_local(), variant_ev, Level::Reachable); } - for field in variant.data.fields() { - self.update(field.def_id, variant_ev, Level::Reachable); - self.reach(field.def_id, variant_ev).ty(); + for field in &variant.fields { + let field = field.did.expect_local(); + self.update(field, variant_ev, Level::Reachable); + self.reach(field, variant_ev).ty(); } // Corner case: if the variant is reachable, but its // enum is not, make the enum reachable as well. - self.reach(item.owner_id.def_id, variant_ev).ty(); + self.reach(owner_id.def_id, variant_ev).ty(); } - if let Some(ctor_def_id) = variant.data.ctor_def_id() { - if let Some(ctor_ev) = self.get(ctor_def_id) { - self.reach(item.owner_id.def_id, ctor_ev).ty(); + if let Some(ctor_def_id) = variant.ctor_def_id() { + if let Some(ctor_ev) = self.get(ctor_def_id.expect_local()) { + self.reach(owner_id.def_id, ctor_ev).ty(); } } } } - hir::ItemKind::ForeignMod { items, .. } => { - for foreign_item in items { - if let Some(foreign_item_ev) = self.get(foreign_item.owner_id.def_id) { - self.reach(foreign_item.owner_id.def_id, foreign_item_ev) - .generics() - .predicates() - .ty(); - } - } - } - hir::ItemKind::Struct(_, _, ref struct_def) - | hir::ItemKind::Union(_, _, ref struct_def) => { + DefKind::Struct | DefKind::Union => { + let def = self.tcx.adt_def(owner_id).non_enum_variant(); if let Some(item_ev) = item_ev { - self.reach(item.owner_id.def_id, item_ev).generics().predicates(); - for field in struct_def.fields() { - self.update(field.def_id, item_ev, Level::Reachable); - if let Some(field_ev) = self.get(field.def_id) { - self.reach(field.def_id, field_ev).ty(); + self.reach(owner_id.def_id, item_ev).generics().predicates(); + for field in &def.fields { + let field = field.did.expect_local(); + self.update(field, item_ev, Level::Reachable); + if let Some(field_ev) = self.get(field) { + self.reach(field, field_ev).ty(); } } } - if let Some(ctor_def_id) = struct_def.ctor_def_id() { + if let Some(ctor_def_id) = def.ctor_def_id() { if let Some(item_ev) = item_ev { - self.update(ctor_def_id, item_ev, Level::Reachable); + self.update(ctor_def_id.expect_local(), item_ev, Level::Reachable); } - if let Some(ctor_ev) = self.get(ctor_def_id) { - self.reach(item.owner_id.def_id, ctor_ev).ty(); + if let Some(ctor_ev) = self.get(ctor_def_id.expect_local()) { + self.reach(owner_id.def_id, ctor_ev).ty(); } } } + // Contents are checked directly. + DefKind::ForeignMod => {} + DefKind::Field + | DefKind::Variant + | DefKind::AssocFn + | DefKind::AssocTy + | DefKind::AssocConst + | DefKind::TyParam + | DefKind::AnonConst + | DefKind::InlineConst + | DefKind::OpaqueTy + | DefKind::Closure + | DefKind::SyntheticCoroutineBody + | DefKind::ConstParam + | DefKind::LifetimeParam + | DefKind::Ctor(..) => { + bug!("should be checked while checking parent") + } } } } @@ -838,7 +858,7 @@ pub struct TestReachabilityVisitor<'a, 'tcx> { } impl<'a, 'tcx> TestReachabilityVisitor<'a, 'tcx> { - fn effective_visibility_diagnostic(&mut self, def_id: LocalDefId) { + fn effective_visibility_diagnostic(&self, def_id: LocalDefId) { if self.tcx.has_attr(def_id, sym::rustc_effective_visibility) { let mut error_msg = String::new(); let span = self.tcx.def_span(def_id.to_def_id()); @@ -858,43 +878,35 @@ impl<'a, 'tcx> TestReachabilityVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for TestReachabilityVisitor<'a, 'tcx> { - fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { - self.effective_visibility_diagnostic(item.owner_id.def_id); +impl<'a, 'tcx> TestReachabilityVisitor<'a, 'tcx> { + fn check_def_id(&self, owner_id: OwnerId) { + self.effective_visibility_diagnostic(owner_id.def_id); - match item.kind { - hir::ItemKind::Enum(_, _, ref def) => { - for variant in def.variants.iter() { - self.effective_visibility_diagnostic(variant.def_id); - if let Some(ctor_def_id) = variant.data.ctor_def_id() { - self.effective_visibility_diagnostic(ctor_def_id); + match self.tcx.def_kind(owner_id) { + DefKind::Enum => { + let def = self.tcx.adt_def(owner_id.def_id); + for variant in def.variants() { + self.effective_visibility_diagnostic(variant.def_id.expect_local()); + if let Some(ctor_def_id) = variant.ctor_def_id() { + self.effective_visibility_diagnostic(ctor_def_id.expect_local()); } - for field in variant.data.fields() { - self.effective_visibility_diagnostic(field.def_id); + for field in &variant.fields { + self.effective_visibility_diagnostic(field.did.expect_local()); } } } - hir::ItemKind::Struct(_, _, ref def) | hir::ItemKind::Union(_, _, ref def) => { + DefKind::Struct | DefKind::Union => { + let def = self.tcx.adt_def(owner_id.def_id).non_enum_variant(); if let Some(ctor_def_id) = def.ctor_def_id() { - self.effective_visibility_diagnostic(ctor_def_id); + self.effective_visibility_diagnostic(ctor_def_id.expect_local()); } - for field in def.fields() { - self.effective_visibility_diagnostic(field.def_id); + for field in &def.fields { + self.effective_visibility_diagnostic(field.did.expect_local()); } } _ => {} } } - - fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem<'tcx>) { - self.effective_visibility_diagnostic(item.owner_id.def_id); - } - fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem<'tcx>) { - self.effective_visibility_diagnostic(item.owner_id.def_id); - } - fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { - self.effective_visibility_diagnostic(item.owner_id.def_id); - } } ////////////////////////////////////////////////////////////////////////////////////// @@ -1422,8 +1434,6 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { }; let vis = self.tcx.local_visibility(local_def_id); - let span = self.tcx.def_span(self.item_def_id.to_def_id()); - let vis_span = self.tcx.def_span(def_id); if self.in_assoc_ty && !vis.is_at_least(self.required_visibility, self.tcx) { let vis_descr = match vis { ty::Visibility::Public => "public", @@ -1440,6 +1450,8 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { } }; + let span = self.tcx.def_span(self.item_def_id.to_def_id()); + let vis_span = self.tcx.def_span(def_id); self.tcx.dcx().emit_err(InPublicInterface { span, vis_descr, @@ -1462,6 +1474,8 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { } else { lint::builtin::PRIVATE_BOUNDS }; + let span = self.tcx.def_span(self.item_def_id.to_def_id()); + let vis_span = self.tcx.def_span(def_id); self.tcx.emit_node_span_lint( lint, self.tcx.local_def_id_to_hir_id(self.item_def_id), @@ -1593,7 +1607,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'_, 'tcx> { self.effective_visibilities.effective_vis(def_id).copied() } - fn check_item(&mut self, id: ItemId) { + fn check_item(&self, id: ItemId) { let tcx = self.tcx; let def_id = id.owner_id.def_id; let item_visibility = tcx.local_visibility(def_id); @@ -1721,7 +1735,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'_, 'tcx> { } } - fn check_foreign_item(&mut self, id: ForeignItemId) { + fn check_foreign_item(&self, id: ForeignItemId) { let tcx = self.tcx; let def_id = id.owner_id.def_id; let item_visibility = tcx.local_visibility(def_id); @@ -1835,8 +1849,14 @@ fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities { visitor.changed = false; } + let crate_items = tcx.hir_crate_items(()); loop { - tcx.hir_visit_all_item_likes_in_crate(&mut visitor); + for id in crate_items.free_items() { + visitor.check_def_id(id.owner_id); + } + for id in crate_items.foreign_items() { + visitor.check_def_id(id.owner_id); + } if visitor.changed { visitor.changed = false; } else { @@ -1845,24 +1865,21 @@ fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities { } visitor.effective_visibilities.check_invariants(tcx); - let mut check_visitor = + let check_visitor = TestReachabilityVisitor { tcx, effective_visibilities: &visitor.effective_visibilities }; - check_visitor.effective_visibility_diagnostic(CRATE_DEF_ID); - tcx.hir_visit_all_item_likes_in_crate(&mut check_visitor); + for id in crate_items.owners() { + check_visitor.check_def_id(id); + } tcx.arena.alloc(visitor.effective_visibilities) } -fn check_private_in_public(tcx: TyCtxt<'_>, (): ()) { +fn check_private_in_public(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { let effective_visibilities = tcx.effective_visibilities(()); // Check for private types in public interfaces. - let mut checker = PrivateItemsInPublicInterfacesChecker { tcx, effective_visibilities }; + let checker = PrivateItemsInPublicInterfacesChecker { tcx, effective_visibilities }; - let crate_items = tcx.hir_crate_items(()); - for id in crate_items.free_items() { - checker.check_item(id); - } - for id in crate_items.foreign_items() { - checker.check_foreign_item(id); - } + let crate_items = tcx.hir_module_items(module_def_id); + let _ = crate_items.par_items(|id| Ok(checker.check_item(id))); + let _ = crate_items.par_foreign_items(|id| Ok(checker.check_foreign_item(id))); } diff --git a/compiler/rustc_proc_macro/Cargo.toml b/compiler/rustc_proc_macro/Cargo.toml index 762acf9a1eb..beb95aa3b52 100644 --- a/compiler/rustc_proc_macro/Cargo.toml +++ b/compiler/rustc_proc_macro/Cargo.toml @@ -15,7 +15,11 @@ test = false doctest = false [dependencies] +# tidy-alphabetical-start rustc-literal-escaper = "0.0.5" +# tidy-alphabetical-end [features] +# tidy-alphabetical-start rustc-dep-of-std = [] +# tidy-alphabetical-end diff --git a/compiler/rustc_public/Cargo.toml b/compiler/rustc_public/Cargo.toml index fa782166e4f..70af30c1a5f 100644 --- a/compiler/rustc_public/Cargo.toml +++ b/compiler/rustc_public/Cargo.toml @@ -18,7 +18,9 @@ tracing = "0.1" # tidy-alphabetical-end [features] +# tidy-alphabetical-start # Provides access to APIs that expose internals of the rust compiler. # APIs enabled by this feature are unstable. They can be removed or modified # at any point and they are not included in the crate's semantic versioning. rustc_internal = [] +# tidy-alphabetical-end diff --git a/compiler/rustc_public/src/mir/body.rs b/compiler/rustc_public/src/mir/body.rs index 3d595286041..276adacd99e 100644 --- a/compiler/rustc_public/src/mir/body.rs +++ b/compiler/rustc_public/src/mir/body.rs @@ -349,7 +349,7 @@ impl AssertMessage { } } -#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub enum BinOp { Add, AddUnchecked, @@ -384,7 +384,7 @@ impl BinOp { } } -#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub enum UnOp { Not, Neg, @@ -490,7 +490,7 @@ pub enum StatementKind { Nop, } -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub enum Rvalue { /// Creates a pointer with the indicated mutability to the place. /// @@ -666,7 +666,7 @@ impl Rvalue { } } -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub enum AggregateKind { Array(Ty), Tuple, @@ -677,14 +677,14 @@ pub enum AggregateKind { RawPtr(Ty, Mutability), } -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub enum Operand { Copy(Place), Move(Place), Constant(ConstOperand), } -#[derive(Clone, Eq, PartialEq, Serialize)] +#[derive(Clone, Eq, PartialEq, Hash, Serialize)] pub struct Place { pub local: Local, /// projection out of a place (access a field, deref a pointer, etc) @@ -697,7 +697,7 @@ impl From<Local> for Place { } } -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub struct ConstOperand { pub span: Span, pub user_ty: Option<UserTypeAnnotationIndex>, @@ -770,7 +770,7 @@ pub enum VarDebugInfoContents { // ProjectionElem<Local, Ty>) and user-provided type annotations (for which the projection elements // are of type ProjectionElem<(), ()>). // In rustc_public's IR we don't need this generality, so we just use ProjectionElem for Places. -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub enum ProjectionElem { /// Dereference projections (e.g. `*_1`) project to the address referenced by the base place. Deref, @@ -913,7 +913,7 @@ impl SwitchTargets { } } -#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub enum BorrowKind { /// Data must be immutable and is aliasable. Shared, @@ -940,7 +940,7 @@ impl BorrowKind { } } -#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub enum RawPtrKind { Mut, Const, @@ -958,14 +958,14 @@ impl RawPtrKind { } } -#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub enum MutBorrowKind { Default, TwoPhaseBorrow, ClosureCapture, } -#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub enum FakeBorrowKind { /// A shared (deep) borrow. Data must be immutable and is aliasable. Deep, @@ -982,13 +982,13 @@ pub enum Mutability { Mut, } -#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub enum Safety { Safe, Unsafe, } -#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub enum PointerCoercion { /// Go from a fn-item type to a fn-pointer type. ReifyFnPointer, @@ -1015,7 +1015,7 @@ pub enum PointerCoercion { Unsize, } -#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub enum CastKind { // FIXME(smir-rename): rename this to PointerExposeProvenance PointerExposeAddress, @@ -1030,7 +1030,7 @@ pub enum CastKind { Transmute, } -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub enum NullOp { /// Returns the size of a value of that type. SizeOf, diff --git a/compiler/rustc_public/src/mir/pretty.rs b/compiler/rustc_public/src/mir/pretty.rs index 3183c020772..9dd1ce4de0e 100644 --- a/compiler/rustc_public/src/mir/pretty.rs +++ b/compiler/rustc_public/src/mir/pretty.rs @@ -100,7 +100,7 @@ fn pretty_statement<W: Write>(writer: &mut W, statement: &StatementKind) -> io:: writeln!(writer, "{INDENT}FakeRead({cause:?}, {place:?});") } StatementKind::SetDiscriminant { place, variant_index } => { - writeln!(writer, "{INDENT}discriminant({place:?} = {};", variant_index.to_index()) + writeln!(writer, "{INDENT}discriminant({place:?}) = {};", variant_index.to_index()) } StatementKind::Deinit(place) => writeln!(writer, "Deinit({place:?};"), StatementKind::StorageLive(local) => { diff --git a/compiler/rustc_public/src/ty.rs b/compiler/rustc_public/src/ty.rs index de4b21b1764..1b5f0ed1429 100644 --- a/compiler/rustc_public/src/ty.rs +++ b/compiler/rustc_public/src/ty.rs @@ -113,7 +113,7 @@ pub enum Pattern { } /// Represents a constant in the type system -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub struct TyConst { pub(crate) kind: TyConstKind, pub id: TyConstId, @@ -140,7 +140,7 @@ impl TyConst { } } -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub enum TyConstKind { Param(ParamConst), Bound(DebruijnIndex, BoundVar), @@ -151,11 +151,11 @@ pub enum TyConstKind { ZSTValue(Ty), } -#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub struct TyConstId(usize); /// Represents a constant in MIR -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub struct MirConst { /// The constant kind. pub(crate) kind: ConstantKind, @@ -212,17 +212,17 @@ impl MirConst { } } -#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)] pub struct MirConstId(usize); type Ident = Opaque; -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub struct Region { pub kind: RegionKind, } -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub enum RegionKind { ReEarlyParam(EarlyParamRegion), ReBound(DebruijnIndex, BoundRegion), @@ -233,7 +233,7 @@ pub enum RegionKind { pub(crate) type DebruijnIndex = u32; -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub struct EarlyParamRegion { pub index: u32, pub name: Symbol, @@ -241,7 +241,7 @@ pub struct EarlyParamRegion { pub(crate) type BoundVar = u32; -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub struct BoundRegion { pub var: BoundVar, pub kind: BoundRegionKind, @@ -249,13 +249,13 @@ pub struct BoundRegion { pub(crate) type UniverseIndex = u32; -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub struct Placeholder<T> { pub universe: UniverseIndex, pub bound: T, } -#[derive(Clone, Copy, PartialEq, Eq, Serialize)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize)] pub struct Span(usize); impl Debug for Span { @@ -997,7 +997,7 @@ crate_def! { } /// A list of generic arguments. -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub struct GenericArgs(pub Vec<GenericArgKind>); impl std::ops::Index<ParamTy> for GenericArgs { @@ -1016,7 +1016,7 @@ impl std::ops::Index<ParamConst> for GenericArgs { } } -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub enum GenericArgKind { Lifetime(Region), Type(Ty), @@ -1199,7 +1199,7 @@ pub enum BoundTyKind { Param(ParamDef, String), } -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub enum BoundRegionKind { BrAnon, BrNamed(BrNamedDef, String), @@ -1354,7 +1354,7 @@ impl Allocation { } } -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub enum ConstantKind { Ty(TyConst), Allocated(Allocation), @@ -1365,13 +1365,13 @@ pub enum ConstantKind { ZeroSized, } -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub struct ParamConst { pub index: u32, pub name: String, } -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub struct UnevaluatedConst { pub def: ConstDef, pub args: GenericArgs, diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml index 3d2d879a764..7480ba03474 100644 --- a/compiler/rustc_query_system/Cargo.toml +++ b/compiler/rustc_query_system/Cargo.toml @@ -8,7 +8,6 @@ edition = "2024" parking_lot = "0.12" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } -rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } diff --git a/compiler/rustc_query_system/src/ich/hcx.rs b/compiler/rustc_query_system/src/ich/hcx.rs index 96d0c02c4a6..be838f689e5 100644 --- a/compiler/rustc_query_system/src/ich/hcx.rs +++ b/compiler/rustc_query_system/src/ich/hcx.rs @@ -129,4 +129,3 @@ impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> { } impl<'a> rustc_session::HashStableContext for StableHashingContext<'a> {} -impl<'a> rustc_attr_data_structures::HashStableContext for StableHashingContext<'a> {} diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml index 1238ce0125a..eb98a6e85c0 100644 --- a/compiler/rustc_resolve/Cargo.toml +++ b/compiler/rustc_resolve/Cargo.toml @@ -6,12 +6,12 @@ edition = "2024" [dependencies] # tidy-alphabetical-start bitflags = "2.4.1" +indexmap = "2.4.0" itertools = "0.12" pulldown-cmark = { version = "0.11", features = ["html"], default-features = false } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } -rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 39e9a9cc58a..ceef558c0cf 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -243,7 +243,7 @@ resolve_lowercase_self = .suggestion = try using `Self` resolve_macro_cannot_use_as_attr = - `{$ident}` exists, but a declarative macro cannot be used as an attribute macro + `{$ident}` exists, but has no `attr` rules resolve_macro_cannot_use_as_derive = `{$ident}` exists, but a declarative macro cannot be used as a derive macro diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index b15b478a6be..2ad8543bf8c 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -13,12 +13,12 @@ use rustc_ast::{ self as ast, AssocItem, AssocItemKind, Block, ConstItem, Delegation, Fn, ForeignItem, ForeignItemKind, Impl, Item, ItemKind, NodeId, StaticItem, StmtKind, TyAlias, }; -use rustc_attr_data_structures::{AttributeKind, MacroUseArgs}; use rustc_attr_parsing as attr; use rustc_attr_parsing::AttributeParser; use rustc_expand::base::ResolverExpand; use rustc_expand::expand::AstFragment; use rustc_hir::Attribute; +use rustc_hir::attrs::{AttributeKind, MacroUseArgs}; use rustc_hir::def::{self, *}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; use rustc_index::bit_set::DenseBitSet; @@ -27,7 +27,7 @@ use rustc_middle::metadata::ModChild; use rustc_middle::ty::{Feed, Visibility}; use rustc_middle::{bug, span_bug}; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind}; -use rustc_span::{Ident, Span, Symbol, kw, sym}; +use rustc_span::{Ident, Macros20NormalizedIdent, Span, Symbol, kw, sym}; use thin_vec::ThinVec; use tracing::debug; @@ -223,7 +223,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { pub(crate) fn build_reduced_graph_external(&self, module: Module<'ra>) { for child in self.tcx.module_children(module.def_id()) { - let parent_scope = ParentScope::module(module, self); + let parent_scope = ParentScope::module(module, self.arenas); self.build_reduced_graph_for_external_crate_res(child, parent_scope) } } @@ -373,7 +373,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { res, )) }; - match self.r.resolve_path( + match self.r.cm().resolve_path( &segments, None, parent_scope, @@ -968,9 +968,9 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } self.r.potentially_unused_imports.push(import); let imported_binding = self.r.import(binding, import); - if parent == self.r.graph_root { - let ident = ident.normalize_to_macros_2_0(); - if let Some(entry) = self.r.extern_prelude.get(&ident) + if ident.name != kw::Underscore && parent == self.r.graph_root { + let norm_ident = Macros20NormalizedIdent::new(ident); + if let Some(entry) = self.r.extern_prelude.get(&norm_ident) && expansion != LocalExpnId::ROOT && orig_name.is_some() && !entry.is_import() @@ -984,24 +984,29 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { // more details: https://github.com/rust-lang/rust/pull/111761 return; } - let entry = self - .r - .extern_prelude - .entry(ident) - .or_insert(ExternPreludeEntry { binding: None, introduced_by_item: true }); - if orig_name.is_some() { - entry.introduced_by_item = true; - } - // Binding from `extern crate` item in source code can replace - // a binding from `--extern` on command line here. - if !entry.is_import() { - entry.binding = Some(imported_binding) - } else if ident.name != kw::Underscore { - self.r.dcx().span_delayed_bug( - item.span, - format!("it had been define the external module '{ident}' multiple times"), - ); - } + + use indexmap::map::Entry; + match self.r.extern_prelude.entry(norm_ident) { + Entry::Occupied(mut occupied) => { + let entry = occupied.get_mut(); + if let Some(old_binding) = entry.binding.get() + && old_binding.is_import() + { + let msg = format!("extern crate `{ident}` already in extern prelude"); + self.r.tcx.dcx().span_delayed_bug(item.span, msg); + } else { + // Binding from `extern crate` item in source code can replace + // a binding from `--extern` on command line here. + entry.binding.set(Some(imported_binding)); + entry.introduced_by_item = orig_name.is_some(); + } + entry + } + Entry::Vacant(vacant) => vacant.insert(ExternPreludeEntry { + binding: Cell::new(Some(imported_binding)), + introduced_by_item: true, + }), + }; } self.r.define_binding_local(parent, ident, TypeNS, imported_binding); } @@ -1123,7 +1128,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { }); } else { for ident in single_imports.iter().cloned() { - let result = self.r.maybe_resolve_ident_in_module( + let result = self.r.cm().maybe_resolve_ident_in_module( ModuleOrUniformRoot::Module(module), ident, MacroNS, diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index b85a814776a..11d93a58ae2 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -33,7 +33,7 @@ use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ MACRO_USE_EXTERN_CRATE, UNUSED_EXTERN_CRATES, UNUSED_IMPORTS, UNUSED_QUALIFICATIONS, }; -use rustc_span::{DUMMY_SP, Ident, Span, kw}; +use rustc_span::{DUMMY_SP, Ident, Macros20NormalizedIdent, Span, kw}; use crate::imports::{Import, ImportKind}; use crate::{LexicalScopeBinding, NameBindingKind, Resolver, module_to_string}; @@ -203,7 +203,7 @@ impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> { if self .r .extern_prelude - .get(&extern_crate.ident) + .get(&Macros20NormalizedIdent::new(extern_crate.ident)) .is_none_or(|entry| entry.introduced_by_item) { continue; diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 3af69b28780..66f79585d92 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1,12 +1,8 @@ -use rustc_ast::ptr::P; use rustc_ast::visit::{self, Visitor}; use rustc_ast::{ self as ast, CRATE_NODE_ID, Crate, ItemKind, ModKind, NodeId, Path, join_path_idents, }; use rustc_ast_pretty::pprust; -use rustc_attr_data_structures::{ - self as attr, AttributeKind, CfgEntry, Stability, StrippedCfgItem, find_attr, -}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::codes::*; @@ -15,10 +11,11 @@ use rustc_errors::{ report_ambiguity_error, struct_span_code_err, }; use rustc_feature::BUILTIN_ATTRIBUTES; -use rustc_hir::PrimTy; +use rustc_hir::attrs::{AttributeKind, CfgEntry, StrippedCfgItem}; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind, PerNS}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId}; +use rustc_hir::{PrimTy, Stability, StabilityLevel, find_attr}; use rustc_middle::bug; use rustc_middle::ty::TyCtxt; use rustc_session::Session; @@ -32,7 +29,7 @@ use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::edition::Edition; use rustc_span::hygiene::MacroKind; use rustc_span::source_map::SourceMap; -use rustc_span::{BytePos, Ident, Span, Symbol, SyntaxContext, kw, sym}; +use rustc_span::{BytePos, Ident, Macros20NormalizedIdent, Span, Symbol, SyntaxContext, kw, sym}; use thin_vec::{ThinVec, thin_vec}; use tracing::{debug, instrument}; @@ -322,8 +319,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Check if the target of the use for both bindings is the same. let duplicate = new_binding.res().opt_def_id() == old_binding.res().opt_def_id(); let has_dummy_span = new_binding.span.is_dummy() || old_binding.span.is_dummy(); - let from_item = - self.extern_prelude.get(&ident).is_none_or(|entry| entry.introduced_by_item); + let from_item = self + .extern_prelude + .get(&Macros20NormalizedIdent::new(ident)) + .is_none_or(|entry| entry.introduced_by_item); // Only suggest removing an import if both bindings are to the same def, if both spans // aren't dummy spans. Further, if both bindings are imports, then the ident must have // been introduced by an item. @@ -469,13 +468,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { pub(crate) fn lint_if_path_starts_with_module( &mut self, - finalize: Option<Finalize>, + finalize: Finalize, path: &[Segment], second_binding: Option<NameBinding<'_>>, ) { - let Some(Finalize { node_id, root_span, .. }) = finalize else { - return; - }; + let Finalize { node_id, root_span, .. } = finalize; let first_name = match path.get(0) { // In the 2018 edition this lint is a hard error, so nothing to do @@ -532,7 +529,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { module.for_each_child(self, |_this, ident, _ns, binding| { let res = binding.res(); if filter_fn(res) && ctxt.is_none_or(|ctxt| ctxt == ident.span.ctxt()) { - names.push(TypoSuggestion::typo_from_ident(ident, res)); + names.push(TypoSuggestion::typo_from_ident(ident.0, res)); } }); } @@ -803,10 +800,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } err.multipart_suggestion(msg, suggestions, applicability); } - if let Some(ModuleOrUniformRoot::Module(module)) = module - && let Some(module) = module.opt_def_id() - && let Some(segment) = segment - { + + if let Some(segment) = segment { + let module = match module { + Some(ModuleOrUniformRoot::Module(m)) if let Some(id) = m.opt_def_id() => id, + _ => CRATE_DEF_ID.to_def_id(), + }; self.find_cfg_stripped(&mut err, &segment, module); } @@ -1027,7 +1026,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) -> Option<TypoSuggestion> { let mut suggestions = Vec::new(); let ctxt = ident.span.ctxt(); - self.visit_scopes(scope_set, parent_scope, ctxt, |this, scope, use_prelude, _| { + self.cm().visit_scopes(scope_set, parent_scope, ctxt, |this, scope, use_prelude, _| { match scope { Scope::DeriveHelpers(expn_id) => { let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper); @@ -1046,7 +1045,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if filter_fn(res) { for derive in parent_scope.derives { let parent_scope = &ParentScope { derives: &[], ..*parent_scope }; - let Ok((Some(ext), _)) = this.resolve_macro_path( + let Ok((Some(ext), _)) = this.reborrow().resolve_macro_path( derive, Some(MacroKind::Derive), parent_scope, @@ -1098,9 +1097,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } Scope::ExternPrelude => { - suggestions.extend(this.extern_prelude.iter().filter_map(|(ident, _)| { + suggestions.extend(this.extern_prelude.keys().filter_map(|ident| { let res = Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id()); - filter_fn(res).then_some(TypoSuggestion::typo_from_ident(*ident, res)) + filter_fn(res).then_some(TypoSuggestion::typo_from_ident(ident.0, res)) })); } Scope::ToolPrelude => { @@ -1246,7 +1245,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; segms.append(&mut path_segments.clone()); - segms.push(ast::PathSegment::from_ident(ident)); + segms.push(ast::PathSegment::from_ident(ident.0)); let path = Path { span: name_binding.span, segments: segms, tokens: None }; if child_accessible @@ -1319,7 +1318,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if let Some(def_id) = name_binding.res().module_like_def_id() { // form the path let mut path_segments = path_segments.clone(); - path_segments.push(ast::PathSegment::from_ident(ident)); + path_segments.push(ast::PathSegment::from_ident(ident.0)); let alias_import = if let NameBindingKind::Import { import, .. } = name_binding.kind @@ -1362,9 +1361,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { match self.tcx.lookup_stability(did) { Some(Stability { - level: attr::StabilityLevel::Unstable { implied_by, .. }, - feature, - .. + level: StabilityLevel::Unstable { implied_by, .. }, feature, .. }) => { if span.allows_unstable(feature) { true @@ -1411,7 +1408,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ); if lookup_ident.span.at_least_rust_2018() { - for ident in self.extern_prelude.clone().into_keys() { + for &ident in self.extern_prelude.keys() { if ident.span.from_expansion() { // Idents are adjusted to the root context before being // resolved in the extern prelude, so reporting this to the @@ -1455,7 +1452,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if needs_disambiguation { crate_path.push(ast::PathSegment::path_root(rustc_span::DUMMY_SP)); } - crate_path.push(ast::PathSegment::from_ident(ident)); + crate_path.push(ast::PathSegment::from_ident(ident.0)); suggestions.extend(self.lookup_import_candidates_from_module( lookup_ident, @@ -1482,7 +1479,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) { // Bring imported but unused `derive` macros into `macro_map` so we ensure they can be used // for suggestions. - self.visit_scopes( + self.cm().visit_scopes( ScopeSet::Macro(MacroKind::Derive), &parent_scope, ident.span.ctxt(), @@ -1591,7 +1588,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }); } for ns in [Namespace::MacroNS, Namespace::TypeNS, Namespace::ValueNS] { - let Ok(binding) = self.early_resolve_ident_in_lexical_scope( + let Ok(binding) = self.cm().early_resolve_ident_in_lexical_scope( ident, ScopeSet::All(ns), parent_scope, @@ -2271,16 +2268,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if ns == TypeNS || ns == ValueNS { let ns_to_try = if ns == TypeNS { ValueNS } else { TypeNS }; let binding = if let Some(module) = module { - self.resolve_ident_in_module( - module, - ident, - ns_to_try, - parent_scope, - None, - ignore_binding, - ignore_import, - ) - .ok() + self.cm() + .resolve_ident_in_module( + module, + ident, + ns_to_try, + parent_scope, + None, + ignore_binding, + ignore_import, + ) + .ok() } else if let Some(ribs) = ribs && let Some(TypeNS | ValueNS) = opt_ns { @@ -2298,16 +2296,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { _ => None, } } else { - self.early_resolve_ident_in_lexical_scope( - ident, - ScopeSet::All(ns_to_try), - parent_scope, - None, - false, - ignore_binding, - ignore_import, - ) - .ok() + self.cm() + .early_resolve_ident_in_lexical_scope( + ident, + ScopeSet::All(ns_to_try), + parent_scope, + None, + false, + ignore_binding, + ignore_import, + ) + .ok() }; if let Some(binding) = binding { msg = format!( @@ -2401,7 +2400,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }, ) }); - if let Ok(binding) = self.early_resolve_ident_in_lexical_scope( + if let Ok(binding) = self.cm().early_resolve_ident_in_lexical_scope( ident, ScopeSet::All(ValueNS), parent_scope, @@ -2531,7 +2530,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) -> Option<(Vec<Segment>, Option<String>)> { // Replace first ident with `self` and check if that is valid. path[0].ident.name = kw::SelfLower; - let result = self.maybe_resolve_path(&path, None, parent_scope, None); + let result = self.cm().maybe_resolve_path(&path, None, parent_scope, None); debug!(?path, ?result); if let PathResult::Module(..) = result { Some((path, None)) } else { None } } @@ -2551,7 +2550,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) -> Option<(Vec<Segment>, Option<String>)> { // Replace first ident with `crate` and check if that is valid. path[0].ident.name = kw::Crate; - let result = self.maybe_resolve_path(&path, None, parent_scope, None); + let result = self.cm().maybe_resolve_path(&path, None, parent_scope, None); debug!(?path, ?result); if let PathResult::Module(..) = result { Some(( @@ -2583,7 +2582,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) -> Option<(Vec<Segment>, Option<String>)> { // Replace first ident with `crate` and check if that is valid. path[0].ident.name = kw::Super; - let result = self.maybe_resolve_path(&path, None, parent_scope, None); + let result = self.cm().maybe_resolve_path(&path, None, parent_scope, None); debug!(?path, ?result); if let PathResult::Module(..) = result { Some((path, None)) } else { None } } @@ -2618,7 +2617,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for name in extern_crate_names.into_iter() { // Replace first ident with a crate name and check if that is valid. path[0].ident.name = name; - let result = self.maybe_resolve_path(&path, None, parent_scope, None); + let result = self.cm().maybe_resolve_path(&path, None, parent_scope, None); debug!(?path, ?name, ?result); if let PathResult::Module(..) = result { return Some((path, None)); @@ -2843,16 +2842,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { continue; } - let note = errors::FoundItemConfigureOut { span: ident.span }; - err.subdiagnostic(note); - - if let CfgEntry::NameValue { value: Some((feature, _)), .. } = cfg.0 { - let note = errors::ItemWasBehindFeature { feature, span: cfg.1 }; - err.subdiagnostic(note); + let item_was = if let CfgEntry::NameValue { value: Some((feature, _)), .. } = cfg.0 { + errors::ItemWas::BehindFeature { feature, span: cfg.1 } } else { - let note = errors::ItemWasCfgOut { span: cfg.1 }; - err.subdiagnostic(note); - } + errors::ItemWas::CfgOut { span: cfg.1 } + }; + let note = errors::FoundItemConfigureOut { span: ident.span, item_was }; + err.subdiagnostic(note); } } } @@ -3350,7 +3346,7 @@ impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder { } } -fn search_for_any_use_in_items(items: &[P<ast::Item>]) -> Option<Span> { +fn search_for_any_use_in_items(items: &[Box<ast::Item>]) -> Option<Span> { for item in items { if let ItemKind::Use(..) = item.kind && is_span_suitable_for_use_injection(item.span) diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index d6b1e4de6ea..2747ba135ed 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -1,10 +1,13 @@ use rustc_errors::codes::*; -use rustc_errors::{Applicability, ElidedLifetimeInPathSubdiag, MultiSpan}; +use rustc_errors::{ + Applicability, Diag, ElidedLifetimeInPathSubdiag, EmissionGuarantee, IntoDiagArg, MultiSpan, + Subdiagnostic, +}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Ident, Span, Symbol}; -use crate::Res; use crate::late::PatternSource; +use crate::{Res, fluent_generated as fluent}; #[derive(Diagnostic)] #[diag(resolve_generic_params_from_outer_item, code = E0401)] @@ -1201,26 +1204,35 @@ pub(crate) struct IdentInScopeButItIsDesc<'a> { pub(crate) imported_ident_desc: &'a str, } -#[derive(Subdiagnostic)] -#[note(resolve_found_an_item_configured_out)] pub(crate) struct FoundItemConfigureOut { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Subdiagnostic)] -#[note(resolve_item_was_behind_feature)] -pub(crate) struct ItemWasBehindFeature { - pub(crate) feature: Symbol, - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Subdiagnostic)] -#[note(resolve_item_was_cfg_out)] -pub(crate) struct ItemWasCfgOut { - #[primary_span] pub(crate) span: Span, + pub(crate) item_was: ItemWas, +} + +pub(crate) enum ItemWas { + BehindFeature { feature: Symbol, span: Span }, + CfgOut { span: Span }, +} + +impl Subdiagnostic for FoundItemConfigureOut { + fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) { + let mut multispan: MultiSpan = self.span.into(); + match self.item_was { + ItemWas::BehindFeature { feature, span } => { + let key = "feature".into(); + let value = feature.into_diag_arg(&mut None); + let msg = diag.dcx.eagerly_translate_to_string( + fluent::resolve_item_was_behind_feature, + [(&key, &value)].into_iter(), + ); + multispan.push_span_label(span, msg); + } + ItemWas::CfgOut { span } => { + multispan.push_span_label(span, fluent::resolve_item_was_cfg_out); + } + } + diag.span_note(multispan, fluent::resolve_found_an_item_configured_out); + } } #[derive(Diagnostic)] diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index f5bc46bf053..092bb6fc4f9 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -16,10 +16,10 @@ use crate::imports::{Import, NameResolution}; use crate::late::{ConstantHasGenerics, NoConstantGenericsReason, PathSource, Rib, RibKind}; use crate::macros::{MacroRulesScope, sub_namespace_match}; use crate::{ - AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingKey, Determinacy, Finalize, - ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot, NameBinding, - NameBindingKind, ParentScope, PathResult, PrivacyError, Res, ResolutionError, Resolver, Scope, - ScopeSet, Segment, Used, Weak, errors, + AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingKey, CmResolver, Determinacy, + Finalize, ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot, + NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, Res, ResolutionError, + Resolver, Scope, ScopeSet, Segment, Used, Weak, errors, }; #[derive(Copy, Clone)] @@ -44,12 +44,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// A generic scope visitor. /// Visits scopes in order to resolve some identifier in them or perform other actions. /// If the callback returns `Some` result, we stop visiting scopes and return it. - pub(crate) fn visit_scopes<T>( - &mut self, + pub(crate) fn visit_scopes<'r, T>( + mut self: CmResolver<'r, 'ra, 'tcx>, scope_set: ScopeSet<'ra>, parent_scope: &ParentScope<'ra>, ctxt: SyntaxContext, - mut visitor: impl FnMut(&mut Self, Scope<'ra>, UsePrelude, SyntaxContext) -> Option<T>, + mut visitor: impl FnMut( + &mut CmResolver<'r, 'ra, 'tcx>, + Scope<'ra>, + UsePrelude, + SyntaxContext, + ) -> Option<T>, ) -> Option<T> { // General principles: // 1. Not controlled (user-defined) names should have higher priority than controlled names @@ -146,7 +151,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if visit { let use_prelude = if use_prelude { UsePrelude::Yes } else { UsePrelude::No }; - if let break_result @ Some(..) = visitor(self, scope, use_prelude, ctxt) { + if let break_result @ Some(..) = visitor(&mut self, scope, use_prelude, ctxt) { return break_result; } } @@ -341,7 +346,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { _ => break, } - let item = self.resolve_ident_in_module_unadjusted( + let item = self.cm().resolve_ident_in_module_unadjusted( ModuleOrUniformRoot::Module(module), ident, ns, @@ -356,17 +361,18 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return Some(LexicalScopeBinding::Item(binding)); } } - self.early_resolve_ident_in_lexical_scope( - orig_ident, - ScopeSet::Late(ns, module, finalize.map(|finalize| finalize.node_id)), - parent_scope, - finalize, - finalize.is_some(), - ignore_binding, - None, - ) - .ok() - .map(LexicalScopeBinding::Item) + self.cm() + .early_resolve_ident_in_lexical_scope( + orig_ident, + ScopeSet::Late(ns, module, finalize.map(|finalize| finalize.node_id)), + parent_scope, + finalize, + finalize.is_some(), + ignore_binding, + None, + ) + .ok() + .map(LexicalScopeBinding::Item) } /// Resolve an identifier in lexical scope. @@ -375,8 +381,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// The function is used for resolving initial segments of macro paths (e.g., `foo` in /// `foo::bar!();` or `foo!();`) and also for import paths on 2018 edition. #[instrument(level = "debug", skip(self))] - pub(crate) fn early_resolve_ident_in_lexical_scope( - &mut self, + pub(crate) fn early_resolve_ident_in_lexical_scope<'r>( + self: CmResolver<'r, 'ra, 'tcx>, orig_ident: Ident, scope_set: ScopeSet<'ra>, parent_scope: &ParentScope<'ra>, @@ -450,7 +456,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut result = Err(Determinacy::Determined); for derive in parent_scope.derives { let parent_scope = &ParentScope { derives: &[], ..*parent_scope }; - match this.resolve_macro_path( + match this.reborrow().resolve_macro_path( derive, Some(MacroKind::Derive), parent_scope, @@ -497,7 +503,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { finalize.map(|f| Finalize { used: Used::Scope, ..f }), ) }; - let binding = this.resolve_ident_in_module_unadjusted( + let binding = this.reborrow().resolve_ident_in_module_unadjusted( ModuleOrUniformRoot::Module(module), ident, ns, @@ -514,7 +520,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { match binding { Ok(binding) => { if let Some(lint_id) = derive_fallback_lint_id { - this.lint_buffer.buffer_lint( + this.get_mut().lint_buffer.buffer_lint( PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, lint_id, orig_ident.span, @@ -556,7 +562,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None => Err(Determinacy::Determined), }, Scope::ExternPrelude => { - match this.extern_prelude_get(ident, finalize.is_some()) { + match this.reborrow().extern_prelude_get(ident, finalize.is_some()) { Some(binding) => Ok((binding, Flags::empty())), None => Err(Determinacy::determined( this.graph_root.unexpanded_invocations.borrow().is_empty(), @@ -570,7 +576,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Scope::StdLibPrelude => { let mut result = Err(Determinacy::Determined); if let Some(prelude) = this.prelude - && let Ok(binding) = this.resolve_ident_in_module_unadjusted( + && let Ok(binding) = this.reborrow().resolve_ident_in_module_unadjusted( ModuleOrUniformRoot::Module(prelude), ident, ns, @@ -625,9 +631,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; match result { - Ok((binding, flags)) - if sub_namespace_match(binding.macro_kind(), macro_kind) => - { + Ok((binding, flags)) => { + let binding_macro_kind = binding.macro_kind(); + // If we're looking for an attribute, that might be supported by a + // `macro_rules!` macro. + // FIXME: Replace this with tracking multiple macro kinds for one Def. + if !(sub_namespace_match(binding_macro_kind, macro_kind) + || (binding_macro_kind == Some(MacroKind::Bang) + && macro_kind == Some(MacroKind::Attr) + && this + .get_macro(binding.res()) + .is_some_and(|macro_data| macro_data.attr_ext.is_some()))) + { + return None; + } + if finalize.is_none() || matches!(scope_set, ScopeSet::Late(..)) { return Some(Ok(binding)); } @@ -687,7 +705,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { AmbiguityErrorMisc::None } }; - this.ambiguity_errors.push(AmbiguityError { + this.get_mut().ambiguity_errors.push(AmbiguityError { kind, ident: orig_ident, b1: innermost_binding, @@ -704,7 +722,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { innermost_result = Some((binding, flags)); } } - Ok(..) | Err(Determinacy::Determined) => {} + Err(Determinacy::Determined) => {} Err(Determinacy::Undetermined) => determinacy = Determinacy::Undetermined, } @@ -725,8 +743,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } #[instrument(level = "debug", skip(self))] - pub(crate) fn maybe_resolve_ident_in_module( - &mut self, + pub(crate) fn maybe_resolve_ident_in_module<'r>( + self: CmResolver<'r, 'ra, 'tcx>, module: ModuleOrUniformRoot<'ra>, ident: Ident, ns: Namespace, @@ -738,8 +756,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } #[instrument(level = "debug", skip(self))] - pub(crate) fn resolve_ident_in_module( - &mut self, + pub(crate) fn resolve_ident_in_module<'r>( + self: CmResolver<'r, 'ra, 'tcx>, module: ModuleOrUniformRoot<'ra>, mut ident: Ident, ns: Namespace, @@ -776,12 +794,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ignore_import, ) } - /// Attempts to resolve `ident` in namespaces `ns` of `module`. /// Invariant: if `finalize` is `Some`, expansion and import resolution must be complete. #[instrument(level = "debug", skip(self))] - fn resolve_ident_in_module_unadjusted( - &mut self, + fn resolve_ident_in_module_unadjusted<'r>( + mut self: CmResolver<'r, 'ra, 'tcx>, module: ModuleOrUniformRoot<'ra>, ident: Ident, ns: Namespace, @@ -812,7 +829,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { assert_eq!(shadowing, Shadowing::Unrestricted); return if ns != TypeNS { Err((Determined, Weak::No)) - } else if let Some(binding) = self.extern_prelude_get(ident, finalize.is_some()) { + } else if let Some(binding) = + self.reborrow().extern_prelude_get(ident, finalize.is_some()) + { Ok(binding) } else if !self.graph_root.unexpanded_invocations.borrow().is_empty() { // Macro-expanded `extern crate` items can add names to extern prelude. @@ -865,7 +884,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .find_map(|binding| if binding == ignore_binding { None } else { binding }); if let Some(finalize) = finalize { - return self.finalize_module_binding( + return self.get_mut().finalize_module_binding( ident, binding, if resolution.non_glob_binding.is_some() { resolution.glob_binding } else { None }, @@ -875,7 +894,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ); } - let check_usable = |this: &Self, binding: NameBinding<'ra>| { + let check_usable = |this: CmResolver<'r, 'ra, 'tcx>, binding: NameBinding<'ra>| { let usable = this.is_accessible_from(binding.vis, parent_scope.module); if usable { Ok(binding) } else { Err((Determined, Weak::No)) } }; @@ -891,7 +910,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Check if one of single imports can still define the name, // if it can then our result is not determined and can be invalidated. - if self.single_import_can_define_name( + if self.reborrow().single_import_can_define_name( &resolution, binding, ns, @@ -962,7 +981,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Some(None) => {} None => continue, }; - let result = self.resolve_ident_in_module_unadjusted( + let result = self.reborrow().resolve_ident_in_module_unadjusted( ModuleOrUniformRoot::Module(module), ident, ns, @@ -1049,8 +1068,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Checks if a single import can define the `Ident` corresponding to `binding`. // This is used to check whether we can definitively accept a glob as a resolution. - fn single_import_can_define_name( - &mut self, + fn single_import_can_define_name<'r>( + mut self: CmResolver<'r, 'ra, 'tcx>, resolution: &NameResolution<'ra>, binding: Option<NameBinding<'ra>>, ns: Namespace, @@ -1086,7 +1105,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - match self.resolve_ident_in_module( + match self.reborrow().resolve_ident_in_module( module, *source, ns, @@ -1409,8 +1428,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } #[instrument(level = "debug", skip(self))] - pub(crate) fn maybe_resolve_path( - &mut self, + pub(crate) fn maybe_resolve_path<'r>( + self: CmResolver<'r, 'ra, 'tcx>, path: &[Segment], opt_ns: Option<Namespace>, // `None` indicates a module path in import parent_scope: &ParentScope<'ra>, @@ -1418,10 +1437,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) -> PathResult<'ra> { self.resolve_path_with_ribs(path, opt_ns, parent_scope, None, None, None, ignore_import) } - #[instrument(level = "debug", skip(self))] - pub(crate) fn resolve_path( - &mut self, + pub(crate) fn resolve_path<'r>( + self: CmResolver<'r, 'ra, 'tcx>, path: &[Segment], opt_ns: Option<Namespace>, // `None` indicates a module path in import parent_scope: &ParentScope<'ra>, @@ -1440,8 +1458,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) } - pub(crate) fn resolve_path_with_ribs( - &mut self, + pub(crate) fn resolve_path_with_ribs<'r>( + mut self: CmResolver<'r, 'ra, 'tcx>, path: &[Segment], opt_ns: Option<Namespace>, // `None` indicates a module path in import parent_scope: &ParentScope<'ra>, @@ -1457,18 +1475,23 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // We'll provide more context to the privacy errors later, up to `len`. let privacy_errors_len = self.privacy_errors.len(); + fn record_segment_res<'r, 'ra, 'tcx>( + mut this: CmResolver<'r, 'ra, 'tcx>, + finalize: Option<Finalize>, + res: Res, + id: Option<NodeId>, + ) { + if finalize.is_some() + && let Some(id) = id + && !this.partial_res_map.contains_key(&id) + { + assert!(id != ast::DUMMY_NODE_ID, "Trying to resolve dummy id"); + this.get_mut().record_partial_res(id, PartialRes::new(res)); + } + } for (segment_idx, &Segment { ident, id, .. }) in path.iter().enumerate() { debug!("resolve_path ident {} {:?} {:?}", segment_idx, ident, id); - let record_segment_res = |this: &mut Self, res| { - if finalize.is_some() - && let Some(id) = id - && !this.partial_res_map.contains_key(&id) - { - assert!(id != ast::DUMMY_NODE_ID, "Trying to resolve dummy id"); - this.record_partial_res(id, PartialRes::new(res)); - } - }; let is_last = segment_idx + 1 == path.len(); let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS }; @@ -1507,7 +1530,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut ctxt = ident.span.ctxt().normalize_to_macros_2_0(); let self_mod = self.resolve_self(&mut ctxt, parent_scope.module); if let Some(res) = self_mod.res() { - record_segment_res(self, res); + record_segment_res(self.reborrow(), finalize, res, id); } module = Some(ModuleOrUniformRoot::Module(self_mod)); continue; @@ -1529,7 +1552,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // `::a::b`, `crate::a::b` or `$crate::a::b` let crate_root = self.resolve_crate_root(ident); if let Some(res) = crate_root.res() { - record_segment_res(self, res); + record_segment_res(self.reborrow(), finalize, res, id); } module = Some(ModuleOrUniformRoot::Module(crate_root)); continue; @@ -1562,21 +1585,22 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } let binding = if let Some(module) = module { - self.resolve_ident_in_module( - module, - ident, - ns, - parent_scope, - finalize, - ignore_binding, - ignore_import, - ) - .map_err(|(determinacy, _)| determinacy) + self.reborrow() + .resolve_ident_in_module( + module, + ident, + ns, + parent_scope, + finalize, + ignore_binding, + ignore_import, + ) + .map_err(|(determinacy, _)| determinacy) } else if let Some(ribs) = ribs && let Some(TypeNS | ValueNS) = opt_ns { assert!(ignore_import.is_none()); - match self.resolve_ident_in_lexical_scope( + match self.get_mut().resolve_ident_in_lexical_scope( ident, ns, parent_scope, @@ -1588,7 +1612,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Some(LexicalScopeBinding::Item(binding)) => Ok(binding), // we found a local variable or type param Some(LexicalScopeBinding::Res(res)) => { - record_segment_res(self, res); + record_segment_res(self.reborrow(), finalize, res, id); return PathResult::NonModule(PartialRes::with_unresolved_segments( res, path.len() - 1, @@ -1597,7 +1621,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { _ => Err(Determinacy::determined(finalize.is_some())), } } else { - self.early_resolve_ident_in_lexical_scope( + self.reborrow().early_resolve_ident_in_lexical_scope( ident, ScopeSet::All(ns), parent_scope, @@ -1618,8 +1642,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Mark every privacy error in this path with the res to the last element. This allows us // to detect the item the user cares about and either find an alternative import, or tell // the user it is not accessible. - for error in &mut self.privacy_errors[privacy_errors_len..] { - error.outermost_res = Some((res, ident)); + if finalize.is_some() { + for error in &mut self.get_mut().privacy_errors[privacy_errors_len..] { + error.outermost_res = Some((res, ident)); + } } let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(res); @@ -1628,7 +1654,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { module_had_parse_errors = true; } module = Some(ModuleOrUniformRoot::Module(self.expect_module(def_id))); - record_segment_res(self, res); + record_segment_res(self.reborrow(), finalize, res, id); } else if res == Res::ToolMod && !is_last && opt_ns.is_some() { if binding.is_import() { self.dcx().emit_err(errors::ToolModuleImported { @@ -1641,8 +1667,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } else if res == Res::Err { return PathResult::NonModule(PartialRes::new(Res::Err)); } else if opt_ns.is_some() && (is_last || maybe_assoc) { - self.lint_if_path_starts_with_module(finalize, path, second_binding); - record_segment_res(self, res); + if let Some(finalize) = finalize { + self.get_mut().lint_if_path_starts_with_module( + finalize, + path, + second_binding, + ); + } + record_segment_res(self.reborrow(), finalize, res, id); return PathResult::NonModule(PartialRes::with_unresolved_segments( res, path.len() - segment_idx - 1, @@ -1677,6 +1709,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { )); } + let mut this = self.reborrow(); return PathResult::failed( ident, is_last, @@ -1684,7 +1717,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { module_had_parse_errors, module, || { - self.report_path_resolution_error( + this.get_mut().report_path_resolution_error( path, opt_ns, parent_scope, @@ -1701,7 +1734,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - self.lint_if_path_starts_with_module(finalize, path, second_binding); + if let Some(finalize) = finalize { + self.get_mut().lint_if_path_starts_with_module(finalize, path, second_binding); + } PathResult::Module(match module { Some(module) => module, diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 156df45147f..403d440bee7 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -33,9 +33,10 @@ use crate::errors::{ ConsiderAddingMacroExport, ConsiderMarkingAsPub, }; use crate::{ - AmbiguityError, AmbiguityKind, BindingKey, Determinacy, Finalize, ImportSuggestion, Module, - ModuleOrUniformRoot, NameBinding, NameBindingData, NameBindingKind, ParentScope, PathResult, - PerNS, ResolutionError, Resolver, ScopeSet, Segment, Used, module_to_string, names_to_string, + AmbiguityError, AmbiguityKind, BindingKey, CmResolver, Determinacy, Finalize, ImportSuggestion, + Module, ModuleOrUniformRoot, NameBinding, NameBindingData, NameBindingKind, ParentScope, + PathResult, PerNS, ResolutionError, Resolver, ScopeSet, Segment, Used, module_to_string, + names_to_string, }; type Res = def::Res<NodeId>; @@ -489,7 +490,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Define or update `binding` in `module`s glob importers. for import in glob_importers.iter() { let mut ident = key.ident; - let scope = match ident.span.reverse_glob_adjust(module.expansion, import.span) { + let scope = match ident.0.span.reverse_glob_adjust(module.expansion, import.span) { Some(Some(def)) => self.expn_def_scope(def), Some(None) => import.parent_scope.module, None => continue, @@ -498,7 +499,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let imported_binding = self.import(binding, *import); let _ = self.try_define_local( import.parent_scope.module, - ident, + ident.0, key.ns, imported_binding, warn_ambiguity, @@ -551,13 +552,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// Resolves all imports for the crate. This method performs the fixed- /// point iteration. pub(crate) fn resolve_imports(&mut self) { + self.assert_speculative = true; let mut prev_indeterminate_count = usize::MAX; let mut indeterminate_count = self.indeterminate_imports.len() * 3; while indeterminate_count < prev_indeterminate_count { prev_indeterminate_count = indeterminate_count; indeterminate_count = 0; for import in mem::take(&mut self.indeterminate_imports) { - let import_indeterminate_count = self.resolve_import(import); + let import_indeterminate_count = self.cm().resolve_import(import); indeterminate_count += import_indeterminate_count; match import_indeterminate_count { 0 => self.determined_imports.push(import), @@ -565,6 +567,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } } + self.assert_speculative = false; } pub(crate) fn finalize_imports(&mut self) { @@ -837,7 +840,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// /// Meanwhile, if resolve successful, the resolved bindings are written /// into the module. - fn resolve_import(&mut self, import: Import<'ra>) -> usize { + fn resolve_import<'r>(mut self: CmResolver<'r, 'ra, 'tcx>, import: Import<'ra>) -> usize { debug!( "(resolving import for module) resolving import `{}::...` in `{}`", Segment::names_to_string(&import.module_path), @@ -846,7 +849,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let module = if let Some(module) = import.imported_module.get() { module } else { - let path_res = self.maybe_resolve_path( + let path_res = self.reborrow().maybe_resolve_path( &import.module_path, None, &import.parent_scope, @@ -866,19 +869,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { (source, target, bindings, type_ns_only) } ImportKind::Glob { .. } => { - self.resolve_glob_import(import); + // FIXME: Use mutable resolver directly as a hack, this should be an output of + // specualtive resolution. + self.get_mut_unchecked().resolve_glob_import(import); return 0; } _ => unreachable!(), }; let mut indeterminate_count = 0; - self.per_ns(|this, ns| { + self.per_ns_cm(|this, ns| { if !type_ns_only || ns == TypeNS { if bindings[ns].get() != PendingBinding::Pending { return; }; - let binding_result = this.maybe_resolve_ident_in_module( + let binding_result = this.reborrow().maybe_resolve_ident_in_module( module, source, ns, @@ -901,16 +906,30 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // We need the `target`, `source` can be extracted. let imported_binding = this.import(binding, import); - this.define_binding_local(parent, target, ns, imported_binding); + // FIXME: Use mutable resolver directly as a hack, this should be an output of + // specualtive resolution. + this.get_mut_unchecked().define_binding_local( + parent, + target, + ns, + imported_binding, + ); PendingBinding::Ready(Some(imported_binding)) } Err(Determinacy::Determined) => { // Don't remove underscores from `single_imports`, they were never added. if target.name != kw::Underscore { let key = BindingKey::new(target, ns); - this.update_local_resolution(parent, key, false, |_, resolution| { - resolution.single_imports.swap_remove(&import); - }); + // FIXME: Use mutable resolver directly as a hack, this should be an output of + // specualtive resolution. + this.get_mut_unchecked().update_local_resolution( + parent, + key, + false, + |_, resolution| { + resolution.single_imports.swap_remove(&import); + }, + ); } PendingBinding::Ready(None) } @@ -943,7 +962,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // We'll provide more context to the privacy errors later, up to `len`. let privacy_errors_len = self.privacy_errors.len(); - let path_res = self.resolve_path( + let path_res = self.cm().resolve_path( &import.module_path, None, &import.parent_scope, @@ -1060,7 +1079,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // 2 segments, so the `resolve_path` above won't trigger it. let mut full_path = import.module_path.clone(); full_path.push(Segment::from_ident(Ident::dummy())); - self.lint_if_path_starts_with_module(Some(finalize), &full_path, None); + self.lint_if_path_starts_with_module(finalize, &full_path, None); } if let ModuleOrUniformRoot::Module(module) = module @@ -1103,7 +1122,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // importing it if available. let mut path = import.module_path.clone(); path.push(Segment::from_ident(ident)); - if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = self.resolve_path( + if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = self.cm().resolve_path( &path, None, &import.parent_scope, @@ -1121,7 +1140,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut all_ns_err = true; self.per_ns(|this, ns| { if !type_ns_only || ns == TypeNS { - let binding = this.resolve_ident_in_module( + let binding = this.cm().resolve_ident_in_module( module, ident, ns, @@ -1184,7 +1203,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut all_ns_failed = true; self.per_ns(|this, ns| { if !type_ns_only || ns == TypeNS { - let binding = this.resolve_ident_in_module( + let binding = this.cm().resolve_ident_in_module( module, ident, ns, @@ -1373,7 +1392,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { full_path.push(Segment::from_ident(ident)); self.per_ns(|this, ns| { if let Some(binding) = bindings[ns].get().binding().map(|b| b.import_source()) { - this.lint_if_path_starts_with_module(Some(finalize), &full_path, Some(binding)); + this.lint_if_path_starts_with_module(finalize, &full_path, Some(binding)); } }); } @@ -1426,7 +1445,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return; } - match this.early_resolve_ident_in_lexical_scope( + match this.cm().early_resolve_ident_in_lexical_scope( target, ScopeSet::All(ns), &import.parent_scope, @@ -1504,7 +1523,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }) .collect::<Vec<_>>(); for (mut key, binding) in bindings { - let scope = match key.ident.span.reverse_glob_adjust(module.expansion, import.span) { + let scope = match key.ident.0.span.reverse_glob_adjust(module.expansion, import.span) { Some(Some(def)) => self.expn_def_scope(def), Some(None) => import.parent_scope.module, None => continue, @@ -1517,7 +1536,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .is_some_and(|binding| binding.warn_ambiguity_recursive()); let _ = self.try_define_local( import.parent_scope.module, - key.ident, + key.ident.0, key.ns, imported_binding, warn_ambiguity, @@ -1550,7 +1569,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { next_binding = binding; } - children.push(ModChild { ident, res, vis: binding.vis, reexport_chain }); + children.push(ModChild { ident: ident.0, res, vis: binding.vis, reexport_chain }); } }); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index ed9622a0d81..8f0c08c3998 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -12,7 +12,6 @@ use std::collections::BTreeSet; use std::collections::hash_map::Entry; use std::mem::{replace, swap, take}; -use rustc_ast::ptr::P; use rustc_ast::visit::{ AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor, try_visit, visit_opt, walk_list, }; @@ -670,7 +669,7 @@ pub(crate) struct UnnecessaryQualification<'ra> { #[derive(Default, Debug)] struct DiagMetadata<'ast> { /// The current trait's associated items' ident, used for diagnostic suggestions. - current_trait_assoc_items: Option<&'ast [P<AssocItem>]>, + current_trait_assoc_items: Option<&'ast [Box<AssocItem>]>, /// The current self type if inside an impl (used for better errors). current_self_type: Option<Ty>, @@ -720,7 +719,7 @@ struct DiagMetadata<'ast> { current_type_path: Option<&'ast Ty>, /// The current impl items (used to suggest). - current_impl_items: Option<&'ast [P<AssocItem>]>, + current_impl_items: Option<&'ast [Box<AssocItem>]>, /// When processing impl trait currently_processing_impl_trait: Option<(TraitRef, Ty)>, @@ -910,22 +909,15 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc span, |this| { this.visit_generic_params(&fn_ptr.generic_params, false); - this.with_lifetime_rib( - LifetimeRibKind::AnonymousCreateParameter { - binder: ty.id, - report_in_path: false, - }, - |this| { - this.resolve_fn_signature( - ty.id, - false, - // We don't need to deal with patterns in parameters, because - // they are not possible for foreign or bodiless functions. - fn_ptr.decl.inputs.iter().map(|Param { ty, .. }| (None, &**ty)), - &fn_ptr.decl.output, - ) - }, - ); + this.resolve_fn_signature( + ty.id, + false, + // We don't need to deal with patterns in parameters, because + // they are not possible for foreign or bodiless functions. + fn_ptr.decl.inputs.iter().map(|Param { ty, .. }| (None, &**ty)), + &fn_ptr.decl.output, + false, + ) }, ) } @@ -1042,19 +1034,12 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc self.visit_fn_header(&sig.header); self.visit_ident(ident); self.visit_generics(generics); - self.with_lifetime_rib( - LifetimeRibKind::AnonymousCreateParameter { - binder: fn_id, - report_in_path: false, - }, - |this| { - this.resolve_fn_signature( - fn_id, - sig.decl.has_self(), - sig.decl.inputs.iter().map(|Param { ty, .. }| (None, &**ty)), - &sig.decl.output, - ); - }, + self.resolve_fn_signature( + fn_id, + sig.decl.has_self(), + sig.decl.inputs.iter().map(|Param { ty, .. }| (None, &**ty)), + &sig.decl.output, + false, ); return; } @@ -1080,22 +1065,15 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc .coroutine_kind .map(|coroutine_kind| coroutine_kind.return_id()); - this.with_lifetime_rib( - LifetimeRibKind::AnonymousCreateParameter { - binder: fn_id, - report_in_path: coro_node_id.is_some(), - }, - |this| { - this.resolve_fn_signature( - fn_id, - declaration.has_self(), - declaration - .inputs - .iter() - .map(|Param { pat, ty, .. }| (Some(&**pat), &**ty)), - &declaration.output, - ); - }, + this.resolve_fn_signature( + fn_id, + declaration.has_self(), + declaration + .inputs + .iter() + .map(|Param { pat, ty, .. }| (Some(&**pat), &**ty)), + &declaration.output, + coro_node_id.is_some(), ); if let Some(contract) = contract { @@ -1307,19 +1285,12 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc kind: LifetimeBinderKind::PolyTrait, .. } => { - self.with_lifetime_rib( - LifetimeRibKind::AnonymousCreateParameter { - binder, - report_in_path: false, - }, - |this| { - this.resolve_fn_signature( - binder, - false, - p_args.inputs.iter().map(|ty| (None, &**ty)), - &p_args.output, - ) - }, + self.resolve_fn_signature( + binder, + false, + p_args.inputs.iter().map(|ty| (None, &**ty)), + &p_args.output, + false, ); break; } @@ -1452,7 +1423,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // During late resolution we only track the module component of the parent scope, // although it may be useful to track other components as well for diagnostics. let graph_root = resolver.graph_root; - let parent_scope = ParentScope::module(graph_root, resolver); + let parent_scope = ParentScope::module(graph_root, resolver.arenas); let start_rib_kind = RibKind::Module(graph_root); LateResolutionVisitor { r: resolver, @@ -1512,7 +1483,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { opt_ns: Option<Namespace>, // `None` indicates a module path in import finalize: Option<Finalize>, ) -> PathResult<'ra> { - self.r.resolve_path_with_ribs( + self.r.cm().resolve_path_with_ribs( path, opt_ns, &self.parent_scope, @@ -2236,25 +2207,32 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { has_self: bool, inputs: impl Iterator<Item = (Option<&'ast Pat>, &'ast Ty)> + Clone, output_ty: &'ast FnRetTy, + report_elided_lifetimes_in_path: bool, ) { - // Add each argument to the rib. - let elision_lifetime = self.resolve_fn_params(has_self, inputs); - debug!(?elision_lifetime); - - let outer_failures = take(&mut self.diag_metadata.current_elision_failures); - let output_rib = if let Ok(res) = elision_lifetime.as_ref() { - self.r.lifetime_elision_allowed.insert(fn_id); - LifetimeRibKind::Elided(*res) - } else { - LifetimeRibKind::ElisionFailure + let rib = LifetimeRibKind::AnonymousCreateParameter { + binder: fn_id, + report_in_path: report_elided_lifetimes_in_path, }; - self.with_lifetime_rib(output_rib, |this| visit::walk_fn_ret_ty(this, output_ty)); - let elision_failures = - replace(&mut self.diag_metadata.current_elision_failures, outer_failures); - if !elision_failures.is_empty() { - let Err(failure_info) = elision_lifetime else { bug!() }; - self.report_missing_lifetime_specifiers(elision_failures, Some(failure_info)); - } + self.with_lifetime_rib(rib, |this| { + // Add each argument to the rib. + let elision_lifetime = this.resolve_fn_params(has_self, inputs); + debug!(?elision_lifetime); + + let outer_failures = take(&mut this.diag_metadata.current_elision_failures); + let output_rib = if let Ok(res) = elision_lifetime.as_ref() { + this.r.lifetime_elision_allowed.insert(fn_id); + LifetimeRibKind::Elided(*res) + } else { + LifetimeRibKind::ElisionFailure + }; + this.with_lifetime_rib(output_rib, |this| visit::walk_fn_ret_ty(this, output_ty)); + let elision_failures = + replace(&mut this.diag_metadata.current_elision_failures, outer_failures); + if !elision_failures.is_empty() { + let Err(failure_info) = elision_lifetime else { bug!() }; + this.report_missing_lifetime_specifiers(elision_failures, Some(failure_info)); + } + }); } /// Resolve inside function parameters and parameter types. @@ -3059,7 +3037,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } /// When evaluating a `trait` use its associated types' idents for suggestions in E0412. - fn resolve_trait_items(&mut self, trait_items: &'ast [P<AssocItem>]) { + fn resolve_trait_items(&mut self, trait_items: &'ast [Box<AssocItem>]) { let trait_assoc_items = replace(&mut self.diag_metadata.current_trait_assoc_items, Some(trait_items)); @@ -3200,7 +3178,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { opt_trait_reference: &'ast Option<TraitRef>, self_type: &'ast Ty, item_id: NodeId, - impl_items: &'ast [P<AssocItem>], + impl_items: &'ast [Box<AssocItem>], ) { debug!("resolve_implementation"); // If applicable, create a rib for the type parameters. @@ -3692,7 +3670,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { /// pattern as a whole counts as a never pattern (since it's definitionallly unreachable). fn compute_and_check_or_pat_binding_map( &mut self, - pats: &[P<Pat>], + pats: &[Box<Pat>], ) -> Result<FxIndexMap<Ident, BindingInfo>, IsNeverPattern> { let mut missing_vars = FxIndexMap::default(); let mut inconsistent_vars = FxIndexMap::default(); @@ -4130,7 +4108,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { fn smart_resolve_path( &mut self, id: NodeId, - qself: &Option<P<QSelf>>, + qself: &Option<Box<QSelf>>, path: &Path, source: PathSource<'_, 'ast, '_>, ) { @@ -4147,7 +4125,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { #[instrument(level = "debug", skip(self))] fn smart_resolve_path_fragment( &mut self, - qself: &Option<P<QSelf>>, + qself: &Option<Box<QSelf>>, path: &[Segment], source: PathSource<'_, 'ast, '_>, finalize: Finalize, @@ -4252,13 +4230,21 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // // And that's what happens below - we're just mixing both messages // into a single one. + let failed_to_resolve = match parent_err.node { + ResolutionError::FailedToResolve { .. } => true, + _ => false, + }; let mut parent_err = this.r.into_struct_error(parent_err.span, parent_err.node); // overwrite all properties with the parent's error message err.messages = take(&mut parent_err.messages); err.code = take(&mut parent_err.code); swap(&mut err.span, &mut parent_err.span); - err.children = take(&mut parent_err.children); + if failed_to_resolve { + err.children = take(&mut parent_err.children); + } else { + err.children.append(&mut parent_err.children); + } err.sort_span = parent_err.sort_span; err.is_lint = parent_err.is_lint.clone(); @@ -4447,7 +4433,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // Resolve in alternative namespaces if resolution in the primary namespace fails. fn resolve_qpath_anywhere( &mut self, - qself: &Option<P<QSelf>>, + qself: &Option<Box<QSelf>>, path: &[Segment], primary_ns: Namespace, span: Span, @@ -4479,9 +4465,15 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { if qself.is_none() { let path_seg = |seg: &Segment| PathSegment::from_ident(seg.ident); let path = Path { segments: path.iter().map(path_seg).collect(), span, tokens: None }; - if let Ok((_, res)) = - self.r.resolve_macro_path(&path, None, &self.parent_scope, false, false, None, None) - { + if let Ok((_, res)) = self.r.cm().resolve_macro_path( + &path, + None, + &self.parent_scope, + false, + false, + None, + None, + ) { return Ok(Some(PartialRes::new(res))); } } @@ -4492,7 +4484,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { /// Handles paths that may refer to associated items. fn resolve_qpath( &mut self, - qself: &Option<P<QSelf>>, + qself: &Option<Box<QSelf>>, path: &[Segment], ns: Namespace, finalize: Finalize, diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 98e48664e68..0807142a7c3 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -4,7 +4,6 @@ use std::borrow::Cow; use std::iter; use std::ops::Deref; -use rustc_ast::ptr::P; use rustc_ast::visit::{FnCtxt, FnKind, LifetimeCtxt, Visitor, walk_ty}; use rustc_ast::{ self as ast, AssocItemKind, DUMMY_NODE_ID, Expr, ExprKind, GenericParam, GenericParamKind, @@ -525,9 +524,8 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } self.err_code_special_cases(&mut err, source, path, span); - if let Some(module) = base_error.module { - self.r.find_cfg_stripped(&mut err, &path.last().unwrap().ident.name, module); - } + let module = base_error.module.unwrap_or_else(|| CRATE_DEF_ID.to_def_id()); + self.r.find_cfg_stripped(&mut err, &path.last().unwrap().ident.name, module); (err, candidates) } @@ -1473,7 +1471,10 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { }) .collect(); if let [target] = targets.as_slice() { - return Some(TypoSuggestion::single_item_from_ident(target.0.ident, target.1)); + return Some(TypoSuggestion::single_item_from_ident( + target.0.ident.0, + target.1, + )); } } } @@ -2148,7 +2149,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { err: &mut Diag<'_>, path_span: Span, call_span: Span, - args: &[P<Expr>], + args: &[Box<Expr>], ) { if def_id.is_local() { // Doing analysis on local `DefId`s would cause infinite recursion. @@ -2387,7 +2388,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { // Look for associated items in the current trait. if let Some((module, _)) = self.current_trait_ref - && let Ok(binding) = self.r.maybe_resolve_ident_in_module( + && let Ok(binding) = self.r.cm().maybe_resolve_ident_in_module( ModuleOrUniformRoot::Module(module), ident, ns, @@ -2477,19 +2478,10 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } else { // Items from the prelude if !module.no_implicit_prelude { - let extern_prelude = self.r.extern_prelude.clone(); - names.extend(extern_prelude.iter().flat_map(|(ident, _)| { - self.r - .cstore_mut() - .maybe_process_path_extern(self.r.tcx, ident.name) - .and_then(|crate_id| { - let crate_mod = - Res::Def(DefKind::Mod, crate_id.as_def_id()); - - filter_fn(crate_mod).then(|| { - TypoSuggestion::typo_from_ident(*ident, crate_mod) - }) - }) + names.extend(self.r.extern_prelude.keys().flat_map(|ident| { + let res = Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id()); + filter_fn(res) + .then_some(TypoSuggestion::typo_from_ident(ident.0, res)) })); if let Some(prelude) = self.r.prelude { @@ -2649,7 +2641,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { if let Some(module_def_id) = name_binding.res().module_like_def_id() { // form the path let mut path_segments = path_segments.clone(); - path_segments.push(ast::PathSegment::from_ident(ident)); + path_segments.push(ast::PathSegment::from_ident(ident.0)); let doc_visible = doc_visible && (module_def_id.is_local() || !r.tcx.is_doc_hidden(module_def_id)); if module_def_id == def_id { @@ -2688,7 +2680,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { enum_module.for_each_child(self.r, |_, ident, _, name_binding| { if let Res::Def(DefKind::Ctor(CtorOf::Variant, kind), def_id) = name_binding.res() { let mut segms = enum_import_suggestion.path.segments.clone(); - segms.push(ast::PathSegment::from_ident(ident)); + segms.push(ast::PathSegment::from_ident(ident.0)); let path = Path { span: name_binding.span, segments: segms, tokens: None }; variants.push((path, def_id, kind)); } @@ -3795,7 +3787,7 @@ fn mk_where_bound_predicate( ident: last.ident, gen_args: None, kind: ast::AssocItemConstraintKind::Equality { - term: ast::Term::Ty(ast::ptr::P(ast::Ty { + term: ast::Term::Ty(Box::new(ast::Ty { kind: ast::TyKind::Path(None, poly_trait_ref.trait_ref.path.clone()), id: DUMMY_NODE_ID, span: DUMMY_SP, @@ -3812,7 +3804,7 @@ fn mk_where_bound_predicate( Some(_) => return None, None => { second_last.args = - Some(ast::ptr::P(ast::GenericArgs::AngleBracketed(ast::AngleBracketedArgs { + Some(Box::new(ast::GenericArgs::AngleBracketed(ast::AngleBracketedArgs { args: ThinVec::from([added_constraint]), span: DUMMY_SP, }))); @@ -3825,7 +3817,7 @@ fn mk_where_bound_predicate( let new_where_bound_predicate = ast::WhereBoundPredicate { bound_generic_params: ThinVec::new(), - bounded_ty: ast::ptr::P(ty.clone()), + bounded_ty: Box::new(ty.clone()), bounds: vec![ast::GenericBound::Trait(ast::PolyTraitRef { bound_generic_params: ThinVec::new(), modifiers: ast::TraitBoundModifiers::NONE, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 8115b87dcae..23f44ff1658 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -12,6 +12,7 @@ #![allow(rustc::untranslatable_diagnostic)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] +#![feature(arbitrary_self_types)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(if_let_guard)] @@ -41,7 +42,6 @@ use rustc_ast::{ self as ast, AngleBracketedArg, CRATE_NODE_ID, Crate, Expr, ExprKind, GenericArg, GenericArgs, LitKind, NodeId, Path, attr, }; -use rustc_attr_data_structures::StrippedCfgItem; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_data_structures::steal::Steal; @@ -50,6 +50,7 @@ use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::{Applicability, Diag, ErrCode, ErrorGuaranteed}; use rustc_expand::base::{DeriveResolution, SyntaxExtension, SyntaxExtensionKind}; use rustc_feature::BUILTIN_ATTRIBUTES; +use rustc_hir::attrs::StrippedCfgItem; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{ self, CtorOf, DefKind, DocLinkResMap, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS, @@ -64,14 +65,14 @@ use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::query::Providers; use rustc_middle::span_bug; use rustc_middle::ty::{ - self, DelegationFnSig, Feed, MainDefinition, RegisteredTools, ResolverGlobalCtxt, - ResolverOutputs, TyCtxt, TyCtxtFeed, Visibility, + self, DelegationFnSig, Feed, MainDefinition, RegisteredTools, ResolverAstLowering, + ResolverGlobalCtxt, TyCtxt, TyCtxtFeed, Visibility, }; use rustc_query_system::ich::StableHashingContext; use rustc_session::lint::builtin::PRIVATE_MACRO_USE; use rustc_session::lint::{BuiltinLintDiag, LintBuffer}; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transparency}; -use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; +use rustc_span::{DUMMY_SP, Ident, Macros20NormalizedIdent, Span, Symbol, kw, sym}; use smallvec::{SmallVec, smallvec}; use tracing::debug; @@ -162,11 +163,11 @@ struct ParentScope<'ra> { impl<'ra> ParentScope<'ra> { /// Creates a parent scope with the passed argument used as the module scope component, /// and other scope components set to default empty values. - fn module(module: Module<'ra>, resolver: &Resolver<'ra, '_>) -> ParentScope<'ra> { + fn module(module: Module<'ra>, arenas: &'ra ResolverArenas<'ra>) -> ParentScope<'ra> { ParentScope { module, expansion: LocalExpnId::ROOT, - macro_rules: resolver.arenas.alloc_macro_rules_scope(MacroRulesScope::Empty), + macro_rules: arenas.alloc_macro_rules_scope(MacroRulesScope::Empty), derives: &[], } } @@ -531,7 +532,7 @@ impl ModuleKind { struct BindingKey { /// The identifier for the binding, always the `normalize_to_macros_2_0` version of the /// identifier. - ident: Ident, + ident: Macros20NormalizedIdent, ns: Namespace, /// When we add an underscore binding (with ident `_`) to some module, this field has /// a non-zero value that uniquely identifies this binding in that module. @@ -543,7 +544,7 @@ struct BindingKey { impl BindingKey { fn new(ident: Ident, ns: Namespace) -> Self { - BindingKey { ident: ident.normalize_to_macros_2_0(), ns, disambiguator: 0 } + BindingKey { ident: Macros20NormalizedIdent::new(ident), ns, disambiguator: 0 } } fn new_disambiguated( @@ -552,7 +553,7 @@ impl BindingKey { disambiguator: impl FnOnce() -> u32, ) -> BindingKey { let disambiguator = if ident.name == kw::Underscore { disambiguator() } else { 0 }; - BindingKey { ident: ident.normalize_to_macros_2_0(), ns, disambiguator } + BindingKey { ident: Macros20NormalizedIdent::new(ident), ns, disambiguator } } } @@ -593,7 +594,8 @@ struct ModuleData<'ra> { globs: RefCell<Vec<Import<'ra>>>, /// Used to memoize the traits in this module for faster searches through all traits in scope. - traits: RefCell<Option<Box<[(Ident, NameBinding<'ra>, Option<Module<'ra>>)]>>>, + traits: + RefCell<Option<Box<[(Macros20NormalizedIdent, NameBinding<'ra>, Option<Module<'ra>>)]>>>, /// Span of the module itself. Used for error reporting. span: Span, @@ -659,7 +661,7 @@ impl<'ra> Module<'ra> { fn for_each_child<'tcx, R: AsRef<Resolver<'ra, 'tcx>>>( self, resolver: &R, - mut f: impl FnMut(&R, Ident, Namespace, NameBinding<'ra>), + mut f: impl FnMut(&R, Macros20NormalizedIdent, Namespace, NameBinding<'ra>), ) { for (key, name_resolution) in resolver.as_ref().resolutions(self).borrow().iter() { if let Some(binding) = name_resolution.borrow().best_binding() { @@ -671,7 +673,7 @@ impl<'ra> Module<'ra> { fn for_each_child_mut<'tcx, R: AsMut<Resolver<'ra, 'tcx>>>( self, resolver: &mut R, - mut f: impl FnMut(&mut R, Ident, Namespace, NameBinding<'ra>), + mut f: impl FnMut(&mut R, Macros20NormalizedIdent, Namespace, NameBinding<'ra>), ) { for (key, name_resolution) in resolver.as_mut().resolutions(self).borrow().iter() { if let Some(binding) = name_resolution.borrow().best_binding() { @@ -1009,13 +1011,13 @@ impl<'ra> NameBindingData<'ra> { #[derive(Default, Clone)] struct ExternPreludeEntry<'ra> { - binding: Option<NameBinding<'ra>>, + binding: Cell<Option<NameBinding<'ra>>>, introduced_by_item: bool, } impl ExternPreludeEntry<'_> { fn is_import(&self) -> bool { - self.binding.is_some_and(|binding| binding.is_import()) + self.binding.get().is_some_and(|binding| binding.is_import()) } } @@ -1027,16 +1029,22 @@ struct DeriveData { struct MacroData { ext: Arc<SyntaxExtension>, + attr_ext: Option<Arc<SyntaxExtension>>, nrules: usize, macro_rules: bool, } impl MacroData { fn new(ext: Arc<SyntaxExtension>) -> MacroData { - MacroData { ext, nrules: 0, macro_rules: false } + MacroData { ext, attr_ext: None, nrules: 0, macro_rules: false } } } +pub struct ResolverOutputs { + pub global_ctxt: ResolverGlobalCtxt, + pub ast_lowering: ResolverAstLowering, +} + /// The main resolver class. /// /// This is the visitor that walks the whole crate. @@ -1048,8 +1056,11 @@ pub struct Resolver<'ra, 'tcx> { graph_root: Module<'ra>, + /// Assert that we are in speculative resolution mode. + assert_speculative: bool, + prelude: Option<Module<'ra>>, - extern_prelude: FxIndexMap<Ident, ExternPreludeEntry<'ra>>, + extern_prelude: FxIndexMap<Macros20NormalizedIdent, ExternPreludeEntry<'ra>>, /// N.B., this is used only for better diagnostics, not name resolution itself. field_names: LocalDefIdMap<Vec<Ident>>, @@ -1150,10 +1161,11 @@ pub struct Resolver<'ra, 'tcx> { unused_macro_rules: FxIndexMap<NodeId, DenseBitSet<usize>>, proc_macro_stubs: FxHashSet<LocalDefId>, /// Traces collected during macro resolution and validated when it's complete. + // FIXME: Remove interior mutability when speculative resolution produces these as outputs. single_segment_macro_resolutions: - Vec<(Ident, MacroKind, ParentScope<'ra>, Option<NameBinding<'ra>>, Option<Span>)>, + RefCell<Vec<(Ident, MacroKind, ParentScope<'ra>, Option<NameBinding<'ra>>, Option<Span>)>>, multi_segment_macro_resolutions: - Vec<(Vec<Segment>, Span, MacroKind, ParentScope<'ra>, Option<Res>, Namespace)>, + RefCell<Vec<(Vec<Segment>, Span, MacroKind, ParentScope<'ra>, Option<Res>, Namespace)>>, builtin_attrs: Vec<(Ident, ParentScope<'ra>)>, /// `derive(Copy)` marks items they are applied to so they are treated specially later. /// Derive macros cannot modify the item themselves and have to store the markers in the global @@ -1482,19 +1494,31 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut invocation_parents = FxHashMap::default(); invocation_parents.insert(LocalExpnId::ROOT, InvocationParent::ROOT); - let mut extern_prelude: FxIndexMap<Ident, ExternPreludeEntry<'_>> = tcx + let mut extern_prelude: FxIndexMap<_, _> = tcx .sess .opts .externs .iter() - .filter(|(_, entry)| entry.add_prelude) - .map(|(name, _)| (Ident::from_str(name), Default::default())) + .filter_map(|(name, entry)| { + // Make sure `self`, `super`, `_` etc do not get into extern prelude. + // FIXME: reject `--extern self` and similar in option parsing instead. + if entry.add_prelude + && let name = Symbol::intern(name) + && name.can_be_raw() + { + Some((Macros20NormalizedIdent::with_dummy_span(name), Default::default())) + } else { + None + } + }) .collect(); if !attr::contains_name(attrs, sym::no_core) { - extern_prelude.insert(Ident::with_dummy_span(sym::core), Default::default()); + extern_prelude + .insert(Macros20NormalizedIdent::with_dummy_span(sym::core), Default::default()); if !attr::contains_name(attrs, sym::no_std) { - extern_prelude.insert(Ident::with_dummy_span(sym::std), Default::default()); + extern_prelude + .insert(Macros20NormalizedIdent::with_dummy_span(sym::std), Default::default()); } } @@ -1509,6 +1533,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // The outermost module has def ID 0; this is not reflected in the // AST. graph_root, + assert_speculative: false, // Only set/cleared in Resolver::resolve_imports for now prelude: None, extern_prelude, @@ -1626,7 +1651,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { impl_trait_names: Default::default(), }; - let root_parent_scope = ParentScope::module(graph_root, &resolver); + let root_parent_scope = ParentScope::module(graph_root, resolver.arenas); resolver.invocation_parent_scopes.insert(LocalExpnId::ROOT, root_parent_scope); resolver.feed_visibility(crate_feed, Visibility::Public); @@ -1774,6 +1799,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } + /// Returns a conditionally mutable resolver. + /// + /// Currently only dependent on `assert_speculative`, if `assert_speculative` is false, + /// the resolver will allow mutation; otherwise, it will be immutable. + fn cm(&mut self) -> CmResolver<'_, 'ra, 'tcx> { + CmResolver::new(self, !self.assert_speculative) + } + /// Runs the function on each namespace. fn per_ns<F: FnMut(&mut Self, Namespace)>(&mut self, mut f: F) { f(self, TypeNS); @@ -1781,6 +1814,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { f(self, MacroNS); } + fn per_ns_cm<'r, F: FnMut(&mut CmResolver<'r, 'ra, 'tcx>, Namespace)>( + mut self: CmResolver<'r, 'ra, 'tcx>, + mut f: F, + ) { + f(&mut self, TypeNS); + f(&mut self, ValueNS); + f(&mut self, MacroNS); + } + fn is_builtin_macro(&self, res: Res) -> bool { self.get_macro(res).is_some_and(|macro_data| macro_data.ext.builtin_name.is_some()) } @@ -1834,14 +1876,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - self.visit_scopes(ScopeSet::All(TypeNS), parent_scope, ctxt, |this, scope, _, _| { + self.cm().visit_scopes(ScopeSet::All(TypeNS), parent_scope, ctxt, |this, scope, _, _| { match scope { Scope::Module(module, _) => { - this.traits_in_module(module, assoc_item, &mut found_traits); + this.get_mut().traits_in_module(module, assoc_item, &mut found_traits); } Scope::StdLibPrelude => { if let Some(module) = this.prelude { - this.traits_in_module(module, assoc_item, &mut found_traits); + this.get_mut().traits_in_module(module, assoc_item, &mut found_traits); } } Scope::ExternPrelude | Scope::ToolPrelude | Scope::BuiltinTypes => {} @@ -1864,7 +1906,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for &(trait_name, trait_binding, trait_module) in traits.as_ref().unwrap().iter() { if self.trait_may_have_item(trait_module, assoc_item) { let def_id = trait_binding.res().def_id(); - let import_ids = self.find_transitive_imports(&trait_binding.kind, trait_name); + let import_ids = self.find_transitive_imports(&trait_binding.kind, trait_name.0); found_traits.push(TraitCandidate { def_id, import_ids }); } } @@ -1984,14 +2026,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Do not report the lint if the macro name resolves in stdlib prelude // even without the problematic `macro_use` import. let found_in_stdlib_prelude = self.prelude.is_some_and(|prelude| { - self.maybe_resolve_ident_in_module( - ModuleOrUniformRoot::Module(prelude), - ident, - MacroNS, - &ParentScope::module(self.empty_module, self), - None, - ) - .is_ok() + let empty_module = self.empty_module; + let arenas = self.arenas; + self.cm() + .maybe_resolve_ident_in_module( + ModuleOrUniformRoot::Module(prelude), + ident, + MacroNS, + &ParentScope::module(empty_module, arenas), + None, + ) + .is_ok() }); if !found_in_stdlib_prelude { self.lint_buffer().buffer_lint( @@ -2005,8 +2050,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Avoid marking `extern crate` items that refer to a name from extern prelude, // but not introduce it, as used if they are accessed from lexical scope. if used == Used::Scope { - if let Some(entry) = self.extern_prelude.get(&ident.normalize_to_macros_2_0()) { - if !entry.introduced_by_item && entry.binding == Some(used_binding) { + if let Some(entry) = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)) { + if !entry.introduced_by_item && entry.binding.get() == Some(used_binding) { return; } } @@ -2162,41 +2207,47 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - fn extern_prelude_get(&mut self, ident: Ident, finalize: bool) -> Option<NameBinding<'ra>> { - if ident.is_path_segment_keyword() { - // Make sure `self`, `super` etc produce an error when passed to here. - return None; - } - - let norm_ident = ident.normalize_to_macros_2_0(); - let binding = self.extern_prelude.get(&norm_ident).cloned().and_then(|entry| { - Some(if let Some(binding) = entry.binding { + fn extern_prelude_get<'r>( + mut self: CmResolver<'r, 'ra, 'tcx>, + ident: Ident, + finalize: bool, + ) -> Option<NameBinding<'ra>> { + let mut record_use = None; + let entry = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)); + let binding = entry.and_then(|entry| match entry.binding.get() { + Some(binding) if binding.is_import() => { if finalize { - if !entry.is_import() { - self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span); - } else if entry.introduced_by_item { - self.record_use(ident, binding, Used::Other); - } + record_use = Some(binding); } - binding - } else { + Some(binding) + } + Some(binding) => { + if finalize { + self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span); + } + Some(binding) + } + None => { let crate_id = if finalize { - let Some(crate_id) = - self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span) - else { - return Some(self.dummy_binding); - }; - crate_id + self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span) } else { - self.cstore_mut().maybe_process_path_extern(self.tcx, ident.name)? + self.cstore_mut().maybe_process_path_extern(self.tcx, ident.name) }; - let res = Res::Def(DefKind::Mod, crate_id.as_def_id()); - self.arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT) - }) + match crate_id { + Some(crate_id) => { + let res = Res::Def(DefKind::Mod, crate_id.as_def_id()); + let binding = + self.arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT); + entry.binding.set(Some(binding)); + Some(binding) + } + None => finalize.then_some(self.dummy_binding), + } + } }); - if let Some(entry) = self.extern_prelude.get_mut(&norm_ident) { - entry.binding = binding; + if let Some(binding) = record_use { + self.get_mut().record_use(ident, binding, Used::Scope); } binding @@ -2231,7 +2282,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .collect(); let Ok(segments) = segments else { return None }; - match self.maybe_resolve_path(&segments, Some(ns), &parent_scope, None) { + match self.cm().maybe_resolve_path(&segments, Some(ns), &parent_scope, None) { PathResult::Module(ModuleOrUniformRoot::Module(module)) => Some(module.res().unwrap()), PathResult::NonModule(path_res) => { path_res.full_res().filter(|res| !matches!(res, Res::Def(DefKind::Ctor(..), _))) @@ -2310,9 +2361,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn resolve_main(&mut self) { let module = self.graph_root; let ident = Ident::with_dummy_span(sym::main); - let parent_scope = &ParentScope::module(module, self); + let parent_scope = &ParentScope::module(module, self.arenas); - let Ok(name_binding) = self.maybe_resolve_ident_in_module( + let Ok(name_binding) = self.cm().maybe_resolve_ident_in_module( ModuleOrUniformRoot::Module(module), ident, ValueNS, @@ -2406,3 +2457,63 @@ impl Finalize { pub fn provide(providers: &mut Providers) { providers.registered_tools = macros::registered_tools; } + +mod ref_mut { + use std::ops::Deref; + + /// A wrapper around a mutable reference that conditionally allows mutable access. + pub(crate) struct RefOrMut<'a, T> { + p: &'a mut T, + mutable: bool, + } + + impl<'a, T> Deref for RefOrMut<'a, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + self.p + } + } + + impl<'a, T> AsRef<T> for RefOrMut<'a, T> { + fn as_ref(&self) -> &T { + self.p + } + } + + impl<'a, T> RefOrMut<'a, T> { + pub(crate) fn new(p: &'a mut T, mutable: bool) -> Self { + RefOrMut { p, mutable } + } + + /// This is needed because this wraps a `&mut T` and is therefore not `Copy`. + pub(crate) fn reborrow(&mut self) -> RefOrMut<'_, T> { + RefOrMut { p: self.p, mutable: self.mutable } + } + + /// Returns a mutable reference to the inner value if allowed. + /// + /// # Panics + /// Panics if the `mutable` flag is false. + #[track_caller] + pub(crate) fn get_mut(&mut self) -> &mut T { + match self.mutable { + false => panic!("Can't mutably borrow speculative resolver"), + true => self.p, + } + } + + /// Returns a mutable reference to the inner value without checking if + /// it's in a mutable state. + pub(crate) fn get_mut_unchecked(&mut self) -> &mut T { + self.p + } + } +} + +/// A wrapper around `&mut Resolver` that may be mutable or immutable, depending on a conditions. +/// +/// `Cm` stands for "conditionally mutable". +/// +/// Prefer constructing it through [`Resolver::cm`] to ensure correctness. +type CmResolver<'r, 'ra, 'tcx> = ref_mut::RefOrMut<'r, Resolver<'ra, 'tcx>>; diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 20504ea609d..9173d0d3ea5 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -8,7 +8,6 @@ use std::sync::Arc; use rustc_ast::{self as ast, Crate, NodeId, attr}; use rustc_ast_pretty::pprust; -use rustc_attr_data_structures::{CfgEntry, StabilityLevel, StrippedCfgItem}; use rustc_errors::{Applicability, DiagCtxtHandle, StashKey}; use rustc_expand::base::{ Annotatable, DeriveResolution, Indeterminate, ResolverExpand, SyntaxExtension, @@ -18,6 +17,8 @@ use rustc_expand::expand::{ AstFragment, AstFragmentKind, Invocation, InvocationKind, SupportsMacroExpansion, }; use rustc_expand::{MacroRulesMacroExpander, compile_declarative_macro}; +use rustc_hir::StabilityLevel; +use rustc_hir::attrs::{CfgEntry, StrippedCfgItem}; use rustc_hir::def::{self, DefKind, Namespace, NonMacroAttrKind}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; use rustc_middle::middle::stability; @@ -40,9 +41,9 @@ use crate::errors::{ }; use crate::imports::Import; use crate::{ - BindingKey, DeriveData, Determinacy, Finalize, InvocationParent, MacroData, ModuleKind, - ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult, ResolutionError, - Resolver, ScopeSet, Segment, Used, + BindingKey, CmResolver, DeriveData, Determinacy, Finalize, InvocationParent, MacroData, + ModuleKind, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult, + ResolutionError, Resolver, ScopeSet, Segment, Used, }; type Res = def::Res<NodeId>; @@ -402,7 +403,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { for (i, resolution) in entry.resolutions.iter_mut().enumerate() { if resolution.exts.is_none() { resolution.exts = Some( - match self.resolve_macro_path( + match self.cm().resolve_macro_path( &resolution.path, Some(MacroKind::Derive), &parent_scope, @@ -535,11 +536,11 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { target_trait.for_each_child(self, |this, ident, ns, _binding| { // FIXME: Adjust hygiene for idents from globs, like for glob imports. if let Some(overriding_keys) = this.impl_binding_keys.get(&impl_def_id) - && overriding_keys.contains(&BindingKey::new(ident, ns)) + && overriding_keys.contains(&BindingKey::new(ident.0, ns)) { // The name is overridden, do not produce it from the glob delegation. } else { - idents.push((ident, None)); + idents.push((ident.0, None)); } }); Ok(idents) @@ -567,7 +568,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { invoc_in_mod_inert_attr: Option<LocalDefId>, suggestion_span: Option<Span>, ) -> Result<(Arc<SyntaxExtension>, Res), Indeterminate> { - let (ext, res) = match self.resolve_macro_or_delegation_path( + let (ext, res) = match self.cm().resolve_macro_or_delegation_path( path, Some(kind), parent_scope, @@ -712,8 +713,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Ok((ext, res)) } - pub(crate) fn resolve_macro_path( - &mut self, + pub(crate) fn resolve_macro_path<'r>( + self: CmResolver<'r, 'ra, 'tcx>, path: &ast::Path, kind: Option<MacroKind>, parent_scope: &ParentScope<'ra>, @@ -735,8 +736,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) } - fn resolve_macro_or_delegation_path( - &mut self, + fn resolve_macro_or_delegation_path<'r>( + mut self: CmResolver<'r, 'ra, 'tcx>, ast_path: &ast::Path, kind: Option<MacroKind>, parent_scope: &ParentScope<'ra>, @@ -762,7 +763,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let res = if deleg_impl.is_some() || path.len() > 1 { let ns = if deleg_impl.is_some() { TypeNS } else { MacroNS }; - let res = match self.maybe_resolve_path(&path, Some(ns), parent_scope, ignore_import) { + let res = match self.reborrow().maybe_resolve_path( + &path, + Some(ns), + parent_scope, + ignore_import, + ) { PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => Ok(res), PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined), PathResult::NonModule(..) @@ -776,7 +782,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if trace { let kind = kind.expect("macro kind must be specified if tracing is enabled"); - self.multi_segment_macro_resolutions.push(( + // FIXME: Should be an output of Speculative Resolution. + self.multi_segment_macro_resolutions.borrow_mut().push(( path, path_span, kind, @@ -790,7 +797,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { res } else { let scope_set = kind.map_or(ScopeSet::All(MacroNS), ScopeSet::Macro); - let binding = self.early_resolve_ident_in_lexical_scope( + let binding = self.reborrow().early_resolve_ident_in_lexical_scope( path[0].ident, scope_set, parent_scope, @@ -805,7 +812,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if trace { let kind = kind.expect("macro kind must be specified if tracing is enabled"); - self.single_segment_macro_resolutions.push(( + // FIXME: Should be an output of Speculative Resolution. + self.single_segment_macro_resolutions.borrow_mut().push(( path[0].ident, kind, *parent_scope, @@ -816,7 +824,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let res = binding.map(|binding| binding.res()); self.prohibit_imported_non_macro_attrs(binding.ok(), res.ok(), path_span); - self.report_out_of_scope_macro_calls( + self.reborrow().report_out_of_scope_macro_calls( ast_path, parent_scope, invoc_in_mod_inert_attr, @@ -834,7 +842,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } _ => None, }, - None => self.get_macro(res).map(|macro_data| Arc::clone(¯o_data.ext)), + None => self.get_macro(res).map(|macro_data| match kind { + Some(MacroKind::Attr) if let Some(ref ext) = macro_data.attr_ext => Arc::clone(ext), + _ => Arc::clone(¯o_data.ext), + }), }; Ok((ext, res)) } @@ -871,13 +882,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } }; - let macro_resolutions = mem::take(&mut self.multi_segment_macro_resolutions); + // FIXME: Should be an output of Speculative Resolution. + let macro_resolutions = self.multi_segment_macro_resolutions.take(); for (mut path, path_span, kind, parent_scope, initial_res, ns) in macro_resolutions { // FIXME: Path resolution will ICE if segment IDs present. for seg in &mut path { seg.id = None; } - match self.resolve_path( + match self.cm().resolve_path( &path, Some(ns), &parent_scope, @@ -904,8 +916,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { path_res { // try to suggest if it's not a macro, maybe a function - if let PathResult::NonModule(partial_res) = - self.maybe_resolve_path(&path, Some(ValueNS), &parent_scope, None) + if let PathResult::NonModule(partial_res) = self + .cm() + .maybe_resolve_path(&path, Some(ValueNS), &parent_scope, None) && partial_res.unresolved_segments() == 0 { let sm = self.tcx.sess.source_map(); @@ -947,9 +960,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - let macro_resolutions = mem::take(&mut self.single_segment_macro_resolutions); + // FIXME: Should be an output of Speculative Resolution. + let macro_resolutions = self.single_segment_macro_resolutions.take(); for (ident, kind, parent_scope, initial_binding, sugg_span) in macro_resolutions { - match self.early_resolve_ident_in_lexical_scope( + match self.cm().early_resolve_ident_in_lexical_scope( ident, ScopeSet::Macro(kind), &parent_scope, @@ -1004,7 +1018,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let builtin_attrs = mem::take(&mut self.builtin_attrs); for (ident, parent_scope) in builtin_attrs { - let _ = self.early_resolve_ident_in_lexical_scope( + let _ = self.cm().early_resolve_ident_in_lexical_scope( ident, ScopeSet::Macro(MacroKind::Attr), &parent_scope, @@ -1089,8 +1103,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - fn report_out_of_scope_macro_calls( - &mut self, + fn report_out_of_scope_macro_calls<'r>( + mut self: CmResolver<'r, 'ra, 'tcx>, path: &ast::Path, parent_scope: &ParentScope<'ra>, invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>, @@ -1109,7 +1123,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // If such resolution is successful and gives the same result // (e.g. if the macro is re-imported), then silence the lint. let no_macro_rules = self.arenas.alloc_macro_rules_scope(MacroRulesScope::Empty); - let fallback_binding = self.early_resolve_ident_in_lexical_scope( + let fallback_binding = self.reborrow().early_resolve_ident_in_lexical_scope( path.segments[0].ident, ScopeSet::Macro(MacroKind::Bang), &ParentScope { macro_rules: no_macro_rules, ..*parent_scope }, @@ -1167,7 +1181,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { node_id: NodeId, edition: Edition, ) -> MacroData { - let (mut ext, mut nrules) = compile_declarative_macro( + let (mut ext, mut attr_ext, mut nrules) = compile_declarative_macro( self.tcx.sess, self.tcx.features(), macro_def, @@ -1184,13 +1198,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // The macro is a built-in, replace its expander function // while still taking everything else from the source code. ext.kind = builtin_ext_kind.clone(); + attr_ext = None; nrules = 0; } else { self.dcx().emit_err(errors::CannotFindBuiltinMacroWithName { span, ident }); } } - MacroData { ext: Arc::new(ext), nrules, macro_rules: macro_def.macro_rules } + MacroData { ext: Arc::new(ext), attr_ext, nrules, macro_rules: macro_def.macro_rules } } fn path_accessible( @@ -1205,7 +1220,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut indeterminate = false; for ns in namespaces { - match self.maybe_resolve_path(path, Some(*ns), &parent_scope, None) { + match self.cm().maybe_resolve_path(path, Some(*ns), &parent_scope, None) { PathResult::Module(ModuleOrUniformRoot::Module(_)) => return Ok(true), PathResult::NonModule(partial_res) if partial_res.unresolved_segments() == 0 => { return Ok(true); diff --git a/compiler/rustc_sanitizers/Cargo.toml b/compiler/rustc_sanitizers/Cargo.toml index 66488bc9625..9069d2c233d 100644 --- a/compiler/rustc_sanitizers/Cargo.toml +++ b/compiler/rustc_sanitizers/Cargo.toml @@ -4,9 +4,8 @@ version = "0.0.0" edition = "2024" [dependencies] +# tidy-alphabetical-start bitflags = "2.5.0" -tracing = "0.1" -twox-hash = "1.6.3" rustc_abi = { path = "../rustc_abi" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_hir = { path = "../rustc_hir" } @@ -14,3 +13,6 @@ rustc_middle = { path = "../rustc_middle" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } +tracing = "0.1" +twox-hash = "1.6.3" +# tidy-alphabetical-end diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 8f624e0fb2f..c665c85d1fe 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -182,14 +182,7 @@ pub enum InstrumentCoverage { pub struct CoverageOptions { pub level: CoverageLevel, - /// `-Zcoverage-options=no-mir-spans`: Don't extract block coverage spans - /// from MIR statements/terminators, making it easier to inspect/debug - /// branch and MC/DC coverage mappings. - /// - /// For internal debugging only. If other code changes would make it hard - /// to keep supporting this flag, remove it. - pub no_mir_spans: bool, - + /// **(internal test-only flag)** /// `-Zcoverage-options=discard-all-spans-in-codegen`: During codegen, /// discard all coverage spans as though they were invalid. Needed by /// regression tests for #133606, because we don't have an easy way to @@ -197,7 +190,7 @@ pub struct CoverageOptions { pub discard_all_spans_in_codegen: bool, } -/// Controls whether branch coverage or MC/DC coverage is enabled. +/// Controls whether branch coverage is enabled. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)] pub enum CoverageLevel { /// Instrument for coverage at the MIR block level. @@ -221,9 +214,6 @@ pub enum CoverageLevel { /// instrumentation, so it might be removed in the future when MC/DC is /// sufficiently complete, or if it is making MC/DC changes difficult. Condition, - /// Instrument for MC/DC. Mostly a superset of condition coverage, but might - /// differ in some corner cases. - Mcdc, } // The different settings that the `-Z offload` flag can have. diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 44b35e8921e..7c18fd89098 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -755,8 +755,7 @@ mod desc { pub(crate) const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavorCli::one_of(); pub(crate) const parse_dump_mono_stats: &str = "`markdown` (default) or `json`"; pub(crate) const parse_instrument_coverage: &str = parse_bool; - pub(crate) const parse_coverage_options: &str = - "`block` | `branch` | `condition` | `mcdc` | `no-mir-spans`"; + pub(crate) const parse_coverage_options: &str = "`block` | `branch` | `condition`"; pub(crate) const parse_instrument_xray: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), or a comma separated list of settings: `always` or `never` (mutually exclusive), `ignore-loops`, `instruction-threshold=N`, `skip-entry`, `skip-exit`"; pub(crate) const parse_unpretty: &str = "`string` or `string=string`"; pub(crate) const parse_treat_err_as_bug: &str = "either no value or a non-negative number"; @@ -1459,8 +1458,6 @@ pub mod parse { "block" => slot.level = CoverageLevel::Block, "branch" => slot.level = CoverageLevel::Branch, "condition" => slot.level = CoverageLevel::Condition, - "mcdc" => slot.level = CoverageLevel::Mcdc, - "no-mir-spans" => slot.no_mir_spans = true, "discard-all-spans-in-codegen" => slot.discard_all_spans_in_codegen = true, _ => return false, } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index e7097ec8327..c6956cf5f23 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -39,8 +39,8 @@ use rustc_target::spec::{ use crate::code_stats::CodeStats; pub use crate::code_stats::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo}; use crate::config::{ - self, CoverageLevel, CrateType, DebugInfo, ErrorOutputType, FunctionReturn, Input, - InstrumentCoverage, OptLevel, OutFileName, OutputType, RemapPathScopeComponents, + self, CoverageLevel, CoverageOptions, CrateType, DebugInfo, ErrorOutputType, FunctionReturn, + Input, InstrumentCoverage, OptLevel, OutFileName, OutputType, RemapPathScopeComponents, SwitchWithOptPath, }; use crate::filesearch::FileSearch; @@ -354,19 +354,11 @@ impl Session { && self.opts.unstable_opts.coverage_options.level >= CoverageLevel::Condition } - pub fn instrument_coverage_mcdc(&self) -> bool { - self.instrument_coverage() - && self.opts.unstable_opts.coverage_options.level >= CoverageLevel::Mcdc - } - - /// True if `-Zcoverage-options=no-mir-spans` was passed. - pub fn coverage_no_mir_spans(&self) -> bool { - self.opts.unstable_opts.coverage_options.no_mir_spans - } - - /// True if `-Zcoverage-options=discard-all-spans-in-codegen` was passed. - pub fn coverage_discard_all_spans_in_codegen(&self) -> bool { - self.opts.unstable_opts.coverage_options.discard_all_spans_in_codegen + /// Provides direct access to the `CoverageOptions` struct, so that + /// individual flags for debugging/testing coverage instrumetation don't + /// need separate accessors. + pub fn coverage_options(&self) -> &CoverageOptions { + &self.opts.unstable_opts.coverage_options } pub fn is_sanitizer_cfi_enabled(&self) -> bool { diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 97d1d9c2d2a..19494ffc37e 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -768,7 +768,9 @@ impl SyntaxContext { /// /// ```rust /// #![feature(decl_macro)] - /// mod foo { pub fn f() {} } // `f`'s `SyntaxContext` is empty. + /// mod foo { + /// pub fn f() {} // `f`'s `SyntaxContext` is empty. + /// } /// m!(f); /// macro m($f:ident) { /// mod bar { diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index dbc67da37b5..d647ec28aae 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -66,7 +66,8 @@ pub use span_encoding::{DUMMY_SP, Span}; pub mod symbol; pub use symbol::{ - ByteSymbol, Ident, MacroRulesNormalizedIdent, STDLIB_STABLE_CRATES, Symbol, kw, sym, + ByteSymbol, Ident, MacroRulesNormalizedIdent, Macros20NormalizedIdent, STDLIB_STABLE_CRATES, + Symbol, kw, sym, }; mod analyze_source_file; @@ -716,12 +717,17 @@ impl Span { (!ctxt.is_root()).then(|| ctxt.outer_expn_data().call_site) } - /// Walk down the expansion ancestors to find a span that's contained within `outer`. + /// Find the first ancestor span that's contained within `outer`. /// - /// The span returned by this method may have a different [`SyntaxContext`] as `outer`. + /// This method traverses the macro expansion ancestors until it finds the first span + /// that's contained within `outer`. + /// + /// The span returned by this method may have a different [`SyntaxContext`] than `outer`. /// If you need to extend the span, use [`find_ancestor_inside_same_ctxt`] instead, /// because joining spans with different syntax contexts can create unexpected results. /// + /// This is used to find the span of the macro call when a parent expr span, i.e. `outer`, is known. + /// /// [`find_ancestor_inside_same_ctxt`]: Self::find_ancestor_inside_same_ctxt pub fn find_ancestor_inside(mut self, outer: Span) -> Option<Span> { while !outer.contains(self) { @@ -730,8 +736,10 @@ impl Span { Some(self) } - /// Walk down the expansion ancestors to find a span with the same [`SyntaxContext`] as - /// `other`. + /// Find the first ancestor span with the same [`SyntaxContext`] as `other`. + /// + /// This method traverses the macro expansion ancestors until it finds a span + /// that has the same [`SyntaxContext`] as `other`. /// /// Like [`find_ancestor_inside_same_ctxt`], but specifically for when spans might not /// overlap. Take care when using this, and prefer [`find_ancestor_inside`] or @@ -747,9 +755,12 @@ impl Span { Some(self) } - /// Walk down the expansion ancestors to find a span that's contained within `outer` and + /// Find the first ancestor span that's contained within `outer` and /// has the same [`SyntaxContext`] as `outer`. /// + /// This method traverses the macro expansion ancestors until it finds a span + /// that is both contained within `outer` and has the same [`SyntaxContext`] as `outer`. + /// /// This method is the combination of [`find_ancestor_inside`] and /// [`find_ancestor_in_same_ctxt`] and should be preferred when extending the returned span. /// If you do not need to modify the span, use [`find_ancestor_inside`] instead. @@ -763,43 +774,43 @@ impl Span { Some(self) } - /// Recursively walk down the expansion ancestors to find the oldest ancestor span with the same - /// [`SyntaxContext`] the initial span. + /// Find the first ancestor span that does not come from an external macro. /// - /// This method is suitable for peeling through *local* macro expansions to find the "innermost" - /// span that is still local and shares the same [`SyntaxContext`]. For example, given + /// This method traverses the macro expansion ancestors until it finds a span + /// that is either from user-written code or from a local macro (defined in the current crate). /// - /// ```ignore (illustrative example, contains type error) - /// macro_rules! outer { - /// ($x: expr) => { - /// inner!($x) - /// } - /// } + /// External macros are those defined in dependencies or the standard library. + /// This method is useful for reporting errors in user-controllable code and avoiding + /// diagnostics inside external macros. /// - /// macro_rules! inner { - /// ($x: expr) => { - /// format!("error: {}", $x) - /// //~^ ERROR mismatched types - /// } - /// } + /// # See also /// - /// fn bar(x: &str) -> Result<(), Box<dyn std::error::Error>> { - /// Err(outer!(x)) - /// } - /// ``` + /// - [`Self::find_ancestor_not_from_macro`] + /// - [`Self::in_external_macro`] + pub fn find_ancestor_not_from_extern_macro(mut self, sm: &SourceMap) -> Option<Span> { + while self.in_external_macro(sm) { + self = self.parent_callsite()?; + } + Some(self) + } + + /// Find the first ancestor span that does not come from any macro expansion. /// - /// if provided the initial span of `outer!(x)` inside `bar`, this method will recurse - /// the parent callsites until we reach `format!("error: {}", $x)`, at which point it is the - /// oldest ancestor span that is both still local and shares the same [`SyntaxContext`] as the - /// initial span. - pub fn find_oldest_ancestor_in_same_ctxt(self) -> Span { - let mut cur = self; - while cur.eq_ctxt(self) - && let Some(parent_callsite) = cur.parent_callsite() - { - cur = parent_callsite; + /// This method traverses the macro expansion ancestors until it finds a span + /// that originates from user-written code rather than any macro-generated code. + /// + /// This method is useful for reporting errors at the exact location users wrote code + /// and providing suggestions at directly editable locations. + /// + /// # See also + /// + /// - [`Self::find_ancestor_not_from_extern_macro`] + /// - [`Span::from_expansion`] + pub fn find_ancestor_not_from_macro(mut self) -> Option<Span> { + while self.from_expansion() { + self = self.parent_callsite()?; } - cur + Some(self) } /// Edition of the crate from which this span came. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index d54175548e3..acbed7a9eed 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -3,6 +3,7 @@ //! type, and vice versa. use std::hash::{Hash, Hasher}; +use std::ops::Deref; use std::{fmt, str}; use rustc_arena::DroplessArena; @@ -279,6 +280,7 @@ symbols! { IterPeekable, Iterator, IteratorItem, + IteratorMap, Layout, Left, LinkedList, @@ -1310,6 +1312,7 @@ symbols! { lt, m68k_target_feature, macro_at_most_once_rep, + macro_attr, macro_attributes_in_derive_output, macro_concat, macro_escape, @@ -1512,6 +1515,7 @@ symbols! { not, notable_trait, note, + nvptx_target_feature, object_safe_for_dispatch, of, off, @@ -2562,16 +2566,17 @@ impl fmt::Display for IdentPrinter { } /// An newtype around `Ident` that calls [Ident::normalize_to_macro_rules] on -/// construction. -// FIXME(matthewj, petrochenkov) Use this more often, add a similar -// `ModernIdent` struct and use that as well. +/// construction for "local variable hygiene" comparisons. +/// +/// Use this type when you need to compare identifiers according to macro_rules hygiene. +/// This ensures compile-time safety and avoids manual normalization calls. #[derive(Copy, Clone, Eq, PartialEq, Hash)] pub struct MacroRulesNormalizedIdent(Ident); impl MacroRulesNormalizedIdent { #[inline] pub fn new(ident: Ident) -> Self { - Self(ident.normalize_to_macro_rules()) + MacroRulesNormalizedIdent(ident.normalize_to_macro_rules()) } } @@ -2587,6 +2592,48 @@ impl fmt::Display for MacroRulesNormalizedIdent { } } +/// An newtype around `Ident` that calls [Ident::normalize_to_macros_2_0] on +/// construction for "item hygiene" comparisons. +/// +/// Identifiers with same string value become same if they came from the same macro 2.0 macro +/// (e.g., `macro` item, but not `macro_rules` item) and stay different if they came from +/// different macro 2.0 macros. +#[derive(Copy, Clone, Eq, PartialEq, Hash)] +pub struct Macros20NormalizedIdent(pub Ident); + +impl Macros20NormalizedIdent { + #[inline] + pub fn new(ident: Ident) -> Self { + Macros20NormalizedIdent(ident.normalize_to_macros_2_0()) + } + + // dummy_span does not need to be normalized, so we can use `Ident` directly + pub fn with_dummy_span(name: Symbol) -> Self { + Macros20NormalizedIdent(Ident::with_dummy_span(name)) + } +} + +impl fmt::Debug for Macros20NormalizedIdent { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.0, f) + } +} + +impl fmt::Display for Macros20NormalizedIdent { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } +} + +/// By impl Deref, we can access the wrapped Ident as if it were a normal Ident +/// such as `norm_ident.name` instead of `norm_ident.0.name`. +impl Deref for Macros20NormalizedIdent { + type Target = Ident; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + /// An interned UTF-8 string. /// /// Internally, a `Symbol` is implemented as an index, and all operations diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml index 12fe6b719f9..0df9c7682bf 100644 --- a/compiler/rustc_symbol_mangling/Cargo.toml +++ b/compiler/rustc_symbol_mangling/Cargo.toml @@ -7,7 +7,6 @@ edition = "2024" # tidy-alphabetical-start punycode = "0.4.0" rustc-demangle = "0.1.21" - rustc_abi = { path = "../rustc_abi" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 12d1de46313..a7f64085bd9 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -58,59 +58,57 @@ pub(super) fn mangle<'tcx>( let hash = get_symbol_hash(tcx, instance, instance_ty, instantiating_crate); - let mut printer = SymbolPrinter { tcx, path: SymbolPath::new(), keep_within_component: false }; - printer - .print_def_path( - def_id, - if let ty::InstanceKind::DropGlue(_, _) - | ty::InstanceKind::AsyncDropGlueCtorShim(_, _) - | ty::InstanceKind::FutureDropPollShim(_, _, _) = instance.def - { - // Add the name of the dropped type to the symbol name - &*instance.args - } else if let ty::InstanceKind::AsyncDropGlue(_, ty) = instance.def { - let ty::Coroutine(_, cor_args) = ty.kind() else { - bug!(); - }; - let drop_ty = cor_args.first().unwrap().expect_ty(); - tcx.mk_args(&[GenericArg::from(drop_ty)]) - } else { - &[] - }, - ) - .unwrap(); + let mut p = SymbolPrinter { tcx, path: SymbolPath::new(), keep_within_component: false }; + p.print_def_path( + def_id, + if let ty::InstanceKind::DropGlue(_, _) + | ty::InstanceKind::AsyncDropGlueCtorShim(_, _) + | ty::InstanceKind::FutureDropPollShim(_, _, _) = instance.def + { + // Add the name of the dropped type to the symbol name + &*instance.args + } else if let ty::InstanceKind::AsyncDropGlue(_, ty) = instance.def { + let ty::Coroutine(_, cor_args) = ty.kind() else { + bug!(); + }; + let drop_ty = cor_args.first().unwrap().expect_ty(); + tcx.mk_args(&[GenericArg::from(drop_ty)]) + } else { + &[] + }, + ) + .unwrap(); match instance.def { ty::InstanceKind::ThreadLocalShim(..) => { - printer.write_str("{{tls-shim}}").unwrap(); + p.write_str("{{tls-shim}}").unwrap(); } ty::InstanceKind::VTableShim(..) => { - printer.write_str("{{vtable-shim}}").unwrap(); + p.write_str("{{vtable-shim}}").unwrap(); } ty::InstanceKind::ReifyShim(_, reason) => { - printer.write_str("{{reify-shim").unwrap(); + p.write_str("{{reify-shim").unwrap(); match reason { - Some(ReifyReason::FnPtr) => printer.write_str("-fnptr").unwrap(), - Some(ReifyReason::Vtable) => printer.write_str("-vtable").unwrap(), + Some(ReifyReason::FnPtr) => p.write_str("-fnptr").unwrap(), + Some(ReifyReason::Vtable) => p.write_str("-vtable").unwrap(), None => (), } - printer.write_str("}}").unwrap(); + p.write_str("}}").unwrap(); } // FIXME(async_closures): This shouldn't be needed when we fix // `Instance::ty`/`Instance::def_id`. ty::InstanceKind::ConstructCoroutineInClosureShim { receiver_by_ref, .. } => { - printer - .write_str(if receiver_by_ref { "{{by-move-shim}}" } else { "{{by-ref-shim}}" }) + p.write_str(if receiver_by_ref { "{{by-move-shim}}" } else { "{{by-ref-shim}}" }) .unwrap(); } _ => {} } if let ty::InstanceKind::FutureDropPollShim(..) = instance.def { - let _ = printer.write_str("{{drop-shim}}"); + let _ = p.write_str("{{drop-shim}}"); } - printer.path.finish(hash) + p.path.finish(hash) } fn get_symbol_hash<'tcx>( @@ -236,6 +234,8 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> { } fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> { + // This might be reachable (via `pretty_print_dyn_existential`) even though + // `<Self As PrettyPrinter>::should_print_region` returns false. See #144994. Ok(()) } @@ -334,7 +334,6 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> { fn path_append_impl( &mut self, print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, - _disambiguated_data: &DisambiguatedDefPathData, self_ty: Ty<'tcx>, trait_ref: Option<ty::TraitRef<'tcx>>, ) -> Result<(), PrintError> { @@ -460,6 +459,8 @@ impl<'tcx> PrettyPrinter<'tcx> for SymbolPrinter<'tcx> { fn should_print_region(&self, _region: ty::Region<'_>) -> bool { false } + + // Identical to `PrettyPrinter::comma_sep` except there is no space after each comma. fn comma_sep<T>(&mut self, mut elems: impl Iterator<Item = T>) -> Result<(), PrintError> where T: Print<'tcx, Self>, diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index fe0f8e6113e..c2458ae814b 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -33,7 +33,7 @@ pub(super) fn mangle<'tcx>( let args = tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), instance.args); let prefix = "_R"; - let mut cx: SymbolMangler<'_> = SymbolMangler { + let mut p: SymbolMangler<'_> = SymbolMangler { tcx, start_offset: prefix.len(), is_exportable, @@ -69,16 +69,16 @@ pub(super) fn mangle<'tcx>( bug!(); }; let drop_ty = cor_args.first().unwrap().expect_ty(); - cx.print_def_path(def_id, tcx.mk_args(&[GenericArg::from(drop_ty)])).unwrap() + p.print_def_path(def_id, tcx.mk_args(&[GenericArg::from(drop_ty)])).unwrap() } else if let Some(shim_kind) = shim_kind { - cx.path_append_ns(|cx| cx.print_def_path(def_id, args), 'S', 0, shim_kind).unwrap() + p.path_append_ns(|p| p.print_def_path(def_id, args), 'S', 0, shim_kind).unwrap() } else { - cx.print_def_path(def_id, args).unwrap() + p.print_def_path(def_id, args).unwrap() }; if let Some(instantiating_crate) = instantiating_crate { - cx.print_def_path(instantiating_crate.as_def_id(), &[]).unwrap(); + p.print_def_path(instantiating_crate.as_def_id(), &[]).unwrap(); } - std::mem::take(&mut cx.out) + std::mem::take(&mut p.out) } pub fn mangle_internal_symbol<'tcx>(tcx: TyCtxt<'tcx>, item_name: &str) -> String { @@ -88,7 +88,7 @@ pub fn mangle_internal_symbol<'tcx>(tcx: TyCtxt<'tcx>, item_name: &str) -> Strin } let prefix = "_R"; - let mut cx: SymbolMangler<'_> = SymbolMangler { + let mut p: SymbolMangler<'_> = SymbolMangler { tcx, start_offset: prefix.len(), is_exportable: false, @@ -99,10 +99,10 @@ pub fn mangle_internal_symbol<'tcx>(tcx: TyCtxt<'tcx>, item_name: &str) -> Strin out: String::from(prefix), }; - cx.path_append_ns( - |cx| { - cx.push("C"); - cx.push_disambiguator({ + p.path_append_ns( + |p| { + p.push("C"); + p.push_disambiguator({ let mut hasher = StableHasher::new(); // Incorporate the rustc version to ensure #[rustc_std_internal_symbol] functions // get a different symbol name depending on the rustc version. @@ -114,7 +114,7 @@ pub fn mangle_internal_symbol<'tcx>(tcx: TyCtxt<'tcx>, item_name: &str) -> Strin let hash: Hash64 = hasher.finish(); hash.as_u64() }); - cx.push_ident("__rustc"); + p.push_ident("__rustc"); Ok(()) }, 'v', @@ -123,7 +123,7 @@ pub fn mangle_internal_symbol<'tcx>(tcx: TyCtxt<'tcx>, item_name: &str) -> Strin ) .unwrap(); - std::mem::take(&mut cx.out) + std::mem::take(&mut p.out) } pub(super) fn mangle_typeid_for_trait_ref<'tcx>( @@ -131,7 +131,7 @@ pub(super) fn mangle_typeid_for_trait_ref<'tcx>( trait_ref: ty::ExistentialTraitRef<'tcx>, ) -> String { // FIXME(flip1995): See comment in `mangle_typeid_for_fnabi`. - let mut cx = SymbolMangler { + let mut p = SymbolMangler { tcx, start_offset: 0, is_exportable: false, @@ -141,8 +141,8 @@ pub(super) fn mangle_typeid_for_trait_ref<'tcx>( binders: vec![], out: String::new(), }; - cx.print_def_path(trait_ref.def_id, &[]).unwrap(); - std::mem::take(&mut cx.out) + p.print_def_path(trait_ref.def_id, &[]).unwrap(); + std::mem::take(&mut p.out) } struct BinderLevel { @@ -368,7 +368,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { self.path_generic_args( |this| { this.path_append_ns( - |cx| cx.print_def_path(parent_def_id, &[]), + |p| p.print_def_path(parent_def_id, &[]), 'I', key.disambiguated_data.disambiguator as u64, "", @@ -425,7 +425,6 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { ty::Bool => "b", ty::Char => "c", ty::Str => "e", - ty::Tuple(_) if ty.is_unit() => "u", ty::Int(IntTy::I8) => "a", ty::Int(IntTy::I16) => "s", ty::Int(IntTy::I32) => "l", @@ -444,12 +443,12 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { ty::Float(FloatTy::F128) => "C4f128", ty::Never => "z", + ty::Tuple(_) if ty.is_unit() => "u", + // Should only be encountered within the identity-substituted // impl header of an item nested within an impl item. ty::Param(_) => "p", - ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => bug!(), - _ => "", }; if !basic_type.is_empty() { @@ -468,11 +467,9 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { unreachable!() } ty::Tuple(_) if ty.is_unit() => unreachable!(), + ty::Param(_) => unreachable!(), - // Placeholders, also handled as part of basic types. - ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => { - unreachable!() - } + ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => bug!(), ty::Ref(r, ty, mutbl) => { self.push(match mutbl { @@ -542,31 +539,31 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { ty::FnPtr(sig_tys, hdr) => { let sig = sig_tys.with(hdr); self.push("F"); - self.wrap_binder(&sig, |cx, sig| { + self.wrap_binder(&sig, |p, sig| { if sig.safety.is_unsafe() { - cx.push("U"); + p.push("U"); } match sig.abi { ExternAbi::Rust => {} - ExternAbi::C { unwind: false } => cx.push("KC"), + ExternAbi::C { unwind: false } => p.push("KC"), abi => { - cx.push("K"); + p.push("K"); let name = abi.as_str(); if name.contains('-') { - cx.push_ident(&name.replace('-', "_")); + p.push_ident(&name.replace('-', "_")); } else { - cx.push_ident(name); + p.push_ident(name); } } } for &ty in sig.inputs() { - ty.print(cx)?; + ty.print(p)?; } if sig.c_variadic { - cx.push("v"); + p.push("v"); } - cx.push("E"); - sig.output().print(cx) + p.push("E"); + sig.output().print(p) })?; } @@ -623,7 +620,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { // [<Trait> [{<Projection>}]] [{<Auto>}] // Since any predicates after the first one shouldn't change the binders, // just put them all in the binders of the first. - self.wrap_binder(&predicates[0], |cx, _| { + self.wrap_binder(&predicates[0], |p, _| { for predicate in predicates.iter() { // It would be nice to be able to validate bound vars here, but // projections can actually include bound vars from super traits @@ -632,21 +629,21 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { match predicate.as_ref().skip_binder() { ty::ExistentialPredicate::Trait(trait_ref) => { // Use a type that can't appear in defaults of type parameters. - let dummy_self = Ty::new_fresh(cx.tcx, 0); - let trait_ref = trait_ref.with_self_ty(cx.tcx, dummy_self); - cx.print_def_path(trait_ref.def_id, trait_ref.args)?; + let dummy_self = Ty::new_fresh(p.tcx, 0); + let trait_ref = trait_ref.with_self_ty(p.tcx, dummy_self); + p.print_def_path(trait_ref.def_id, trait_ref.args)?; } ty::ExistentialPredicate::Projection(projection) => { - let name = cx.tcx.associated_item(projection.def_id).name(); - cx.push("p"); - cx.push_ident(name.as_str()); + let name = p.tcx.associated_item(projection.def_id).name(); + p.push("p"); + p.push_ident(name.as_str()); match projection.term.kind() { - ty::TermKind::Ty(ty) => ty.print(cx), - ty::TermKind::Const(c) => c.print(cx), + ty::TermKind::Ty(ty) => ty.print(p), + ty::TermKind::Const(c) => c.print(p), }?; } ty::ExistentialPredicate::AutoTrait(def_id) => { - cx.print_def_path(*def_id, &[])?; + p.print_def_path(*def_id, &[])?; } } } @@ -849,7 +846,6 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { fn path_append_impl( &mut self, _: impl FnOnce(&mut Self) -> Result<(), PrintError>, - _: &DisambiguatedDefPathData, _: Ty<'tcx>, _: Option<ty::TraitRef<'tcx>>, ) -> Result<(), PrintError> { diff --git a/compiler/rustc_target/src/spec/abi_map.rs b/compiler/rustc_target/src/spec/abi_map.rs index b13e2112478..23e74539ddc 100644 --- a/compiler/rustc_target/src/spec/abi_map.rs +++ b/compiler/rustc_target/src/spec/abi_map.rs @@ -60,7 +60,15 @@ impl AbiMap { "x86_64" => Arch::X86_64, _ => Arch::Other, }; - let os = if target.is_like_windows { OsKind::Windows } else { OsKind::Other }; + + let os = if target.is_like_windows { + OsKind::Windows + } else if target.is_like_vexos { + OsKind::VEXos + } else { + OsKind::Other + }; + AbiMap { arch, os } } @@ -82,6 +90,10 @@ impl AbiMap { (ExternAbi::System { .. }, Arch::X86) if os == OsKind::Windows && !has_c_varargs => { CanonAbi::X86(X86Call::Stdcall) } + (ExternAbi::System { .. }, Arch::Arm(..)) if self.os == OsKind::VEXos => { + // Calls to VEXos APIs do not use VFP registers. + CanonAbi::Arm(ArmCall::Aapcs) + } (ExternAbi::System { .. }, _) => CanonAbi::C, // fallible lowerings @@ -191,6 +203,7 @@ enum Arch { #[derive(Debug, PartialEq, Copy, Clone)] enum OsKind { Windows, + VEXos, Other, } diff --git a/compiler/rustc_target/src/spec/base/apple/mod.rs b/compiler/rustc_target/src/spec/base/apple/mod.rs index aa6d1ec7009..da9f96ce37d 100644 --- a/compiler/rustc_target/src/spec/base/apple/mod.rs +++ b/compiler/rustc_target/src/spec/base/apple/mod.rs @@ -51,14 +51,14 @@ impl Arch { }) } - fn target_cpu(self, abi: TargetAbi) -> &'static str { + fn target_cpu(self, env: TargetEnv) -> &'static str { match self { Armv7k => "cortex-a8", Armv7s => "swift", // iOS 10 is only supported on iPhone 5 or higher. - Arm64 => match abi { - TargetAbi::Normal => "apple-a7", - TargetAbi::Simulator => "apple-a12", - TargetAbi::MacCatalyst => "apple-a12", + Arm64 => match env { + TargetEnv::Normal => "apple-a7", + TargetEnv::Simulator => "apple-a12", + TargetEnv::MacCatalyst => "apple-a12", }, Arm64e => "apple-a12", Arm64_32 => "apple-s4", @@ -83,14 +83,14 @@ impl Arch { } #[derive(Copy, Clone, PartialEq)] -pub(crate) enum TargetAbi { +pub(crate) enum TargetEnv { Normal, Simulator, MacCatalyst, } -impl TargetAbi { - fn target_abi(self) -> &'static str { +impl TargetEnv { + fn target_env(self) -> &'static str { match self { Self::Normal => "", Self::MacCatalyst => "macabi", @@ -104,13 +104,20 @@ impl TargetAbi { pub(crate) fn base( os: &'static str, arch: Arch, - abi: TargetAbi, + env: TargetEnv, ) -> (TargetOptions, StaticCow<str>, StaticCow<str>) { let mut opts = TargetOptions { - abi: abi.target_abi().into(), llvm_floatabi: Some(FloatAbi::Hard), os: os.into(), - cpu: arch.target_cpu(abi).into(), + env: env.target_env().into(), + // NOTE: We originally set `cfg(target_abi = "macabi")` / `cfg(target_abi = "sim")`, + // before it was discovered that those are actually environments: + // https://github.com/rust-lang/rust/issues/133331 + // + // But let's continue setting them for backwards compatibility. + // FIXME(madsmtm): Warn about using these in the future. + abi: env.target_env().into(), + cpu: arch.target_cpu(env).into(), link_env_remove: link_env_remove(os), vendor: "apple".into(), linker_flavor: LinkerFlavor::Darwin(Cc::Yes, Lld::No), @@ -168,14 +175,14 @@ pub(crate) fn base( // All Apple x86-32 targets have SSE2. opts.rustc_abi = Some(RustcAbi::X86Sse2); } - (opts, unversioned_llvm_target(os, arch, abi), arch.target_arch()) + (opts, unversioned_llvm_target(os, arch, env), arch.target_arch()) } /// Generate part of the LLVM target triple. /// /// See `rustc_codegen_ssa::back::versioned_llvm_target` for the full triple passed to LLVM and /// Clang. -fn unversioned_llvm_target(os: &str, arch: Arch, abi: TargetAbi) -> StaticCow<str> { +fn unversioned_llvm_target(os: &str, arch: Arch, env: TargetEnv) -> StaticCow<str> { let arch = arch.target_name(); // Convert to the "canonical" OS name used by LLVM: // https://github.com/llvm/llvm-project/blob/llvmorg-18.1.8/llvm/lib/TargetParser/Triple.cpp#L236-L282 @@ -187,10 +194,10 @@ fn unversioned_llvm_target(os: &str, arch: Arch, abi: TargetAbi) -> StaticCow<st "visionos" => "xros", _ => unreachable!("tried to get LLVM target OS for non-Apple platform"), }; - let environment = match abi { - TargetAbi::Normal => "", - TargetAbi::MacCatalyst => "-macabi", - TargetAbi::Simulator => "-simulator", + let environment = match env { + TargetEnv::Normal => "", + TargetEnv::MacCatalyst => "-macabi", + TargetEnv::Simulator => "-simulator", }; format!("{arch}-apple-{os}{environment}").into() } @@ -309,7 +316,7 @@ impl OSVersion { /// This matches what LLVM does, see in part: /// <https://github.com/llvm/llvm-project/blob/llvmorg-18.1.8/llvm/lib/TargetParser/Triple.cpp#L1900-L1932> pub fn minimum_deployment_target(target: &Target) -> Self { - let (major, minor, patch) = match (&*target.os, &*target.arch, &*target.abi) { + let (major, minor, patch) = match (&*target.os, &*target.arch, &*target.env) { ("macos", "aarch64", _) => (11, 0, 0), ("ios", "aarch64", "macabi") => (14, 0, 0), ("ios", "aarch64", "sim") => (14, 0, 0), diff --git a/compiler/rustc_target/src/spec/base/apple/tests.rs b/compiler/rustc_target/src/spec/base/apple/tests.rs index 391f3470104..bca86ce33c3 100644 --- a/compiler/rustc_target/src/spec/base/apple/tests.rs +++ b/compiler/rustc_target/src/spec/base/apple/tests.rs @@ -6,7 +6,7 @@ use crate::spec::targets::{ }; #[test] -fn simulator_targets_set_abi() { +fn simulator_targets_set_env() { let all_sim_targets = [ x86_64_apple_ios::target(), x86_64_apple_tvos::target(), @@ -18,7 +18,9 @@ fn simulator_targets_set_abi() { ]; for target in &all_sim_targets { - assert_eq!(target.abi, "sim") + assert_eq!(target.env, "sim"); + // Ensure backwards compat + assert_eq!(target.abi, "sim"); } } diff --git a/compiler/rustc_target/src/spec/json.rs b/compiler/rustc_target/src/spec/json.rs index d27c1929aef..6c44b7ff52f 100644 --- a/compiler/rustc_target/src/spec/json.rs +++ b/compiler/rustc_target/src/spec/json.rs @@ -153,6 +153,7 @@ impl Target { forward!(is_like_msvc); forward!(is_like_wasm); forward!(is_like_android); + forward!(is_like_vexos); forward!(binary_format); forward!(default_dwarf_version); forward!(allows_weak_linkage); @@ -345,6 +346,7 @@ impl ToJson for Target { target_option_val!(is_like_msvc); target_option_val!(is_like_wasm); target_option_val!(is_like_android); + target_option_val!(is_like_vexos); target_option_val!(binary_format); target_option_val!(default_dwarf_version); target_option_val!(allows_weak_linkage); @@ -538,6 +540,7 @@ struct TargetSpecJson { is_like_msvc: Option<bool>, is_like_wasm: Option<bool>, is_like_android: Option<bool>, + is_like_vexos: Option<bool>, binary_format: Option<BinaryFormat>, default_dwarf_version: Option<u32>, allows_weak_linkage: Option<bool>, diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index c64cd9a51b7..b9fbff8db05 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2101,6 +2101,7 @@ supported_targets! { ("armv7a-none-eabihf", armv7a_none_eabihf), ("armv7a-nuttx-eabi", armv7a_nuttx_eabi), ("armv7a-nuttx-eabihf", armv7a_nuttx_eabihf), + ("armv7a-vex-v5", armv7a_vex_v5), ("msp430-none-elf", msp430_none_elf), @@ -2571,6 +2572,8 @@ pub struct TargetOptions { pub is_like_wasm: bool, /// Whether a target toolchain is like Android, implying a Linux kernel and a Bionic libc pub is_like_android: bool, + /// Whether a target toolchain is like VEXos, the operating system used by the VEX Robotics V5 Brain. + pub is_like_vexos: bool, /// Target's binary file format. Defaults to BinaryFormat::Elf pub binary_format: BinaryFormat, /// Default supported version of DWARF on this platform. @@ -2953,6 +2956,7 @@ impl Default for TargetOptions { is_like_msvc: false, is_like_wasm: false, is_like_android: false, + is_like_vexos: false, binary_format: BinaryFormat::Elf, default_dwarf_version: 4, allows_weak_linkage: true, @@ -3598,6 +3602,7 @@ impl Target { ), "x86" => (Architecture::I386, None), "s390x" => (Architecture::S390x, None), + "m68k" => (Architecture::M68k, None), "mips" | "mips32r6" => (Architecture::Mips, None), "mips64" | "mips64r6" => ( // While there are currently no builtin targets diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs index 4dd39877715..e1960472555 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("macos", Arch::Arm64, TargetAbi::Normal); + let (opts, llvm_target, arch) = base("macos", Arch::Arm64, TargetEnv::Normal); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs index 769a7b6c391..3b522c34522 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("ios", Arch::Arm64, TargetAbi::Normal); + let (opts, llvm_target, arch) = base("ios", Arch::Arm64, TargetEnv::Normal); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs index 4bb2f73e4f9..4d6a3103ee3 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("ios", Arch::Arm64, TargetAbi::MacCatalyst); + let (opts, llvm_target, arch) = base("ios", Arch::Arm64, TargetEnv::MacCatalyst); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs index 7d04034e759..d366ed26482 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("ios", Arch::Arm64, TargetAbi::Simulator); + let (opts, llvm_target, arch) = base("ios", Arch::Arm64, TargetEnv::Simulator); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs index ec92a40e255..7aef6f96e1c 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("tvos", Arch::Arm64, TargetAbi::Normal); + let (opts, llvm_target, arch) = base("tvos", Arch::Arm64, TargetEnv::Normal); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs index 74fbe5a89ca..f0d17db873b 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("tvos", Arch::Arm64, TargetAbi::Simulator); + let (opts, llvm_target, arch) = base("tvos", Arch::Arm64, TargetEnv::Simulator); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs index dc595fbe7b6..22ce52e637f 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("visionos", Arch::Arm64, TargetAbi::Normal); + let (opts, llvm_target, arch) = base("visionos", Arch::Arm64, TargetEnv::Normal); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs index 06ff1bfb2f0..21739ba9fdb 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("visionos", Arch::Arm64, TargetAbi::Simulator); + let (opts, llvm_target, arch) = base("visionos", Arch::Arm64, TargetEnv::Simulator); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs index 23596271107..2e88f95f1dd 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("watchos", Arch::Arm64, TargetAbi::Normal); + let (opts, llvm_target, arch) = base("watchos", Arch::Arm64, TargetEnv::Normal); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs index bad9f6c1485..272dc682dc0 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("watchos", Arch::Arm64, TargetAbi::Simulator); + let (opts, llvm_target, arch) = base("watchos", Arch::Arm64, TargetEnv::Simulator); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs b/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs index 4c3a2f43743..564ac2cd708 100644 --- a/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs +++ b/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("watchos", Arch::Arm64_32, TargetAbi::Normal); + let (opts, llvm_target, arch) = base("watchos", Arch::Arm64_32, TargetEnv::Normal); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs index 326f2b16d59..86e178a9572 100644 --- a/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("macos", Arch::Arm64e, TargetAbi::Normal); + let (opts, llvm_target, arch) = base("macos", Arch::Arm64e, TargetEnv::Normal); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs b/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs index 01c6f0b888d..dae3f77d7ae 100644 --- a/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("ios", Arch::Arm64e, TargetAbi::Normal); + let (opts, llvm_target, arch) = base("ios", Arch::Arm64e, TargetEnv::Normal); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/arm64e_apple_tvos.rs b/compiler/rustc_target/src/spec/targets/arm64e_apple_tvos.rs index cad3650bda1..a99fc5dc68c 100644 --- a/compiler/rustc_target/src/spec/targets/arm64e_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/targets/arm64e_apple_tvos.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("tvos", Arch::Arm64e, TargetAbi::Normal); + let (opts, llvm_target, arch) = base("tvos", Arch::Arm64e, TargetEnv::Normal); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs new file mode 100644 index 00000000000..e78f7839974 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs @@ -0,0 +1,44 @@ +use crate::spec::{ + Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, + TargetOptions, +}; + +const LINKER_SCRIPT: &str = include_str!("./armv7a_vex_v5_linker_script.ld"); + +pub(crate) fn target() -> Target { + let opts = TargetOptions { + vendor: "vex".into(), + env: "v5".into(), + os: "vexos".into(), + cpu: "cortex-a9".into(), + abi: "eabihf".into(), + is_like_vexos: true, + llvm_floatabi: Some(FloatAbi::Hard), + linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), + linker: Some("rust-lld".into()), + features: "+v7,+neon,+vfp3d16,+thumb2".into(), + relocation_model: RelocModel::Static, + disable_redzone: true, + max_atomic_width: Some(64), + panic_strategy: PanicStrategy::Abort, + emit_debug_gdb_scripts: false, + c_enum_min_bits: Some(8), + default_uwtable: true, + has_thumb_interworking: true, + link_script: Some(LINKER_SCRIPT.into()), + ..Default::default() + }; + Target { + llvm_target: "armv7a-none-eabihf".into(), + metadata: TargetMetadata { + description: Some("ARMv7-A Cortex-A9 VEX V5 Brain".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), + }, + pointer_width: 32, + data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), + arch: "arm".into(), + options: opts, + } +} diff --git a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld new file mode 100644 index 00000000000..a4783de0183 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld @@ -0,0 +1,144 @@ +OUTPUT_FORMAT("elf32-littlearm") +ENTRY(_boot) + +/* + * PROVIDE() is used here so that users can override default values. + * This is intended to give developers the option to use this Rust + * target even if the default values in this linker script aren't + * suitable for their needs. + * + * For example: `-C link-arg=--defsym=__stack_length=8M` could + * be used to increase the stack size above the value set in this + * file. + */ + +PROVIDE(__vcodesig_magic = 0x35585658); /* XVX5 */ +PROVIDE(__vcodesig_type = 0); /* V5_SIG_TYPE_USER */ +PROVIDE(__vcodesig_owner = 2); /* V5_SIG_OWNER_PARTNER */ +PROVIDE(__vcodesig_options = 0); /* none (0) */ + +PROVIDE(__user_ram_start = 0x03800000); +PROVIDE(__user_ram_length = 48M); +PROVIDE(__user_ram_end = __user_ram_start + __user_ram_length); /* 0x8000000 */ + +PROVIDE(__code_signature_length = 0x20); + +PROVIDE(__stack_length = 4M); +PROVIDE(__heap_end = __user_ram_end - __stack_length); +PROVIDE(__user_length = __heap_start - __user_ram_start); + +MEMORY { + USER_RAM (RWX) : ORIGIN = __user_ram_start, LENGTH = __user_ram_length +} + +SECTIONS { + /* + * VEXos expects program binaries to have a 32-byte header called a "code signature" + * at their start which tells the OS that we are a valid program and configures some + * miscellaneous startup behavior. + */ + .code_signature : { + LONG(__vcodesig_magic) + LONG(__vcodesig_type) + LONG(__vcodesig_owner) + LONG(__vcodesig_options) + + FILL(0) + . = __user_ram_start + __code_signature_length; + } > USER_RAM + + /* + * Executable program instructions. + */ + .text : { + /* _boot routine (entry point from VEXos, must be at 0x03800020) */ + *(.boot) + + /* The rest of the program. */ + *(.text .text.*) + } > USER_RAM + + /* + * Global/uninitialized/static/constant data sections. + */ + .rodata : { + *(.rodata .rodata1 .rodata.*) + *(.srodata .srodata.*) + } > USER_RAM + + /* + * ARM Stack Unwinding Sections + * + * These sections are added by the compiler in some cases to facilitate stack unwinding. + * __eh_frame_start and similar symbols are used by libunwind. + */ + + .except_ordered : { + PROVIDE(__extab_start = .); + *(.gcc_except_table *.gcc_except_table.*) + *(.ARM.extab*) + PROVIDE(__extab_end = .); + } > USER_RAM + + .eh_frame_hdr : { + /* see https://github.com/llvm/llvm-project/blob/main/libunwind/src/AddressSpace.hpp#L78 */ + PROVIDE(__eh_frame_hdr_start = .); + KEEP(*(.eh_frame_hdr)) + PROVIDE(__eh_frame_hdr_end = .); + } > USER_RAM + + .eh_frame : { + PROVIDE(__eh_frame_start = .); + KEEP(*(.eh_frame)) + PROVIDE(__eh_frame_end = .); + } > USER_RAM + + .except_unordered : { + PROVIDE(__exidx_start = .); + *(.ARM.exidx*) + PROVIDE(__exidx_end = .); + } > USER_RAM + + /* -- Data intended to be mutable at runtime begins here. -- */ + + .data : { + *(.data .data1 .data.*) + *(.sdata .sdata.* .sdata2.*) + } > USER_RAM + + /* -- End of loadable sections - anything beyond this point shouldn't go in the binary uploaded to the device. -- */ + + .bss (NOLOAD) : { + __bss_start = .; + *(.sbss*) + *(.bss .bss.*) + + /* Align the heap */ + . = ALIGN(8); + __bss_end = .; + } > USER_RAM + + /* + * Active memory sections for the stack/heap. + * + * Because these are (NOLOAD), they will not influence the final size of the binary. + */ + .heap (NOLOAD) : { + __heap_start = .; + . = __heap_end; + } > USER_RAM + + .stack (NOLOAD) : ALIGN(8) { + __stack_bottom = .; + . += __stack_length; + __stack_top = .; + } > USER_RAM + + /* + * `.ARM.attributes` contains arch metadata for compatibility purposes, but we + * only target one hardware configuration, meaning it'd just take up space. + */ + /DISCARD/ : { + *(.ARM.attributes*) + } +} diff --git a/compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs b/compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs index 8103d132cea..df58559848a 100644 --- a/compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs +++ b/compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("watchos", Arch::Armv7k, TargetAbi::Normal); + let (opts, llvm_target, arch) = base("watchos", Arch::Armv7k, TargetEnv::Normal); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs b/compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs index ba9edd71461..63259043b73 100644 --- a/compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("ios", Arch::Armv7s, TargetAbi::Normal); + let (opts, llvm_target, arch) = base("ios", Arch::Armv7s, TargetEnv::Normal); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/hexagon_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/hexagon_unknown_linux_musl.rs index f7416a7e0fd..1abf0537cda 100644 --- a/compiler/rustc_target/src/spec/targets/hexagon_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/hexagon_unknown_linux_musl.rs @@ -7,7 +7,6 @@ pub(crate) fn target() -> Target { // FIXME: HVX length defaults are per-CPU base.features = "-small-data,+hvx-length128b".into(); - base.crt_static_default = false; base.has_rpath = true; base.linker_flavor = LinkerFlavor::Unix(Cc::Yes); diff --git a/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs b/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs index 29865fcd4c4..a919be765a2 100644 --- a/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs @@ -1,10 +1,10 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { // i386-apple-ios is a simulator target, even though it isn't declared // that way in the target name like the other ones... - let (opts, llvm_target, arch) = base("ios", Arch::I386, TargetAbi::Simulator); + let (opts, llvm_target, arch) = base("ios", Arch::I386, TargetEnv::Simulator); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs index d1339c57b00..96c477d5236 100644 --- a/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("macos", Arch::I686, TargetAbi::Normal); + let (opts, llvm_target, arch) = base("macos", Arch::I686, TargetEnv::Normal); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs index f95ce756354..94ecd3590a9 100644 --- a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs @@ -23,8 +23,6 @@ pub(crate) fn target() -> Target { abi: "abi64".into(), endian: Endian::Big, mcount: "_mcount".into(), - // FIXME(compiler-team#422): musl targets should be dynamically linked by default. - crt_static_default: true, llvm_abiname: "n64".into(), ..base }, diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs index 4dc76f0936c..482b6790dad 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs @@ -10,8 +10,6 @@ pub(crate) fn target() -> Target { base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::Inline; - // FIXME(compiler-team#422): musl targets should be dynamically linked by default. - base.crt_static_default = true; base.abi = "elfv2".into(); base.llvm_abiname = "elfv2".into(); diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_musl.rs index 316b62d941b..f39142d0101 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_musl.rs @@ -9,8 +9,6 @@ pub(crate) fn target() -> Target { base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m32"]); base.max_atomic_width = Some(32); base.stack_probes = StackProbeType::Inline; - // FIXME(compiler-team#422): musl targets should be dynamically linked by default. - base.crt_static_default = true; Target { llvm_target: "powerpc-unknown-linux-musl".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_muslspe.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_muslspe.rs index 30d0d9cb60a..8ddb45483b3 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_muslspe.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_muslspe.rs @@ -9,8 +9,6 @@ pub(crate) fn target() -> Target { base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-mspe"]); base.max_atomic_width = Some(32); base.stack_probes = StackProbeType::Inline; - // FIXME(compiler-team#422): musl targets should be dynamically linked by default. - base.crt_static_default = true; Target { llvm_target: "powerpc-unknown-linux-muslspe".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs index 938b39b10c6..eb592cca1c8 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs @@ -23,8 +23,6 @@ pub(crate) fn target() -> Target { llvm_abiname: "ilp32d".into(), max_atomic_width: Some(32), supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]), - // FIXME(compiler-team#422): musl targets should be dynamically linked by default. - crt_static_default: true, ..base::linux_musl::opts() }, } diff --git a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs index e9522ac760e..0cdbb626739 100644 --- a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs @@ -13,8 +13,6 @@ pub(crate) fn target() -> Target { base.stack_probes = StackProbeType::Inline; base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::MEMORY | SanitizerSet::THREAD; - // FIXME(compiler-team#422): musl targets should be dynamically linked by default. - base.crt_static_default = true; Target { llvm_target: "s390x-unknown-linux-musl".into(), diff --git a/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_musleabihf.rs index 81c502bfead..e026595439f 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_musleabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_musleabihf.rs @@ -27,8 +27,6 @@ pub(crate) fn target() -> Target { features: "+v7,+thumb-mode,+thumb2,+vfp3,+neon".into(), max_atomic_width: Some(64), mcount: "\u{1}mcount".into(), - // FIXME(compiler-team#422): musl targets should be dynamically linked by default. - crt_static_default: true, ..base::linux_musl::opts() }, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs index eba595ba7dd..53e2cb469ee 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("macos", Arch::X86_64, TargetAbi::Normal); + let (opts, llvm_target, arch) = base("macos", Arch::X86_64, TargetEnv::Normal); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs index df45f430ecb..d74a688fa0f 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs @@ -1,10 +1,10 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { // x86_64-apple-ios is a simulator target, even though it isn't declared // that way in the target name like the other ones... - let (opts, llvm_target, arch) = base("ios", Arch::X86_64, TargetAbi::Simulator); + let (opts, llvm_target, arch) = base("ios", Arch::X86_64, TargetEnv::Simulator); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs index ee0c2bf31cd..193e26f94c9 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("ios", Arch::X86_64, TargetAbi::MacCatalyst); + let (opts, llvm_target, arch) = base("ios", Arch::X86_64, TargetEnv::MacCatalyst); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs index 80ca80013f0..e69bd17a049 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs @@ -1,10 +1,10 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { // x86_64-apple-tvos is a simulator target, even though it isn't declared // that way in the target name like the other ones... - let (opts, llvm_target, arch) = base("tvos", Arch::X86_64, TargetAbi::Simulator); + let (opts, llvm_target, arch) = base("tvos", Arch::X86_64, TargetEnv::Simulator); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs index c503baedb8b..9490ca6aa36 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (opts, llvm_target, arch) = base("watchos", Arch::X86_64, TargetAbi::Simulator); + let (opts, llvm_target, arch) = base("watchos", Arch::X86_64, TargetEnv::Simulator); Target { llvm_target, metadata: TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs index e64556c4132..67b5a160a89 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::base::apple::{Arch, TargetEnv, base}; use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { - let (mut opts, llvm_target, arch) = base("macos", Arch::X86_64h, TargetAbi::Normal); + let (mut opts, llvm_target, arch) = base("macos", Arch::X86_64h, TargetEnv::Normal); opts.max_atomic_width = Some(128); opts.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::LEAK | SanitizerSet::THREAD; diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index b2af99228fe..297d9ed84c5 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -517,6 +517,71 @@ const MIPS_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-end ]; +const NVPTX_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ + // tidy-alphabetical-start + ("sm_20", Unstable(sym::nvptx_target_feature), &[]), + ("sm_21", Unstable(sym::nvptx_target_feature), &["sm_20"]), + ("sm_30", Unstable(sym::nvptx_target_feature), &["sm_21"]), + ("sm_32", Unstable(sym::nvptx_target_feature), &["sm_30"]), + ("sm_35", Unstable(sym::nvptx_target_feature), &["sm_32"]), + ("sm_37", Unstable(sym::nvptx_target_feature), &["sm_35"]), + ("sm_50", Unstable(sym::nvptx_target_feature), &["sm_37"]), + ("sm_52", Unstable(sym::nvptx_target_feature), &["sm_50"]), + ("sm_53", Unstable(sym::nvptx_target_feature), &["sm_52"]), + ("sm_60", Unstable(sym::nvptx_target_feature), &["sm_53"]), + ("sm_61", Unstable(sym::nvptx_target_feature), &["sm_60"]), + ("sm_62", Unstable(sym::nvptx_target_feature), &["sm_61"]), + ("sm_70", Unstable(sym::nvptx_target_feature), &["sm_62"]), + ("sm_72", Unstable(sym::nvptx_target_feature), &["sm_70"]), + ("sm_75", Unstable(sym::nvptx_target_feature), &["sm_72"]), + ("sm_80", Unstable(sym::nvptx_target_feature), &["sm_75"]), + ("sm_86", Unstable(sym::nvptx_target_feature), &["sm_80"]), + ("sm_87", Unstable(sym::nvptx_target_feature), &["sm_86"]), + ("sm_89", Unstable(sym::nvptx_target_feature), &["sm_87"]), + ("sm_90", Unstable(sym::nvptx_target_feature), &["sm_89"]), + ("sm_90a", Unstable(sym::nvptx_target_feature), &["sm_90"]), + // tidy-alphabetical-end + // tidy-alphabetical-start + ("sm_100", Unstable(sym::nvptx_target_feature), &["sm_90"]), + ("sm_100a", Unstable(sym::nvptx_target_feature), &["sm_100"]), + ("sm_101", Unstable(sym::nvptx_target_feature), &["sm_100"]), + ("sm_101a", Unstable(sym::nvptx_target_feature), &["sm_101"]), + ("sm_120", Unstable(sym::nvptx_target_feature), &["sm_101"]), + ("sm_120a", Unstable(sym::nvptx_target_feature), &["sm_120"]), + // tidy-alphabetical-end + // tidy-alphabetical-start + ("ptx32", Unstable(sym::nvptx_target_feature), &[]), + ("ptx40", Unstable(sym::nvptx_target_feature), &["ptx32"]), + ("ptx41", Unstable(sym::nvptx_target_feature), &["ptx40"]), + ("ptx42", Unstable(sym::nvptx_target_feature), &["ptx41"]), + ("ptx43", Unstable(sym::nvptx_target_feature), &["ptx42"]), + ("ptx50", Unstable(sym::nvptx_target_feature), &["ptx43"]), + ("ptx60", Unstable(sym::nvptx_target_feature), &["ptx50"]), + ("ptx61", Unstable(sym::nvptx_target_feature), &["ptx60"]), + ("ptx62", Unstable(sym::nvptx_target_feature), &["ptx61"]), + ("ptx63", Unstable(sym::nvptx_target_feature), &["ptx62"]), + ("ptx64", Unstable(sym::nvptx_target_feature), &["ptx63"]), + ("ptx65", Unstable(sym::nvptx_target_feature), &["ptx64"]), + ("ptx70", Unstable(sym::nvptx_target_feature), &["ptx65"]), + ("ptx71", Unstable(sym::nvptx_target_feature), &["ptx70"]), + ("ptx72", Unstable(sym::nvptx_target_feature), &["ptx71"]), + ("ptx73", Unstable(sym::nvptx_target_feature), &["ptx72"]), + ("ptx74", Unstable(sym::nvptx_target_feature), &["ptx73"]), + ("ptx75", Unstable(sym::nvptx_target_feature), &["ptx74"]), + ("ptx76", Unstable(sym::nvptx_target_feature), &["ptx75"]), + ("ptx77", Unstable(sym::nvptx_target_feature), &["ptx76"]), + ("ptx78", Unstable(sym::nvptx_target_feature), &["ptx77"]), + ("ptx80", Unstable(sym::nvptx_target_feature), &["ptx78"]), + ("ptx81", Unstable(sym::nvptx_target_feature), &["ptx80"]), + ("ptx82", Unstable(sym::nvptx_target_feature), &["ptx81"]), + ("ptx83", Unstable(sym::nvptx_target_feature), &["ptx82"]), + ("ptx84", Unstable(sym::nvptx_target_feature), &["ptx83"]), + ("ptx85", Unstable(sym::nvptx_target_feature), &["ptx84"]), + ("ptx86", Unstable(sym::nvptx_target_feature), &["ptx85"]), + ("ptx87", Unstable(sym::nvptx_target_feature), &["ptx86"]), + // tidy-alphabetical-end +]; + static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-start ("a", Stable, &["zaamo", "zalrsc"]), @@ -782,6 +847,7 @@ pub fn all_rust_features() -> impl Iterator<Item = (&'static str, Stability)> { .chain(HEXAGON_FEATURES.iter()) .chain(POWERPC_FEATURES.iter()) .chain(MIPS_FEATURES.iter()) + .chain(NVPTX_FEATURES.iter()) .chain(RISCV_FEATURES.iter()) .chain(WASM_FEATURES.iter()) .chain(BPF_FEATURES.iter()) @@ -847,6 +913,7 @@ impl Target { "x86" | "x86_64" => X86_FEATURES, "hexagon" => HEXAGON_FEATURES, "mips" | "mips32r6" | "mips64" | "mips64r6" => MIPS_FEATURES, + "nvptx64" => NVPTX_FEATURES, "powerpc" | "powerpc64" => POWERPC_FEATURES, "riscv32" | "riscv64" => RISCV_FEATURES, "wasm32" | "wasm64" => WASM_FEATURES, @@ -873,7 +940,7 @@ impl Target { "sparc" | "sparc64" => SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI, "hexagon" => HEXAGON_FEATURES_FOR_CORRECT_VECTOR_ABI, "mips" | "mips32r6" | "mips64" | "mips64r6" => MIPS_FEATURES_FOR_CORRECT_VECTOR_ABI, - "bpf" | "m68k" => &[], // no vector ABI + "nvptx64" | "bpf" | "m68k" => &[], // no vector ABI "csky" => CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI, // FIXME: for some tier3 targets, we are overly cautious and always give warnings // when passing args in vector registers. diff --git a/compiler/rustc_thread_pool/Cargo.toml b/compiler/rustc_thread_pool/Cargo.toml index b0194834264..c92984470b7 100644 --- a/compiler/rustc_thread_pool/Cargo.toml +++ b/compiler/rustc_thread_pool/Cargo.toml @@ -7,7 +7,6 @@ authors = [ ] description = "Core APIs for Rayon - fork for rustc" license = "MIT OR Apache-2.0" -rust-version = "1.63" edition = "2021" readme = "README.md" keywords = ["parallel", "thread", "concurrency", "join", "performance"] diff --git a/compiler/rustc_thread_pool/src/scope/mod.rs b/compiler/rustc_thread_pool/src/scope/mod.rs index 38230383965..677009a9bc3 100644 --- a/compiler/rustc_thread_pool/src/scope/mod.rs +++ b/compiler/rustc_thread_pool/src/scope/mod.rs @@ -501,9 +501,9 @@ impl<'scope> Scope<'scope> { /// let mut value_c = None; /// rayon::scope(|s| { /// s.spawn(|s1| { - /// // ^ this is the same scope as `s`; this handle `s1` - /// // is intended for use by the spawned task, - /// // since scope handles cannot cross thread boundaries. + /// // ^ this is the same scope as `s`; this handle `s1` + /// // is intended for use by the spawned task, + /// // since scope handles cannot cross thread boundaries. /// /// value_a = Some(22); /// diff --git a/compiler/rustc_thread_pool/src/sleep/mod.rs b/compiler/rustc_thread_pool/src/sleep/mod.rs index 31bf7184b42..aa666609214 100644 --- a/compiler/rustc_thread_pool/src/sleep/mod.rs +++ b/compiler/rustc_thread_pool/src/sleep/mod.rs @@ -44,7 +44,7 @@ impl SleepData { /// jobs are published, and it either blocks threads or wakes them in response to these /// events. See the [`README.md`] in this module for more details. /// -/// [`README.md`] README.md +/// [`README.md`]: README.md pub(super) struct Sleep { /// One "sleep state" per worker. Used to track if a worker is sleeping and to have /// them block. diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index 62f1d908601..1071105522d 100644 --- a/compiler/rustc_trait_selection/Cargo.toml +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -8,7 +8,6 @@ edition = "2024" itertools = "0.12" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } -rustc_attr_data_structures = {path = "../rustc_attr_data_structures"} rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl index 8232da4df43..fcb25025087 100644 --- a/compiler/rustc_trait_selection/messages.ftl +++ b/compiler/rustc_trait_selection/messages.ftl @@ -171,8 +171,6 @@ trait_selection_fps_remove_ref = consider removing the reference trait_selection_fps_use_ref = consider using a reference trait_selection_fulfill_req_lifetime = the type `{$ty}` does not fulfill the required lifetime -trait_selection_full_type_written = the full type name has been written to '{$path}' - trait_selection_ignored_diagnostic_option = `{$option_name}` is ignored due to previous definition of `{$option_name}` .other_label = `{$option_name}` is first declared here .label = `{$option_name}` is already declared here diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index b9acadc406e..1c890821b1d 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -235,28 +235,29 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> { - Err(fmt::Error) + unreachable!(); // because `path_generic_args` ignores the `GenericArgs` } fn print_type(&mut self, _ty: Ty<'tcx>) -> Result<(), PrintError> { - Err(fmt::Error) + unreachable!(); // because `path_generic_args` ignores the `GenericArgs` } fn print_dyn_existential( &mut self, _predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, ) -> Result<(), PrintError> { - Err(fmt::Error) + unreachable!(); // because `path_generic_args` ignores the `GenericArgs` } fn print_const(&mut self, _ct: ty::Const<'tcx>) -> Result<(), PrintError> { - Err(fmt::Error) + unreachable!(); // because `path_generic_args` ignores the `GenericArgs` } fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> { self.segments = vec![self.tcx.crate_name(cnum)]; Ok(()) } + fn path_qualified( &mut self, _self_ty: Ty<'tcx>, @@ -268,12 +269,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { fn path_append_impl( &mut self, _print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, - _disambiguated_data: &DisambiguatedDefPathData, _self_ty: Ty<'tcx>, _trait_ref: Option<ty::TraitRef<'tcx>>, ) -> Result<(), PrintError> { Err(fmt::Error) } + fn path_append( &mut self, print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, @@ -283,6 +284,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { self.segments.push(disambiguated_data.as_sym(true)); Ok(()) } + fn path_generic_args( &mut self, print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, @@ -298,8 +300,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // let _ = [{struct Foo; Foo}, {struct Foo; Foo}]; if did1.krate != did2.krate { let abs_path = |def_id| { - let mut printer = AbsolutePathPrinter { tcx: self.tcx, segments: vec![] }; - printer.print_def_path(def_id, &[]).map(|_| printer.segments) + let mut p = AbsolutePathPrinter { tcx: self.tcx, segments: vec![] }; + p.print_def_path(def_id, &[]).map(|_| p.segments) }; // We compare strings because DefPath can be different @@ -1928,7 +1930,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &self, trace: &TypeTrace<'tcx>, terr: TypeError<'tcx>, - path: &mut Option<PathBuf>, + long_ty_path: &mut Option<PathBuf>, ) -> Vec<TypeErrorAdditionalDiags> { let mut suggestions = Vec::new(); let span = trace.cause.span; @@ -2007,7 +2009,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }) | ObligationCauseCode::BlockTailExpression(.., source)) = code && let hir::MatchSource::TryDesugar(_) = source - && let Some((expected_ty, found_ty)) = self.values_str(trace.values, &trace.cause, path) + && let Some((expected_ty, found_ty)) = + self.values_str(trace.values, &trace.cause, long_ty_path) { suggestions.push(TypeErrorAdditionalDiags::TryCannotConvert { found: found_ty.content(), @@ -2137,11 +2140,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &self, values: ValuePairs<'tcx>, cause: &ObligationCause<'tcx>, - file: &mut Option<PathBuf>, + long_ty_path: &mut Option<PathBuf>, ) -> Option<(DiagStyledString, DiagStyledString)> { match values { ValuePairs::Regions(exp_found) => self.expected_found_str(exp_found), - ValuePairs::Terms(exp_found) => self.expected_found_str_term(exp_found, file), + ValuePairs::Terms(exp_found) => self.expected_found_str_term(exp_found, long_ty_path), ValuePairs::Aliases(exp_found) => self.expected_found_str(exp_found), ValuePairs::ExistentialTraitRef(exp_found) => self.expected_found_str(exp_found), ValuePairs::ExistentialProjection(exp_found) => self.expected_found_str(exp_found), @@ -2181,7 +2184,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { fn expected_found_str_term( &self, exp_found: ty::error::ExpectedFound<ty::Term<'tcx>>, - path: &mut Option<PathBuf>, + long_ty_path: &mut Option<PathBuf>, ) -> Option<(DiagStyledString, DiagStyledString)> { let exp_found = self.resolve_vars_if_possible(exp_found); if exp_found.references_error() { @@ -2198,11 +2201,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let exp_s = exp.content(); let fnd_s = fnd.content(); if exp_s.len() > len { - let exp_s = self.tcx.short_string(expected, path); + let exp_s = self.tcx.short_string(expected, long_ty_path); exp = DiagStyledString::highlighted(exp_s); } if fnd_s.len() > len { - let fnd_s = self.tcx.short_string(found, path); + let fnd_s = self.tcx.short_string(found, long_ty_path); fnd = DiagStyledString::highlighted(fnd_s); } (exp, fnd) diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs index 022d549a9df..ec2287ed516 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs @@ -244,7 +244,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for ClosureEraser<'a, 'tcx> { } fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinter<'a, 'tcx> { - let mut printer = FmtPrinter::new(infcx.tcx, ns); + let mut p = FmtPrinter::new(infcx.tcx, ns); let ty_getter = move |ty_vid| { if infcx.probe_ty_var(ty_vid).is_ok() { warn!("resolved ty var in error message"); @@ -270,11 +270,11 @@ fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinte None } }; - printer.ty_infer_name_resolver = Some(Box::new(ty_getter)); + p.ty_infer_name_resolver = Some(Box::new(ty_getter)); let const_getter = move |ct_vid| Some(infcx.tcx.item_name(infcx.const_var_origin(ct_vid)?.param_def_id?)); - printer.const_infer_name_resolver = Some(Box::new(const_getter)); - printer + p.const_infer_name_resolver = Some(Box::new(const_getter)); + p } fn ty_to_string<'tcx>( @@ -282,7 +282,7 @@ fn ty_to_string<'tcx>( ty: Ty<'tcx>, called_method_def_id: Option<DefId>, ) -> String { - let mut printer = fmt_printer(infcx, Namespace::TypeNS); + let mut p = fmt_printer(infcx, Namespace::TypeNS); let ty = infcx.resolve_vars_if_possible(ty); // We use `fn` ptr syntax for closures, but this only works when the closure does not capture // anything. We also remove all type parameters that are fully known to the type system. @@ -292,8 +292,8 @@ fn ty_to_string<'tcx>( // We don't want the regular output for `fn`s because it includes its path in // invalid pseudo-syntax, we want the `fn`-pointer output instead. (ty::FnDef(..), _) => { - ty.fn_sig(infcx.tcx).print(&mut printer).unwrap(); - printer.into_buffer() + ty.fn_sig(infcx.tcx).print(&mut p).unwrap(); + p.into_buffer() } (_, Some(def_id)) if ty.is_ty_or_numeric_infer() @@ -303,8 +303,8 @@ fn ty_to_string<'tcx>( } _ if ty.is_ty_or_numeric_infer() => "/* Type */".to_string(), _ => { - ty.print(&mut printer).unwrap(); - printer.into_buffer() + ty.print(&mut p).unwrap(); + p.into_buffer() } } } @@ -436,8 +436,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { infer_subdiags, multi_suggestions, bad_label, - was_written: false, - path: Default::default(), }), TypeAnnotationNeeded::E0283 => self.dcx().create_err(AmbiguousImpl { span, @@ -447,8 +445,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { infer_subdiags, multi_suggestions, bad_label, - was_written: false, - path: Default::default(), }), TypeAnnotationNeeded::E0284 => self.dcx().create_err(AmbiguousReturn { span, @@ -458,8 +454,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { infer_subdiags, multi_suggestions, bad_label, - was_written: false, - path: Default::default(), }), } } @@ -496,7 +490,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return self.bad_inference_failure_err(failure_span, arg_data, error_code); }; - let (source_kind, name, path) = kind.ty_localized_msg(self); + let (source_kind, name, long_ty_path) = kind.ty_localized_msg(self); let failure_span = if should_label_span && !failure_span.overlaps(span) { Some(failure_span) } else { @@ -561,21 +555,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { { "Vec<_>".to_string() } else { - let mut printer = fmt_printer(self, Namespace::TypeNS); - printer - .comma_sep(generic_args.iter().copied().map(|arg| { - if arg.is_suggestable(self.tcx, true) { - return arg; - } + let mut p = fmt_printer(self, Namespace::TypeNS); + p.comma_sep(generic_args.iter().copied().map(|arg| { + if arg.is_suggestable(self.tcx, true) { + return arg; + } - match arg.kind() { - GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"), - GenericArgKind::Type(_) => self.next_ty_var(DUMMY_SP).into(), - GenericArgKind::Const(_) => self.next_const_var(DUMMY_SP).into(), - } - })) - .unwrap(); - printer.into_buffer() + match arg.kind() { + GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"), + GenericArgKind::Type(_) => self.next_ty_var(DUMMY_SP).into(), + GenericArgKind::Const(_) => self.next_const_var(DUMMY_SP).into(), + } + })) + .unwrap(); + p.into_buffer() }; if !have_turbofish { @@ -589,9 +582,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { InferSourceKind::FullyQualifiedMethodCall { receiver, successor, args, def_id } => { let placeholder = Some(self.next_ty_var(DUMMY_SP)); if let Some(args) = args.make_suggestable(self.infcx.tcx, true, placeholder) { - let mut printer = fmt_printer(self, Namespace::ValueNS); - printer.print_def_path(def_id, args).unwrap(); - let def_path = printer.into_buffer(); + let mut p = fmt_printer(self, Namespace::ValueNS); + p.print_def_path(def_id, args).unwrap(); + let def_path = p.into_buffer(); // We only care about whether we have to add `&` or `&mut ` for now. // This is the case if the last adjustment is a borrow and the @@ -629,7 +622,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } } - match error_code { + let mut err = match error_code { TypeAnnotationNeeded::E0282 => self.dcx().create_err(AnnotationRequired { span, source_kind, @@ -638,8 +631,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { infer_subdiags, multi_suggestions, bad_label: None, - was_written: path.is_some(), - path: path.unwrap_or_default(), }), TypeAnnotationNeeded::E0283 => self.dcx().create_err(AmbiguousImpl { span, @@ -649,8 +640,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { infer_subdiags, multi_suggestions, bad_label: None, - was_written: path.is_some(), - path: path.unwrap_or_default(), }), TypeAnnotationNeeded::E0284 => self.dcx().create_err(AmbiguousReturn { span, @@ -660,10 +649,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { infer_subdiags, multi_suggestions, bad_label: None, - was_written: path.is_some(), - path: path.unwrap_or_default(), }), - } + }; + *err.long_ty_path() = long_ty_path; + err } } @@ -727,22 +716,24 @@ impl<'tcx> InferSource<'tcx> { impl<'tcx> InferSourceKind<'tcx> { fn ty_localized_msg(&self, infcx: &InferCtxt<'tcx>) -> (&'static str, String, Option<PathBuf>) { - let mut path = None; + let mut long_ty_path = None; match *self { InferSourceKind::LetBinding { ty, .. } | InferSourceKind::ClosureArg { ty, .. } | InferSourceKind::ClosureReturn { ty, .. } => { if ty.is_closure() { - ("closure", closure_as_fn_str(infcx, ty), path) + ("closure", closure_as_fn_str(infcx, ty), long_ty_path) } else if !ty.is_ty_or_numeric_infer() { - ("normal", infcx.tcx.short_string(ty, &mut path), path) + ("normal", infcx.tcx.short_string(ty, &mut long_ty_path), long_ty_path) } else { - ("other", String::new(), path) + ("other", String::new(), long_ty_path) } } // FIXME: We should be able to add some additional info here. InferSourceKind::GenericArg { .. } - | InferSourceKind::FullyQualifiedMethodCall { .. } => ("other", String::new(), path), + | InferSourceKind::FullyQualifiedMethodCall { .. } => { + ("other", String::new(), long_ty_path) + } } } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs index 64fc365c44a..373b756dcdb 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs @@ -47,11 +47,11 @@ where T: for<'a> Print<'tcx, FmtPrinter<'a, 'tcx>>, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut printer = ty::print::FmtPrinter::new(self.tcx, self.ns); - printer.region_highlight_mode = self.highlight; + let mut p = ty::print::FmtPrinter::new(self.tcx, self.ns); + p.region_highlight_mode = self.highlight; - self.value.print(&mut printer)?; - f.write_str(&printer.into_buffer()) + self.value.print(&mut p)?; + f.write_str(&p.into_buffer()) } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs index db35c988bf7..8f0f6d0bf26 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs @@ -1,8 +1,9 @@ -use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect}; use rustc_errors::{Diag, MultiSpan, pluralize}; use rustc_hir as hir; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::DefKind; +use rustc_hir::find_attr; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fast_reject::DeepRejectCtxt; @@ -652,7 +653,6 @@ impl<T> Trait<T> for X { ) ); let impl_comparison = matches!(cause_code, ObligationCauseCode::CompareImplItem { .. }); - let assoc = tcx.associated_item(proj_ty.def_id); if impl_comparison { // We do not want to suggest calling functions when the reason of the // type error is a comparison of an `impl` with its `trait`. @@ -660,7 +660,7 @@ impl<T> Trait<T> for X { let point_at_assoc_fn = if callable_scope && self.point_at_methods_that_satisfy_associated_type( diag, - assoc.container_id(tcx), + tcx.parent(proj_ty.def_id), current_method_ident, proj_ty.def_id, values.expected, @@ -945,8 +945,8 @@ fn foo(&self) -> Self::T { String::new() } } pub fn format_generic_args(&self, args: &[ty::GenericArg<'tcx>]) -> String { - FmtPrinter::print_string(self.tcx, hir::def::Namespace::TypeNS, |cx| { - cx.path_generic_args(|_| Ok(()), args) + FmtPrinter::print_string(self.tcx, hir::def::Namespace::TypeNS, |p| { + p.path_generic_args(|_| Ok(()), args) }) .expect("could not write to `String`.") } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index f3441a8d72a..7369134420c 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -581,7 +581,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let trait_args = trait_ref .instantiate_identity() // Replace the explicit self type with `Self` for better suggestion rendering - .with_self_ty(self.tcx, Ty::new_param(self.tcx, 0, kw::SelfUpper)) + .with_replaced_self_ty(self.tcx, Ty::new_param(self.tcx, 0, kw::SelfUpper)) .args; let trait_item_args = ty::GenericArgs::identity_for_item(self.tcx, impl_item_def_id) .rebase_onto(self.tcx, impl_def_id, trait_args); diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs index cdf1402252a..af912227ce4 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -169,7 +169,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let predicate = self.resolve_vars_if_possible(obligation.predicate); let span = obligation.cause.span; - let mut file = None; + let mut long_ty_path = None; debug!(?predicate, obligation.cause.code = ?obligation.cause.code()); @@ -211,19 +211,18 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { self.tcx.as_lang_item(trait_pred.def_id()), Some(LangItem::Sized | LangItem::MetaSized) ) { - match self.tainted_by_errors() { - None => { - let err = self.emit_inference_failure_err( + return match self.tainted_by_errors() { + None => self + .emit_inference_failure_err( obligation.cause.body_id, span, trait_pred.self_ty().skip_binder().into(), TypeAnnotationNeeded::E0282, false, - ); - return err.emit(); - } - Some(e) => return e, - } + ) + .emit(), + Some(e) => e, + }; } // Typically, this ambiguity should only happen if @@ -260,8 +259,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { span, E0283, "type annotations needed: cannot satisfy `{}`", - self.tcx.short_string(predicate, &mut file), + self.tcx.short_string(predicate, &mut long_ty_path), ) + .with_long_ty_path(long_ty_path) }; let mut ambiguities = compute_applicable_impls_for_diagnostics( @@ -307,7 +307,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { err.cancel(); return e; } - let pred = self.tcx.short_string(predicate, &mut file); + let pred = self.tcx.short_string(predicate, &mut err.long_ty_path()); err.note(format!("cannot satisfy `{pred}`")); let impl_candidates = self.find_similar_impl_candidates(predicate.as_trait_clause().unwrap()); @@ -512,6 +512,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { true, ) } + ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => { if let Err(e) = predicate.error_reported() { return e; @@ -536,7 +537,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .filter_map(ty::GenericArg::as_term) .chain([data.term]) .find(|g| g.has_non_region_infer()); - let predicate = self.tcx.short_string(predicate, &mut file); + let predicate = self.tcx.short_string(predicate, &mut long_ty_path); if let Some(term) = term { self.emit_inference_failure_err( obligation.cause.body_id, @@ -546,6 +547,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { true, ) .with_note(format!("cannot satisfy `{predicate}`")) + .with_long_ty_path(long_ty_path) } else { // If we can't find a generic parameter, just print a generic error struct_span_code_err!( @@ -555,6 +557,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { "type annotations needed: cannot satisfy `{predicate}`", ) .with_span_label(span, format!("cannot satisfy `{predicate}`")) + .with_long_ty_path(long_ty_path) } } @@ -568,17 +571,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let term = data.walk().filter_map(ty::GenericArg::as_term).find(|term| term.is_infer()); if let Some(term) = term { - let err = self.emit_inference_failure_err( + self.emit_inference_failure_err( obligation.cause.body_id, span, term, TypeAnnotationNeeded::E0284, true, - ); - err + ) } else { // If we can't find a generic parameter, just print a generic error - let predicate = self.tcx.short_string(predicate, &mut file); + let predicate = self.tcx.short_string(predicate, &mut long_ty_path); struct_span_code_err!( self.dcx(), span, @@ -586,6 +588,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { "type annotations needed: cannot satisfy `{predicate}`", ) .with_span_label(span, format!("cannot satisfy `{predicate}`")) + .with_long_ty_path(long_ty_path) } } @@ -597,13 +600,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { TypeAnnotationNeeded::E0284, true, ), + ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term }) if term.is_infer() => { if let Some(e) = self.tainted_by_errors() { return e; } - let alias = self.tcx.short_string(alias, &mut file); + let alias = self.tcx.short_string(alias, &mut long_ty_path); struct_span_code_err!( self.dcx(), span, @@ -611,37 +615,34 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { "type annotations needed: cannot normalize `{alias}`", ) .with_span_label(span, format!("cannot normalize `{alias}`")) + .with_long_ty_path(long_ty_path) } + ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(sym)) => { if let Some(e) = self.tainted_by_errors() { return e; } - let mut err; - if self.tcx.features().staged_api() { - err = self.dcx().struct_span_err( + self.dcx().struct_span_err( span, format!("unstable feature `{sym}` is used without being enabled."), - ); - - err.help(format!("The feature can be enabled by marking the current item with `#[unstable_feature_bound({sym})]`")); + ).with_help(format!("The feature can be enabled by marking the current item with `#[unstable_feature_bound({sym})]`")) } else { - err = feature_err_unstable_feature_bound( + feature_err_unstable_feature_bound( &self.tcx.sess, sym, span, format!("use of unstable library feature `{sym}`"), - ); + ) } - err } _ => { if let Some(e) = self.tainted_by_errors() { return e; } - let predicate = self.tcx.short_string(predicate, &mut file); + let predicate = self.tcx.short_string(predicate, &mut long_ty_path); struct_span_code_err!( self.dcx(), span, @@ -649,9 +650,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { "type annotations needed: cannot satisfy `{predicate}`", ) .with_span_label(span, format!("cannot satisfy `{predicate}`")) + .with_long_ty_path(long_ty_path) } }; - *err.long_ty_path() = file; self.note_obligation_cause(&mut err, obligation); err.emit() } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 1ac309da101..62859329de3 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -208,16 +208,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { performs a conversion on the error value \ using the `From` trait"; let (message, notes, append_const_msg) = if is_try_conversion { + let ty = self.tcx.short_string( + main_trait_predicate.skip_binder().self_ty(), + &mut long_ty_file, + ); // We have a `-> Result<_, E1>` and `gives_E2()?`. ( - Some(format!( - "`?` couldn't convert the error to `{}`", - main_trait_predicate.skip_binder().self_ty(), - )), + Some(format!("`?` couldn't convert the error to `{ty}`")), vec![question_mark_message.to_owned()], Some(AppendConstMessage::Default), ) } else if is_question_mark { + let main_trait_predicate = + self.tcx.short_string(main_trait_predicate, &mut long_ty_file); // Similar to the case above, but in this case the conversion is for a // trait object: `-> Result<_, Box<dyn Error>` and `gives_E()?` when // `E: Error` isn't met. @@ -233,7 +236,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { (message, notes, append_const_msg) }; - let err_msg = self.get_standard_error_message( + let default_err_msg = || self.get_standard_error_message( main_trait_predicate, message, None, @@ -258,7 +261,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); } GetSafeTransmuteErrorAndReason::Default => { - (err_msg, None) + (default_err_msg(), None) } GetSafeTransmuteErrorAndReason::Error { err_msg, @@ -266,7 +269,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } => (err_msg, safe_transmute_explanation), } } else { - (err_msg, None) + (default_err_msg(), None) }; let mut err = struct_span_code_err!(self.dcx(), span, E0277, "{}", err_msg); @@ -279,15 +282,21 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if let Some(ret_span) = self.return_type_span(&obligation) { if is_try_conversion { + let ty = self.tcx.short_string( + main_trait_predicate.skip_binder().self_ty(), + err.long_ty_path(), + ); err.span_label( ret_span, - format!( - "expected `{}` because of this", - main_trait_predicate.skip_binder().self_ty() - ), + format!("expected `{ty}` because of this"), ); } else if is_question_mark { - err.span_label(ret_span, format!("required `{main_trait_predicate}` because of this")); + let main_trait_predicate = + self.tcx.short_string(main_trait_predicate, err.long_ty_path()); + err.span_label( + ret_span, + format!("required `{main_trait_predicate}` because of this"), + ); } } @@ -303,6 +312,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &obligation, leaf_trait_predicate, pre_message, + err.long_ty_path(), ); self.check_for_binding_assigned_block_without_tail_expression( @@ -414,11 +424,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } else { vec![(span.shrink_to_hi(), format!(" as {}", cand.self_ty()))] }; + let trait_ = self.tcx.short_string(cand.print_trait_sugared(), err.long_ty_path()); + let ty = self.tcx.short_string(cand.self_ty(), err.long_ty_path()); err.multipart_suggestion( format!( - "the trait `{}` is implemented for fn pointer `{}`, try casting using `as`", - cand.print_trait_sugared(), - cand.self_ty(), + "the trait `{trait_}` is implemented for fn pointer \ + `{ty}`, try casting using `as`", ), suggestion, Applicability::MaybeIncorrect, @@ -512,7 +523,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { && self.fallback_has_occurred { let predicate = leaf_trait_predicate.map_bound(|trait_pred| { - trait_pred.with_self_ty(self.tcx, tcx.types.unit) + trait_pred.with_replaced_self_ty(self.tcx, tcx.types.unit) }); let unit_obligation = obligation.with(tcx, predicate); if self.predicate_may_hold(&unit_obligation) { @@ -522,7 +533,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { <https://github.com/rust-lang/rust/issues/48950> \ for more information)", ); - err.help("did you intend to use the type `()` here instead?"); + err.help("you might have intended to use the type `()` here instead"); } } @@ -722,10 +733,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } SelectionError::ConstArgHasWrongType { ct, ct_ty, expected_ty } => { + let expected_ty_str = self.tcx.short_string(expected_ty, &mut long_ty_file); + let ct_str = self.tcx.short_string(ct, &mut long_ty_file); let mut diag = self.dcx().struct_span_err( span, - format!("the constant `{ct}` is not of type `{expected_ty}`"), + format!("the constant `{ct_str}` is not of type `{expected_ty_str}`"), ); + diag.long_ty_path = long_ty_file; self.note_type_err( &mut diag, @@ -1118,9 +1132,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .must_apply_modulo_regions() { if !suggested { + let err_ty = self.tcx.short_string(err_ty, err.long_ty_path()); err.span_label(span, format!("this has type `Result<_, {err_ty}>`")); } } else { + let err_ty = self.tcx.short_string(err_ty, err.long_ty_path()); err.span_label( span, format!( @@ -1156,12 +1172,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); } (ty::Adt(def, _), None) if def.did().is_local() => { + let trait_path = self.tcx.short_string( + trait_pred.skip_binder().trait_ref.print_only_trait_path(), + err.long_ty_path(), + ); err.span_note( self.tcx.def_span(def.did()), - format!( - "`{self_ty}` needs to implement `{}`", - trait_pred.skip_binder().trait_ref.print_only_trait_path(), - ), + format!("`{self_ty}` needs to implement `{trait_path}`"), ); } (ty::Adt(def, _), Some(ty)) if def.did().is_local() => { @@ -1195,13 +1212,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { bug!() }; + let mut file = None; + let ty_str = self.tcx.short_string(ty, &mut file); let mut diag = match ty.kind() { ty::Float(_) => { struct_span_code_err!( self.dcx(), span, E0741, - "`{ty}` is forbidden as the type of a const generic parameter", + "`{ty_str}` is forbidden as the type of a const generic parameter", ) } ty::FnPtr(..) => { @@ -1226,7 +1245,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { self.dcx(), span, E0741, - "`{ty}` must implement `ConstParamTy` to be used as the type of a const generic parameter", + "`{ty_str}` must implement `ConstParamTy` to be used as the type of a const generic parameter", ); // Only suggest derive if this isn't a derived obligation, // and the struct is local. @@ -1258,21 +1277,22 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { self.dcx(), span, E0741, - "`{ty}` can't be used as a const parameter type", + "`{ty_str}` can't be used as a const parameter type", ) } }; + diag.long_ty_path = file; let mut code = obligation.cause.code(); let mut pred = obligation.predicate.as_trait_clause(); while let Some((next_code, next_pred)) = code.parent_with_predicate() { if let Some(pred) = pred { self.enter_forall(pred, |pred| { - diag.note(format!( - "`{}` must implement `{}`, but it does not", - pred.self_ty(), - pred.print_modifiers_and_trait_path() - )); + let ty = self.tcx.short_string(pred.self_ty(), diag.long_ty_path()); + let trait_path = self + .tcx + .short_string(pred.print_modifiers_and_trait_path(), diag.long_ty_path()); + diag.note(format!("`{ty}` must implement `{trait_path}`, but it does not")); }) } code = next_code; @@ -1584,7 +1604,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { projection_term: ty::AliasTerm<'tcx>, normalized_ty: ty::Term<'tcx>, expected_ty: ty::Term<'tcx>, - file: &mut Option<PathBuf>, + long_ty_path: &mut Option<PathBuf>, ) -> Option<(String, Span, Option<Span>)> { let trait_def_id = projection_term.trait_def_id(self.tcx); let self_ty = projection_term.self_ty(); @@ -1624,17 +1644,25 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }; let item = match self_ty.kind() { ty::FnDef(def, _) => self.tcx.item_name(*def).to_string(), - _ => self.tcx.short_string(self_ty, file), + _ => self.tcx.short_string(self_ty, long_ty_path), }; + let expected_ty = self.tcx.short_string(expected_ty, long_ty_path); + let normalized_ty = self.tcx.short_string(normalized_ty, long_ty_path); Some((format!( "expected `{item}` to return `{expected_ty}`, but it returns `{normalized_ty}`", ), span, closure_span)) } else if self.tcx.is_lang_item(trait_def_id, LangItem::Future) { + let self_ty = self.tcx.short_string(self_ty, long_ty_path); + let expected_ty = self.tcx.short_string(expected_ty, long_ty_path); + let normalized_ty = self.tcx.short_string(normalized_ty, long_ty_path); Some((format!( "expected `{self_ty}` to be a future that resolves to `{expected_ty}`, but it \ resolves to `{normalized_ty}`" ), span, None)) } else if Some(trait_def_id) == self.tcx.get_diagnostic_item(sym::Iterator) { + let self_ty = self.tcx.short_string(self_ty, long_ty_path); + let expected_ty = self.tcx.short_string(expected_ty, long_ty_path); + let normalized_ty = self.tcx.short_string(normalized_ty, long_ty_path); Some((format!( "expected `{self_ty}` to be an iterator that yields `{expected_ty}`, but it \ yields `{normalized_ty}`" @@ -2097,12 +2125,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if let [TypeError::Sorts(exp_found)] = &terrs[..] { let exp_found = self.resolve_vars_if_possible(*exp_found); + let expected = + self.tcx.short_string(exp_found.expected, err.long_ty_path()); + let found = self.tcx.short_string(exp_found.found, err.long_ty_path()); err.highlighted_help(vec![ StringPart::normal("for that trait implementation, "), StringPart::normal("expected `"), - StringPart::highlighted(exp_found.expected.to_string()), + StringPart::highlighted(expected), StringPart::normal("`, found `"), - StringPart::highlighted(exp_found.found.to_string()), + StringPart::highlighted(found), StringPart::normal("`"), ]); self.suggest_function_pointers_impl(None, &exp_found, err); @@ -2135,11 +2166,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { (ty::FnPtr(..), _) => (" implemented for fn pointer `", ""), _ => (" implemented for `", ""), }; + let trait_ = self.tcx.short_string(cand.print_trait_sugared(), err.long_ty_path()); + let self_ty = self.tcx.short_string(cand.self_ty(), err.long_ty_path()); err.highlighted_help(vec![ - StringPart::normal(format!("the trait `{}` ", cand.print_trait_sugared())), + StringPart::normal(format!("the trait `{trait_}` ",)), StringPart::highlighted("is"), StringPart::normal(desc), - StringPart::highlighted(cand.self_ty().to_string()), + StringPart::highlighted(self_ty), StringPart::normal("`"), StringPart::normal(mention_castable), ]); @@ -2159,9 +2192,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .into_iter() .map(|c| { if all_traits_equal { - format!("\n {}", c.self_ty()) + format!("\n {}", self.tcx.short_string(c.self_ty(), err.long_ty_path())) } else { - format!("\n `{}` implements `{}`", c.self_ty(), c.print_only_trait_path()) + format!( + "\n `{}` implements `{}`", + self.tcx.short_string(c.self_ty(), err.long_ty_path()), + self.tcx.short_string(c.print_only_trait_path(), err.long_ty_path()), + ) } }) .collect(); @@ -2364,8 +2401,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { param_env: ty::ParamEnv<'tcx>, trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>, ) -> PredicateObligation<'tcx> { - let trait_pred = - trait_ref_and_ty.map_bound(|(tr, new_self_ty)| tr.with_self_ty(self.tcx, new_self_ty)); + let trait_pred = trait_ref_and_ty + .map_bound(|(tr, new_self_ty)| tr.with_replaced_self_ty(self.tcx, new_self_ty)); Obligation::new(self.tcx, ObligationCause::dummy(), param_env, trait_pred) } @@ -2477,7 +2514,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { predicate_constness: Option<ty::BoundConstness>, append_const_msg: Option<AppendConstMessage>, post_message: String, - long_ty_file: &mut Option<PathBuf>, + long_ty_path: &mut Option<PathBuf>, ) -> String { message .and_then(|cannot_do_this| { @@ -2503,7 +2540,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { "the trait bound `{}` is not satisfied{post_message}", self.tcx.short_string( trait_predicate.print_with_bound_constness(predicate_constness), - long_ty_file, + long_ty_path, ), ) }) @@ -2608,8 +2645,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { dst_min_align, } => { format!( - "the minimum alignment of `{src}` ({src_min_align}) should \ - be greater than that of `{dst}` ({dst_min_align})" + "the minimum alignment of `{src}` ({src_min_align}) should be \ + greater than that of `{dst}` ({dst_min_align})" ) } rustc_transmute::Reason::DstIsMoreUnique => { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index 5765dfd891d..bb5c6469f34 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -99,7 +99,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &self, trait_pred: ty::PolyTraitPredicate<'tcx>, obligation: &PredicateObligation<'tcx>, - long_ty_file: &mut Option<PathBuf>, + long_ty_path: &mut Option<PathBuf>, ) -> OnUnimplementedNote { if trait_pred.polarity() != ty::PredicatePolarity::Positive { return OnUnimplementedNote::default(); @@ -281,7 +281,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { if let Some(ty) = trait_pred.trait_ref.args[param.index as usize].as_type() { - self.tcx.short_string(ty, long_ty_file) + self.tcx.short_string(ty, long_ty_path) } else { trait_pred.trait_ref.args[param.index as usize].to_string() } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs index d929ecf68bf..4f1f5c330e5 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs @@ -66,10 +66,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if s.len() > 50 { // We don't need to save the type to a file, we will be talking about this type already // in a separate note when we explain the obligation, so it will be available that way. - let mut cx: FmtPrinter<'_, '_> = + let mut p: FmtPrinter<'_, '_> = FmtPrinter::new_with_limit(tcx, Namespace::TypeNS, rustc_session::Limit(6)); - value.print(&mut cx).unwrap(); - cx.into_buffer() + value.print(&mut p).unwrap(); + p.into_buffer() } else { s } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index c182fd99b17..ae72178c052 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -3,6 +3,7 @@ use std::assert_matches::debug_assert_matches; use std::borrow::Cow; use std::iter; +use std::path::PathBuf; use itertools::{EitherOrBoth, Itertools}; use rustc_abi::ExternAbi; @@ -737,7 +738,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { get_name(err, &local.pat.kind) } // Different to previous arm because one is `&hir::Local` and the other - // is `P<hir::Local>`. + // is `Box<hir::Local>`. hir::Node::LetStmt(local) => get_name(err, &local.pat.kind), _ => None, } @@ -1369,6 +1370,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); let self_ty_str = self.tcx.short_string(old_pred.self_ty().skip_binder(), err.long_ty_path()); + let trait_path = self + .tcx + .short_string(old_pred.print_modifiers_and_trait_path(), err.long_ty_path()); + if has_custom_message { err.note(msg); } else { @@ -1376,10 +1381,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } err.span_label( span, - format!( - "the trait `{}` is not implemented for `{self_ty_str}`", - old_pred.print_modifiers_and_trait_path() - ), + format!("the trait `{trait_path}` is not implemented for `{self_ty_str}`"), ); }; @@ -3333,17 +3335,22 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { tcx.async_fn_trait_kind_from_def_id(data.parent_trait_pred.def_id()).is_some(); if !is_upvar_tys_infer_tuple && !is_builtin_async_fn_trait { - let ty_str = tcx.short_string(ty, err.long_ty_path()); - let msg = format!("required because it appears within the type `{ty_str}`"); + let mut msg = || { + let ty_str = tcx.short_string(ty, err.long_ty_path()); + format!("required because it appears within the type `{ty_str}`") + }; match ty.kind() { - ty::Adt(def, _) => match tcx.opt_item_ident(def.did()) { - Some(ident) => { - err.span_note(ident.span, msg); - } - None => { - err.note(msg); + ty::Adt(def, _) => { + let msg = msg(); + match tcx.opt_item_ident(def.did()) { + Some(ident) => { + err.span_note(ident.span, msg); + } + None => { + err.note(msg); + } } - }, + } ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => { // If the previous type is async fn, this is the future generated by the body of an async function. // Avoid printing it twice (it was already printed in the `ty::Coroutine` arm below). @@ -3363,6 +3370,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { { // See comment above; skip printing twice. } else { + let msg = msg(); err.span_note(tcx.def_span(def_id), msg); } } @@ -3392,6 +3400,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { err.note("`str` is considered to contain a `[u8]` slice for auto trait purposes"); } _ => { + let msg = msg(); err.note(msg); } }; @@ -3441,7 +3450,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } let self_ty_str = tcx.short_string(parent_trait_pred.skip_binder().self_ty(), err.long_ty_path()); - let trait_name = parent_trait_pred.print_modifiers_and_trait_path().to_string(); + let trait_name = tcx.short_string( + parent_trait_pred.print_modifiers_and_trait_path(), + err.long_ty_path(), + ); let msg = format!("required for `{self_ty_str}` to implement `{trait_name}`"); let mut is_auto_trait = false; match tcx.hir_get_if_local(data.impl_or_alias_def_id) { @@ -3539,10 +3551,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { parent_trait_pred.skip_binder().self_ty(), err.long_ty_path(), ); - err.note(format!( - "required for `{self_ty}` to implement `{}`", - parent_trait_pred.print_modifiers_and_trait_path() - )); + let trait_path = tcx.short_string( + parent_trait_pred.print_modifiers_and_trait_path(), + err.long_ty_path(), + ); + err.note(format!("required for `{self_ty}` to implement `{trait_path}`")); } // #74711: avoid a stack overflow ensure_sufficient_stack(|| { @@ -3558,15 +3571,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }); } ObligationCauseCode::ImplDerivedHost(ref data) => { - let self_ty = - self.resolve_vars_if_possible(data.derived.parent_host_pred.self_ty()); - let msg = format!( - "required for `{self_ty}` to implement `{} {}`", - data.derived.parent_host_pred.skip_binder().constness, + let self_ty = tcx.short_string( + self.resolve_vars_if_possible(data.derived.parent_host_pred.self_ty()), + err.long_ty_path(), + ); + let trait_path = tcx.short_string( data.derived .parent_host_pred .map_bound(|pred| pred.trait_ref) .print_only_trait_path(), + err.long_ty_path(), + ); + let msg = format!( + "required for `{self_ty}` to implement `{} {trait_path}`", + data.derived.parent_host_pred.skip_binder().constness, ); match tcx.hir_get_if_local(data.impl_def_id) { Some(Node::Item(hir::Item { @@ -3942,7 +3960,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if let hir::Expr { kind: hir::ExprKind::MethodCall(_, rcvr, _, _), .. } = expr && let Some(ty) = typeck_results.node_type_opt(rcvr.hir_id) && let Some(failed_pred) = failed_pred.as_trait_clause() - && let pred = failed_pred.map_bound(|pred| pred.with_self_ty(tcx, ty)) + && let pred = failed_pred.map_bound(|pred| pred.with_replaced_self_ty(tcx, ty)) && self.predicate_must_hold_modulo_regions(&Obligation::misc( tcx, expr.span, body_id, param_env, pred, )) @@ -4624,9 +4642,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let Some(root_pred) = root_obligation.predicate.as_trait_clause() else { return }; let trait_ref = root_pred.map_bound(|root_pred| { - root_pred - .trait_ref - .with_self_ty(self.tcx, Ty::new_tup(self.tcx, &[root_pred.trait_ref.self_ty()])) + root_pred.trait_ref.with_replaced_self_ty( + self.tcx, + Ty::new_tup(self.tcx, &[root_pred.trait_ref.self_ty()]), + ) }); let obligation = @@ -5350,6 +5369,7 @@ pub(super) fn get_explanation_based_on_obligation<'tcx>( obligation: &PredicateObligation<'tcx>, trait_predicate: ty::PolyTraitPredicate<'tcx>, pre_message: String, + long_ty_path: &mut Option<PathBuf>, ) -> String { if let ObligationCauseCode::MainFunctionType = obligation.cause.code() { "consider using `()`, or a `Result`".to_owned() @@ -5368,7 +5388,7 @@ pub(super) fn get_explanation_based_on_obligation<'tcx>( format!( "{pre_message}the trait `{}` is not implemented for{desc} `{}`", trait_predicate.print_modifiers_and_trait_path(), - tcx.short_string(trait_predicate.self_ty().skip_binder(), &mut None), + tcx.short_string(trait_predicate.self_ty().skip_binder(), long_ty_path), ) } else { // "the trait bound `T: !Send` is not satisfied" reads better than "`!Send` is diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 7901d52dffb..af241099c01 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -1,5 +1,3 @@ -use std::path::PathBuf; - use rustc_ast::Path; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_errors::codes::*; @@ -224,9 +222,6 @@ pub struct AnnotationRequired<'a> { pub infer_subdiags: Vec<SourceKindSubdiag<'a>>, #[subdiagnostic] pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>, - #[note(trait_selection_full_type_written)] - pub was_written: bool, - pub path: PathBuf, } // Copy of `AnnotationRequired` for E0283 @@ -245,9 +240,6 @@ pub struct AmbiguousImpl<'a> { pub infer_subdiags: Vec<SourceKindSubdiag<'a>>, #[subdiagnostic] pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>, - #[note(trait_selection_full_type_written)] - pub was_written: bool, - pub path: PathBuf, } // Copy of `AnnotationRequired` for E0284 @@ -266,9 +258,6 @@ pub struct AmbiguousReturn<'a> { pub infer_subdiags: Vec<SourceKindSubdiag<'a>>, #[subdiagnostic] pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>, - #[note(trait_selection_full_type_written)] - pub was_written: bool, - pub path: PathBuf, } // Used when a better one isn't available diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 7426504e139..e6a2761db5a 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -135,6 +135,13 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< None } } + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, _)) => { + if self.shallow_resolve_const(ct).is_ct_infer() { + Some(Certainty::AMBIGUOUS) + } else { + None + } + } ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { let arg = self.shallow_resolve_term(arg); if arg.is_trivially_wf(self.tcx) { @@ -205,7 +212,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< let region_assumptions = self.0.inner.borrow().region_assumptions().to_owned(); let region_constraints = self.0.with_region_constraints(|region_constraints| { make_query_region_constraints( - self.tcx, region_obligations, region_constraints, region_assumptions, diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 3ce0f025512..3f628d80662 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -197,6 +197,12 @@ where delegate.compute_goal_fast_path(goal, obligation.cause.span) { match certainty { + // This fast path doesn't depend on region identity so it doesn't + // matter if the goal contains inference variables or not, so we + // don't need to call `push_hir_typeck_potentially_region_dependent_goal` + // here. + // + // Only goals proven via the trait solver should be region dependent. Certainty::Yes => {} Certainty::Maybe(_) => { self.obligations.register(obligation, None); @@ -207,7 +213,7 @@ where let result = delegate.evaluate_root_goal(goal, obligation.cause.span, stalled_on); self.inspect_evaluated_obligation(infcx, &obligation, &result); - let GoalEvaluation { certainty, has_changed, stalled_on } = match result { + let GoalEvaluation { goal, certainty, has_changed, stalled_on } = match result { Ok(result) => result, Err(NoSolution) => { errors.push(E::from_solver_error( @@ -218,6 +224,10 @@ where } }; + // We've resolved the goal in `evaluate_root_goal`, avoid redoing this work + // in the next iteration. This does not resolve the inference variables + // constrained by evaluating the goal. + obligation.predicate = goal.predicate; if has_changed == HasChanged::Yes { // We increment the recursion depth here to track the number of times // this goal has resulted in inference progress. This doesn't precisely @@ -230,7 +240,22 @@ where } match certainty { - Certainty::Yes => {} + Certainty::Yes => { + // Goals may depend on structural identity. Region uniquification at the + // start of MIR borrowck may cause things to no longer be so, potentially + // causing an ICE. + // + // While we uniquify root goals in HIR this does not handle cases where + // regions are hidden inside of a type or const inference variable. + // + // FIXME(-Znext-solver): This does not handle inference variables hidden + // inside of an opaque type, e.g. if there's `Opaque = (?x, ?x)` in the + // storage, we can also rely on structural identity of `?x` even if we + // later uniquify it in MIR borrowck. + if infcx.in_hir_typeck && obligation.has_non_region_infer() { + infcx.push_hir_typeck_potentially_region_dependent_goal(obligation); + } + } Certainty::Maybe(_) => self.obligations.register(obligation, stalled_on), } } @@ -330,7 +355,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for StalledOnCoroutines<'tcx> { return ControlFlow::Continue(()); } - if let ty::CoroutineWitness(def_id, _) = *ty.kind() + if let ty::Coroutine(def_id, _) = *ty.kind() && def_id.as_local().is_some_and(|def_id| self.stalled_coroutines.contains(&def_id)) { ControlFlow::Break(()) diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 759db1d18c0..c63cc0e17ab 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -13,7 +13,7 @@ use tracing::debug; use super::*; use crate::errors::UnableToConstructConstantValue; -use crate::infer::region_constraints::{Constraint, RegionConstraintData}; +use crate::infer::region_constraints::{ConstraintKind, RegionConstraintData}; use crate::regions::OutlivesEnvironmentBuildExt; use crate::traits::project::ProjectAndUnifyResult; @@ -452,37 +452,41 @@ impl<'tcx> AutoTraitFinder<'tcx> { let mut vid_map = FxIndexMap::<RegionTarget<'cx>, RegionDeps<'cx>>::default(); let mut finished_map = FxIndexMap::default(); - for (constraint, _) in ®ions.constraints { - match constraint { - &Constraint::VarSubVar(r1, r2) => { + for (c, _) in ®ions.constraints { + match c.kind { + ConstraintKind::VarSubVar => { + let sub_vid = c.sub.as_var(); + let sup_vid = c.sup.as_var(); { - let deps1 = vid_map.entry(RegionTarget::RegionVid(r1)).or_default(); - deps1.larger.insert(RegionTarget::RegionVid(r2)); + let deps1 = vid_map.entry(RegionTarget::RegionVid(sub_vid)).or_default(); + deps1.larger.insert(RegionTarget::RegionVid(sup_vid)); } - let deps2 = vid_map.entry(RegionTarget::RegionVid(r2)).or_default(); - deps2.smaller.insert(RegionTarget::RegionVid(r1)); + let deps2 = vid_map.entry(RegionTarget::RegionVid(sup_vid)).or_default(); + deps2.smaller.insert(RegionTarget::RegionVid(sub_vid)); } - &Constraint::RegSubVar(region, vid) => { + ConstraintKind::RegSubVar => { + let sup_vid = c.sup.as_var(); { - let deps1 = vid_map.entry(RegionTarget::Region(region)).or_default(); - deps1.larger.insert(RegionTarget::RegionVid(vid)); + let deps1 = vid_map.entry(RegionTarget::Region(c.sub)).or_default(); + deps1.larger.insert(RegionTarget::RegionVid(sup_vid)); } - let deps2 = vid_map.entry(RegionTarget::RegionVid(vid)).or_default(); - deps2.smaller.insert(RegionTarget::Region(region)); + let deps2 = vid_map.entry(RegionTarget::RegionVid(sup_vid)).or_default(); + deps2.smaller.insert(RegionTarget::Region(c.sub)); } - &Constraint::VarSubReg(vid, region) => { - finished_map.insert(vid, region); + ConstraintKind::VarSubReg => { + let sub_vid = c.sub.as_var(); + finished_map.insert(sub_vid, c.sup); } - &Constraint::RegSubReg(r1, r2) => { + ConstraintKind::RegSubReg => { { - let deps1 = vid_map.entry(RegionTarget::Region(r1)).or_default(); - deps1.larger.insert(RegionTarget::Region(r2)); + let deps1 = vid_map.entry(RegionTarget::Region(c.sub)).or_default(); + deps1.larger.insert(RegionTarget::Region(c.sup)); } - let deps2 = vid_map.entry(RegionTarget::Region(r2)).or_default(); - deps2.smaller.insert(RegionTarget::Region(r1)); + let deps2 = vid_map.entry(RegionTarget::Region(c.sup)).or_default(); + deps2.smaller.insert(RegionTarget::Region(c.sub)); } } } diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 07e78da37b3..39afd77a8b6 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -12,6 +12,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::{CRATE_DEF_ID, DefId}; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::PredicateObligations; +use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::bug; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal}; @@ -37,8 +38,20 @@ use crate::traits::{ SelectionContext, SkipLeakCheck, util, }; +/// The "header" of an impl is everything outside the body: a Self type, a trait +/// ref (in the case of a trait impl), and a set of predicates (from the +/// bounds / where-clauses). +#[derive(Clone, Debug, TypeFoldable, TypeVisitable)] +pub struct ImplHeader<'tcx> { + pub impl_def_id: DefId, + pub impl_args: ty::GenericArgsRef<'tcx>, + pub self_ty: Ty<'tcx>, + pub trait_ref: Option<ty::TraitRef<'tcx>>, + pub predicates: Vec<ty::Predicate<'tcx>>, +} + pub struct OverlapResult<'tcx> { - pub impl_header: ty::ImplHeader<'tcx>, + pub impl_header: ImplHeader<'tcx>, pub intercrate_ambiguity_causes: FxIndexSet<IntercrateAmbiguityCause<'tcx>>, /// `true` if the overlap might've been permitted before the shift @@ -151,11 +164,11 @@ pub fn overlapping_impls( } } -fn fresh_impl_header<'tcx>(infcx: &InferCtxt<'tcx>, impl_def_id: DefId) -> ty::ImplHeader<'tcx> { +fn fresh_impl_header<'tcx>(infcx: &InferCtxt<'tcx>, impl_def_id: DefId) -> ImplHeader<'tcx> { let tcx = infcx.tcx; let impl_args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id); - ty::ImplHeader { + ImplHeader { impl_def_id, impl_args, self_ty: tcx.type_of(impl_def_id).instantiate(tcx, impl_args), @@ -173,7 +186,7 @@ fn fresh_impl_header_normalized<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, impl_def_id: DefId, -) -> ty::ImplHeader<'tcx> { +) -> ImplHeader<'tcx> { let header = fresh_impl_header(infcx, impl_def_id); let InferOk { value: mut header, obligations } = @@ -287,8 +300,8 @@ fn overlap<'tcx>( fn equate_impl_headers<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - impl1: &ty::ImplHeader<'tcx>, - impl2: &ty::ImplHeader<'tcx>, + impl1: &ImplHeader<'tcx>, + impl2: &ImplHeader<'tcx>, ) -> Option<PredicateObligations<'tcx>> { let result = match (impl1.trait_ref, impl2.trait_ref) { @@ -535,7 +548,10 @@ fn plug_infer_with_placeholders<'tcx>( ct, ty::Const::new_placeholder( self.infcx.tcx, - ty::Placeholder { universe: self.universe, bound: self.next_var() }, + ty::Placeholder { + universe: self.universe, + bound: ty::BoundConst { var: self.next_var() }, + }, ), ) else { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 9b5e59ce0fd..08315dbd21f 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -706,7 +706,10 @@ fn replace_param_and_infer_args_with_placeholder<'tcx>( self.idx += 1; ty::Const::new_placeholder( self.tcx, - ty::PlaceholderConst { universe: ty::UniverseIndex::ROOT, bound: idx }, + ty::PlaceholderConst { + universe: ty::UniverseIndex::ROOT, + bound: ty::BoundConst { var: idx }, + }, ) } else { c.super_fold_with(self) diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index 38cfdcdc22d..b1b331d1b61 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -318,7 +318,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( }) } - ty::Coroutine(_, args) => { + ty::Coroutine(def_id, args) => { // rust-lang/rust#49918: types can be constructed, stored // in the interior, and sit idle when coroutine yields // (and is subsequently dropped). @@ -346,7 +346,10 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( // While we conservatively assume that all coroutines require drop // to avoid query cycles during MIR building, we can check the actual // witness during borrowck to avoid unnecessary liveness constraints. - if args.witness().needs_drop(tcx, tcx.erase_regions(typing_env)) { + let typing_env = tcx.erase_regions(typing_env); + if tcx.mir_coroutine_witnesses(def_id).is_some_and(|witness| { + witness.field_tys.iter().any(|field| field.ty.needs_drop(tcx, typing_env)) + }) { constraints.outlives.extend(args.upvar_tys().iter().map(ty::GenericArg::from)); constraints.outlives.push(args.resume_ty().into()); } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs index 81b5a131a32..78e7aef78f1 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs @@ -44,7 +44,7 @@ pub fn type_op_ascribe_user_type_with_span<'tcx>( key: ParamEnvAnd<'tcx, AscribeUserType<'tcx>>, span: Span, ) -> Result<(), NoSolution> { - let (param_env, AscribeUserType { mir_ty, user_ty }) = key.into_parts(); + let ty::ParamEnvAnd { param_env, value: AscribeUserType { mir_ty, user_ty } } = key; debug!("type_op_ascribe_user_type: mir_ty={:?} user_ty={:?}", mir_ty, user_ty); match user_ty.kind { UserTypeKind::Ty(user_ty) => relate_mir_and_user_ty(ocx, param_env, span, mir_ty, user_ty)?, diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs index f027ba1c5cb..0ca2d216228 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs @@ -108,7 +108,6 @@ where let region_assumptions = infcx.take_registered_region_assumptions(); let region_constraint_data = infcx.take_and_reset_region_constraints(); let region_constraints = query_response::make_query_region_constraints( - infcx.tcx, region_obligations, ®ion_constraint_data, region_assumptions, diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 2c7089507a8..62795c8a3a6 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -794,18 +794,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // The auto impl might apply; we don't know. candidates.ambiguous = true; } - ty::Coroutine(coroutine_def_id, _) - if self.tcx().is_lang_item(def_id, LangItem::Unpin) => - { - match self.tcx().coroutine_movability(coroutine_def_id) { - hir::Movability::Static => { - // Immovable coroutines are never `Unpin`, so - // suppress the normal auto-impl candidate for it. + ty::Coroutine(coroutine_def_id, _) => { + if self.tcx().is_lang_item(def_id, LangItem::Unpin) { + match self.tcx().coroutine_movability(coroutine_def_id) { + hir::Movability::Static => { + // Immovable coroutines are never `Unpin`, so + // suppress the normal auto-impl candidate for it. + } + hir::Movability::Movable => { + // Movable coroutines are always `Unpin`, so add an + // unconditional builtin candidate with no sub-obligations. + candidates.vec.push(BuiltinCandidate); + } } - hir::Movability::Movable => { - // Movable coroutines are always `Unpin`, so add an - // unconditional builtin candidate. - candidates.vec.push(BuiltinCandidate); + } else { + if self.should_stall_coroutine(coroutine_def_id) { + candidates.ambiguous = true; + } else { + // Coroutines implement all other auto traits normally. + candidates.vec.push(AutoImplCandidate); } } } @@ -842,12 +849,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::CoroutineWitness(def_id, _) => { - if self.should_stall_coroutine_witness(def_id) { - candidates.ambiguous = true; - } else { - candidates.vec.push(AutoImplCandidate); - } + ty::CoroutineWitness(..) => { + candidates.vec.push(AutoImplCandidate); } ty::Bool @@ -866,7 +869,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::FnPtr(..) | ty::Closure(..) | ty::CoroutineClosure(..) - | ty::Coroutine(..) | ty::Never | ty::Tuple(_) | ty::UnsafeBinder(_) => { @@ -1153,15 +1155,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::Ref(_, _, hir::Mutability::Mut) => {} ty::Coroutine(coroutine_def_id, args) => { + if self.should_stall_coroutine(coroutine_def_id) { + candidates.ambiguous = true; + return; + } + match self.tcx().coroutine_movability(coroutine_def_id) { hir::Movability::Static => {} hir::Movability::Movable => { if self.tcx().features().coroutine_clone() { let resolved_upvars = self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty()); - let resolved_witness = - self.infcx.shallow_resolve(args.as_coroutine().witness()); - if resolved_upvars.is_ty_var() || resolved_witness.is_ty_var() { + if resolved_upvars.is_ty_var() { // Not yet resolved. candidates.ambiguous = true; } else { @@ -1194,12 +1199,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::CoroutineWitness(coroutine_def_id, _) => { - if self.should_stall_coroutine_witness(coroutine_def_id) { - candidates.ambiguous = true; - } else { - candidates.vec.push(SizedCandidate); - } + ty::CoroutineWitness(..) => { + candidates.vec.push(SizedCandidate); } // Fallback to whatever user-defined impls or param-env clauses exist in this case. @@ -1238,7 +1239,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::RawPtr(..) | ty::Char | ty::Ref(..) - | ty::Coroutine(..) | ty::Array(..) | ty::Closure(..) | ty::CoroutineClosure(..) @@ -1247,14 +1247,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates.vec.push(SizedCandidate); } - ty::CoroutineWitness(coroutine_def_id, _) => { - if self.should_stall_coroutine_witness(coroutine_def_id) { + ty::Coroutine(coroutine_def_id, _) => { + if self.should_stall_coroutine(coroutine_def_id) { candidates.ambiguous = true; } else { candidates.vec.push(SizedCandidate); } } + ty::CoroutineWitness(..) => { + candidates.vec.push(SizedCandidate); + } + // Conditionally `Sized`. ty::Tuple(..) | ty::Pat(..) | ty::Adt(..) | ty::UnsafeBinder(_) => { candidates.vec.push(SizedCandidate); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index d7c3543cb3f..7ea1548f8f2 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2196,7 +2196,11 @@ impl<'tcx> SelectionContext<'_, 'tcx> { args.as_coroutine() .upvar_tys() .iter() - .chain([args.as_coroutine().witness()]) + .chain([Ty::new_coroutine_witness( + self.tcx(), + coroutine_def_id, + self.tcx().mk_args(args.as_coroutine().parent_args()), + )]) .collect::<Vec<_>>(), ) } else { @@ -2327,9 +2331,13 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ty::Binder::dummy(AutoImplConstituents { types: vec![ty], assumptions: vec![] }) } - ty::Coroutine(_, args) => { + ty::Coroutine(def_id, args) => { let ty = self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty()); - let witness = args.as_coroutine().witness(); + let witness = Ty::new_coroutine_witness( + self.tcx(), + def_id, + self.tcx().mk_args(args.as_coroutine().parent_args()), + ); ty::Binder::dummy(AutoImplConstituents { types: [ty].into_iter().chain(iter::once(witness)).collect(), assumptions: vec![], @@ -2841,7 +2849,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { obligations } - fn should_stall_coroutine_witness(&self, def_id: DefId) -> bool { + fn should_stall_coroutine(&self, def_id: DefId) -> bool { match self.infcx.typing_mode() { TypingMode::Analysis { defining_opaque_types_and_generators: stalled_generators } => { def_id.as_local().is_some_and(|def_id| stalled_generators.contains(&def_id)) diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index c3d60ec45c4..83c0969762f 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -222,7 +222,7 @@ pub struct PlaceholderReplacer<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, mapped_regions: FxIndexMap<ty::PlaceholderRegion, ty::BoundRegion>, mapped_types: FxIndexMap<ty::PlaceholderType, ty::BoundTy>, - mapped_consts: FxIndexMap<ty::PlaceholderConst, ty::BoundVar>, + mapped_consts: FxIndexMap<ty::PlaceholderConst, ty::BoundConst>, universe_indices: &'a [Option<ty::UniverseIndex>], current_index: ty::DebruijnIndex, } @@ -232,7 +232,7 @@ impl<'a, 'tcx> PlaceholderReplacer<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, mapped_regions: FxIndexMap<ty::PlaceholderRegion, ty::BoundRegion>, mapped_types: FxIndexMap<ty::PlaceholderType, ty::BoundTy>, - mapped_consts: FxIndexMap<ty::PlaceholderConst, ty::BoundVar>, + mapped_consts: FxIndexMap<ty::PlaceholderConst, ty::BoundConst>, universe_indices: &'a [Option<ty::UniverseIndex>], value: T, ) -> T { diff --git a/compiler/rustc_traits/src/coroutine_witnesses.rs b/compiler/rustc_traits/src/coroutine_witnesses.rs index 87d17f3e131..8a2a0832ddb 100644 --- a/compiler/rustc_traits/src/coroutine_witnesses.rs +++ b/compiler/rustc_traits/src/coroutine_witnesses.rs @@ -70,7 +70,6 @@ fn compute_assumptions<'tcx>( let region_constraints = infcx.take_and_reset_region_constraints(); let outlives = make_query_region_constraints( - tcx, region_obligations, ®ion_constraints, region_assumptions, diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index 6fb483e6dac..397c24ff70c 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -7,7 +7,7 @@ use rustc_infer::infer::canonical::{self, Canonical}; use rustc_infer::traits::query::OutlivesBound; use rustc_infer::traits::query::type_op::ImpliedOutlivesBounds; use rustc_middle::query::Providers; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; use rustc_span::DUMMY_SP; use rustc_trait_selection::infer::InferCtxtBuilderExt; use rustc_trait_selection::traits::query::type_op::implied_outlives_bounds::compute_implied_outlives_bounds_inner; @@ -25,7 +25,7 @@ fn implied_outlives_bounds<'tcx>( NoSolution, > { tcx.infer_ctxt().enter_canonical_trait_query(&goal, |ocx, key| { - let (param_env, ImpliedOutlivesBounds { ty }) = key.into_parts(); + let ParamEnvAnd { param_env, value: ImpliedOutlivesBounds { ty } } = key; compute_implied_outlives_bounds_inner( ocx, param_env, diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs index e58ad639d20..f77e1994cf4 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -43,7 +43,7 @@ fn type_op_normalize<'tcx, T>( where T: fmt::Debug + TypeFoldable<TyCtxt<'tcx>>, { - let (param_env, Normalize { value }) = key.into_parts(); + let ParamEnvAnd { param_env, value: Normalize { value } } = key; let Normalized { value, obligations } = ocx.infcx.at(&ObligationCause::dummy(), param_env).query_normalize(value)?; ocx.register_obligations(obligations); @@ -96,6 +96,6 @@ pub fn type_op_prove_predicate_with_cause<'tcx>( key: ParamEnvAnd<'tcx, ProvePredicate<'tcx>>, cause: ObligationCause<'tcx>, ) { - let (param_env, ProvePredicate { predicate }) = key.into_parts(); + let ParamEnvAnd { param_env, value: ProvePredicate { predicate } } = key; ocx.register_obligation(Obligation::new(ocx.infcx.tcx, cause, param_env, predicate)); } diff --git a/compiler/rustc_transmute/Cargo.toml b/compiler/rustc_transmute/Cargo.toml index 246b66d3d03..e61717e5e9c 100644 --- a/compiler/rustc_transmute/Cargo.toml +++ b/compiler/rustc_transmute/Cargo.toml @@ -20,9 +20,11 @@ itertools = "0.12" # tidy-alphabetical-end [features] +# tidy-alphabetical-start rustc = [ "dep:rustc_abi", "dep:rustc_hir", "dep:rustc_middle", "dep:rustc_span", ] +# tidy-alphabetical-end diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index af2e000e340..89d1dd8cf23 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -39,7 +39,7 @@ fn fn_sig_for_fn_abi<'tcx>( tcx.thread_local_ptr_ty(instance.def_id()), false, hir::Safety::Safe, - rustc_abi::ExternAbi::Unadjusted, + rustc_abi::ExternAbi::Rust, ); } @@ -268,20 +268,21 @@ fn fn_abi_of_instance<'tcx>( } // Handle safe Rust thin and wide pointers. -fn adjust_for_rust_scalar<'tcx>( +fn arg_attrs_for_rust_scalar<'tcx>( cx: LayoutCx<'tcx>, - attrs: &mut ArgAttributes, scalar: Scalar, layout: TyAndLayout<'tcx>, offset: Size, is_return: bool, drop_target_pointee: Option<Ty<'tcx>>, -) { +) -> ArgAttributes { + let mut attrs = ArgAttributes::new(); + // Booleans are always a noundef i1 that needs to be zero-extended. if scalar.is_bool() { attrs.ext(ArgExtension::Zext); attrs.set(ArgAttribute::NoUndef); - return; + return attrs; } if !scalar.is_uninit_valid() { @@ -289,7 +290,7 @@ fn adjust_for_rust_scalar<'tcx>( } // Only pointer types handled below. - let Scalar::Initialized { value: Pointer(_), valid_range } = scalar else { return }; + let Scalar::Initialized { value: Pointer(_), valid_range } = scalar else { return attrs }; // Set `nonnull` if the validity range excludes zero, or for the argument to `drop_in_place`, // which must be nonnull per its documented safety requirements. @@ -358,6 +359,8 @@ fn adjust_for_rust_scalar<'tcx>( } } } + + attrs } /// Ensure that the ABI makes basic sense. @@ -471,9 +474,10 @@ fn fn_abi_new_uncached<'tcx>( let (caller_location, determined_fn_def_id, is_virtual_call) = if let Some(instance) = instance { let is_virtual_call = matches!(instance.def, ty::InstanceKind::Virtual(..)); + let is_tls_shim_call = matches!(instance.def, ty::InstanceKind::ThreadLocalShim(_)); ( instance.def.requires_caller_location(tcx).then(|| tcx.caller_location_ty()), - if is_virtual_call { None } else { Some(instance.def_id()) }, + if is_virtual_call || is_tls_shim_call { None } else { Some(instance.def_id()) }, is_virtual_call, ) } else { @@ -530,17 +534,7 @@ fn fn_abi_new_uncached<'tcx>( }; let mut arg = ArgAbi::new(cx, layout, |layout, scalar, offset| { - let mut attrs = ArgAttributes::new(); - adjust_for_rust_scalar( - *cx, - &mut attrs, - scalar, - *layout, - offset, - is_return, - drop_target_pointee, - ); - attrs + arg_attrs_for_rust_scalar(*cx, scalar, *layout, offset, is_return, drop_target_pointee) }); if arg.layout.is_zst() { @@ -563,6 +557,7 @@ fn fn_abi_new_uncached<'tcx>( c_variadic: sig.c_variadic, fixed_count: inputs.len() as u32, conv, + // FIXME return false for tls shim can_unwind: fn_can_unwind( tcx, // Since `#[rustc_nounwind]` can change unwinding, we cannot infer unwinding by `fn_def_id` for a virtual call. @@ -575,8 +570,9 @@ fn fn_abi_new_uncached<'tcx>( &mut fn_abi, sig.abi, // If this is a virtual call, we cannot pass the `fn_def_id`, as it might call other - // functions from vtable. Internally, `deduced_param_attrs` attempts to infer attributes by - // visit the function body. + // functions from vtable. And for a tls shim, passing the `fn_def_id` would refer to + // the underlying static. Internally, `deduced_param_attrs` attempts to infer attributes + // by visit the function body. determined_fn_def_id, ); debug!("fn_abi_new_uncached = {:?}", fn_abi); diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index c3b04c20f4b..13d56889bd1 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -101,9 +101,6 @@ fn has_significant_drop_raw<'tcx>( struct NeedsDropTypes<'tcx, F> { tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, - /// Whether to reveal coroutine witnesses, this is set - /// to `false` unless we compute `needs_drop` for a coroutine witness. - reveal_coroutine_witnesses: bool, query_ty: Ty<'tcx>, seen_tys: FxHashSet<Ty<'tcx>>, /// A stack of types left to process, and the recursion depth when we @@ -115,6 +112,15 @@ struct NeedsDropTypes<'tcx, F> { adt_components: F, /// Set this to true if an exhaustive list of types involved in /// drop obligation is requested. + // FIXME: Calling this bool `exhaustive` is confusing and possibly a footgun, + // since it does two things: It makes the iterator yield *all* of the types + // that need drop, and it also affects the computation of the drop components + // on `Coroutine`s. The latter is somewhat confusing, and probably should be + // a function of `typing_env`. See the HACK comment below for why this is + // necessary. If this isn't possible, then we probably should turn this into + // a `NeedsDropMode` so that we can have a variant like `CollectAllSignificantDrops`, + // which will more accurately indicate that we want *all* of the *significant* + // drops, which are the two important behavioral changes toggled by this bool. exhaustive: bool, } @@ -131,7 +137,6 @@ impl<'tcx, F> NeedsDropTypes<'tcx, F> { Self { tcx, typing_env, - reveal_coroutine_witnesses: exhaustive, seen_tys, query_ty: ty, unchecked_tys: vec![(ty, 0)], @@ -195,23 +200,27 @@ where // for the coroutine witness and check whether any of the contained types // need to be dropped, and only require the captured types to be live // if they do. - ty::Coroutine(_, args) => { - if self.reveal_coroutine_witnesses { - queue_type(self, args.as_coroutine().witness()); + ty::Coroutine(def_id, args) => { + // FIXME: See FIXME on `exhaustive` field above. + if self.exhaustive { + for upvar in args.as_coroutine().upvar_tys() { + queue_type(self, upvar); + } + queue_type(self, args.as_coroutine().resume_ty()); + if let Some(witness) = tcx.mir_coroutine_witnesses(def_id) { + for field_ty in &witness.field_tys { + queue_type( + self, + EarlyBinder::bind(field_ty.ty).instantiate(tcx, args), + ); + } + } } else { return Some(self.always_drop_component(ty)); } } - ty::CoroutineWitness(def_id, args) => { - if let Some(witness) = tcx.mir_coroutine_witnesses(def_id) { - self.reveal_coroutine_witnesses = true; - for field_ty in &witness.field_tys { - queue_type( - self, - EarlyBinder::bind(field_ty.ty).instantiate(tcx, args), - ); - } - } + ty::CoroutineWitness(..) => { + unreachable!("witness should be handled in parent"); } ty::UnsafeBinder(bound_ty) => { diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml index 4bd7bfe79be..e7fee574dd4 100644 --- a/compiler/rustc_type_ir/Cargo.toml +++ b/compiler/rustc_type_ir/Cargo.toml @@ -23,14 +23,16 @@ tracing = "0.1" # tidy-alphabetical-end [features] +# tidy-alphabetical-start default = ["nightly"] nightly = [ - "dep:rustc_serialize", - "dep:rustc_span", "dep:rustc_data_structures", "dep:rustc_macros", + "dep:rustc_serialize", + "dep:rustc_span", + "rustc_ast_ir/nightly", + "rustc_index/nightly", "smallvec/may_dangle", "smallvec/union", - "rustc_index/nightly", - "rustc_ast_ir/nightly", ] +# tidy-alphabetical-end diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index a7b915c4845..10d48526fd2 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -15,13 +15,12 @@ use crate::lift::Lift; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; use crate::{self as ty, Interner}; -/// Binder is a binder for higher-ranked lifetimes or types. It is part of the +/// `Binder` is a binder for higher-ranked lifetimes or types. It is part of the /// compiler's representation for things like `for<'a> Fn(&'a isize)` -/// (which would be represented by the type `PolyTraitRef == -/// Binder<I, TraitRef>`). Note that when we instantiate, -/// erase, or otherwise "discharge" these bound vars, we change the -/// type from `Binder<I, T>` to just `T` (see -/// e.g., `liberate_late_bound_regions`). +/// (which would be represented by the type `PolyTraitRef == Binder<I, TraitRef>`). +/// +/// See <https://rustc-dev-guide.rust-lang.org/ty_module/instantiating_binders.html> +/// for more details. /// /// `Decodable` and `Encodable` are implemented for `Binder<T>` using the `impl_binder_encode_decode!` macro. #[derive_where(Clone; I: Interner, T: Clone)] @@ -154,22 +153,19 @@ impl<I: Interner, T: TypeVisitable<I>> TypeSuperVisitable<I> for Binder<I, T> { } impl<I: Interner, T> Binder<I, T> { - /// Skips the binder and returns the "bound" value. This is a - /// risky thing to do because it's easy to get confused about - /// De Bruijn indices and the like. It is usually better to - /// discharge the binder using `no_bound_vars` or - /// `instantiate_bound_regions` or something like - /// that. `skip_binder` is only valid when you are either - /// extracting data that has nothing to do with bound vars, you - /// are doing some sort of test that does not involve bound - /// regions, or you are being very careful about your depth - /// accounting. + /// Returns the value contained inside of this `for<'a>`. Accessing generic args + /// in the returned value is generally incorrect. + /// + /// Please read <https://rustc-dev-guide.rust-lang.org/ty_module/instantiating_binders.html> + /// before using this function. It is usually better to discharge the binder using + /// `no_bound_vars` or `instantiate_bound_regions` or something like that. /// - /// Some examples where `skip_binder` is reasonable: + /// `skip_binder` is only valid when you are either extracting data that does not reference + /// any generic arguments, e.g. a `DefId`, or when you're making sure you only pass the + /// value to things which can handle escaping bound vars. /// - /// - extracting the `DefId` from a PolyTraitRef; - /// - comparing the self type of a PolyTraitRef to see if it is equal to - /// a type parameter `X`, since the type `X` does not reference any regions + /// See existing uses of `.skip_binder()` in `rustc_trait_selection::traits::select` + /// or `rustc_next_trait_solver` for examples. pub fn skip_binder(self) -> T { self.value } @@ -274,8 +270,9 @@ impl<I: Interner, T: IntoIterator> Binder<I, T> { pub struct ValidateBoundVars<I: Interner> { bound_vars: I::BoundVarKinds, binder_index: ty::DebruijnIndex, - // We may encounter the same variable at different levels of binding, so - // this can't just be `Ty` + // We only cache types because any complex const will have to step through + // a type at some point anyways. We may encounter the same variable at + // different levels of binding, so this can't just be `Ty`. visited: SsoHashSet<(ty::DebruijnIndex, I::Ty)>, } @@ -319,6 +316,24 @@ impl<I: Interner> TypeVisitor<I> for ValidateBoundVars<I> { t.super_visit_with(self) } + fn visit_const(&mut self, c: I::Const) -> Self::Result { + if c.outer_exclusive_binder() < self.binder_index { + return ControlFlow::Break(()); + } + match c.kind() { + ty::ConstKind::Bound(debruijn, bound_const) if debruijn == self.binder_index => { + let idx = bound_const.var().as_usize(); + if self.bound_vars.len() <= idx { + panic!("Not enough bound vars: {:?} not found in {:?}", c, self.bound_vars); + } + bound_const.assert_eq(self.bound_vars.get(idx).unwrap()); + } + _ => {} + }; + + c.super_visit_with(self) + } + fn visit_region(&mut self, r: I::Region) -> Self::Result { match r.kind() { ty::ReBound(index, br) if index == self.binder_index => { @@ -336,12 +351,11 @@ impl<I: Interner> TypeVisitor<I> for ValidateBoundVars<I> { } } -/// Similar to [`super::Binder`] except that it tracks early bound generics, i.e. `struct Foo<T>(T)` +/// Similar to [`Binder`] except that it tracks early bound generics, i.e. `struct Foo<T>(T)` /// needs `T` instantiated immediately. This type primarily exists to avoid forgetting to call /// `instantiate`. /// -/// If you don't have anything to `instantiate`, you may be looking for -/// [`instantiate_identity`](EarlyBinder::instantiate_identity) or [`skip_binder`](EarlyBinder::skip_binder). +/// See <https://rustc-dev-guide.rust-lang.org/ty_module/early_binder.html> for more details. #[derive_where(Clone; I: Interner, T: Clone)] #[derive_where(Copy; I: Interner, T: Copy)] #[derive_where(PartialEq; I: Interner, T: PartialEq)] @@ -357,7 +371,7 @@ impl<I: Interner> TypeVisitor<I> for ValidateBoundVars<I> { pub struct EarlyBinder<I: Interner, T> { value: T, #[derive_where(skip(Debug))] - _tcx: PhantomData<I>, + _tcx: PhantomData<fn() -> I>, } /// For early binders, you should first call `instantiate` before using any visitors. @@ -404,17 +418,22 @@ impl<I: Interner, T> EarlyBinder<I, T> { EarlyBinder { value, _tcx: PhantomData } } - /// Skips the binder and returns the "bound" value. - /// This can be used to extract data that does not depend on generic parameters - /// (e.g., getting the `DefId` of the inner value or getting the number of - /// arguments of an `FnSig`). Otherwise, consider using - /// [`instantiate_identity`](EarlyBinder::instantiate_identity). + /// Skips the binder and returns the "bound" value. Accessing generic args + /// in the returned value is generally incorrect. + /// + /// Please read <https://rustc-dev-guide.rust-lang.org/ty_module/early_binder.html> + /// before using this function. + /// + /// Only use this to extract data that does not depend on generic parameters, e.g. + /// to get the `DefId` of the inner value or the number of arguments ofan `FnSig`, + /// or while making sure to only pass the value to functions which are explicitly + /// set up to handle these uninstantiated generic parameters. /// /// To skip the binder on `x: &EarlyBinder<I, T>` to obtain `&T`, leverage /// [`EarlyBinder::as_ref`](EarlyBinder::as_ref): `x.as_ref().skip_binder()`. /// - /// See also [`Binder::skip_binder`](super::Binder::skip_binder), which is - /// the analogous operation on [`super::Binder`]. + /// See also [`Binder::skip_binder`](Binder::skip_binder), which is + /// the analogous operation on [`Binder`]. pub fn skip_binder(self) -> T { self.value } diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs index c66a83662d7..0cb8d8902c6 100644 --- a/compiler/rustc_type_ir/src/canonical.rs +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -199,7 +199,6 @@ impl<I: Interner> CanonicalVarKind<I> { /// usize or f32). In order to faithfully reproduce a type, we need to /// know what set of types a given type variable can be unified with. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr( feature = "nightly", derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index d7b9e0ca340..23b7f55fbbe 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -131,10 +131,7 @@ bitflags::bitflags! { /// Does this have any binders with bound vars (e.g. that need to be anonymized)? const HAS_BINDER_VARS = 1 << 23; - /// Does this type have any coroutine witnesses in it? - // FIXME: This should probably be changed to track whether the type has any - // *coroutines* in it, though this will happen if we remove coroutine witnesses - // altogether. + /// Does this type have any coroutines in it? const HAS_TY_CORO = 1 << 24; } } @@ -246,11 +243,13 @@ impl<I: Interner> FlagComputation<I> { self.add_flags(TypeFlags::HAS_TY_PARAM); } - ty::Closure(_, args) | ty::Coroutine(_, args) | ty::CoroutineClosure(_, args) => { + ty::Closure(_, args) + | ty::CoroutineClosure(_, args) + | ty::CoroutineWitness(_, args) => { self.add_args(args.as_slice()); } - ty::CoroutineWitness(_, args) => { + ty::Coroutine(_, args) => { self.add_flags(TypeFlags::HAS_TY_CORO); self.add_args(args.as_slice()); } diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index e86a2305e23..e6462a97f8a 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -1,7 +1,6 @@ use derive_where::derive_where; #[cfg(feature = "nightly")] use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; -use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; use crate::fold::TypeFoldable; use crate::inherent::*; @@ -20,7 +19,6 @@ use crate::{self as ty, Interner}; /// If neither of these functions are available, feel free to reach out to /// t-types for help. #[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] -#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr( feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) @@ -148,6 +146,10 @@ pub trait InferCtxtLike: Sized { true } + fn in_hir_typeck(&self) -> bool { + false + } + fn typing_mode(&self) -> TypingMode<Self::Interner>; fn universe(&self) -> ty::UniverseIndex; diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 0e307e15d5b..1a6c99ce7de 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -251,7 +251,7 @@ pub trait Const<I: Interner<Const = Self>>: fn new_var(interner: I, var: ty::ConstVid) -> Self; - fn new_bound(interner: I, debruijn: ty::DebruijnIndex, var: I::BoundConst) -> Self; + fn new_bound(interner: I, debruijn: ty::DebruijnIndex, bound_const: I::BoundConst) -> Self; fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self; diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index a483c18813b..50b588029ae 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -75,7 +75,7 @@ pub use pattern::*; pub use predicate::*; pub use predicate_kind::*; pub use region_kind::*; -pub use rustc_ast_ir::{Movability, Mutability, Pinnedness}; +pub use rustc_ast_ir::{FloatTy, IntTy, Movability, Mutability, Pinnedness, UintTy}; pub use ty_info::*; pub use ty_kind::*; pub use upcast::*; @@ -387,16 +387,6 @@ rustc_index::newtype_index! { pub struct BoundVar {} } -impl<I: Interner> inherent::BoundVarLike<I> for BoundVar { - fn var(self) -> BoundVar { - self - } - - fn assert_eq(self, _var: I::BoundVarKind) { - unreachable!("FIXME: We really should have a separate `BoundConst` for consts") - } -} - /// Represents the various closure traits in the language. This /// will determine the type of the environment (`self`, in the /// desugaring) argument that the closure expects. diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index 4643cd0ab85..9e4447ccd99 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -97,7 +97,7 @@ impl<I: Interner> TraitRef<I> { ) } - pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self { + pub fn with_replaced_self_ty(self, interner: I, self_ty: I::Ty) -> Self { TraitRef::new( interner, self.def_id, @@ -146,8 +146,11 @@ pub struct TraitPredicate<I: Interner> { } impl<I: Interner> TraitPredicate<I> { - pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self { - Self { trait_ref: self.trait_ref.with_self_ty(interner, self_ty), polarity: self.polarity } + pub fn with_replaced_self_ty(self, interner: I, self_ty: I::Ty) -> Self { + Self { + trait_ref: self.trait_ref.with_replaced_self_ty(interner, self_ty), + polarity: self.polarity, + } } pub fn def_id(self) -> I::DefId { @@ -181,6 +184,15 @@ impl<I: Interner> UpcastFrom<I, TraitRef<I>> for TraitPredicate<I> { } } +impl<I: Interner> UpcastFrom<I, ty::Binder<I, TraitRef<I>>> for ty::Binder<I, TraitPredicate<I>> { + fn upcast_from(from: ty::Binder<I, TraitRef<I>>, _tcx: I) -> Self { + from.map_bound(|trait_ref| TraitPredicate { + trait_ref, + polarity: PredicatePolarity::Positive, + }) + } +} + impl<I: Interner> fmt::Debug for TraitPredicate<I> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "TraitPredicate({:?}, polarity:{:?})", self.trait_ref, self.polarity) @@ -645,7 +657,7 @@ impl<I: Interner> AliasTerm<I> { self.args.type_at(0) } - pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self { + pub fn with_replaced_self_ty(self, interner: I, self_ty: I::Ty) -> Self { AliasTerm::new( interner, self.def_id, @@ -756,8 +768,11 @@ impl<I: Interner> ProjectionPredicate<I> { self.projection_term.self_ty() } - pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> ProjectionPredicate<I> { - Self { projection_term: self.projection_term.with_self_ty(interner, self_ty), ..self } + pub fn with_replaced_self_ty(self, interner: I, self_ty: I::Ty) -> ProjectionPredicate<I> { + Self { + projection_term: self.projection_term.with_replaced_self_ty(interner, self_ty), + ..self + } } pub fn trait_def_id(self, interner: I) -> I::DefId { @@ -814,8 +829,8 @@ impl<I: Interner> NormalizesTo<I> { self.alias.self_ty() } - pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> NormalizesTo<I> { - Self { alias: self.alias.with_self_ty(interner, self_ty), ..self } + pub fn with_replaced_self_ty(self, interner: I, self_ty: I::Ty) -> NormalizesTo<I> { + Self { alias: self.alias.with_replaced_self_ty(interner, self_ty), ..self } } pub fn trait_def_id(self, interner: I) -> I::DefId { @@ -849,8 +864,8 @@ impl<I: Interner> HostEffectPredicate<I> { self.trait_ref.self_ty() } - pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self { - Self { trait_ref: self.trait_ref.with_self_ty(interner, self_ty), ..self } + pub fn with_replaced_self_ty(self, interner: I, self_ty: I::Ty) -> Self { + Self { trait_ref: self.trait_ref.with_replaced_self_ty(interner, self_ty), ..self } } pub fn def_id(self) -> I::DefId { diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 7c665424750..73aeab5092d 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -15,7 +15,7 @@ pub use self::closure::*; use crate::inherent::*; #[cfg(feature = "nightly")] use crate::visit::TypeVisitable; -use crate::{self as ty, DebruijnIndex, Interner}; +use crate::{self as ty, DebruijnIndex, FloatTy, IntTy, Interner, UintTy}; mod closure; @@ -475,7 +475,7 @@ impl<I: Interner> AliasTy<I> { self.args.type_at(0) } - pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self { + pub fn with_replaced_self_ty(self, interner: I, self_ty: I::Ty) -> Self { AliasTy::new( interner, self.def_id, @@ -509,160 +509,6 @@ impl<I: Interner> AliasTy<I> { } } -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[cfg_attr( - feature = "nightly", - derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) -)] -pub enum IntTy { - Isize, - I8, - I16, - I32, - I64, - I128, -} - -impl IntTy { - pub fn name_str(&self) -> &'static str { - match *self { - IntTy::Isize => "isize", - IntTy::I8 => "i8", - IntTy::I16 => "i16", - IntTy::I32 => "i32", - IntTy::I64 => "i64", - IntTy::I128 => "i128", - } - } - - pub fn bit_width(&self) -> Option<u64> { - Some(match *self { - IntTy::Isize => return None, - IntTy::I8 => 8, - IntTy::I16 => 16, - IntTy::I32 => 32, - IntTy::I64 => 64, - IntTy::I128 => 128, - }) - } - - pub fn normalize(&self, target_width: u32) -> Self { - match self { - IntTy::Isize => match target_width { - 16 => IntTy::I16, - 32 => IntTy::I32, - 64 => IntTy::I64, - _ => unreachable!(), - }, - _ => *self, - } - } - - pub fn to_unsigned(self) -> UintTy { - match self { - IntTy::Isize => UintTy::Usize, - IntTy::I8 => UintTy::U8, - IntTy::I16 => UintTy::U16, - IntTy::I32 => UintTy::U32, - IntTy::I64 => UintTy::U64, - IntTy::I128 => UintTy::U128, - } - } -} - -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] -#[cfg_attr( - feature = "nightly", - derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) -)] -pub enum UintTy { - Usize, - U8, - U16, - U32, - U64, - U128, -} - -impl UintTy { - pub fn name_str(&self) -> &'static str { - match *self { - UintTy::Usize => "usize", - UintTy::U8 => "u8", - UintTy::U16 => "u16", - UintTy::U32 => "u32", - UintTy::U64 => "u64", - UintTy::U128 => "u128", - } - } - - pub fn bit_width(&self) -> Option<u64> { - Some(match *self { - UintTy::Usize => return None, - UintTy::U8 => 8, - UintTy::U16 => 16, - UintTy::U32 => 32, - UintTy::U64 => 64, - UintTy::U128 => 128, - }) - } - - pub fn normalize(&self, target_width: u32) -> Self { - match self { - UintTy::Usize => match target_width { - 16 => UintTy::U16, - 32 => UintTy::U32, - 64 => UintTy::U64, - _ => unreachable!(), - }, - _ => *self, - } - } - - pub fn to_signed(self) -> IntTy { - match self { - UintTy::Usize => IntTy::Isize, - UintTy::U8 => IntTy::I8, - UintTy::U16 => IntTy::I16, - UintTy::U32 => IntTy::I32, - UintTy::U64 => IntTy::I64, - UintTy::U128 => IntTy::I128, - } - } -} - -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[cfg_attr( - feature = "nightly", - derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) -)] -pub enum FloatTy { - F16, - F32, - F64, - F128, -} - -impl FloatTy { - pub fn name_str(self) -> &'static str { - match self { - FloatTy::F16 => "f16", - FloatTy::F32 => "f32", - FloatTy::F64 => "f64", - FloatTy::F128 => "f128", - } - } - - pub fn bit_width(self) -> u64 { - match self { - FloatTy::F16 => 16, - FloatTy::F32 => 32, - FloatTy::F64 => 64, - FloatTy::F128 => 128, - } - } -} - #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum IntVarValue { Unknown, @@ -860,24 +706,6 @@ impl fmt::Display for InferTy { } } -impl fmt::Debug for IntTy { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.name_str()) - } -} - -impl fmt::Debug for UintTy { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.name_str()) - } -} - -impl fmt::Debug for FloatTy { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.name_str()) - } -} - impl fmt::Debug for InferTy { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use InferTy::*; diff --git a/compiler/rustc_type_ir/src/ty_kind/closure.rs b/compiler/rustc_type_ir/src/ty_kind/closure.rs index d1ca9bdb7fb..c32f8339d0b 100644 --- a/compiler/rustc_type_ir/src/ty_kind/closure.rs +++ b/compiler/rustc_type_ir/src/ty_kind/closure.rs @@ -101,7 +101,6 @@ use crate::{self as ty, Interner}; /// `yield` inside the coroutine. /// * `GR`: The "return type", which is the type of value returned upon /// completion of the coroutine. -/// * `GW`: The "coroutine witness". #[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] pub struct ClosureArgs<I: Interner> { @@ -239,8 +238,6 @@ pub struct CoroutineClosureArgsParts<I: Interner> { /// while the `tupled_upvars_ty`, representing the by-move version of the same /// captures, will be `(String,)`. pub coroutine_captures_by_ref_ty: I::Ty, - /// Witness type returned by the generator produced by this coroutine-closure. - pub coroutine_witness_ty: I::Ty, } impl<I: Interner> CoroutineClosureArgs<I> { @@ -251,7 +248,6 @@ impl<I: Interner> CoroutineClosureArgs<I> { parts.signature_parts_ty.into(), parts.tupled_upvars_ty.into(), parts.coroutine_captures_by_ref_ty.into(), - parts.coroutine_witness_ty.into(), ])), } } @@ -292,7 +288,6 @@ impl<I: Interner> CoroutineClosureArgs<I> { } pub fn coroutine_closure_sig(self) -> ty::Binder<I, CoroutineClosureSignature<I>> { - let interior = self.coroutine_witness_ty(); let ty::FnPtr(sig_tys, hdr) = self.signature_parts_ty().kind() else { panic!() }; sig_tys.map_bound(|sig_tys| { let [resume_ty, tupled_inputs_ty] = *sig_tys.inputs().as_slice() else { @@ -302,7 +297,6 @@ impl<I: Interner> CoroutineClosureArgs<I> { panic!() }; CoroutineClosureSignature { - interior, tupled_inputs_ty, resume_ty, yield_ty, @@ -318,10 +312,6 @@ impl<I: Interner> CoroutineClosureArgs<I> { self.split().coroutine_captures_by_ref_ty } - pub fn coroutine_witness_ty(self) -> I::Ty { - self.split().coroutine_witness_ty - } - pub fn has_self_borrows(&self) -> bool { match self.coroutine_captures_by_ref_ty().kind() { ty::FnPtr(sig_tys, _) => sig_tys @@ -361,7 +351,6 @@ impl<I: Interner> TypeVisitor<I> for HasRegionsBoundAt { #[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] pub struct CoroutineClosureSignature<I: Interner> { - pub interior: I::Ty, pub tupled_inputs_ty: I::Ty, pub resume_ty: I::Ty, pub yield_ty: I::Ty, @@ -407,7 +396,6 @@ impl<I: Interner> CoroutineClosureSignature<I> { resume_ty: self.resume_ty, yield_ty: self.yield_ty, return_ty: self.return_ty, - witness: self.interior, tupled_upvars_ty, }, ); @@ -587,11 +575,6 @@ pub struct CoroutineArgsParts<I: Interner> { pub yield_ty: I::Ty, pub return_ty: I::Ty, - /// The interior type of the coroutine. - /// Represents all types that are stored in locals - /// in the coroutine's body. - pub witness: I::Ty, - /// The upvars captured by the closure. Remains an inference variable /// until the upvar analysis, which happens late in HIR typeck. pub tupled_upvars_ty: I::Ty, @@ -607,7 +590,6 @@ impl<I: Interner> CoroutineArgs<I> { parts.resume_ty.into(), parts.yield_ty.into(), parts.return_ty.into(), - parts.witness.into(), parts.tupled_upvars_ty.into(), ])), } @@ -629,15 +611,6 @@ impl<I: Interner> CoroutineArgs<I> { self.split().kind_ty } - /// This describes the types that can be contained in a coroutine. - /// It will be a type variable initially and unified in the last stages of typeck of a body. - /// It contains a tuple of all the types that could end up on a coroutine frame. - /// The state transformation MIR pass may only produce layouts which mention types - /// in this tuple. Upvars are not counted here. - pub fn witness(self) -> I::Ty { - self.split().witness - } - /// Returns an iterator over the list of types of captured paths by the coroutine. /// In case there was a type error in figuring out the types of the captured path, an /// empty iterator is returned. |
