diff --git a/Cargo.lock b/Cargo.lock index 60daa453c60d..361d237b3af8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4494,7 +4494,6 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_transmute", - "rustc_type_ir", "smallvec", "thin-vec", "tracing", diff --git a/bootstrap.example.toml b/bootstrap.example.toml index b8f863bbed13..1371fd6442f9 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml @@ -570,6 +570,12 @@ # Defaults to rust.debug-assertions value #debug-assertions-std = rust.debug-assertions (boolean) +# Whether or not debug assertions are enabled for the tools built by bootstrap. +# Overrides the `debug-assertions` option, if defined. +# +# Defaults to rust.debug-assertions value +#debug-assertions-tools = rust.debug-assertions (boolean) + # Whether or not to leave debug! and trace! calls in the rust binary. # # Defaults to rust.debug-assertions value diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 6aaac072e4b2..d3b7e679d171 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -21,8 +21,10 @@ #![feature(decl_macro)] #![feature(dropck_eyepatch)] #![feature(maybe_uninit_slice)] +#![feature(never_type)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] +#![feature(unwrap_infallible)] // tidy-alphabetical-end use std::alloc::Layout; @@ -200,6 +202,18 @@ impl TypedArena { /// storing the elements in the arena. #[inline] pub fn alloc_from_iter>(&self, iter: I) -> &mut [T] { + self.try_alloc_from_iter(iter.into_iter().map(Ok::)).into_ok() + } + + /// Allocates the elements of this iterator into a contiguous slice in the `TypedArena`. + /// + /// Note: for reasons of reentrancy and panic safety we collect into a `SmallVec<[_; 8]>` before + /// storing the elements in the arena. + #[inline] + pub fn try_alloc_from_iter( + &self, + iter: impl IntoIterator>, + ) -> Result<&mut [T], E> { // Despite the similarlty with `DroplessArena`, we cannot reuse their fast case. The reason // is subtle: these arenas are reentrant. In other words, `iter` may very well be holding a // reference to `self` and adding elements to the arena during iteration. @@ -214,18 +228,19 @@ impl TypedArena { // doesn't need to be hyper-optimized. assert!(size_of::() != 0); - let mut vec: SmallVec<[_; 8]> = iter.into_iter().collect(); + let vec: Result, E> = iter.into_iter().collect(); + let mut vec = vec?; if vec.is_empty() { - return &mut []; + return Ok(&mut []); } // Move the content to the arena by copying and then forgetting it. let len = vec.len(); let start_ptr = self.alloc_raw_slice(len); - unsafe { + Ok(unsafe { vec.as_ptr().copy_to_nonoverlapping(start_ptr, len); vec.set_len(0); slice::from_raw_parts_mut(start_ptr, len) - } + }) } /// Grows the arena. @@ -566,27 +581,34 @@ impl DroplessArena { // `drop`. unsafe { self.write_from_iter(iter, len, mem) } } - (_, _) => { - outline(move || -> &mut [T] { - // Takes care of reentrancy. - let mut vec: SmallVec<[_; 8]> = iter.collect(); - if vec.is_empty() { - return &mut []; - } - // Move the content to the arena by copying it and then forgetting - // the content of the SmallVec - unsafe { - let len = vec.len(); - let start_ptr = - self.alloc_raw(Layout::for_value::<[T]>(vec.as_slice())) as *mut T; - vec.as_ptr().copy_to_nonoverlapping(start_ptr, len); - vec.set_len(0); - slice::from_raw_parts_mut(start_ptr, len) - } - }) - } + (_, _) => outline(move || self.try_alloc_from_iter(iter.map(Ok::)).into_ok()), } } + + #[inline] + pub fn try_alloc_from_iter( + &self, + iter: impl IntoIterator>, + ) -> Result<&mut [T], E> { + // Despite the similarlty with `alloc_from_iter`, we cannot reuse their fast case, as we + // cannot know the minimum length of the iterator in this case. + assert!(size_of::() != 0); + + // Takes care of reentrancy. + let vec: Result, E> = iter.into_iter().collect(); + let mut vec = vec?; + if vec.is_empty() { + return Ok(&mut []); + } + // Move the content to the arena by copying and then forgetting it. + let len = vec.len(); + Ok(unsafe { + let start_ptr = self.alloc_raw(Layout::for_value::<[T]>(vec.as_slice())) as *mut T; + vec.as_ptr().copy_to_nonoverlapping(start_ptr, len); + vec.set_len(0); + slice::from_raw_parts_mut(start_ptr, len) + }) + } } /// Declare an `Arena` containing one dropless arena and many typed arenas (the diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 8986430141be..9d216ef3dd84 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2469,6 +2469,8 @@ pub enum TyPatKind { /// A range pattern (e.g., `1...2`, `1..2`, `1..`, `..2`, `1..=2`, `..=2`). Range(Option>, Option>, Spanned), + Or(ThinVec>), + /// Placeholder for a pattern that wasn't syntactically well formed in some way. Err(ErrorGuaranteed), } diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 1471262d2d67..e572ec99dabf 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -12,6 +12,7 @@ test(attr(deny(warnings))) )] #![doc(rust_logo)] +#![feature(array_windows)] #![feature(associated_type_defaults)] #![feature(box_patterns)] #![feature(if_let_guard)] @@ -19,6 +20,7 @@ #![feature(never_type)] #![feature(rustdoc_internals)] #![feature(stmt_expr_attributes)] +#![recursion_limit = "256"] // tidy-alphabetical-end pub mod util { diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 6aae2e481a59..e49886721e36 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -9,7 +9,6 @@ use std::ops::DerefMut; use std::panic; -use std::sync::Arc; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -20,7 +19,6 @@ use thin_vec::ThinVec; use crate::ast::*; use crate::ptr::P; -use crate::token::{self, Token}; use crate::tokenstream::*; use crate::visit::{AssocCtxt, BoundKind, FnCtxt}; @@ -48,11 +46,6 @@ pub trait WalkItemKind { } pub trait MutVisitor: Sized { - /// Mutable token visiting only exists for the `macro_rules` token marker and should not be - /// used otherwise. Token visitor would be entirely separate from the regular visitor if - /// the marker didn't have to visit AST fragments in nonterminal tokens. - const VISIT_TOKENS: bool = false; - // Methods in this trait have one of three forms: // // fn visit_t(&mut self, t: &mut T); // common @@ -360,6 +353,8 @@ pub trait MutVisitor: Sized { // Do nothing. } + // Span visiting is no longer used, but we keep it for now, + // in case it's needed for something like #127241. fn visit_span(&mut self, _sp: &mut Span) { // Do nothing. } @@ -473,12 +468,8 @@ fn visit_attr_args(vis: &mut T, args: &mut AttrArgs) { // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. fn visit_delim_args(vis: &mut T, args: &mut DelimArgs) { - let DelimArgs { dspan, delim: _, tokens } = args; - visit_tts(vis, tokens); - visit_delim_span(vis, dspan); -} - -pub fn visit_delim_span(vis: &mut T, DelimSpan { open, close }: &mut DelimSpan) { + let DelimArgs { dspan, delim: _, tokens: _ } = args; + let DelimSpan { open, close } = dspan; vis.visit_span(open); vis.visit_span(close); } @@ -552,7 +543,7 @@ fn walk_assoc_item_constraint( } pub fn walk_ty(vis: &mut T, ty: &mut P) { - let Ty { id, kind, span, tokens } = ty.deref_mut(); + let Ty { id, kind, span, tokens: _ } = ty.deref_mut(); vis.visit_id(id); match kind { TyKind::Err(_guar) => {} @@ -600,21 +591,20 @@ pub fn walk_ty(vis: &mut T, ty: &mut P) { } TyKind::MacCall(mac) => vis.visit_mac_call(mac), } - visit_lazy_tts(vis, tokens); vis.visit_span(span); } pub fn walk_ty_pat(vis: &mut T, ty: &mut P) { - let TyPat { id, kind, span, tokens } = ty.deref_mut(); + let TyPat { id, kind, span, tokens: _ } = ty.deref_mut(); vis.visit_id(id); match kind { TyPatKind::Range(start, end, _include_end) => { visit_opt(start, |c| vis.visit_anon_const(c)); visit_opt(end, |c| vis.visit_anon_const(c)); } + TyPatKind::Or(variants) => visit_thin_vec(variants, |p| vis.visit_ty_pat(p)), TyPatKind::Err(_) => {} } - visit_lazy_tts(vis, tokens); vis.visit_span(span); } @@ -654,11 +644,10 @@ fn walk_path_segment(vis: &mut T, segment: &mut PathSegment) { visit_opt(args, |args| vis.visit_generic_args(args)); } -fn walk_path(vis: &mut T, Path { segments, span, tokens }: &mut Path) { +fn walk_path(vis: &mut T, Path { segments, span, tokens: _ }: &mut Path) { for segment in segments { vis.visit_path_segment(segment); } - visit_lazy_tts(vis, tokens); vis.visit_span(span); } @@ -704,7 +693,7 @@ fn walk_parenthesized_parameter_data(vis: &mut T, args: &mut Pare } fn walk_local(vis: &mut T, local: &mut P) { - let Local { id, super_, pat, ty, kind, span, colon_sp, attrs, tokens } = local.deref_mut(); + let Local { id, super_, pat, ty, kind, span, colon_sp, attrs, tokens: _ } = local.deref_mut(); visit_opt(super_, |sp| vis.visit_span(sp)); vis.visit_id(id); visit_attrs(vis, attrs); @@ -720,7 +709,6 @@ fn walk_local(vis: &mut T, local: &mut P) { vis.visit_block(els); } } - visit_lazy_tts(vis, tokens); visit_opt(colon_sp, |sp| vis.visit_span(sp)); vis.visit_span(span); } @@ -729,14 +717,10 @@ fn walk_attribute(vis: &mut T, attr: &mut Attribute) { let Attribute { kind, id: _, style: _, span } = attr; match kind { AttrKind::Normal(normal) => { - let NormalAttr { - item: AttrItem { unsafety: _, path, args, tokens }, - tokens: attr_tokens, - } = &mut **normal; + let NormalAttr { item: AttrItem { unsafety: _, path, args, tokens: _ }, tokens: _ } = + &mut **normal; vis.visit_path(path); visit_attr_args(vis, args); - visit_lazy_tts(vis, tokens); - visit_lazy_tts(vis, attr_tokens); } AttrKind::DocComment(_kind, _sym) => {} } @@ -785,90 +769,6 @@ pub fn walk_flat_map_param(vis: &mut T, mut param: Param) -> Smal smallvec![param] } -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -fn visit_attr_tt(vis: &mut T, tt: &mut AttrTokenTree) { - match tt { - AttrTokenTree::Token(token, _spacing) => { - visit_token(vis, token); - } - AttrTokenTree::Delimited(dspan, _spacing, _delim, tts) => { - visit_attr_tts(vis, tts); - visit_delim_span(vis, dspan); - } - AttrTokenTree::AttrsTarget(AttrsTarget { attrs, tokens }) => { - visit_attrs(vis, attrs); - visit_lazy_tts_opt_mut(vis, Some(tokens)); - } - } -} - -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -fn visit_tt(vis: &mut T, tt: &mut TokenTree) { - match tt { - TokenTree::Token(token, _spacing) => { - visit_token(vis, token); - } - TokenTree::Delimited(dspan, _spacing, _delim, tts) => { - visit_tts(vis, tts); - visit_delim_span(vis, dspan); - } - } -} - -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -fn visit_tts(vis: &mut T, TokenStream(tts): &mut TokenStream) { - if T::VISIT_TOKENS && !tts.is_empty() { - let tts = Arc::make_mut(tts); - visit_vec(tts, |tree| visit_tt(vis, tree)); - } -} - -fn visit_attr_tts(vis: &mut T, AttrTokenStream(tts): &mut AttrTokenStream) { - if T::VISIT_TOKENS && !tts.is_empty() { - let tts = Arc::make_mut(tts); - visit_vec(tts, |tree| visit_attr_tt(vis, tree)); - } -} - -fn visit_lazy_tts_opt_mut(vis: &mut T, lazy_tts: Option<&mut LazyAttrTokenStream>) { - if T::VISIT_TOKENS { - if let Some(lazy_tts) = lazy_tts { - let mut tts = lazy_tts.to_attr_token_stream(); - visit_attr_tts(vis, &mut tts); - *lazy_tts = LazyAttrTokenStream::new(tts); - } - } -} - -fn visit_lazy_tts(vis: &mut T, lazy_tts: &mut Option) { - visit_lazy_tts_opt_mut(vis, lazy_tts.as_mut()); -} - -/// Applies ident visitor if it's an ident. In practice this is not actually -/// used by specific visitors right now, but there's a test below checking that -/// it works. -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_token(vis: &mut T, t: &mut Token) { - let Token { kind, span } = t; - match kind { - token::Ident(name, _is_raw) | token::Lifetime(name, _is_raw) => { - let mut ident = Ident::new(*name, *span); - vis.visit_ident(&mut ident); - *name = ident.name; - *span = ident.span; - return; // Avoid visiting the span for the second time. - } - token::NtIdent(ident, _is_raw) => { - vis.visit_ident(ident); - } - token::NtLifetime(ident, _is_raw) => { - vis.visit_ident(ident); - } - _ => {} - } - vis.visit_span(span); -} - // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. fn visit_defaultness(vis: &mut T, defaultness: &mut Defaultness) { match defaultness { @@ -1187,10 +1087,9 @@ fn walk_mt(vis: &mut T, MutTy { ty, mutbl: _ }: &mut MutTy) { } pub fn walk_block(vis: &mut T, block: &mut P) { - let Block { id, stmts, rules: _, span, tokens } = block.deref_mut(); + let Block { id, stmts, rules: _, span, tokens: _ } = block.deref_mut(); vis.visit_id(id); stmts.flat_map_in_place(|stmt| vis.flat_map_stmt(stmt)); - visit_lazy_tts(vis, tokens); vis.visit_span(span); } @@ -1471,12 +1370,11 @@ fn walk_item_ctxt( item: &mut P>, ctxt: K::Ctxt, ) { - let Item { attrs, id, kind, vis, span, tokens } = item.deref_mut(); + let Item { attrs, id, kind, vis, span, tokens: _ } = item.deref_mut(); visitor.visit_id(id); visit_attrs(visitor, attrs); visitor.visit_vis(vis); kind.walk(*span, *id, vis, ctxt, visitor); - visit_lazy_tts(visitor, tokens); visitor.visit_span(span); } @@ -1550,7 +1448,7 @@ impl WalkItemKind for ForeignItemKind { } pub fn walk_pat(vis: &mut T, pat: &mut P) { - let Pat { id, kind, span, tokens } = pat.deref_mut(); + let Pat { id, kind, span, tokens: _ } = pat.deref_mut(); vis.visit_id(id); match kind { PatKind::Err(_guar) => {} @@ -1592,7 +1490,6 @@ pub fn walk_pat(vis: &mut T, pat: &mut P) { PatKind::Paren(inner) => vis.visit_pat(inner), PatKind::MacCall(mac) => vis.visit_mac_call(mac), } - visit_lazy_tts(vis, tokens); vis.visit_span(span); } @@ -1656,7 +1553,7 @@ fn walk_format_args(vis: &mut T, fmt: &mut FormatArgs) { vis.visit_span(span); } -pub fn walk_expr(vis: &mut T, Expr { kind, id, span, attrs, tokens }: &mut Expr) { +pub fn walk_expr(vis: &mut T, Expr { kind, id, span, attrs, tokens: _ }: &mut Expr) { vis.visit_id(id); visit_attrs(vis, attrs); match kind { @@ -1847,7 +1744,6 @@ pub fn walk_expr(vis: &mut T, Expr { kind, id, span, attrs, token ExprKind::Err(_guar) => {} ExprKind::Dummy => {} } - visit_lazy_tts(vis, tokens); vis.visit_span(span); } @@ -1889,17 +1785,16 @@ fn walk_flat_map_stmt_kind(vis: &mut T, kind: StmtKind) -> SmallV StmtKind::Semi(expr) => vis.filter_map_expr(expr).into_iter().map(StmtKind::Semi).collect(), StmtKind::Empty => smallvec![StmtKind::Empty], StmtKind::MacCall(mut mac) => { - let MacCallStmt { mac: mac_, style: _, attrs, tokens } = mac.deref_mut(); + let MacCallStmt { mac: mac_, style: _, attrs, tokens: _ } = mac.deref_mut(); visit_attrs(vis, attrs); vis.visit_mac_call(mac_); - visit_lazy_tts(vis, tokens); smallvec![StmtKind::MacCall(mac)] } } } fn walk_vis(vis: &mut T, visibility: &mut Visibility) { - let Visibility { kind, span, tokens } = visibility; + let Visibility { kind, span, tokens: _ } = visibility; match kind { VisibilityKind::Public | VisibilityKind::Inherited => {} VisibilityKind::Restricted { path, id, shorthand: _ } => { @@ -1907,7 +1802,6 @@ fn walk_vis(vis: &mut T, visibility: &mut Visibility) { vis.visit_path(path); } } - visit_lazy_tts(vis, tokens); vis.visit_span(span); } diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 43d25d180750..636c26bcde04 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -14,14 +14,16 @@ //! ownership of the original. use std::borrow::Cow; +use std::ops::Range; use std::sync::Arc; -use std::{cmp, fmt, iter}; +use std::{cmp, fmt, iter, mem}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_serialize::{Decodable, Encodable}; use rustc_span::{DUMMY_SP, Span, SpanDecoder, SpanEncoder, Symbol, sym}; +use thin_vec::ThinVec; use crate::ast::AttrStyle; use crate::ast_traits::{HasAttrs, HasTokens}; @@ -106,25 +108,30 @@ where } } -pub trait ToAttrTokenStream: sync::DynSend + sync::DynSync { - fn to_attr_token_stream(&self) -> AttrTokenStream; -} - -impl ToAttrTokenStream for AttrTokenStream { - fn to_attr_token_stream(&self) -> AttrTokenStream { - self.clone() - } -} - -/// A lazy version of [`TokenStream`], which defers creation -/// of an actual `TokenStream` until it is needed. -/// `Box` is here only to reduce the structure size. +/// A lazy version of [`AttrTokenStream`], which defers creation of an actual +/// `AttrTokenStream` until it is needed. #[derive(Clone)] -pub struct LazyAttrTokenStream(Arc>); +pub struct LazyAttrTokenStream(Arc); impl LazyAttrTokenStream { - pub fn new(inner: impl ToAttrTokenStream + 'static) -> LazyAttrTokenStream { - LazyAttrTokenStream(Arc::new(Box::new(inner))) + pub fn new_direct(stream: AttrTokenStream) -> LazyAttrTokenStream { + LazyAttrTokenStream(Arc::new(LazyAttrTokenStreamInner::Direct(stream))) + } + + pub fn new_pending( + start_token: (Token, Spacing), + cursor_snapshot: TokenCursor, + num_calls: u32, + break_last_token: u32, + node_replacements: ThinVec, + ) -> LazyAttrTokenStream { + LazyAttrTokenStream(Arc::new(LazyAttrTokenStreamInner::Pending { + start_token, + cursor_snapshot, + num_calls, + break_last_token, + node_replacements, + })) } pub fn to_attr_token_stream(&self) -> AttrTokenStream { @@ -156,6 +163,184 @@ impl HashStable for LazyAttrTokenStream { } } +/// A token range within a `Parser`'s full token stream. +#[derive(Clone, Debug)] +pub struct ParserRange(pub Range); + +/// A token range within an individual AST node's (lazy) token stream, i.e. +/// relative to that node's first token. Distinct from `ParserRange` so the two +/// kinds of range can't be mixed up. +#[derive(Clone, Debug)] +pub struct NodeRange(pub Range); + +/// Indicates a range of tokens that should be replaced by an `AttrsTarget` +/// (replacement) or be replaced by nothing (deletion). This is used in two +/// places during token collection. +/// +/// 1. Replacement. During the parsing of an AST node that may have a +/// `#[derive]` attribute, when we parse a nested AST node that has `#[cfg]` +/// or `#[cfg_attr]`, we replace the entire inner AST node with +/// `FlatToken::AttrsTarget`. This lets us perform eager cfg-expansion on an +/// `AttrTokenStream`. +/// +/// 2. Deletion. We delete inner attributes from all collected token streams, +/// and instead track them through the `attrs` field on the AST node. This +/// lets us manipulate them similarly to outer attributes. When we create a +/// `TokenStream`, the inner attributes are inserted into the proper place +/// in the token stream. +/// +/// Each replacement starts off in `ParserReplacement` form but is converted to +/// `NodeReplacement` form when it is attached to a single AST node, via +/// `LazyAttrTokenStreamImpl`. +pub type ParserReplacement = (ParserRange, Option); + +/// See the comment on `ParserReplacement`. +pub type NodeReplacement = (NodeRange, Option); + +impl NodeRange { + // Converts a range within a parser's tokens to a range within a + // node's tokens beginning at `start_pos`. + // + // For example, imagine a parser with 50 tokens in its token stream, a + // function that spans `ParserRange(20..40)` and an inner attribute within + // that function that spans `ParserRange(30..35)`. We would find the inner + // attribute's range within the function's tokens by subtracting 20, which + // is the position of the function's start token. This gives + // `NodeRange(10..15)`. + pub fn new(ParserRange(parser_range): ParserRange, start_pos: u32) -> NodeRange { + assert!(!parser_range.is_empty()); + assert!(parser_range.start >= start_pos); + NodeRange((parser_range.start - start_pos)..(parser_range.end - start_pos)) + } +} + +enum LazyAttrTokenStreamInner { + // The token stream has already been produced. + Direct(AttrTokenStream), + + // From a value of this type we can reconstruct the `TokenStream` seen by + // the `f` callback passed to a call to `Parser::collect_tokens`, by + // replaying the getting of the tokens. This saves us producing a + // `TokenStream` if it is never needed, e.g. a captured `macro_rules!` + // argument that is never passed to a proc macro. In practice, token stream + // creation happens rarely compared to calls to `collect_tokens` (see some + // statistics in #78736) so we are doing as little up-front work as + // possible. + // + // This also makes `Parser` very cheap to clone, since there is no + // intermediate collection buffer to clone. + Pending { + start_token: (Token, Spacing), + cursor_snapshot: TokenCursor, + num_calls: u32, + break_last_token: u32, + node_replacements: ThinVec, + }, +} + +impl LazyAttrTokenStreamInner { + fn to_attr_token_stream(&self) -> AttrTokenStream { + match self { + LazyAttrTokenStreamInner::Direct(stream) => stream.clone(), + LazyAttrTokenStreamInner::Pending { + start_token, + cursor_snapshot, + num_calls, + break_last_token, + node_replacements, + } => { + // The token produced by the final call to `{,inlined_}next` was not + // actually consumed by the callback. The combination of chaining the + // initial token and using `take` produces the desired result - we + // produce an empty `TokenStream` if no calls were made, and omit the + // final token otherwise. + let mut cursor_snapshot = cursor_snapshot.clone(); + let tokens = iter::once(FlatToken::Token(*start_token)) + .chain(iter::repeat_with(|| FlatToken::Token(cursor_snapshot.next()))) + .take(*num_calls as usize); + + if node_replacements.is_empty() { + make_attr_token_stream(tokens, *break_last_token) + } else { + let mut tokens: Vec<_> = tokens.collect(); + let mut node_replacements = node_replacements.to_vec(); + node_replacements.sort_by_key(|(range, _)| range.0.start); + + #[cfg(debug_assertions)] + for [(node_range, tokens), (next_node_range, next_tokens)] in + node_replacements.array_windows() + { + assert!( + node_range.0.end <= next_node_range.0.start + || node_range.0.end >= next_node_range.0.end, + "Node ranges should be disjoint or nested: ({:?}, {:?}) ({:?}, {:?})", + node_range, + tokens, + next_node_range, + next_tokens, + ); + } + + // Process the replace ranges, starting from the highest start + // position and working our way back. If have tokens like: + // + // `#[cfg(FALSE)] struct Foo { #[cfg(FALSE)] field: bool }` + // + // Then we will generate replace ranges for both + // the `#[cfg(FALSE)] field: bool` and the entire + // `#[cfg(FALSE)] struct Foo { #[cfg(FALSE)] field: bool }` + // + // By starting processing from the replace range with the greatest + // start position, we ensure that any (outer) replace range which + // encloses another (inner) replace range will fully overwrite the + // inner range's replacement. + for (node_range, target) in node_replacements.into_iter().rev() { + assert!( + !node_range.0.is_empty(), + "Cannot replace an empty node range: {:?}", + node_range.0 + ); + + // Replace the tokens in range with zero or one `FlatToken::AttrsTarget`s, + // plus enough `FlatToken::Empty`s to fill up the rest of the range. This + // keeps the total length of `tokens` constant throughout the replacement + // process, allowing us to do all replacements without adjusting indices. + let target_len = target.is_some() as usize; + tokens.splice( + (node_range.0.start as usize)..(node_range.0.end as usize), + target.into_iter().map(|target| FlatToken::AttrsTarget(target)).chain( + iter::repeat(FlatToken::Empty) + .take(node_range.0.len() - target_len), + ), + ); + } + make_attr_token_stream(tokens.into_iter(), *break_last_token) + } + } + } + } +} + +/// A helper struct used when building an `AttrTokenStream` from +/// a `LazyAttrTokenStream`. Both delimiter and non-delimited tokens +/// are stored as `FlatToken::Token`. A vector of `FlatToken`s +/// is then 'parsed' to build up an `AttrTokenStream` with nested +/// `AttrTokenTree::Delimited` tokens. +#[derive(Debug, Clone)] +enum FlatToken { + /// A token - this holds both delimiter (e.g. '{' and '}') + /// and non-delimiter tokens + Token((Token, Spacing)), + /// Holds the `AttrsTarget` for an AST node. The `AttrsTarget` is inserted + /// directly into the constructed `AttrTokenStream` as an + /// `AttrTokenTree::AttrsTarget`. + AttrsTarget(AttrsTarget), + /// A special 'empty' token that is ignored during the conversion + /// to an `AttrTokenStream`. This is used to simplify the + /// handling of replace ranges. + Empty, +} + /// An `AttrTokenStream` is similar to a `TokenStream`, but with extra /// information about the tokens for attribute targets. This is used /// during expansion to perform early cfg-expansion, and to process attributes @@ -163,6 +348,71 @@ impl HashStable for LazyAttrTokenStream { #[derive(Clone, Debug, Default, Encodable, Decodable)] pub struct AttrTokenStream(pub Arc>); +/// Converts a flattened iterator of tokens (including open and close delimiter tokens) into an +/// `AttrTokenStream`, creating an `AttrTokenTree::Delimited` for each matching pair of open and +/// close delims. +fn make_attr_token_stream( + iter: impl Iterator, + break_last_token: u32, +) -> AttrTokenStream { + #[derive(Debug)] + struct FrameData { + // This is `None` for the first frame, `Some` for all others. + open_delim_sp: Option<(Delimiter, Span, Spacing)>, + inner: Vec, + } + // The stack always has at least one element. Storing it separately makes for shorter code. + let mut stack_top = FrameData { open_delim_sp: None, inner: vec![] }; + let mut stack_rest = vec![]; + for flat_token in iter { + match flat_token { + FlatToken::Token((token @ Token { kind, span }, spacing)) => { + if let Some(delim) = kind.open_delim() { + stack_rest.push(mem::replace( + &mut stack_top, + FrameData { open_delim_sp: Some((delim, span, spacing)), inner: vec![] }, + )); + } else if let Some(delim) = kind.close_delim() { + let frame_data = mem::replace(&mut stack_top, stack_rest.pop().unwrap()); + let (open_delim, open_sp, open_spacing) = frame_data.open_delim_sp.unwrap(); + assert!( + open_delim.eq_ignoring_invisible_origin(&delim), + "Mismatched open/close delims: open={open_delim:?} close={span:?}" + ); + let dspan = DelimSpan::from_pair(open_sp, span); + let dspacing = DelimSpacing::new(open_spacing, spacing); + let stream = AttrTokenStream::new(frame_data.inner); + let delimited = AttrTokenTree::Delimited(dspan, dspacing, delim, stream); + stack_top.inner.push(delimited); + } else { + stack_top.inner.push(AttrTokenTree::Token(token, spacing)) + } + } + FlatToken::AttrsTarget(target) => { + stack_top.inner.push(AttrTokenTree::AttrsTarget(target)) + } + FlatToken::Empty => {} + } + } + + if break_last_token > 0 { + let last_token = stack_top.inner.pop().unwrap(); + if let AttrTokenTree::Token(last_token, spacing) = last_token { + let (unglued, _) = last_token.kind.break_two_token_op(break_last_token).unwrap(); + + // Tokens are always ASCII chars, so we can use byte arithmetic here. + let mut first_span = last_token.span.shrink_to_lo(); + first_span = + first_span.with_hi(first_span.lo() + rustc_span::BytePos(break_last_token)); + + stack_top.inner.push(AttrTokenTree::Token(Token::new(unglued, first_span), spacing)); + } else { + panic!("Unexpected last token {last_token:?}") + } + } + AttrTokenStream::new(stack_top.inner) +} + /// Like `TokenTree`, but for `AttrTokenStream`. #[derive(Clone, Debug, Encodable, Decodable)] pub enum AttrTokenTree { @@ -641,6 +891,104 @@ impl<'t> Iterator for TokenStreamIter<'t> { } } +#[derive(Clone, Debug)] +pub struct TokenTreeCursor { + stream: TokenStream, + /// Points to the current token tree in the stream. In `TokenCursor::curr`, + /// this can be any token tree. In `TokenCursor::stack`, this is always a + /// `TokenTree::Delimited`. + index: usize, +} + +impl TokenTreeCursor { + #[inline] + pub fn new(stream: TokenStream) -> Self { + TokenTreeCursor { stream, index: 0 } + } + + #[inline] + pub fn curr(&self) -> Option<&TokenTree> { + self.stream.get(self.index) + } + + pub fn look_ahead(&self, n: usize) -> Option<&TokenTree> { + self.stream.get(self.index + n) + } + + #[inline] + pub fn bump(&mut self) { + self.index += 1; + } +} + +/// A `TokenStream` cursor that produces `Token`s. It's a bit odd that +/// we (a) lex tokens into a nice tree structure (`TokenStream`), and then (b) +/// use this type to emit them as a linear sequence. But a linear sequence is +/// what the parser expects, for the most part. +#[derive(Clone, Debug)] +pub struct TokenCursor { + // Cursor for the current (innermost) token stream. The index within the + // cursor can point to any token tree in the stream (or one past the end). + // The delimiters for this token stream are found in `self.stack.last()`; + // if that is `None` we are in the outermost token stream which never has + // delimiters. + pub curr: TokenTreeCursor, + + // Token streams surrounding the current one. The index within each cursor + // always points to a `TokenTree::Delimited`. + pub stack: Vec, +} + +impl TokenCursor { + pub fn next(&mut self) -> (Token, Spacing) { + self.inlined_next() + } + + /// This always-inlined version should only be used on hot code paths. + #[inline(always)] + pub fn inlined_next(&mut self) -> (Token, Spacing) { + loop { + // FIXME: we currently don't return `Delimiter::Invisible` open/close delims. To fix + // #67062 we will need to, whereupon the `delim != Delimiter::Invisible` conditions + // below can be removed. + if let Some(tree) = self.curr.curr() { + match tree { + &TokenTree::Token(token, spacing) => { + debug_assert!(!token.kind.is_delim()); + let res = (token, spacing); + self.curr.bump(); + return res; + } + &TokenTree::Delimited(sp, spacing, delim, ref tts) => { + let trees = TokenTreeCursor::new(tts.clone()); + self.stack.push(mem::replace(&mut self.curr, trees)); + if !delim.skip() { + return (Token::new(delim.as_open_token_kind(), sp.open), spacing.open); + } + // No open delimiter to return; continue on to the next iteration. + } + }; + } else if let Some(parent) = self.stack.pop() { + // We have exhausted this token stream. Move back to its parent token stream. + let Some(&TokenTree::Delimited(span, spacing, delim, _)) = parent.curr() else { + panic!("parent should be Delimited") + }; + self.curr = parent; + self.curr.bump(); // move past the `Delimited` + if !delim.skip() { + return (Token::new(delim.as_close_token_kind(), span.close), spacing.close); + } + // No close delimiter to return; continue on to the next iteration. + } else { + // We have exhausted the outermost token stream. The use of + // `Spacing::Alone` is arbitrary and immaterial, because the + // `Eof` token's spacing is never used. + return (Token::new(token::Eof, DUMMY_SP), Spacing::Alone); + } + } + } +} + #[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)] pub struct DelimSpan { pub open: Span, @@ -687,6 +1035,7 @@ mod size_asserts { static_assert_size!(AttrTokenStream, 8); static_assert_size!(AttrTokenTree, 32); static_assert_size!(LazyAttrTokenStream, 8); + static_assert_size!(LazyAttrTokenStreamInner, 88); static_assert_size!(Option, 8); // must be small, used in many AST nodes static_assert_size!(TokenStream, 8); static_assert_size!(TokenTree, 32); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 79193fcec63a..69a186c8cf1b 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -608,6 +608,7 @@ pub fn walk_ty_pat<'a, V: Visitor<'a>>(visitor: &mut V, tp: &'a TyPat) -> V::Res visit_opt!(visitor, visit_anon_const, start); visit_opt!(visitor, visit_anon_const, end); } + TyPatKind::Or(variants) => walk_list!(visitor, visit_ty_pat, variants), TyPatKind::Err(_) => {} } V::Result::output() diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 1e14b4d6723f..8b1c63cd21d8 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -49,6 +49,7 @@ use rustc_attr_parsing::{AttributeParser, OmitDoc}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::sync::spawn; use rustc_data_structures::tagged_ptr::TaggedRef; use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey}; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; @@ -454,9 +455,14 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> { .lower_node(def_id); } - // Drop AST to free memory drop(ast_index); - sess.time("drop_ast", || drop(krate)); + + // Drop AST to free memory. It can be expensive so try to drop it on a separate thread. + let prof = sess.prof.clone(); + spawn(move || { + let _timer = prof.verbose_generic_activity("drop_ast"); + drop(krate); + }); // Don't hash unless necessary, because it's expensive. let opt_hir_hash = diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index f94d788a9b0e..4a6929ef0117 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -464,6 +464,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) }), ), + TyPatKind::Or(variants) => { + hir::TyPatKind::Or(self.arena.alloc_from_iter( + variants.iter().map(|pat| self.lower_ty_pat_mut(pat, base_type)), + )) + } TyPatKind::Err(guar) => hir::TyPatKind::Err(*guar), }; diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 985359e1234e..b5925fab7d95 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -634,6 +634,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere false, None, *delim, + None, tokens, true, span, @@ -679,6 +680,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere false, None, *delim, + Some(spacing.open), tts, convert_dollar_crate, dspan.entire(), @@ -735,6 +737,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere has_bang: bool, ident: Option, delim: Delimiter, + open_spacing: Option, tts: &TokenStream, convert_dollar_crate: bool, span: Span, @@ -758,16 +761,26 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere self.nbsp(); } self.word("{"); - if !tts.is_empty() { + + // Respect `Alone`, if provided, and print a space. Unless the list is empty. + let open_space = (open_spacing == None || open_spacing == Some(Spacing::Alone)) + && !tts.is_empty(); + if open_space { self.space(); } let ib = self.ibox(0); self.print_tts(tts, convert_dollar_crate); self.end(ib); - let empty = tts.is_empty(); - self.bclose(span, empty, cb.unwrap()); + + // Use `open_space` for the spacing *before* the closing delim. + // Because spacing on delimiters is lost when going through + // proc macros, and otherwise we can end up with ugly cases + // like `{ x}`. Symmetry is better. + self.bclose(span, !open_space, cb.unwrap()); } delim => { + // `open_spacing` is ignored. We never print spaces after + // non-brace opening delims or before non-brace closing delims. let token_str = self.token_kind_to_string(&delim.as_open_token_kind()); self.word(token_str); let ib = self.ibox(0); @@ -797,6 +810,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere has_bang, Some(*ident), macro_def.body.delim, + None, ¯o_def.body.tokens, true, sp, @@ -844,9 +858,9 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere self.end(ib); } - fn bclose_maybe_open(&mut self, span: rustc_span::Span, empty: bool, cb: Option) { + fn bclose_maybe_open(&mut self, span: rustc_span::Span, no_space: bool, cb: Option) { let has_comment = self.maybe_print_comment(span.hi()); - if !empty || has_comment { + if !no_space || has_comment { self.break_offset_if_not_bol(1, -INDENT_UNIT); } self.word("}"); @@ -855,9 +869,9 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere } } - fn bclose(&mut self, span: rustc_span::Span, empty: bool, cb: BoxMarker) { + fn bclose(&mut self, span: rustc_span::Span, no_space: bool, cb: BoxMarker) { let cb = Some(cb); - self.bclose_maybe_open(span, empty, cb) + self.bclose_maybe_open(span, no_space, cb) } fn break_offset_if_not_bol(&mut self, n: usize, off: isize) { @@ -1158,6 +1172,17 @@ impl<'a> State<'a> { self.print_expr_anon_const(end, &[]); } } + rustc_ast::TyPatKind::Or(variants) => { + let mut first = true; + for pat in variants { + if first { + first = false + } else { + self.word(" | "); + } + self.print_ty_pat(pat); + } + } rustc_ast::TyPatKind::Err(_) => { self.popen(); self.word("/*ERROR*/"); @@ -1423,8 +1448,8 @@ impl<'a> State<'a> { } } - let empty = !has_attrs && blk.stmts.is_empty(); - self.bclose_maybe_open(blk.span, empty, cb); + let no_space = !has_attrs && blk.stmts.is_empty(); + self.bclose_maybe_open(blk.span, no_space, cb); self.ann.post(self, AnnNode::Block(blk)) } @@ -1471,6 +1496,7 @@ impl<'a> State<'a> { true, None, m.args.delim, + None, &m.args.tokens, true, m.span(), diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index b9692c01e2c4..874fccf7ff6d 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -80,6 +80,7 @@ #![cfg_attr(bootstrap, feature(let_chains))] #![doc(rust_logo)] #![feature(rustdoc_internals)] +#![recursion_limit = "256"] // tidy-alphabetical-end #[macro_use] diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index 6d97dfa3a4d4..8c5c20c7af48 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -323,9 +323,9 @@ mod llvm_enzyme { Spacing::Joint, )]; let never_arg = ast::DelimArgs { - dspan: ast::tokenstream::DelimSpan::from_single(span), + dspan: DelimSpan::from_single(span), delim: ast::token::Delimiter::Parenthesis, - tokens: ast::tokenstream::TokenStream::from_iter(ts2), + tokens: TokenStream::from_iter(ts2), }; let inline_item = ast::AttrItem { unsafety: ast::Safety::Default, diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 70e817db2a63..c2f5bf0f4571 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -18,6 +18,7 @@ #![feature(rustdoc_internals)] #![feature(string_from_utf8_lossy_owned)] #![feature(try_blocks)] +#![recursion_limit = "256"] // tidy-alphabetical-end extern crate proc_macro; diff --git a/compiler/rustc_builtin_macros/src/pattern_type.rs b/compiler/rustc_builtin_macros/src/pattern_type.rs index a55c7e962d09..3529e5525fcd 100644 --- a/compiler/rustc_builtin_macros/src/pattern_type.rs +++ b/compiler/rustc_builtin_macros/src/pattern_type.rs @@ -1,9 +1,10 @@ use rustc_ast::ptr::P; use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{AnonConst, DUMMY_NODE_ID, Ty, TyPat, TyPatKind, ast}; +use rustc_ast::{AnonConst, DUMMY_NODE_ID, Ty, TyPat, TyPatKind, ast, token}; use rustc_errors::PResult; use rustc_expand::base::{self, DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult}; use rustc_parse::exp; +use rustc_parse::parser::{CommaRecoveryMode, RecoverColon, RecoverComma}; use rustc_span::Span; pub(crate) fn expand<'cx>( @@ -26,19 +27,42 @@ fn parse_pat_ty<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P let ty = parser.parse_ty()?; parser.expect_keyword(exp!(Is))?; - let pat = parser.parse_pat_no_top_alt(None, None)?.into_inner(); + let pat = pat_to_ty_pat( + cx, + parser + .parse_pat_no_top_guard( + None, + RecoverComma::No, + RecoverColon::No, + CommaRecoveryMode::EitherTupleOrPipe, + )? + .into_inner(), + ); + + if parser.token != token::Eof { + parser.unexpected()?; + } + + Ok((ty, pat)) +} + +fn ty_pat(kind: TyPatKind, span: Span) -> P { + P(TyPat { id: DUMMY_NODE_ID, kind, span, tokens: None }) +} + +fn pat_to_ty_pat(cx: &mut ExtCtxt<'_>, pat: ast::Pat) -> P { 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 })), include_end, ), + ast::PatKind::Or(variants) => TyPatKind::Or( + variants.into_iter().map(|pat| pat_to_ty_pat(cx, pat.into_inner())).collect(), + ), ast::PatKind::Err(guar) => TyPatKind::Err(guar), _ => TyPatKind::Err(cx.dcx().span_err(pat.span, "pattern not supported in pattern types")), }; - - let pat = P(TyPat { id: pat.id, kind, span: pat.span, tokens: pat.tokens }); - - Ok((ty, pat)) + ty_pat(kind, pat.span) } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index e9c7186b03c9..524e0d9fe35e 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -8,8 +8,6 @@ use rustc_ast::InlineAsmOptions; use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_index::IndexVec; -use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::mir::InlineAsmMacro; use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv}; @@ -18,7 +16,6 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use crate::constant::ConstantCx; use crate::debuginfo::{FunctionDebugContext, TypeDebugContext}; use crate::enable_verifier; -use crate::inline_asm::codegen_naked_asm; use crate::prelude::*; use crate::pretty_clif::CommentWriter; @@ -37,7 +34,7 @@ pub(crate) fn codegen_fn<'tcx>( cached_func: Function, module: &mut dyn Module, instance: Instance<'tcx>, -) -> Option { +) -> CodegenedFunction { debug_assert!(!instance.args.has_infer()); let symbol_name = tcx.symbol_name(instance).name.to_string(); @@ -54,38 +51,6 @@ pub(crate) fn codegen_fn<'tcx>( String::from_utf8_lossy(&buf).into_owned() }); - if tcx.codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED) { - assert_eq!(mir.basic_blocks.len(), 1); - assert!(mir.basic_blocks[START_BLOCK].statements.is_empty()); - - match &mir.basic_blocks[START_BLOCK].terminator().kind { - TerminatorKind::InlineAsm { - asm_macro: InlineAsmMacro::NakedAsm, - template, - operands, - options, - line_spans: _, - targets: _, - unwind: _, - } => { - codegen_naked_asm( - tcx, - cx, - module, - instance, - mir.basic_blocks[START_BLOCK].terminator().source_info.span, - &symbol_name, - template, - operands, - *options, - ); - } - _ => unreachable!(), - } - - return None; - } - // Declare function let sig = get_function_sig(tcx, module.target_config().default_call_conv, instance); let func_id = module.declare_function(&symbol_name, Linkage::Local, &sig).unwrap(); @@ -166,7 +131,7 @@ pub(crate) fn codegen_fn<'tcx>( // Verify function verify_func(tcx, &clif_comments, &func); - Some(CodegenedFunction { symbol_name, func_id, func, clif_comments, func_debug_cx }) + CodegenedFunction { symbol_name, func_id, func, clif_comments, func_debug_cx } } pub(crate) fn compile_fn( diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index 00136ac4a574..5d07c94859f3 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -22,7 +22,10 @@ use rustc_data_structures::sync::{IntoDynSyncSend, par_map}; use rustc_metadata::EncodedMetadata; use rustc_metadata::fs::copy_to_stdout; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; -use rustc_middle::mir::mono::{CodegenUnit, MonoItem}; +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use rustc_middle::mir::mono::{ + CodegenUnit, Linkage as RLinkage, MonoItem, MonoItemData, Visibility, +}; use rustc_session::Session; use rustc_session::config::{DebugInfo, OutFileName, OutputFilenames, OutputType}; @@ -30,7 +33,7 @@ use crate::CodegenCx; use crate::base::CodegenedFunction; use crate::concurrency_limiter::{ConcurrencyLimiter, ConcurrencyLimiterToken}; use crate::debuginfo::TypeDebugContext; -use crate::global_asm::GlobalAsmConfig; +use crate::global_asm::{GlobalAsmConfig, GlobalAsmContext}; use crate::prelude::*; use crate::unwind_module::UnwindModule; @@ -530,19 +533,35 @@ fn codegen_cgu_content( let mut type_dbg = TypeDebugContext::default(); super::predefine_mono_items(tcx, module, &mono_items); let mut codegened_functions = vec![]; - for (mono_item, _) in mono_items { + for (mono_item, item_data) in mono_items { match mono_item { - MonoItem::Fn(inst) => { - if let Some(codegened_function) = crate::base::codegen_fn( + MonoItem::Fn(instance) => { + if tcx.codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED) + { + rustc_codegen_ssa::mir::naked_asm::codegen_naked_asm( + &mut GlobalAsmContext { tcx, global_asm: &mut cx.global_asm }, + instance, + MonoItemData { + linkage: RLinkage::External, + visibility: if item_data.linkage == RLinkage::Internal { + Visibility::Hidden + } else { + item_data.visibility + }, + ..item_data + }, + ); + continue; + } + let codegened_function = crate::base::codegen_fn( tcx, &mut cx, &mut type_dbg, Function::new(), module, - inst, - ) { - codegened_functions.push(codegened_function); - } + instance, + ); + codegened_functions.push(codegened_function); } MonoItem::Static(def_id) => { let data_id = crate::constant::codegen_static(tcx, module, def_id); @@ -551,7 +570,10 @@ fn codegen_cgu_content( } } MonoItem::GlobalAsm(item_id) => { - crate::global_asm::codegen_global_asm_item(tcx, &mut cx.global_asm, item_id); + rustc_codegen_ssa::base::codegen_global_asm( + &mut GlobalAsmContext { tcx, global_asm: &mut cx.global_asm }, + item_id, + ); } } } diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs index 41f8bb9161ca..e368cf4386d0 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs @@ -126,6 +126,11 @@ pub(crate) fn codegen_and_compile_fn<'tcx>( module: &mut dyn Module, instance: Instance<'tcx>, ) { + if tcx.codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED) { + tcx.dcx() + .span_fatal(tcx.def_span(instance.def_id()), "Naked asm is not supported in JIT mode"); + } + cranelift_codegen::timing::set_thread_profiler(Box::new(super::MeasuremeProfiler( tcx.prof.clone(), ))); @@ -135,16 +140,15 @@ pub(crate) fn codegen_and_compile_fn<'tcx>( crate::PrintOnPanic(|| format!("{:?} {}", instance, tcx.symbol_name(instance).name)); let cached_func = std::mem::replace(&mut cached_context.func, Function::new()); - if let Some(codegened_func) = crate::base::codegen_fn( + let codegened_func = crate::base::codegen_fn( tcx, cx, &mut TypeDebugContext::default(), cached_func, module, instance, - ) { - crate::base::compile_fn(cx, &tcx.prof, cached_context, module, codegened_func); - } + ); + crate::base::compile_fn(cx, &tcx.prof, cached_context, module, codegened_func); }); } diff --git a/compiler/rustc_codegen_cranelift/src/global_asm.rs b/compiler/rustc_codegen_cranelift/src/global_asm.rs index 79cefb05de32..203b443269fa 100644 --- a/compiler/rustc_codegen_cranelift/src/global_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/global_asm.rs @@ -7,102 +7,139 @@ use std::process::{Command, Stdio}; use std::sync::Arc; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; -use rustc_hir::{InlineAsmOperand, ItemId}; -use rustc_middle::mir::interpret::ErrorHandled; +use rustc_codegen_ssa::traits::{AsmCodegenMethods, GlobalAsmOperandRef}; +use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::layout::{ + FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTyCtxt, HasTypingEnv, LayoutError, LayoutOfHelpers, +}; use rustc_session::config::{OutputFilenames, OutputType}; use rustc_target::asm::InlineAsmArch; use crate::prelude::*; -pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String, item_id: ItemId) { - let item = tcx.hir_item(item_id); - if let rustc_hir::ItemKind::GlobalAsm { asm, .. } = item.kind { - let is_x86 = - matches!(tcx.sess.asm_arch.unwrap(), InlineAsmArch::X86 | InlineAsmArch::X86_64); +pub(crate) struct GlobalAsmContext<'a, 'tcx> { + pub tcx: TyCtxt<'tcx>, + pub global_asm: &'a mut String, +} - if is_x86 { - if !asm.options.contains(InlineAsmOptions::ATT_SYNTAX) { - global_asm.push_str("\n.intel_syntax noprefix\n"); - } else { - global_asm.push_str("\n.att_syntax\n"); - } +impl<'tcx> AsmCodegenMethods<'tcx> for GlobalAsmContext<'_, 'tcx> { + fn codegen_global_asm( + &mut self, + template: &[InlineAsmTemplatePiece], + operands: &[GlobalAsmOperandRef<'tcx>], + options: InlineAsmOptions, + _line_spans: &[Span], + ) { + codegen_global_asm_inner(self.tcx, self.global_asm, template, operands, options); + } + + fn mangled_name(&self, instance: Instance<'tcx>) -> String { + let symbol_name = self.tcx.symbol_name(instance).name.to_owned(); + if self.tcx.sess.target.is_like_darwin { format!("_{symbol_name}") } else { symbol_name } + } +} + +impl<'tcx> LayoutOfHelpers<'tcx> for GlobalAsmContext<'_, 'tcx> { + #[inline] + fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { + if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err { + self.tcx.sess.dcx().span_fatal(span, err.to_string()) + } else { + self.tcx + .sess + .dcx() + .span_fatal(span, format!("failed to get layout for `{}`: {}", ty, err)) } - for piece in asm.template { - match *piece { - InlineAsmTemplatePiece::String(ref s) => global_asm.push_str(s), - InlineAsmTemplatePiece::Placeholder { operand_idx, modifier: _, span: op_sp } => { - match asm.operands[operand_idx].0 { - InlineAsmOperand::Const { ref anon_const } => { - match tcx.const_eval_poly(anon_const.def_id.to_def_id()) { - Ok(const_value) => { - let ty = tcx - .typeck_body(anon_const.body) - .node_type(anon_const.hir_id); - let string = rustc_codegen_ssa::common::asm_const_to_str( - tcx, - op_sp, - const_value, - FullyMonomorphizedLayoutCx(tcx).layout_of(ty), - ); - global_asm.push_str(&string); - } - Err(ErrorHandled::Reported { .. }) => { - // An error has already been reported and compilation is - // guaranteed to fail if execution hits this path. - } - Err(ErrorHandled::TooGeneric(_)) => { - span_bug!(op_sp, "asm const cannot be resolved; too generic"); - } - } - } - InlineAsmOperand::SymFn { expr } => { - if cfg!(not(feature = "inline_asm_sym")) { - tcx.dcx().span_err( - item.span, - "asm! and global_asm! sym operands are not yet supported", - ); - } + } +} - let ty = tcx.typeck(item_id.owner_id).expr_ty(expr); - let instance = match ty.kind() { - &ty::FnDef(def_id, args) => Instance::new(def_id, args), - _ => span_bug!(op_sp, "asm sym is not a function"), - }; - let symbol = tcx.symbol_name(instance); - // FIXME handle the case where the function was made private to the - // current codegen unit - global_asm.push_str(symbol.name); - } - InlineAsmOperand::SymStatic { path: _, def_id } => { - if cfg!(not(feature = "inline_asm_sym")) { - tcx.dcx().span_err( - item.span, - "asm! and global_asm! sym operands are not yet supported", - ); - } +impl<'tcx> FnAbiOfHelpers<'tcx> for GlobalAsmContext<'_, 'tcx> { + #[inline] + fn handle_fn_abi_err( + &self, + err: FnAbiError<'tcx>, + span: Span, + fn_abi_request: FnAbiRequest<'tcx>, + ) -> ! { + FullyMonomorphizedLayoutCx(self.tcx).handle_fn_abi_err(err, span, fn_abi_request) + } +} - let instance = Instance::mono(tcx, def_id); - let symbol = tcx.symbol_name(instance); - global_asm.push_str(symbol.name); +impl<'tcx> HasTyCtxt<'tcx> for GlobalAsmContext<'_, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { + self.tcx + } +} + +impl<'tcx> rustc_abi::HasDataLayout for GlobalAsmContext<'_, 'tcx> { + fn data_layout(&self) -> &rustc_abi::TargetDataLayout { + &self.tcx.data_layout + } +} + +impl<'tcx> HasTypingEnv<'tcx> for GlobalAsmContext<'_, 'tcx> { + fn typing_env(&self) -> ty::TypingEnv<'tcx> { + ty::TypingEnv::fully_monomorphized() + } +} + +fn codegen_global_asm_inner<'tcx>( + tcx: TyCtxt<'tcx>, + global_asm: &mut String, + template: &[InlineAsmTemplatePiece], + operands: &[GlobalAsmOperandRef<'tcx>], + options: InlineAsmOptions, +) { + let is_x86 = matches!(tcx.sess.asm_arch.unwrap(), InlineAsmArch::X86 | InlineAsmArch::X86_64); + + if is_x86 { + if !options.contains(InlineAsmOptions::ATT_SYNTAX) { + global_asm.push_str("\n.intel_syntax noprefix\n"); + } else { + global_asm.push_str("\n.att_syntax\n"); + } + } + for piece in template { + match *piece { + InlineAsmTemplatePiece::String(ref s) => global_asm.push_str(s), + InlineAsmTemplatePiece::Placeholder { operand_idx, modifier: _, span } => { + match operands[operand_idx] { + GlobalAsmOperandRef::Const { ref string } => { + global_asm.push_str(string); + } + GlobalAsmOperandRef::SymFn { instance } => { + if cfg!(not(feature = "inline_asm_sym")) { + tcx.dcx().span_err( + span, + "asm! and global_asm! sym operands are not yet supported", + ); } - InlineAsmOperand::In { .. } - | InlineAsmOperand::Out { .. } - | InlineAsmOperand::InOut { .. } - | InlineAsmOperand::SplitInOut { .. } - | InlineAsmOperand::Label { .. } => { - span_bug!(op_sp, "invalid operand type for global_asm!") + + let symbol = tcx.symbol_name(instance); + // FIXME handle the case where the function was made private to the + // current codegen unit + global_asm.push_str(symbol.name); + } + GlobalAsmOperandRef::SymStatic { def_id } => { + if cfg!(not(feature = "inline_asm_sym")) { + tcx.dcx().span_err( + span, + "asm! and global_asm! sym operands are not yet supported", + ); } + + let instance = Instance::mono(tcx, def_id); + let symbol = tcx.symbol_name(instance); + global_asm.push_str(symbol.name); } } } } + } - global_asm.push('\n'); - if is_x86 { - global_asm.push_str(".att_syntax\n\n"); - } - } else { - bug!("Expected GlobalAsm found {:?}", item); + global_asm.push('\n'); + if is_x86 { + global_asm.push_str(".att_syntax\n\n"); } } diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs index fbc33a642853..afee50955497 100644 --- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs @@ -161,7 +161,6 @@ pub(crate) fn codegen_inline_asm_inner<'tcx>( stack_slots_input: Vec::new(), stack_slots_output: Vec::new(), stack_slot_size: Size::from_bytes(0), - is_naked: false, }; asm_gen.allocate_registers(); asm_gen.allocate_stack_slots(); @@ -201,114 +200,6 @@ pub(crate) fn codegen_inline_asm_inner<'tcx>( call_inline_asm(fx, &asm_name, asm_gen.stack_slot_size, inputs, outputs); } -pub(crate) fn codegen_naked_asm<'tcx>( - tcx: TyCtxt<'tcx>, - cx: &mut crate::CodegenCx, - module: &mut dyn Module, - instance: Instance<'tcx>, - span: Span, - symbol_name: &str, - template: &[InlineAsmTemplatePiece], - operands: &[InlineAsmOperand<'tcx>], - options: InlineAsmOptions, -) { - // FIXME add .eh_frame unwind info directives - - let operands = operands - .iter() - .map(|operand| match *operand { - InlineAsmOperand::In { .. } - | InlineAsmOperand::Out { .. } - | InlineAsmOperand::InOut { .. } => { - span_bug!(span, "invalid operand type for naked asm") - } - InlineAsmOperand::Const { ref value } => { - let cv = instance.instantiate_mir_and_normalize_erasing_regions( - tcx, - ty::TypingEnv::fully_monomorphized(), - ty::EarlyBinder::bind(value.const_), - ); - let const_value = cv - .eval(tcx, ty::TypingEnv::fully_monomorphized(), value.span) - .expect("erroneous constant missed by mono item collection"); - - let value = rustc_codegen_ssa::common::asm_const_to_str( - tcx, - span, - const_value, - FullyMonomorphizedLayoutCx(tcx).layout_of(cv.ty()), - ); - CInlineAsmOperand::Const { value } - } - InlineAsmOperand::SymFn { ref value } => { - if cfg!(not(feature = "inline_asm_sym")) { - tcx.dcx() - .span_err(span, "asm! and global_asm! sym operands are not yet supported"); - } - - let const_ = instance.instantiate_mir_and_normalize_erasing_regions( - tcx, - ty::TypingEnv::fully_monomorphized(), - ty::EarlyBinder::bind(value.const_), - ); - if let ty::FnDef(def_id, args) = *const_.ty().kind() { - let instance = ty::Instance::resolve_for_fn_ptr( - tcx, - ty::TypingEnv::fully_monomorphized(), - def_id, - args, - ) - .unwrap(); - let symbol = tcx.symbol_name(instance); - - // Pass a wrapper rather than the function itself as the function itself may not - // be exported from the main codegen unit and may thus be unreachable from the - // object file created by an external assembler. - let wrapper_name = format!( - "__inline_asm_{}_wrapper_n{}", - cx.cgu_name.as_str().replace('.', "__").replace('-', "_"), - cx.inline_asm_index - ); - cx.inline_asm_index += 1; - let sig = - get_function_sig(tcx, module.target_config().default_call_conv, instance); - create_wrapper_function(module, sig, &wrapper_name, symbol.name); - - CInlineAsmOperand::Symbol { symbol: wrapper_name } - } else { - span_bug!(span, "invalid type for asm sym (fn)"); - } - } - InlineAsmOperand::SymStatic { def_id } => { - assert!(tcx.is_static(def_id)); - let instance = Instance::mono(tcx, def_id); - CInlineAsmOperand::Symbol { symbol: tcx.symbol_name(instance).name.to_owned() } - } - InlineAsmOperand::Label { .. } => { - span_bug!(span, "asm! label operands are not yet supported"); - } - }) - .collect::>(); - - let asm_gen = InlineAssemblyGenerator { - tcx, - arch: tcx.sess.asm_arch.unwrap(), - enclosing_def_id: instance.def_id(), - template, - operands: &operands, - options, - registers: Vec::new(), - stack_slots_clobber: Vec::new(), - stack_slots_input: Vec::new(), - stack_slots_output: Vec::new(), - stack_slot_size: Size::from_bytes(0), - is_naked: true, - }; - - let generated_asm = asm_gen.generate_asm_wrapper(symbol_name); - cx.global_asm.push_str(&generated_asm); -} - struct InlineAssemblyGenerator<'a, 'tcx> { tcx: TyCtxt<'tcx>, arch: InlineAsmArch, @@ -321,13 +212,10 @@ struct InlineAssemblyGenerator<'a, 'tcx> { stack_slots_input: Vec>, stack_slots_output: Vec>, stack_slot_size: Size, - is_naked: bool, } impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { fn allocate_registers(&mut self) { - assert!(!self.is_naked); - let sess = self.tcx.sess; let map = allocatable_registers( self.arch, @@ -451,8 +339,6 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { } fn allocate_stack_slots(&mut self) { - assert!(!self.is_naked); - let mut slot_size = Size::from_bytes(0); let mut slots_clobber = vec![None; self.operands.len()]; let mut slots_input = vec![None; self.operands.len()]; @@ -582,32 +468,31 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { if is_x86 { generated_asm.push_str(".intel_syntax noprefix\n"); } - if !self.is_naked { - Self::prologue(&mut generated_asm, self.arch); - // Save clobbered registers - if !self.options.contains(InlineAsmOptions::NORETURN) { - for (reg, slot) in self - .registers - .iter() - .zip(self.stack_slots_clobber.iter().copied()) - .filter_map(|(r, s)| r.zip(s)) - { - Self::save_register(&mut generated_asm, self.arch, reg, slot); - } - } + Self::prologue(&mut generated_asm, self.arch); - // Write input registers + // Save clobbered registers + if !self.options.contains(InlineAsmOptions::NORETURN) { for (reg, slot) in self .registers .iter() - .zip(self.stack_slots_input.iter().copied()) + .zip(self.stack_slots_clobber.iter().copied()) .filter_map(|(r, s)| r.zip(s)) { - Self::restore_register(&mut generated_asm, self.arch, reg, slot); + Self::save_register(&mut generated_asm, self.arch, reg, slot); } } + // Write input registers + for (reg, slot) in self + .registers + .iter() + .zip(self.stack_slots_input.iter().copied()) + .filter_map(|(r, s)| r.zip(s)) + { + Self::restore_register(&mut generated_asm, self.arch, reg, slot); + } + if is_x86 && self.options.contains(InlineAsmOptions::ATT_SYNTAX) { generated_asm.push_str(".att_syntax\n"); } @@ -701,32 +586,30 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { generated_asm.push_str(".intel_syntax noprefix\n"); } - if !self.is_naked { - if !self.options.contains(InlineAsmOptions::NORETURN) { - // Read output registers - for (reg, slot) in self - .registers - .iter() - .zip(self.stack_slots_output.iter().copied()) - .filter_map(|(r, s)| r.zip(s)) - { - Self::save_register(&mut generated_asm, self.arch, reg, slot); - } - - // Restore clobbered registers - for (reg, slot) in self - .registers - .iter() - .zip(self.stack_slots_clobber.iter().copied()) - .filter_map(|(r, s)| r.zip(s)) - { - Self::restore_register(&mut generated_asm, self.arch, reg, slot); - } - - Self::epilogue(&mut generated_asm, self.arch); - } else { - Self::epilogue_noreturn(&mut generated_asm, self.arch); + if !self.options.contains(InlineAsmOptions::NORETURN) { + // Read output registers + for (reg, slot) in self + .registers + .iter() + .zip(self.stack_slots_output.iter().copied()) + .filter_map(|(r, s)| r.zip(s)) + { + Self::save_register(&mut generated_asm, self.arch, reg, slot); } + + // Restore clobbered registers + for (reg, slot) in self + .registers + .iter() + .zip(self.stack_slots_clobber.iter().copied()) + .filter_map(|(r, s)| r.zip(s)) + { + Self::restore_register(&mut generated_asm, self.arch, reg, slot); + } + + Self::epilogue(&mut generated_asm, self.arch); + } else { + Self::epilogue_noreturn(&mut generated_asm, self.arch); } if is_x86 { diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index 396c6d579501..c35337ae7ce0 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -829,7 +829,7 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl impl<'gcc, 'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn codegen_global_asm( - &self, + &mut self, template: &[InlineAsmTemplatePiece], operands: &[GlobalAsmOperandRef<'tcx>], options: InlineAsmOptions, diff --git a/compiler/rustc_codegen_gcc/src/base.rs b/compiler/rustc_codegen_gcc/src/base.rs index 9b495174a3fa..a9d7808c833b 100644 --- a/compiler/rustc_codegen_gcc/src/base.rs +++ b/compiler/rustc_codegen_gcc/src/base.rs @@ -206,7 +206,7 @@ pub fn compile_codegen_unit( let f128_type_supported = target_info.supports_target_dependent_type(CType::Float128); let u128_type_supported = target_info.supports_target_dependent_type(CType::UInt128t); // TODO: improve this to avoid passing that many arguments. - let cx = CodegenCx::new( + let mut cx = CodegenCx::new( &context, cgu, tcx, @@ -223,8 +223,8 @@ pub fn compile_codegen_unit( } // ... and now that we have everything pre-defined, fill out those definitions. - for &(mono_item, _) in &mono_items { - mono_item.define::>(&cx); + for &(mono_item, item_data) in &mono_items { + mono_item.define::>(&mut cx, item_data); } // If this codegen unit contains the main function, also create the diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 5c70f4a7df93..6720f6186d16 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -45,7 +45,7 @@ enum ExtremumOperation { Min, } -pub struct Builder<'a: 'gcc, 'gcc, 'tcx> { +pub struct Builder<'a, 'gcc, 'tcx> { pub cx: &'a CodegenCx<'gcc, 'tcx>, pub block: Block<'gcc>, pub location: Option>, diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 88daa0257404..e481b99afcc6 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -376,7 +376,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { impl<'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { fn codegen_global_asm( - &self, + &mut self, template: &[InlineAsmTemplatePiece], operands: &[GlobalAsmOperandRef<'tcx>], options: InlineAsmOptions, diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index 6bd27914dbd1..e4fac35aa449 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -83,15 +83,15 @@ pub(crate) fn compile_codegen_unit( // Instantiate monomorphizations without filling out definitions yet... let llvm_module = ModuleLlvm::new(tcx, cgu_name.as_str()); { - let cx = CodegenCx::new(tcx, cgu, &llvm_module); + let mut cx = CodegenCx::new(tcx, cgu, &llvm_module); let mono_items = cx.codegen_unit.items_in_deterministic_order(cx.tcx); for &(mono_item, data) in &mono_items { mono_item.predefine::>(&cx, data.linkage, data.visibility); } // ... and now that we have everything pre-defined, fill out those definitions. - for &(mono_item, _) in &mono_items { - mono_item.define::>(&cx); + for &(mono_item, item_data) in &mono_items { + mono_item.define::>(&mut cx, item_data); } // If this codegen unit contains the main function, also create the diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index ae1bdac1655d..6412a537a793 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -466,13 +466,9 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) { _ => true, }; - cfg.has_reliable_f16_math = match (target_arch, target_os) { - // x86 has a crash for `powi`: - ("x86" | "x86_64", _) => false, - // Assume that working `f16` means working `f16` math for most platforms, since - // operations just go through `f32`. - _ => true, - } && cfg.has_reliable_f16; + // Assume that working `f16` means working `f16` math for most platforms, since + // operations just go through `f32`. + cfg.has_reliable_f16_math = cfg.has_reliable_f16; cfg.has_reliable_f128_math = match (target_arch, target_os) { // LLVM lowers `fp128` math to `long double` symbols even on platforms where diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 12b7a4874556..f5480da2808f 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -12,19 +12,21 @@ 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::ItemId; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::lang_items::LangItem; use rustc_metadata::EncodedMetadata; -use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType}; use rustc_middle::middle::exported_symbols::SymbolExportKind; use rustc_middle::middle::{exported_symbols, lang_items}; use rustc_middle::mir::BinOp; +use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem, MonoItemPartitions}; use rustc_middle::query::Providers; use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; +use rustc_middle::{bug, span_bug}; use rustc_session::Session; use rustc_session::config::{self, CrateType, EntryFnType, OutputType}; use rustc_span::{DUMMY_SP, Symbol, sym}; @@ -417,6 +419,69 @@ pub(crate) fn codegen_instance<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( mir::codegen_mir::(cx, instance); } +pub fn codegen_global_asm<'tcx, Cx>(cx: &mut Cx, item_id: ItemId) +where + Cx: LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>> + AsmCodegenMethods<'tcx>, +{ + let item = cx.tcx().hir_item(item_id); + if let rustc_hir::ItemKind::GlobalAsm { asm, .. } = item.kind { + let operands: Vec<_> = asm + .operands + .iter() + .map(|(op, op_sp)| match *op { + rustc_hir::InlineAsmOperand::Const { ref anon_const } => { + match cx.tcx().const_eval_poly(anon_const.def_id.to_def_id()) { + Ok(const_value) => { + let ty = + cx.tcx().typeck_body(anon_const.body).node_type(anon_const.hir_id); + let string = common::asm_const_to_str( + cx.tcx(), + *op_sp, + const_value, + cx.layout_of(ty), + ); + GlobalAsmOperandRef::Const { string } + } + Err(ErrorHandled::Reported { .. }) => { + // An error has already been reported and + // compilation is guaranteed to fail if execution + // hits this path. So an empty string instead of + // a stringified constant value will suffice. + GlobalAsmOperandRef::Const { string: String::new() } + } + Err(ErrorHandled::TooGeneric(_)) => { + span_bug!(*op_sp, "asm const cannot be resolved; too generic") + } + } + } + rustc_hir::InlineAsmOperand::SymFn { expr } => { + let ty = cx.tcx().typeck(item_id.owner_id).expr_ty(expr); + let instance = match ty.kind() { + &ty::FnDef(def_id, args) => Instance::new(def_id, args), + _ => span_bug!(*op_sp, "asm sym is not a function"), + }; + + GlobalAsmOperandRef::SymFn { instance } + } + rustc_hir::InlineAsmOperand::SymStatic { path: _, def_id } => { + GlobalAsmOperandRef::SymStatic { def_id } + } + rustc_hir::InlineAsmOperand::In { .. } + | rustc_hir::InlineAsmOperand::Out { .. } + | rustc_hir::InlineAsmOperand::InOut { .. } + | rustc_hir::InlineAsmOperand::SplitInOut { .. } + | rustc_hir::InlineAsmOperand::Label { .. } => { + span_bug!(*op_sp, "invalid operand type for global_asm!") + } + }) + .collect(); + + cx.codegen_global_asm(asm.template, &operands, asm.options, asm.line_spans); + } else { + span_bug!(item.span, "Mismatch between hir::Item type and MonoItem type") + } +} + /// Creates the `main` function which will initialize the rust runtime and call /// users main function. pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index b0c53ec93ce1..5d09e62f2742 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -87,6 +87,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { let mut link_ordinal_span = None; let mut no_sanitize_span = None; let mut mixed_export_name_no_mangle_lint_state = MixedExportNameAndNoMangleState::default(); + let mut no_mangle_span = None; for attr in attrs.iter() { // In some cases, attribute are only valid on functions, but it's the `check_attr` @@ -139,6 +140,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } sym::naked => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED, sym::no_mangle => { + no_mangle_span = Some(attr.span()); if tcx.opt_item_name(did.to_def_id()).is_some() { codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE; mixed_export_name_no_mangle_lint_state.track_no_mangle( @@ -621,6 +623,34 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } check_link_name_xor_ordinal(tcx, &codegen_fn_attrs, link_ordinal_span); + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) + && codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) + { + 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.unwrap_or_default(), + "`#[no_mangle]` cannot be used on internal language items", + ) + .with_note("Rustc requires this item to have a specific mangled name.") + .with_span_label(tcx.def_span(did), "should be the internal language item"); + if let Some(lang_item) = lang_item { + if let Some(link_name) = lang_item.link_name() { + err = err + .with_note("If you are trying to prevent mangling to ease debugging, many") + .with_note(format!( + "debuggers support a command such as `rbreak {link_name}` to" + )) + .with_note(format!( + "match `.*{link_name}.*` instead of `break {link_name}` on a specific name" + )) + } + } + err.emit(); + } + // Any linkage to LLVM intrinsics for now forcibly marks them all as never // unwinds since LLVM sometimes can't handle codegen which `invoke`s // intrinsic functions. diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index b67c871cac9f..bfec208c4aed 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -14,6 +14,7 @@ #![feature(string_from_utf8_lossy_owned)] #![feature(trait_alias)] #![feature(try_blocks)] +#![recursion_limit = "256"] // tidy-alphabetical-end //! This crate contains codegen code that is used by all codegen backends (LLVM and others). diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 6a37889217ab..96a04473aba2 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -20,7 +20,7 @@ mod coverageinfo; pub mod debuginfo; mod intrinsic; mod locals; -mod naked_asm; +pub mod naked_asm; pub mod operand; pub mod place; mod rvalue; @@ -178,11 +178,6 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty()); debug!("fn_abi: {:?}", fn_abi); - if tcx.codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED) { - crate::mir::naked_asm::codegen_naked_asm::(cx, &mir, instance); - return; - } - if tcx.features().ergonomic_clones() { let monomorphized_mir = instance.instantiate_mir_and_normalize_erasing_regions( tcx, diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs index 3a6b1f8d4efc..0301ef437c0d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs @@ -1,23 +1,33 @@ use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind}; use rustc_attr_parsing::InstructionSetAttr; use rustc_hir::def_id::DefId; -use rustc_middle::mir::mono::{Linkage, MonoItem, MonoItemData, Visibility}; -use rustc_middle::mir::{Body, InlineAsmOperand}; -use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv, LayoutOf}; -use rustc_middle::ty::{Instance, Ty, TyCtxt}; +use rustc_middle::mir::mono::{Linkage, MonoItemData, Visibility}; +use rustc_middle::mir::{InlineAsmOperand, START_BLOCK}; +use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout}; +use rustc_middle::ty::{Instance, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::{bug, span_bug, ty}; use rustc_span::sym; use rustc_target::callconv::{ArgAbi, FnAbi, PassMode}; use rustc_target::spec::{BinaryFormat, WasmCAbi}; use crate::common; -use crate::traits::{AsmCodegenMethods, BuilderMethods, GlobalAsmOperandRef, MiscCodegenMethods}; +use crate::mir::AsmCodegenMethods; +use crate::traits::GlobalAsmOperandRef; -pub(crate) fn codegen_naked_asm<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - cx: &'a Bx::CodegenCx, - mir: &Body<'tcx>, +pub fn codegen_naked_asm< + 'a, + 'tcx, + Cx: LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>> + + FnAbiOf<'tcx, FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>> + + AsmCodegenMethods<'tcx>, +>( + cx: &'a mut Cx, instance: Instance<'tcx>, + item_data: MonoItemData, ) { + assert!(!instance.args.has_infer()); + let mir = cx.tcx().instance_mir(instance.def); + let rustc_middle::mir::TerminatorKind::InlineAsm { asm_macro: _, template, @@ -26,15 +36,14 @@ pub(crate) fn codegen_naked_asm<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( line_spans, targets: _, unwind: _, - } = mir.basic_blocks.iter().next().unwrap().terminator().kind + } = mir.basic_blocks[START_BLOCK].terminator().kind else { bug!("#[naked] functions should always terminate with an asm! block") }; let operands: Vec<_> = - operands.iter().map(|op| inline_to_global_operand::(cx, instance, op)).collect(); + operands.iter().map(|op| inline_to_global_operand::(cx, instance, op)).collect(); - let item_data = cx.codegen_unit().items().get(&MonoItem::Fn(instance)).unwrap(); let name = cx.mangled_name(instance); let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty()); let (begin, end) = prefix_and_suffix(cx.tcx(), instance, &name, item_data, fn_abi); @@ -47,8 +56,8 @@ pub(crate) fn codegen_naked_asm<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( cx.codegen_global_asm(&template_vec, &operands, options, line_spans); } -fn inline_to_global_operand<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - cx: &'a Bx::CodegenCx, +fn inline_to_global_operand<'a, 'tcx, Cx: LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>>>( + cx: &'a Cx, instance: Instance<'tcx>, op: &InlineAsmOperand<'tcx>, ) -> GlobalAsmOperandRef<'tcx> { @@ -108,7 +117,7 @@ fn prefix_and_suffix<'tcx>( tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, asm_name: &str, - item_data: &MonoItemData, + item_data: MonoItemData, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, ) -> (String, String) { use std::fmt::Write; @@ -210,8 +219,10 @@ fn prefix_and_suffix<'tcx>( writeln!(begin, ".pushsection {section},\"ax\", {progbits}").unwrap(); writeln!(begin, ".balign {align_bytes}").unwrap(); write_linkage(&mut begin).unwrap(); - if let Visibility::Hidden = item_data.visibility { - writeln!(begin, ".hidden {asm_name}").unwrap(); + match item_data.visibility { + Visibility::Default => {} + Visibility::Protected => writeln!(begin, ".protected {asm_name}").unwrap(), + Visibility::Hidden => writeln!(begin, ".hidden {asm_name}").unwrap(), } writeln!(begin, ".type {asm_name}, {function}").unwrap(); if !arch_prefix.is_empty() { @@ -231,8 +242,9 @@ fn prefix_and_suffix<'tcx>( writeln!(begin, ".pushsection {},regular,pure_instructions", section).unwrap(); writeln!(begin, ".balign {align_bytes}").unwrap(); write_linkage(&mut begin).unwrap(); - if let Visibility::Hidden = item_data.visibility { - writeln!(begin, ".private_extern {asm_name}").unwrap(); + match item_data.visibility { + Visibility::Default | Visibility::Protected => {} + Visibility::Hidden => writeln!(begin, ".private_extern {asm_name}").unwrap(), } writeln!(begin, "{asm_name}:").unwrap(); diff --git a/compiler/rustc_codegen_ssa/src/mono_item.rs b/compiler/rustc_codegen_ssa/src/mono_item.rs index f6af889fd6ec..c2067e52afec 100644 --- a/compiler/rustc_codegen_ssa/src/mono_item.rs +++ b/compiler/rustc_codegen_ssa/src/mono_item.rs @@ -1,17 +1,18 @@ -use rustc_hir as hir; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::mir::interpret::ErrorHandled; -use rustc_middle::mir::mono::{Linkage, MonoItem, Visibility}; -use rustc_middle::ty::Instance; -use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; -use rustc_middle::{span_bug, ty}; +use rustc_middle::mir::mono::{Linkage, MonoItem, MonoItemData, Visibility}; +use rustc_middle::ty::layout::HasTyCtxt; use tracing::debug; +use crate::base; +use crate::mir::naked_asm; use crate::traits::*; -use crate::{base, common}; pub trait MonoItemExt<'a, 'tcx> { - fn define>(&self, cx: &'a Bx::CodegenCx); + fn define>( + &self, + cx: &'a mut Bx::CodegenCx, + item_data: MonoItemData, + ); fn predefine>( &self, cx: &'a Bx::CodegenCx, @@ -22,7 +23,11 @@ pub trait MonoItemExt<'a, 'tcx> { } impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> { - fn define>(&self, cx: &'a Bx::CodegenCx) { + fn define>( + &self, + cx: &'a mut Bx::CodegenCx, + item_data: MonoItemData, + ) { debug!( "BEGIN IMPLEMENTING '{} ({})' in cgu {}", self, @@ -35,71 +40,19 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> { cx.codegen_static(def_id); } MonoItem::GlobalAsm(item_id) => { - let item = cx.tcx().hir_item(item_id); - if let hir::ItemKind::GlobalAsm { asm, .. } = item.kind { - let operands: Vec<_> = asm - .operands - .iter() - .map(|(op, op_sp)| match *op { - hir::InlineAsmOperand::Const { ref anon_const } => { - match cx.tcx().const_eval_poly(anon_const.def_id.to_def_id()) { - Ok(const_value) => { - let ty = cx - .tcx() - .typeck_body(anon_const.body) - .node_type(anon_const.hir_id); - let string = common::asm_const_to_str( - cx.tcx(), - *op_sp, - const_value, - cx.layout_of(ty), - ); - GlobalAsmOperandRef::Const { string } - } - Err(ErrorHandled::Reported { .. }) => { - // An error has already been reported and - // compilation is guaranteed to fail if execution - // hits this path. So an empty string instead of - // a stringified constant value will suffice. - GlobalAsmOperandRef::Const { string: String::new() } - } - Err(ErrorHandled::TooGeneric(_)) => { - span_bug!( - *op_sp, - "asm const cannot be resolved; too generic" - ) - } - } - } - hir::InlineAsmOperand::SymFn { expr } => { - let ty = cx.tcx().typeck(item_id.owner_id).expr_ty(expr); - let instance = match ty.kind() { - &ty::FnDef(def_id, args) => Instance::new(def_id, args), - _ => span_bug!(*op_sp, "asm sym is not a function"), - }; - - GlobalAsmOperandRef::SymFn { instance } - } - hir::InlineAsmOperand::SymStatic { path: _, def_id } => { - GlobalAsmOperandRef::SymStatic { def_id } - } - hir::InlineAsmOperand::In { .. } - | hir::InlineAsmOperand::Out { .. } - | hir::InlineAsmOperand::InOut { .. } - | hir::InlineAsmOperand::SplitInOut { .. } - | hir::InlineAsmOperand::Label { .. } => { - span_bug!(*op_sp, "invalid operand type for global_asm!") - } - }) - .collect(); - - cx.codegen_global_asm(asm.template, &operands, asm.options, asm.line_spans); - } else { - span_bug!(item.span, "Mismatch between hir::Item type and MonoItem type") - } + base::codegen_global_asm(cx, item_id); } MonoItem::Fn(instance) => { - base::codegen_instance::(cx, instance); + if cx + .tcx() + .codegen_fn_attrs(instance.def_id()) + .flags + .contains(CodegenFnAttrFlags::NAKED) + { + naked_asm::codegen_naked_asm::(cx, instance, item_data); + } else { + base::codegen_instance::(cx, instance); + } } } diff --git a/compiler/rustc_codegen_ssa/src/traits/asm.rs b/compiler/rustc_codegen_ssa/src/traits/asm.rs index 7767bffbfbfd..cc7a6a3f19e9 100644 --- a/compiler/rustc_codegen_ssa/src/traits/asm.rs +++ b/compiler/rustc_codegen_ssa/src/traits/asm.rs @@ -62,7 +62,7 @@ pub trait AsmBuilderMethods<'tcx>: BackendTypes { pub trait AsmCodegenMethods<'tcx> { fn codegen_global_asm( - &self, + &mut self, template: &[InlineAsmTemplatePiece], operands: &[GlobalAsmOperandRef<'tcx>], options: InlineAsmOptions, diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index e6b50cc7c0cb..e2f1458d0623 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -45,15 +45,14 @@ pub trait CodegenBackend { fn print(&self, _req: &PrintRequest, _out: &mut String, _sess: &Session) {} - /// Returns two feature sets: - /// - The first has the features that should be set in `cfg(target_features)`. - /// - The second is like the first, but also includes unstable features. - /// - /// RUSTC_SPECIFIC_FEATURES should be skipped here, those are handled outside codegen. + /// Collect target-specific options that should be set in `cfg(...)`, including + /// `target_feature` and support for unstable float types. fn target_config(&self, _sess: &Session) -> TargetConfig { TargetConfig { target_features: vec![], unstable_target_features: vec![], + // `true` is used as a default so backends need to acknowledge when they do not + // support the float types, rather than accidentally quietly skipping all tests. has_reliable_f16: true, has_reliable_f16_math: true, has_reliable_f128: true, diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 40c63f2b250f..d67b547ba1a4 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -61,16 +61,21 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>( ensure_monomorphic_enough(tcx, tp_ty)?; ConstValue::from_u128(tcx.type_id_hash(tp_ty).as_u128()) } - sym::variant_count => match tp_ty.kind() { + sym::variant_count => match match tp_ty.kind() { + // Pattern types have the same number of variants as their base type. + // Even if we restrict e.g. which variants are valid, the variants are essentially just uninhabited. + // And `Result<(), !>` still has two variants according to `variant_count`. + ty::Pat(base, _) => *base, + _ => tp_ty, + } + .kind() + { // Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough. ty::Adt(adt, _) => ConstValue::from_target_usize(adt.variants().len() as u64, &tcx), ty::Alias(..) | ty::Param(_) | ty::Placeholder(_) | ty::Infer(_) => { throw_inval!(TooGeneric) } - ty::Pat(_, pat) => match **pat { - ty::PatternKind::Range { .. } => ConstValue::from_target_usize(0u64, &tcx), - // Future pattern kinds may have more variants - }, + ty::Pat(..) => unreachable!(), ty::Bound(_, _) => bug!("bound ty during ctfe"), ty::Bool | ty::Char @@ -178,8 +183,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let res = self.binary_op(op, &a, &b)?; // `binary_op` already called `generate_nan` if needed. - - // FIXME: Miri should add some non-determinism to the result here to catch any dependences on exact computations. This has previously been done, but the behaviour was removed as part of constification. + let res = M::apply_float_nondet(self, res)?; self.write_immediate(*res, dest)?; } diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index e5026eff21f4..a1386b4e1be4 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -276,6 +276,14 @@ pub trait Machine<'tcx>: Sized { F2::NAN } + /// Apply non-determinism to float operations that do not return a precise result. + fn apply_float_nondet( + _ecx: &mut InterpCx<'tcx, Self>, + val: ImmTy<'tcx, Self::Provenance>, + ) -> InterpResult<'tcx, ImmTy<'tcx, Self::Provenance>> { + interp_ok(val) + } + /// Determines the result of `min`/`max` on floats when the arguments are equal. fn equal_float_min_max(_ecx: &InterpCx<'tcx, Self>, a: F, _b: F) -> F { // By default, we pick the left argument. diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index fb7ba6d7ef57..c86af5a9a4b1 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -1248,6 +1248,14 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, // Range patterns are precisely reflected into `valid_range` and thus // handled fully by `visit_scalar` (called below). ty::PatternKind::Range { .. } => {}, + + // FIXME(pattern_types): check that the value is covered by one of the variants. + // For now, we rely on layout computation setting the scalar's `valid_range` to + // match the pattern. However, this cannot always work; the layout may + // pessimistically cover actually illegal ranges and Miri would miss that UB. + // The consolation here is that codegen also will miss that UB, so at least + // we won't see optimizations actually breaking such programs. + ty::PatternKind::Or(_patterns) => {} } } _ => { diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index 616a18a72ab7..80d49effbf8a 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -43,7 +43,7 @@ pub use self::freeze::{FreezeLock, FreezeReadGuard, FreezeWriteGuard}; pub use self::lock::{Lock, LockGuard, Mode}; pub use self::mode::{is_dyn_thread_safe, set_dyn_thread_safe_mode}; pub use self::parallel::{ - join, par_for_each_in, par_map, parallel_guard, scope, try_par_for_each_in, + join, par_for_each_in, par_map, parallel_guard, scope, spawn, try_par_for_each_in, }; pub use self::vec::{AppendOnlyIndexVec, AppendOnlyVec}; pub use self::worker_local::{Registry, WorkerLocal}; diff --git a/compiler/rustc_data_structures/src/sync/parallel.rs b/compiler/rustc_data_structures/src/sync/parallel.rs index ba3c85ef5b15..64db39cc4c6e 100644 --- a/compiler/rustc_data_structures/src/sync/parallel.rs +++ b/compiler/rustc_data_structures/src/sync/parallel.rs @@ -93,6 +93,17 @@ macro_rules! parallel { }; } +pub fn spawn(func: impl FnOnce() + DynSend + 'static) { + if mode::is_dyn_thread_safe() { + let func = FromDyn::from(func); + rayon_core::spawn(|| { + (func.into_inner())(); + }); + } else { + func() + } +} + // This function only works when `mode::is_dyn_thread_safe()`. pub fn scope<'scope, OP, R>(op: OP) -> R where diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 6d616cf84bbd..14b8cc90d97d 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -1,8 +1,10 @@ use rustc_ast::ptr::P; +use rustc_ast::token::Delimiter; +use rustc_ast::tokenstream::TokenStream; use rustc_ast::util::literal; use rustc_ast::{ self as ast, AnonConst, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, PatKind, UnOp, - attr, token, + attr, token, tokenstream, }; use rustc_span::source_map::Spanned; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; @@ -55,13 +57,13 @@ impl<'a> ExtCtxt<'a> { &self, span: Span, path: ast::Path, - delim: ast::token::Delimiter, - tokens: ast::tokenstream::TokenStream, + delim: Delimiter, + tokens: TokenStream, ) -> P { P(ast::MacCall { path, args: P(ast::DelimArgs { - dspan: ast::tokenstream::DelimSpan { open: span, close: span }, + dspan: tokenstream::DelimSpan { open: span, close: span }, delim, tokens, }), @@ -480,8 +482,8 @@ impl<'a> ExtCtxt<'a> { span, [sym::std, sym::unreachable].map(|s| Ident::new(s, span)).to_vec(), ), - ast::token::Delimiter::Parenthesis, - ast::tokenstream::TokenStream::default(), + Delimiter::Parenthesis, + TokenStream::default(), ), ) } diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index d2e45d717d90..2df3281568be 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -162,7 +162,7 @@ pub(crate) fn attr_into_trace(mut attr: Attribute, trace_name: Symbol) -> Attrib let NormalAttr { item, tokens } = &mut **normal; item.path.segments[0].ident.name = trace_name; // This makes the trace attributes unobservable to token-based proc macros. - *tokens = Some(LazyAttrTokenStream::new(AttrTokenStream::default())); + *tokens = Some(LazyAttrTokenStream::new_direct(AttrTokenStream::default())); } AttrKind::DocComment(..) => unreachable!(), } @@ -192,7 +192,7 @@ impl<'a> StripUnconfigured<'a> { if self.config_tokens { if let Some(Some(tokens)) = node.tokens_mut() { let attr_stream = tokens.to_attr_token_stream(); - *tokens = LazyAttrTokenStream::new(self.configure_tokens(&attr_stream)); + *tokens = LazyAttrTokenStream::new_direct(self.configure_tokens(&attr_stream)); } } } @@ -223,7 +223,7 @@ impl<'a> StripUnconfigured<'a> { target.attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr)); if self.in_cfg(&target.attrs) { - target.tokens = LazyAttrTokenStream::new( + target.tokens = LazyAttrTokenStream::new_direct( self.configure_tokens(&target.tokens.to_attr_token_stream()), ); Some(AttrTokenTree::AttrsTarget(target)) @@ -361,7 +361,7 @@ impl<'a> StripUnconfigured<'a> { .to_attr_token_stream(), )); - let tokens = Some(LazyAttrTokenStream::new(AttrTokenStream::new(trees))); + let tokens = Some(LazyAttrTokenStream::new_direct(AttrTokenStream::new(trees))); let attr = ast::attr::mk_attr_from_item( &self.sess.psess.attr_id_generator, item, diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 39186319b1cc..2d3fd7702da5 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -1,6 +1,5 @@ use std::mem; -use rustc_ast::mut_visit::{self, MutVisitor}; use rustc_ast::token::{ self, Delimiter, IdentIsRaw, InvisibleOrigin, Lit, LitKind, MetaVarKind, Token, TokenKind, }; @@ -29,10 +28,8 @@ use crate::mbe::{self, KleeneOp, MetaVarExpr}; // A Marker adds the given mark to the syntax context. struct Marker(LocalExpnId, Transparency, FxHashMap); -impl MutVisitor for Marker { - const VISIT_TOKENS: bool = true; - - fn visit_span(&mut self, span: &mut Span) { +impl Marker { + fn mark_span(&mut self, span: &mut Span) { // `apply_mark` is a relatively expensive operation, both due to taking hygiene lock, and // by itself. All tokens in a macro body typically have the same syntactic context, unless // it's some advanced case with macro-generated macros. So if we cache the marked version @@ -292,7 +289,7 @@ pub(super) fn transcribe<'a>( // Emit as a token stream within `Delimiter::Invisible` to maintain // parsing priorities. - marker.visit_span(&mut sp); + marker.mark_span(&mut sp); with_metavar_spans(|mspans| mspans.insert(mk_span, sp)); // Both the open delim and close delim get the same span, which covers the // `$foo` in the decl macro RHS. @@ -312,13 +309,13 @@ pub(super) fn transcribe<'a>( maybe_use_metavar_location(psess, &stack, sp, tt, &mut marker) } MatchedSingle(ParseNtResult::Ident(ident, is_raw)) => { - marker.visit_span(&mut sp); + marker.mark_span(&mut sp); with_metavar_spans(|mspans| mspans.insert(ident.span, sp)); let kind = token::NtIdent(*ident, *is_raw); TokenTree::token_alone(kind, sp) } MatchedSingle(ParseNtResult::Lifetime(ident, is_raw)) => { - marker.visit_span(&mut sp); + marker.mark_span(&mut sp); with_metavar_spans(|mspans| mspans.insert(ident.span, sp)); let kind = token::NtLifetime(*ident, *is_raw); TokenTree::token_alone(kind, sp) @@ -400,8 +397,8 @@ pub(super) fn transcribe<'a>( } else { // If we aren't able to match the meta-var, we push it back into the result but // with modified syntax context. (I believe this supports nested macros). - marker.visit_span(&mut sp); - marker.visit_ident(&mut original_ident); + marker.mark_span(&mut sp); + marker.mark_span(&mut original_ident.span); result.push(TokenTree::token_joint_hidden(token::Dollar, sp)); result.push(TokenTree::Token( Token::from_ast_ident(original_ident), @@ -430,16 +427,19 @@ pub(super) fn transcribe<'a>( // jump back out of the Delimited, pop the result_stack and add the new results back to // the previous results (from outside the Delimited). &mbe::TokenTree::Delimited(mut span, ref spacing, ref delimited) => { - mut_visit::visit_delim_span(&mut marker, &mut span); + marker.mark_span(&mut span.open); + marker.mark_span(&mut span.close); stack.push(Frame::new_delimited(delimited, span, *spacing)); result_stack.push(mem::take(&mut result)); } // Nothing much to do here. Just push the token to the result, being careful to // preserve syntax context. - mbe::TokenTree::Token(token) => { - let mut token = *token; - mut_visit::visit_token(&mut marker, &mut token); + &mbe::TokenTree::Token(mut token) => { + marker.mark_span(&mut token.span); + if let token::NtIdent(ident, _) | token::NtLifetime(ident, _) = &mut token.kind { + marker.mark_span(&mut ident.span); + } let tt = TokenTree::Token(token, Spacing::Alone); result.push(tt); } @@ -504,7 +504,7 @@ fn maybe_use_metavar_location( return orig_tt.clone(); } - marker.visit_span(&mut metavar_span); + marker.mark_span(&mut metavar_span); let no_collision = match orig_tt { TokenTree::Token(token, ..) => { with_metavar_spans(|mspans| mspans.insert(token.span, metavar_span)) @@ -774,7 +774,7 @@ fn transcribe_metavar_expr<'a>( ) -> PResult<'a, ()> { let mut visited_span = || { let mut span = sp.entire(); - marker.visit_span(&mut span); + marker.mark_span(&mut span); span }; match *expr { diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 2f8a85342478..af587ee5bdcd 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1813,6 +1813,9 @@ pub enum TyPatKind<'hir> { /// A range pattern (e.g., `1..=2` or `1..2`). Range(&'hir ConstArg<'hir>, &'hir ConstArg<'hir>), + /// A list of patterns where only one needs to be satisfied + Or(&'hir [TyPat<'hir>]), + /// A placeholder for a pattern that wasn't well formed in some way. Err(ErrorGuaranteed), } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 3c2897ef1d95..a60de4b1fc31 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -710,6 +710,7 @@ pub fn walk_ty_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v TyPat<'v>) try_visit!(visitor.visit_const_arg_unambig(lower_bound)); try_visit!(visitor.visit_const_arg_unambig(upper_bound)); } + TyPatKind::Or(patterns) => walk_list!(visitor, visit_pattern_type_pattern, patterns), TyPatKind::Err(_) => (), } V::Result::output() diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index 32064f96dd6c..5533920aee4a 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -14,6 +14,7 @@ #![feature(never_type)] #![feature(rustc_attrs)] #![feature(variant_count)] +#![recursion_limit = "256"] // tidy-alphabetical-end extern crate self as rustc_hir; diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 694c12288596..c20b14df7704 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -94,10 +94,12 @@ fn const_arg_anon_type_of<'tcx>(icx: &ItemCtxt<'tcx>, arg_hir_id: HirId, span: S } Node::TyPat(pat) => { - let hir::TyKind::Pat(ty, p) = tcx.parent_hir_node(pat.hir_id).expect_ty().kind else { - bug!() + let node = match tcx.parent_hir_node(pat.hir_id) { + // Or patterns can be nested one level deep + Node::TyPat(p) => tcx.parent_hir_node(p.hir_id), + other => other, }; - assert_eq!(p.hir_id, pat.hir_id); + let hir::TyKind::Pat(ty, _) = node.expect_ty().kind else { bug!() }; icx.lower_ty(ty) } 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 8153e6f87f8a..fcb7382549f4 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2715,30 +2715,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir::TyKind::Pat(ty, pat) => { let ty_span = ty.span; let ty = self.lower_ty(ty); - let pat_ty = match pat.kind { - hir::TyPatKind::Range(start, end) => { - let (ty, start, end) = match ty.kind() { - // Keep this list of types in sync with the list of types that - // the `RangePattern` trait is implemented for. - ty::Int(_) | ty::Uint(_) | ty::Char => { - let start = self.lower_const_arg(start, FeedConstTy::No); - let end = self.lower_const_arg(end, FeedConstTy::No); - (ty, start, end) - } - _ => { - let guar = self.dcx().span_delayed_bug( - ty_span, - "invalid base type for range pattern", - ); - let errc = ty::Const::new_error(tcx, guar); - (Ty::new_error(tcx, guar), errc, errc) - } - }; - - let pat = tcx.mk_pat(ty::PatternKind::Range { start, end }); - Ty::new_pat(tcx, ty, pat) - } - hir::TyPatKind::Err(e) => Ty::new_error(tcx, e), + let pat_ty = match self.lower_pat_ty_pat(ty, ty_span, pat) { + Ok(kind) => Ty::new_pat(tcx, ty, tcx.mk_pat(kind)), + Err(guar) => Ty::new_error(tcx, guar), }; self.record_ty(pat.hir_id, ty, pat.span); pat_ty @@ -2750,6 +2729,39 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { result_ty } + fn lower_pat_ty_pat( + &self, + ty: Ty<'tcx>, + ty_span: Span, + pat: &hir::TyPat<'tcx>, + ) -> Result, ErrorGuaranteed> { + let tcx = self.tcx(); + match pat.kind { + hir::TyPatKind::Range(start, end) => { + match ty.kind() { + // Keep this list of types in sync with the list of types that + // the `RangePattern` trait is implemented for. + ty::Int(_) | ty::Uint(_) | ty::Char => { + let start = self.lower_const_arg(start, FeedConstTy::No); + let end = self.lower_const_arg(end, FeedConstTy::No); + Ok(ty::PatternKind::Range { start, end }) + } + _ => Err(self + .dcx() + .span_delayed_bug(ty_span, "invalid base type for range pattern")), + } + } + hir::TyPatKind::Or(patterns) => { + self.tcx() + .mk_patterns_from_iter(patterns.iter().map(|pat| { + self.lower_pat_ty_pat(ty, ty_span, pat).map(|pat| tcx.mk_pat(pat)) + })) + .map(ty::PatternKind::Or) + } + hir::TyPatKind::Err(e) => Err(e), + } + } + /// Lower an opaque type (i.e., an existential impl-Trait type) from the HIR. #[instrument(level = "debug", skip(self), ret)] fn lower_opaque_ty(&self, def_id: LocalDefId, in_trait: bool) -> Ty<'tcx> { diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs index dc3ce1dd76c4..92cfece77c47 100644 --- a/compiler/rustc_hir_analysis/src/variance/constraints.rs +++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs @@ -251,12 +251,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } ty::Pat(typ, pat) => { - match *pat { - ty::PatternKind::Range { start, end } => { - self.add_constraints_from_const(current, start, variance); - self.add_constraints_from_const(current, end, variance); - } - } + self.add_constraints_from_pat(current, variance, pat); self.add_constraints_from_ty(current, typ, variance); } @@ -334,6 +329,25 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } } + fn add_constraints_from_pat( + &mut self, + current: &CurrentItem, + variance: VarianceTermPtr<'a>, + pat: ty::Pattern<'tcx>, + ) { + match *pat { + ty::PatternKind::Range { start, end } => { + self.add_constraints_from_const(current, start, variance); + self.add_constraints_from_const(current, end, variance); + } + ty::PatternKind::Or(patterns) => { + for pat in patterns { + self.add_constraints_from_pat(current, variance, pat) + } + } + } + } + /// Adds constraints appropriate for a nominal type (enum, struct, /// object, etc) appearing in a context with ambient variance `variance` fn add_constraints_from_args( diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index b878147522dc..15e997aebcb8 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -146,6 +146,7 @@ impl<'a> State<'a> { false, None, *delim, + None, &tokens, true, span, @@ -1882,6 +1883,19 @@ impl<'a> State<'a> { self.word("..="); self.print_const_arg(end); } + TyPatKind::Or(patterns) => { + self.popen(); + let mut first = true; + for pat in patterns { + if first { + first = false; + } else { + self.word(" | "); + } + self.print_ty_pat(pat); + } + self.pclose(); + } TyPatKind::Err(_) => { self.popen(); self.word("/*ERROR*/"); diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 5f5e9e45612a..f555d116c52d 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -14,7 +14,7 @@ use rustc_middle::ty::adjustment::{ use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::{bug, span_bug}; use rustc_span::def_id::LocalDefId; -use rustc_span::{Ident, Span, sym}; +use rustc_span::{Span, sym}; use rustc_trait_selection::error_reporting::traits::DefIdOrName; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; @@ -87,14 +87,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let output = match result { None => { - // this will report an error since original_callee_ty is not a fn - self.confirm_builtin_call( - call_expr, - callee_expr, - original_callee_ty, - arg_exprs, - expected, - ) + // Check all of the arg expressions, but with no expectations + // since we don't have a signature to compare them to. + for arg in arg_exprs { + self.check_expr(arg); + } + + if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = &callee_expr.kind + && let [segment] = path.segments + { + self.dcx().try_steal_modify_and_emit_err( + segment.ident.span, + StashKey::CallIntoMethod, + |err| { + // Try suggesting `foo(a)` -> `a.foo()` if possible. + self.suggest_call_as_method( + err, segment, arg_exprs, call_expr, expected, + ); + }, + ); + } + + let guar = self.report_invalid_callee(call_expr, callee_expr, expr_ty, arg_exprs); + Ty::new_error(self.tcx, guar) } Some(CallStep::Builtin(callee_ty)) => { @@ -296,9 +311,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ty::new_tup_from_iter(self.tcx, arg_exprs.iter().map(|e| self.next_ty_var(e.span))) }); - if let Some(ok) = self.lookup_method_in_trait( + if let Some(ok) = self.lookup_method_for_operator( self.misc(call_expr.span), - Ident::with_dummy_span(method_name), + method_name, trait_def_id, adjusted_ty, opt_input_type, @@ -461,32 +476,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } (fn_sig, Some(def_id)) } + // FIXME(const_trait_impl): these arms should error because we can't enforce them ty::FnPtr(sig_tys, hdr) => (sig_tys.with(hdr), None), - _ => { - for arg in arg_exprs { - self.check_expr(arg); - } - if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = &callee_expr.kind - && let [segment] = path.segments - { - self.dcx().try_steal_modify_and_emit_err( - segment.ident.span, - StashKey::CallIntoMethod, - |err| { - // Try suggesting `foo(a)` -> `a.foo()` if possible. - self.suggest_call_as_method( - err, segment, arg_exprs, call_expr, expected, - ); - }, - ); - } - - let err = self.report_invalid_callee(call_expr, callee_expr, callee_ty, arg_exprs); - - return Ty::new_error(self.tcx, err); - } + _ => unreachable!(), }; // Replace any late-bound regions that appear in the function @@ -908,19 +902,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call_expr: &'tcx hir::Expr<'tcx>, arg_exprs: &'tcx [hir::Expr<'tcx>], expected: Expectation<'tcx>, - method_callee: MethodCallee<'tcx>, + method: MethodCallee<'tcx>, ) -> Ty<'tcx> { - let output_type = self.check_method_argument_types( + self.check_argument_types( call_expr.span, call_expr, - Ok(method_callee), - arg_exprs, - TupleArgumentsFlag::TupleArguments, + &method.sig.inputs()[1..], + method.sig.output(), expected, + arg_exprs, + method.sig.c_variadic, + TupleArgumentsFlag::TupleArguments, + Some(method.def_id), ); - self.write_method_call_and_enforce_effects(call_expr.hir_id, call_expr.span, method_callee); - output_type + self.write_method_call_and_enforce_effects(call_expr.hir_id, call_expr.span, method); + + method.sig.output() } } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 9c6d4ee096f1..db2650ed357e 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -40,7 +40,6 @@ use tracing::{debug, instrument, trace}; use {rustc_ast as ast, rustc_hir as hir}; use crate::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation}; -use crate::TupleArgumentsFlag::DontTupleArguments; use crate::coercion::{CoerceMany, DynamicCoerceMany}; use crate::errors::{ AddressOfTemporaryTaken, BaseExpressionDoubleDot, BaseExpressionDoubleDotAddExpr, @@ -51,8 +50,8 @@ use crate::errors::{ YieldExprOutsideOfCoroutine, }; use crate::{ - BreakableCtxt, CoroutineTypes, Diverges, FnCtxt, Needs, cast, fatally_break_rust, - report_unexpected_variant_res, type_error_struct, + BreakableCtxt, CoroutineTypes, Diverges, FnCtxt, Needs, TupleArgumentsFlag, cast, + fatally_break_rust, report_unexpected_variant_res, type_error_struct, }; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -1591,28 +1590,45 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // no need to check for bot/err -- callee does that let rcvr_t = self.structurally_resolve_type(rcvr.span, rcvr_t); - let method = match self.lookup_method(rcvr_t, segment, segment.ident.span, expr, rcvr, args) - { + match self.lookup_method(rcvr_t, segment, segment.ident.span, expr, rcvr, args) { Ok(method) => { - // We could add a "consider `foo::`" suggestion here, but I wasn't able to - // trigger this codepath causing `structurally_resolve_type` to emit an error. self.write_method_call_and_enforce_effects(expr.hir_id, expr.span, method); - Ok(method) + + self.check_argument_types( + segment.ident.span, + expr, + &method.sig.inputs()[1..], + method.sig.output(), + expected, + args, + method.sig.c_variadic, + TupleArgumentsFlag::DontTupleArguments, + Some(method.def_id), + ); + + method.sig.output() } Err(error) => { - Err(self.report_method_error(expr.hir_id, rcvr_t, error, expected, false)) - } - }; + let guar = self.report_method_error(expr.hir_id, rcvr_t, error, expected, false); - // Call the generic checker. - self.check_method_argument_types( - segment.ident.span, - expr, - method, - args, - DontTupleArguments, - expected, - ) + let err_inputs = self.err_args(args.len(), guar); + let err_output = Ty::new_error(self.tcx, guar); + + self.check_argument_types( + segment.ident.span, + expr, + &err_inputs, + err_output, + NoExpectation, + args, + false, + TupleArgumentsFlag::DontTupleArguments, + None, + ); + + err_output + } + } } /// Checks use `x.use`. diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index e70aa1a70645..c804dc5e7fba 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -33,7 +33,6 @@ use crate::fn_ctxt::arg_matrix::{ArgMatrix, Compatibility, Error, ExpectedIdx, P use crate::fn_ctxt::infer::FnCall; use crate::gather_locals::Declaration; use crate::inline_asm::InlineAsmCtxt; -use crate::method::MethodCallee; use crate::method::probe::IsSuggestion; use crate::method::probe::Mode::MethodCall; use crate::method::probe::ProbeScope::TraitsInScope; @@ -127,61 +126,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - pub(in super::super) fn check_method_argument_types( - &self, - sp: Span, - expr: &'tcx hir::Expr<'tcx>, - method: Result, ErrorGuaranteed>, - args_no_rcvr: &'tcx [hir::Expr<'tcx>], - tuple_arguments: TupleArgumentsFlag, - expected: Expectation<'tcx>, - ) -> Ty<'tcx> { - let has_error = match method { - Ok(method) => method.args.error_reported().and(method.sig.error_reported()), - Err(guar) => Err(guar), - }; - if let Err(guar) = has_error { - let err_inputs = self.err_args( - method.map_or(args_no_rcvr.len(), |method| method.sig.inputs().len() - 1), - guar, - ); - let err_output = Ty::new_error(self.tcx, guar); - - let err_inputs = match tuple_arguments { - DontTupleArguments => err_inputs, - TupleArguments => vec![Ty::new_tup(self.tcx, &err_inputs)], - }; - - self.check_argument_types( - sp, - expr, - &err_inputs, - err_output, - NoExpectation, - args_no_rcvr, - false, - tuple_arguments, - method.ok().map(|method| method.def_id), - ); - return err_output; - } - - let method = method.unwrap(); - self.check_argument_types( - sp, - expr, - &method.sig.inputs()[1..], - method.sig.output(), - expected, - args_no_rcvr, - method.sig.c_variadic, - tuple_arguments, - Some(method.def_id), - ); - - method.sig.output() - } - /// Generic function that factors out common logic from function calls, /// method calls and overloaded operators. pub(in super::super) fn check_argument_types( diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 1b67e2306aa7..34bbb7d7c05e 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -19,7 +19,7 @@ use rustc_middle::ty::{ self, GenericArgs, GenericArgsRef, GenericParamDefKind, Ty, TypeVisitableExt, }; use rustc_middle::{bug, span_bug}; -use rustc_span::{ErrorGuaranteed, Ident, Span}; +use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::{self, NormalizeExt}; use tracing::{debug, instrument}; @@ -329,10 +329,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// an obligation for a particular trait with the given self type and checks /// whether that trait is implemented. #[instrument(level = "debug", skip(self))] - pub(super) fn lookup_method_in_trait( + pub(super) fn lookup_method_for_operator( &self, cause: ObligationCause<'tcx>, - m_name: Ident, + method_name: Symbol, trait_def_id: DefId, self_ty: Ty<'tcx>, opt_rhs_ty: Option>, @@ -374,13 +374,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Trait must have a method named `m_name` and it should not have // type parameters or early-bound regions. let tcx = self.tcx; - let Some(method_item) = self.associated_value(trait_def_id, m_name) else { + // We use `Ident::with_dummy_span` since no built-in operator methods have + // any macro-specific hygeine, so the span's context doesn't really matter. + let Some(method_item) = + self.associated_value(trait_def_id, Ident::with_dummy_span(method_name)) + else { bug!("expected associated item for operator trait") }; let def_id = method_item.def_id; if !method_item.is_fn() { - span_bug!(tcx.def_span(def_id), "expected `{m_name}` to be an associated function"); + span_bug!( + tcx.def_span(def_id), + "expected `{method_name}` to be an associated function" + ); } debug!("lookup_in_trait_adjusted: method_item={:?}", method_item); diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 1d3a081cbb88..bda051f15608 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1213,7 +1213,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { debug!("pick_all_method: step={:?}", step); // skip types that are from a type error or that would require dereferencing // a raw pointer - !step.self_ty.references_error() && !step.from_unsafe_deref + !step.self_ty.value.references_error() && !step.from_unsafe_deref }) .find_map(|step| { let InferOk { value: self_ty, obligations: _ } = self diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index b86991f81ad8..7f7921b66b57 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -12,7 +12,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt, TypeVisitableExt}; use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::Spanned; -use rustc_span::{Ident, Span, Symbol, sym}; +use rustc_span::{Span, Symbol, sym}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{FulfillmentError, Obligation, ObligationCtxt}; use tracing::debug; @@ -975,7 +975,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lhs_ty, opname, trait_did ); - let opname = Ident::with_dummy_span(opname); let (opt_rhs_expr, opt_rhs_ty) = opt_rhs.unzip(); let cause = self.cause( span, @@ -990,7 +989,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); let method = - self.lookup_method_in_trait(cause.clone(), opname, trait_did, lhs_ty, opt_rhs_ty); + self.lookup_method_for_operator(cause.clone(), opname, trait_did, lhs_ty, opt_rhs_ty); match method { Some(ok) => { let method = self.register_infer_ok_obligations(ok); diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs index 4fc903cf68b8..fedc75abe492 100644 --- a/compiler/rustc_hir_typeck/src/place_op.rs +++ b/compiler/rustc_hir_typeck/src/place_op.rs @@ -8,7 +8,7 @@ use rustc_middle::ty::adjustment::{ PointerCoercion, }; use rustc_middle::ty::{self, Ty}; -use rustc_span::{Ident, Span, sym}; +use rustc_span::{Span, sym}; use tracing::debug; use {rustc_ast as ast, rustc_hir as hir}; @@ -211,13 +211,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return None; }; - self.lookup_method_in_trait( - self.misc(span), - Ident::with_dummy_span(imm_op), - imm_tr, - base_ty, - opt_rhs_ty, - ) + self.lookup_method_for_operator(self.misc(span), imm_op, imm_tr, base_ty, opt_rhs_ty) } fn try_mutable_overloaded_place_op( @@ -237,13 +231,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return None; }; - self.lookup_method_in_trait( - self.misc(span), - Ident::with_dummy_span(mut_op), - mut_tr, - base_ty, - opt_rhs_ty, - ) + self.lookup_method_for_operator(self.misc(span), mut_op, mut_tr, base_ty, opt_rhs_ty) } /// Convert auto-derefs, indices, etc of an expression from `Deref` and `Index` diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index c5000171ad75..4a171a08ef72 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -1,6 +1,12 @@ -// Type resolution: the phase that finds all the types in the AST with -// unresolved type variables and replaces "ty_var" types with their -// generic parameters. +//! During type inference, partially inferred terms are +//! represented using inference variables (ty::Infer). These don't appear in +//! the final [`ty::TypeckResults`] since all of the types should have been +//! inferred once typeck is done. +//! +//! When type inference is running however, having to update the typeck results +//! every time a new type is inferred would be unreasonably slow, so instead all +//! of the replacement happens at the end in [`FnCtxt::resolve_type_vars_in_body`], +//! which creates a new `TypeckResults` which doesn't contain any inference variables. use std::mem; @@ -9,7 +15,6 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir::intravisit::{self, InferKind, Visitor}; use rustc_hir::{self as hir, AmbigArg, HirId}; use rustc_infer::traits::solve::Goal; -use rustc_middle::span_bug; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion}; use rustc_middle::ty::{ @@ -27,15 +32,6 @@ use crate::FnCtxt; /////////////////////////////////////////////////////////////////////////// // Entry point -// During type inference, partially inferred types are -// represented using Type variables (ty::Infer). These don't appear in -// the final TypeckResults since all of the types should have been -// inferred once typeck is done. -// When type inference is running however, having to update the typeck -// typeck results every time a new type is inferred would be unreasonably slow, -// so instead all of the replacement happens at the end in -// resolve_type_vars_in_body, which creates a new TypeTables which -// doesn't contain any inference types. impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn resolve_type_vars_in_body( &self, @@ -90,14 +86,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } -/////////////////////////////////////////////////////////////////////////// -// The Writeback context. This visitor walks the HIR, checking the -// fn-specific typeck results to find references to types or regions. It -// resolves those regions to remove inference variables and writes the -// final result back into the master typeck results in the tcx. Here and -// there, it applies a few ad-hoc checks that were not convenient to -// do elsewhere. - +/// The Writeback context. This visitor walks the HIR, checking the +/// fn-specific typeck results to find inference variables. It resolves +/// those inference variables and writes the final result into the +/// `TypeckResults`. It also applies a few ad-hoc checks that were not +/// convenient to do elsewhere. struct WritebackCx<'cx, 'tcx> { fcx: &'cx FnCtxt<'cx, 'tcx>, @@ -513,15 +506,6 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { self.typeck_results.user_provided_types_mut().extend( fcx_typeck_results.user_provided_types().items().map(|(local_id, c_ty)| { let hir_id = HirId { owner: common_hir_owner, local_id }; - - if cfg!(debug_assertions) && c_ty.has_infer() { - span_bug!( - hir_id.to_span(self.fcx.tcx), - "writeback: `{:?}` has inference variables", - c_ty - ); - }; - (hir_id, *c_ty) }), ); @@ -532,17 +516,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); self.typeck_results.user_provided_sigs.extend_unord( - fcx_typeck_results.user_provided_sigs.items().map(|(&def_id, c_sig)| { - if cfg!(debug_assertions) && c_sig.has_infer() { - span_bug!( - self.fcx.tcx.def_span(def_id), - "writeback: `{:?}` has inference variables", - c_sig - ); - }; - - (def_id, *c_sig) - }), + fcx_typeck_results.user_provided_sigs.items().map(|(def_id, c_sig)| (*def_id, *c_sig)), ); } @@ -897,7 +871,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { let cause = ObligationCause::misc(self.span.to_span(tcx), body_id); let at = self.fcx.at(&cause, self.fcx.param_env); let universes = vec![None; outer_exclusive_binder(value).as_usize()]; - match solve::deeply_normalize_with_skipped_universes_and_ambiguous_goals( + match solve::deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals( at, value, universes, ) { Ok((value, goals)) => { diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 66d2a79b93a4..aad63f4edcf3 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -900,6 +900,12 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { // is not defined. So we need to cfg it out. #[cfg(all(not(doc), debug_assertions))] rustc_passes::hir_id_validator::check_crate(tcx); + + // Prefetch this to prevent multiple threads from blocking on it later. + // This is needed since the `hir_id_validator::check_crate` call above is not guaranteed + // to use `hir_crate`. + tcx.ensure_done().hir_crate(()); + let sess = tcx.sess; sess.time("misc_checking_1", || { parallel!( diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index a3e7c84584d3..d1138e8f1fa5 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -422,6 +422,16 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { } } + fn check_ty(&mut self, cx: &LateContext<'_>, ty: &hir::Ty<'_, hir::AmbigArg>) { + if let hir::TyKind::BareFn(hir::BareFnTy { param_idents, .. }) = &ty.kind { + for param_ident in *param_idents { + if let Some(param_ident) = param_ident { + self.check_snake_case(cx, "variable", param_ident); + } + } + } + } + fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &hir::TraitItem<'_>) { if let hir::TraitItemKind::Fn(_, hir::TraitFn::Required(param_idents)) = item.kind { self.check_snake_case(cx, "trait method", &item.ident); diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 7b6a723b0b40..f1c06dfe6ce0 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -755,10 +755,10 @@ declare_lint! { /// *subsequent* fields of the associated structs to use an alignment value /// where the floating-point type is aligned on a 4-byte boundary. /// - /// The power alignment rule for structs needed for C compatibility is - /// unimplementable within `repr(C)` in the compiler without building in - /// handling of references to packed fields and infectious nested layouts, - /// so a warning is produced in these situations. + /// Effectively, subsequent floating-point fields act as-if they are `repr(packed(4))`. This + /// would be unsound to do in a `repr(C)` type without all the restrictions that come with + /// `repr(packed)`. Rust instead chooses a layout that maintains soundness of Rust code, at the + /// expense of incompatibility with C code. /// /// ### Example /// @@ -790,8 +790,10 @@ declare_lint! { /// - offset_of!(Floats, a) == 0 /// - offset_of!(Floats, b) == 8 /// - offset_of!(Floats, c) == 12 - /// However, rust currently aligns `c` at offset_of!(Floats, c) == 16. - /// Thus, a warning should be produced for the above struct in this case. + /// + /// However, Rust currently aligns `c` at `offset_of!(Floats, c) == 16`. + /// Using offset 12 would be unsound since `f64` generally must be 8-aligned on this target. + /// Thus, a warning is produced for the above struct. USES_POWER_ALIGNMENT, Warn, "Structs do not follow the power alignment rule under repr(C)" @@ -878,25 +880,36 @@ fn ty_is_known_nonnull<'tcx>( } ty::Pat(base, pat) => { ty_is_known_nonnull(tcx, typing_env, *base, mode) - || Option::unwrap_or_default( - try { - match **pat { - ty::PatternKind::Range { start, end } => { - let start = start.try_to_value()?.try_to_bits(tcx, typing_env)?; - let end = end.try_to_value()?.try_to_bits(tcx, typing_env)?; - - // This also works for negative numbers, as we just need - // to ensure we aren't wrapping over zero. - start > 0 && end >= start - } - } - }, - ) + || pat_ty_is_known_nonnull(tcx, typing_env, *pat) } _ => false, } } +fn pat_ty_is_known_nonnull<'tcx>( + tcx: TyCtxt<'tcx>, + typing_env: ty::TypingEnv<'tcx>, + pat: ty::Pattern<'tcx>, +) -> bool { + Option::unwrap_or_default( + try { + match *pat { + ty::PatternKind::Range { start, end } => { + let start = start.try_to_value()?.try_to_bits(tcx, typing_env)?; + let end = end.try_to_value()?.try_to_bits(tcx, typing_env)?; + + // This also works for negative numbers, as we just need + // to ensure we aren't wrapping over zero. + start > 0 && end >= start + } + ty::PatternKind::Or(patterns) => { + patterns.iter().all(|pat| pat_ty_is_known_nonnull(tcx, typing_env, pat)) + } + } + }, + ) +} + /// Given a non-null scalar (or transparent) type `ty`, return the nullable version of that type. /// If the type passed in was not scalar, returns None. fn get_nullable_type<'tcx>( @@ -1038,13 +1051,29 @@ pub(crate) fn repr_nullable_ptr<'tcx>( } None } - ty::Pat(base, pat) => match **pat { - ty::PatternKind::Range { .. } => get_nullable_type(tcx, typing_env, *base), - }, + ty::Pat(base, pat) => get_nullable_type_from_pat(tcx, typing_env, *base, *pat), _ => None, } } +fn get_nullable_type_from_pat<'tcx>( + tcx: TyCtxt<'tcx>, + typing_env: ty::TypingEnv<'tcx>, + base: Ty<'tcx>, + pat: ty::Pattern<'tcx>, +) -> Option> { + match *pat { + ty::PatternKind::Range { .. } => get_nullable_type(tcx, typing_env, base), + ty::PatternKind::Or(patterns) => { + let first = get_nullable_type_from_pat(tcx, typing_env, base, patterns[0])?; + for &pat in &patterns[1..] { + assert_eq!(first, get_nullable_type_from_pat(tcx, typing_env, base, pat)?); + } + Some(first) + } + } +} + impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { /// Check if the type is array and emit an unsafe type lint. fn check_for_array_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool { @@ -1628,15 +1657,13 @@ impl ImproperCTypesDefinitions { cx: &LateContext<'tcx>, ty: Ty<'tcx>, ) -> bool { + assert!(cx.tcx.sess.target.os == "aix"); // Structs (under repr(C)) follow the power alignment rule if: // - the first field of the struct is a floating-point type that // is greater than 4-bytes, or // - the first field of the struct is an aggregate whose // recursively first field is a floating-point type greater than // 4 bytes. - if cx.tcx.sess.target.os != "aix" { - return false; - } if ty.is_floating_point() && ty.primitive_size(cx.tcx).bytes() > 4 { return true; } else if let Adt(adt_def, _) = ty.kind() @@ -1674,21 +1701,14 @@ impl ImproperCTypesDefinitions { && !adt_def.all_fields().next().is_none() { let struct_variant_data = item.expect_struct().1; - for (index, ..) in struct_variant_data.fields().iter().enumerate() { + for field_def in struct_variant_data.fields().iter().skip(1) { // Struct fields (after the first field) are checked for the // power alignment rule, as fields after the first are likely // to be the fields that are misaligned. - if index != 0 { - let first_field_def = struct_variant_data.fields()[index]; - let def_id = first_field_def.def_id; - let ty = cx.tcx.type_of(def_id).instantiate_identity(); - if self.check_arg_for_power_alignment(cx, ty) { - cx.emit_span_lint( - USES_POWER_ALIGNMENT, - first_field_def.span, - UsesPowerAlignment, - ); - } + let def_id = field_def.def_id; + let ty = cx.tcx.type_of(def_id).instantiate_identity(); + if self.check_arg_for_power_alignment(cx, ty) { + cx.emit_span_lint(USES_POWER_ALIGNMENT, field_def.span, UsesPowerAlignment); } } } diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 8bee051dd4c3..ebe8eb57f2cd 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -1365,7 +1365,12 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, size_t num_modules, // Convert the preserved symbols set from string to GUID, this is then needed // for internalization. for (size_t i = 0; i < num_symbols; i++) { +#if LLVM_VERSION_GE(21, 0) + auto GUID = + GlobalValue::getGUIDAssumingExternalLinkage(preserved_symbols[i]); +#else auto GUID = GlobalValue::getGUID(preserved_symbols[i]); +#endif Ret->GUIDPreservedSymbols.insert(GUID); } @@ -1685,11 +1690,11 @@ extern "C" void LLVMRustComputeLTOCacheKey(RustStringRef KeyOut, // Based on the 'InProcessThinBackend' constructor in LLVM #if LLVM_VERSION_GE(21, 0) for (auto &Name : Data->Index.cfiFunctionDefs().symbols()) - CfiFunctionDefs.insert( - GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Name))); + CfiFunctionDefs.insert(GlobalValue::getGUIDAssumingExternalLinkage( + GlobalValue::dropLLVMManglingEscape(Name))); for (auto &Name : Data->Index.cfiFunctionDecls().symbols()) - CfiFunctionDecls.insert( - GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Name))); + CfiFunctionDecls.insert(GlobalValue::getGUIDAssumingExternalLinkage( + GlobalValue::dropLLVMManglingEscape(Name))); #else for (auto &Name : Data->Index.cfiFunctionDefs()) CfiFunctionDefs.insert( diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 62bf34ad5adc..33fb13e23bf8 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -407,11 +407,23 @@ pub(super) fn rustc_queries(input: TokenStream) -> TokenStream { } TokenStream::from(quote! { + /// Higher-order macro that invokes the specified macro with a prepared + /// list of all query signatures (including modifiers). + /// + /// This allows multiple simpler macros to each have access to the list + /// of queries. #[macro_export] - macro_rules! rustc_query_append { - ($macro:ident! $( [$($other:tt)*] )?) => { + macro_rules! rustc_with_all_queries { + ( + // The macro to invoke once, on all queries (plus extras). + $macro:ident! + + // Within [], an optional list of extra "query" signatures to + // pass to the given macro, in addition to the actual queries. + $( [$($extra_fake_queries:tt)*] )? + ) => { $macro! { - $( $($other)* )? + $( $($extra_fake_queries)* )? #query_stream } } diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index 644cdac5d554..0c998a2cbb38 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -13,8 +13,11 @@ use crate::ty::TyCtxt; macro_rules! define_dep_nodes { ( - $($(#[$attr:meta])* - [$($modifiers:tt)*] fn $variant:ident($($K:tt)*) -> $V:ty,)*) => { + $( + $(#[$attr:meta])* + [$($modifiers:tt)*] fn $variant:ident($($K:tt)*) -> $V:ty, + )* + ) => { #[macro_export] macro_rules! make_dep_kind_array { @@ -83,7 +86,9 @@ macro_rules! define_dep_nodes { }; } -rustc_query_append!(define_dep_nodes![ +// Create various data structures for each query, and also for a few things +// that aren't queries. +rustc_with_all_queries!(define_dep_nodes![ /// We use this for most things when incr. comp. is turned off. [] fn Null() -> (), /// We use this to create a forever-red node. diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index df025aeebf04..711036865bbd 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -61,6 +61,7 @@ #![feature(try_trait_v2_yeet)] #![feature(type_alias_impl_trait)] #![feature(yeet_expr)] +#![recursion_limit = "256"] // tidy-alphabetical-end #[cfg(test)] diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index 4222a68e5447..e5d1dda3aa0f 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -115,15 +115,16 @@ impl<'tcx> TyCtxt<'tcx> { // @lcnr believes that successfully evaluating even though there are // used generic parameters is a bug of evaluation, so checking for it // here does feel somewhat sensible. - if !self.features().generic_const_exprs() && ct.args.has_non_region_param() { - let def_kind = self.def_kind(instance.def_id()); - assert!( - matches!( - def_kind, - DefKind::InlineConst | DefKind::AnonConst | DefKind::AssocConst - ), - "{cid:?} is {def_kind:?}", - ); + if !self.features().generic_const_exprs() + && ct.args.has_non_region_param() + // We only FCW for anon consts as repeat expr counts with anon consts are the only place + // that we have a back compat hack for. We don't need to check this is a const argument + // as only anon consts as const args should get evaluated "for the type system". + // + // If we don't *only* FCW anon consts we can wind up incorrectly FCW'ing uses of assoc + // consts in pattern positions. #140447 + && self.def_kind(instance.def_id()) == DefKind::AnonConst + { let mir_body = self.mir_for_ctfe(instance.def_id()); if mir_body.is_polymorphic { let Some(local_def_id) = ct.def.as_local() else { return }; diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index b55e4d7d8317..88f4c4ae4d36 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -2578,5 +2578,5 @@ rustc_queries! { } } -rustc_query_append! { define_callbacks! } +rustc_with_all_queries! { define_callbacks! } rustc_feedable_queries! { define_feedable! } diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 69b6f88d72bf..769df1ffd6f9 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -313,8 +313,11 @@ macro_rules! separate_provide_extern_default { macro_rules! define_callbacks { ( - $($(#[$attr:meta])* - [$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => { + $( + $(#[$attr:meta])* + [$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty, + )* + ) => { #[allow(unused_lifetimes)] pub mod queries { diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 23927c112bcd..5ff87959a800 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -442,6 +442,15 @@ impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List> RefDecodable<'tcx, D> for ty::List> { + fn decode(decoder: &mut D) -> &'tcx Self { + let len = decoder.read_usize(); + decoder.interner().mk_patterns_from_iter( + (0..len).map::, _>(|_| Decodable::decode(decoder)), + ) + } +} + impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List> { fn decode(decoder: &mut D) -> &'tcx Self { let len = decoder.read_usize(); @@ -503,6 +512,7 @@ impl_decodable_via_ref! { &'tcx mir::Body<'tcx>, &'tcx mir::ConcreteOpaqueTypes<'tcx>, &'tcx ty::List, + &'tcx ty::List>, &'tcx ty::ListWithCachedTypeInfo>, &'tcx ty::List, &'tcx ty::List<(VariantIdx, FieldIdx)>, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 1efd0d1d14be..0865e378bf3b 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -136,6 +136,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type AllocId = crate::mir::interpret::AllocId; type Pat = Pattern<'tcx>; + type PatList = &'tcx List>; type Safety = hir::Safety; type Abi = ExternAbi; type Const = ty::Const<'tcx>; @@ -842,6 +843,7 @@ pub struct CtxtInterners<'tcx> { captures: InternedSet<'tcx, List<&'tcx ty::CapturedPlace<'tcx>>>, offset_of: InternedSet<'tcx, List<(VariantIdx, FieldIdx)>>, valtree: InternedSet<'tcx, ty::ValTreeKind<'tcx>>, + patterns: InternedSet<'tcx, List>>, } impl<'tcx> CtxtInterners<'tcx> { @@ -878,6 +880,7 @@ impl<'tcx> CtxtInterners<'tcx> { captures: InternedSet::with_capacity(N), offset_of: InternedSet::with_capacity(N), valtree: InternedSet::with_capacity(N), + patterns: InternedSet::with_capacity(N), } } @@ -2662,6 +2665,7 @@ slice_interners!( local_def_ids: intern_local_def_ids(LocalDefId), captures: intern_captures(&'tcx ty::CapturedPlace<'tcx>), offset_of: pub mk_offset_of((VariantIdx, FieldIdx)), + patterns: pub mk_patterns(Pattern<'tcx>), ); impl<'tcx> TyCtxt<'tcx> { @@ -2935,6 +2939,14 @@ impl<'tcx> TyCtxt<'tcx> { self.intern_local_def_ids(def_ids) } + pub fn mk_patterns_from_iter(self, iter: I) -> T::Output + where + I: Iterator, + T: CollectAndApply, &'tcx List>>, + { + T::collect_and_apply(iter, |xs| self.mk_patterns(xs)) + } + pub fn mk_local_def_ids_from_iter(self, iter: I) -> T::Output where I: Iterator, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index eba6d61ba7d3..2f4c03f0953d 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -50,6 +50,7 @@ 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}; +pub use rustc_type_ir::data_structures::DelayedSet; pub use rustc_type_ir::relate::VarianceDiagInfo; pub use rustc_type_ir::*; use tracing::{debug, instrument}; diff --git a/compiler/rustc_middle/src/ty/pattern.rs b/compiler/rustc_middle/src/ty/pattern.rs index 758adc42e3eb..5af9b17dd777 100644 --- a/compiler/rustc_middle/src/ty/pattern.rs +++ b/compiler/rustc_middle/src/ty/pattern.rs @@ -23,6 +23,13 @@ impl<'tcx> Flags for Pattern<'tcx> { FlagComputation::for_const_kind(&start.kind()).flags | FlagComputation::for_const_kind(&end.kind()).flags } + ty::PatternKind::Or(pats) => { + let mut flags = pats[0].flags(); + for pat in pats[1..].iter() { + flags |= pat.flags(); + } + flags + } } } @@ -31,6 +38,13 @@ impl<'tcx> Flags for Pattern<'tcx> { ty::PatternKind::Range { start, end } => { start.outer_exclusive_binder().max(end.outer_exclusive_binder()) } + ty::PatternKind::Or(pats) => { + let mut idx = pats[0].outer_exclusive_binder(); + for pat in pats[1..].iter() { + idx = idx.max(pat.outer_exclusive_binder()); + } + idx + } } } } @@ -77,6 +91,19 @@ impl<'tcx> IrPrint> for TyCtxt<'tcx> { write!(f, "..={end}") } + PatternKind::Or(patterns) => { + write!(f, "(")?; + let mut first = true; + for pat in patterns { + if first { + first = false + } else { + write!(f, " | ")?; + } + write!(f, "{pat:?}")?; + } + write!(f, ")") + } } } diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index b1dfcb80bde5..6ad4e5276b25 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -49,6 +49,7 @@ impl<'tcx> Relate> for ty::Pattern<'tcx> { a: Self, b: Self, ) -> RelateResult<'tcx, Self> { + let tcx = relation.cx(); match (&*a, &*b) { ( &ty::PatternKind::Range { start: start_a, end: end_a }, @@ -56,8 +57,17 @@ impl<'tcx> Relate> for ty::Pattern<'tcx> { ) => { let start = relation.relate(start_a, start_b)?; let end = relation.relate(end_a, end_b)?; - Ok(relation.cx().mk_pat(ty::PatternKind::Range { start, end })) + Ok(tcx.mk_pat(ty::PatternKind::Range { start, end })) } + (&ty::PatternKind::Or(a), &ty::PatternKind::Or(b)) => { + if a.len() != b.len() { + return Err(TypeError::Mismatch); + } + let v = iter::zip(a, b).map(|(a, b)| relation.relate(a, b)); + let patterns = tcx.mk_patterns_from_iter(v)?; + Ok(tcx.mk_pat(ty::PatternKind::Or(patterns))) + } + (ty::PatternKind::Range { .. } | ty::PatternKind::Or(_), _) => Err(TypeError::Mismatch), } } } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 26861666c1db..58f7bc75054b 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -13,7 +13,6 @@ use rustc_type_ir::{ConstKind, TypeFolder, VisitorResult, try_visit}; use super::print::PrettyPrinter; use super::{GenericArg, GenericArgKind, Pattern, Region}; -use crate::infer::canonical::CanonicalVarInfos; use crate::mir::PlaceElem; use crate::ty::print::{FmtPrinter, Printer, with_no_trimmed_paths}; use crate::ty::{ @@ -779,5 +778,5 @@ list_fold! { ty::Clauses<'tcx> : mk_clauses, &'tcx ty::List> : mk_poly_existential_predicates, &'tcx ty::List> : mk_place_elems, - CanonicalVarInfos<'tcx> : mk_canonical_var_infos, + &'tcx ty::List> : mk_patterns, } diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 8c5827d36df1..c6a45f846869 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -716,6 +716,8 @@ pub type CanonicalUserTypeAnnotations<'tcx> = #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub struct CanonicalUserTypeAnnotation<'tcx> { + #[type_foldable(identity)] + #[type_visitable(ignore)] pub user_ty: Box>, pub span: Span, pub inferred_ty: Ty<'tcx>, diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs index 5115583f37c0..8f88613b79f3 100644 --- a/compiler/rustc_mir_transform/src/check_alignment.rs +++ b/compiler/rustc_mir_transform/src/check_alignment.rs @@ -6,7 +6,7 @@ use rustc_middle::mir::*; use rustc_middle::ty::{Ty, TyCtxt}; use rustc_session::Session; -use crate::check_pointers::{BorrowCheckMode, PointerCheck, check_pointers}; +use crate::check_pointers::{BorrowedFieldProjectionMode, PointerCheck, check_pointers}; pub(super) struct CheckAlignment; @@ -19,15 +19,15 @@ impl<'tcx> crate::MirPass<'tcx> for CheckAlignment { // Skip trivially aligned place types. let excluded_pointees = [tcx.types.bool, tcx.types.i8, tcx.types.u8]; - // We have to exclude borrows here: in `&x.field`, the exact - // requirement is that the final reference must be aligned, but - // `check_pointers` would check that `x` is aligned, which would be wrong. + // When checking the alignment of references to field projections (`&(*ptr).a`), + // we need to make sure that the reference is aligned according to the field type + // and not to the pointer type. check_pointers( tcx, body, &excluded_pointees, insert_alignment_check, - BorrowCheckMode::ExcludeBorrows, + BorrowedFieldProjectionMode::FollowProjections, ); } diff --git a/compiler/rustc_mir_transform/src/check_null.rs b/compiler/rustc_mir_transform/src/check_null.rs index 543e1845e655..ad74e335bd9e 100644 --- a/compiler/rustc_mir_transform/src/check_null.rs +++ b/compiler/rustc_mir_transform/src/check_null.rs @@ -4,7 +4,7 @@ use rustc_middle::mir::*; use rustc_middle::ty::{Ty, TyCtxt}; use rustc_session::Session; -use crate::check_pointers::{BorrowCheckMode, PointerCheck, check_pointers}; +use crate::check_pointers::{BorrowedFieldProjectionMode, PointerCheck, check_pointers}; pub(super) struct CheckNull; @@ -14,7 +14,13 @@ impl<'tcx> crate::MirPass<'tcx> for CheckNull { } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - check_pointers(tcx, body, &[], insert_null_check, BorrowCheckMode::IncludeBorrows); + check_pointers( + tcx, + body, + &[], + insert_null_check, + BorrowedFieldProjectionMode::NoFollowProjections, + ); } fn is_required(&self) -> bool { diff --git a/compiler/rustc_mir_transform/src/check_pointers.rs b/compiler/rustc_mir_transform/src/check_pointers.rs index 2d04b6219358..bf94f1aad24b 100644 --- a/compiler/rustc_mir_transform/src/check_pointers.rs +++ b/compiler/rustc_mir_transform/src/check_pointers.rs @@ -12,13 +12,13 @@ pub(crate) struct PointerCheck<'tcx> { pub(crate) assert_kind: Box>>, } -/// Indicates whether we insert the checks for borrow places of a raw pointer. -/// Concretely places with [MutatingUseContext::Borrow] or -/// [NonMutatingUseContext::SharedBorrow]. +/// When checking for borrows of field projections (`&(*ptr).a`), we might want +/// to check for the field type (type of `.a` in the example). This enum defines +/// the variations (pass the pointer [Ty] or the field [Ty]). #[derive(Copy, Clone)] -pub(crate) enum BorrowCheckMode { - IncludeBorrows, - ExcludeBorrows, +pub(crate) enum BorrowedFieldProjectionMode { + FollowProjections, + NoFollowProjections, } /// Utility for adding a check for read/write on every sized, raw pointer. @@ -27,8 +27,8 @@ pub(crate) enum BorrowCheckMode { /// new basic block directly before the pointer access. (Read/write accesses /// are determined by the `PlaceContext` of the MIR visitor.) Then calls /// `on_finding` to insert the actual logic for a pointer check (e.g. check for -/// alignment). A check can choose to be inserted for (mutable) borrows of -/// raw pointers via the `borrow_check_mode` parameter. +/// alignment). A check can choose to follow borrows of field projections via +/// the `field_projection_mode` parameter. /// /// This utility takes care of the right order of blocks, the only thing a /// caller must do in `on_finding` is: @@ -45,7 +45,7 @@ pub(crate) fn check_pointers<'tcx, F>( body: &mut Body<'tcx>, excluded_pointees: &[Ty<'tcx>], on_finding: F, - borrow_check_mode: BorrowCheckMode, + field_projection_mode: BorrowedFieldProjectionMode, ) where F: Fn( /* tcx: */ TyCtxt<'tcx>, @@ -82,7 +82,7 @@ pub(crate) fn check_pointers<'tcx, F>( local_decls, typing_env, excluded_pointees, - borrow_check_mode, + field_projection_mode, ); finder.visit_statement(statement, location); @@ -128,7 +128,7 @@ struct PointerFinder<'a, 'tcx> { typing_env: ty::TypingEnv<'tcx>, pointers: Vec<(Place<'tcx>, Ty<'tcx>, PlaceContext)>, excluded_pointees: &'a [Ty<'tcx>], - borrow_check_mode: BorrowCheckMode, + field_projection_mode: BorrowedFieldProjectionMode, } impl<'a, 'tcx> PointerFinder<'a, 'tcx> { @@ -137,7 +137,7 @@ impl<'a, 'tcx> PointerFinder<'a, 'tcx> { local_decls: &'a mut LocalDecls<'tcx>, typing_env: ty::TypingEnv<'tcx>, excluded_pointees: &'a [Ty<'tcx>], - borrow_check_mode: BorrowCheckMode, + field_projection_mode: BorrowedFieldProjectionMode, ) -> Self { PointerFinder { tcx, @@ -145,7 +145,7 @@ impl<'a, 'tcx> PointerFinder<'a, 'tcx> { typing_env, excluded_pointees, pointers: Vec::new(), - borrow_check_mode, + field_projection_mode, } } @@ -163,15 +163,14 @@ impl<'a, 'tcx> PointerFinder<'a, 'tcx> { MutatingUseContext::Store | MutatingUseContext::Call | MutatingUseContext::Yield - | MutatingUseContext::Drop, + | MutatingUseContext::Drop + | MutatingUseContext::Borrow, ) => true, PlaceContext::NonMutatingUse( - NonMutatingUseContext::Copy | NonMutatingUseContext::Move, + NonMutatingUseContext::Copy + | NonMutatingUseContext::Move + | NonMutatingUseContext::SharedBorrow, ) => true, - PlaceContext::MutatingUse(MutatingUseContext::Borrow) - | PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) => { - matches!(self.borrow_check_mode, BorrowCheckMode::IncludeBorrows) - } _ => false, } } @@ -183,19 +182,29 @@ impl<'a, 'tcx> Visitor<'tcx> for PointerFinder<'a, 'tcx> { return; } - // Since Deref projections must come first and only once, the pointer for an indirect place - // is the Local that the Place is based on. + // Get the place and type we visit. let pointer = Place::from(place.local); - let pointer_ty = self.local_decls[place.local].ty; + let pointer_ty = pointer.ty(self.local_decls, self.tcx).ty; // We only want to check places based on raw pointers - if !pointer_ty.is_raw_ptr() { + let &ty::RawPtr(mut pointee_ty, _) = pointer_ty.kind() else { trace!("Indirect, but not based on an raw ptr, not checking {:?}", place); return; + }; + + // If we see a borrow of a field projection, we want to pass the field type to the + // check and not the pointee type. + if matches!(self.field_projection_mode, BorrowedFieldProjectionMode::FollowProjections) + && matches!( + context, + PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) + | PlaceContext::MutatingUse(MutatingUseContext::Borrow) + ) + { + // Naturally, the field type is type of the initial place we look at. + pointee_ty = place.ty(self.local_decls, self.tcx).ty; } - let pointee_ty = - pointer_ty.builtin_deref(true).expect("no builtin_deref for an raw pointer"); // Ideally we'd support this in the future, but for now we are limited to sized types. if !pointee_ty.is_sized(self.tcx, self.typing_env) { trace!("Raw pointer, but pointee is not known to be sized: {:?}", pointer_ty); @@ -207,6 +216,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PointerFinder<'a, 'tcx> { ty::Array(ty, _) => *ty, _ => pointee_ty, }; + // Check if we excluded this pointee type from the check. if self.excluded_pointees.contains(&element_ty) { trace!("Skipping pointer for type: {:?}", pointee_ty); return; diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs index 6f867f8105d5..73a58160a6aa 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drop.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs @@ -376,7 +376,7 @@ where if self.tcx().features().async_drop() && self.elaborator.body().coroutine.is_some() && self.elaborator.allow_async_drops() - && !self.elaborator.body()[bb].is_cleanup + && !self.elaborator.patch_ref().block(self.elaborator.body(), bb).is_cleanup && drop_ty.needs_async_drop(self.tcx(), self.elaborator.typing_env()) { self.build_async_drop( diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 9732225e48dd..ada2c0b76cf7 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -177,16 +177,8 @@ impl<'a> ConditionSet<'a> { arena: &'a DroplessArena, f: impl Fn(Condition) -> Option, ) -> Option> { - let mut all_ok = true; - let set = arena.alloc_from_iter(self.iter().map_while(|c| { - if let Some(c) = f(c) { - Some(c) - } else { - all_ok = false; - None - } - })); - all_ok.then_some(ConditionSet(set)) + let set = arena.try_alloc_from_iter(self.iter().map(|c| f(c).ok_or(()))).ok()?; + Some(ConditionSet(set)) } } diff --git a/compiler/rustc_mir_transform/src/patch.rs b/compiler/rustc_mir_transform/src/patch.rs index c7eb2a921c73..a872eae15f18 100644 --- a/compiler/rustc_mir_transform/src/patch.rs +++ b/compiler/rustc_mir_transform/src/patch.rs @@ -148,11 +148,20 @@ impl<'tcx> MirPatch<'tcx> { self.term_patch_map[bb].is_some() } + /// Universal getter for block data, either it is in 'old' blocks or in patched ones + pub(crate) fn block<'a>( + &'a self, + body: &'a Body<'tcx>, + bb: BasicBlock, + ) -> &'a BasicBlockData<'tcx> { + match bb.index().checked_sub(body.basic_blocks.len()) { + Some(new) => &self.new_blocks[new], + None => &body[bb], + } + } + pub(crate) fn terminator_loc(&self, body: &Body<'tcx>, bb: BasicBlock) -> Location { - let offset = match bb.index().checked_sub(body.basic_blocks.len()) { - Some(index) => self.new_blocks[index].statements.len(), - None => body[bb].statements.len(), - }; + let offset = self.block(body, bb).statements.len(); Location { block: bb, statement_index: offset } } @@ -284,10 +293,7 @@ impl<'tcx> MirPatch<'tcx> { } pub(crate) fn source_info_for_location(&self, body: &Body<'tcx>, loc: Location) -> SourceInfo { - let data = match loc.block.index().checked_sub(body.basic_blocks.len()) { - Some(new) => &self.new_blocks[new], - None => &body[loc.block], - }; + let data = self.block(body, loc.block); Self::source_info_for_index(data, loc) } } 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 035bfff89b53..b16f74cd8e43 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 @@ -724,6 +724,9 @@ pub(in crate::solve) fn const_conditions_for_destruct( let destruct_def_id = cx.require_lang_item(TraitSolverLangItem::Destruct); match self_ty.kind() { + // `ManuallyDrop` is trivially `~const Destruct` as we do not run any drop glue on it. + ty::Adt(adt_def, _) if adt_def.is_manually_drop() => Ok(vec![]), + // An ADT is `~const Destruct` only if all of the fields are, // *and* if there is a `Drop` impl, that `Drop` impl is also `~const`. ty::Adt(adt_def, args) => { diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index e73d68e2037a..d06922f1e047 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -5,13 +5,13 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] #![cfg_attr(bootstrap, feature(let_chains))] -#![feature(array_windows)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(debug_closure_helpers)] #![feature(if_let_guard)] #![feature(iter_intersperse)] #![feature(string_from_utf8_lossy_owned)] +#![recursion_limit = "256"] // tidy-alphabetical-end use std::path::{Path, PathBuf}; diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index 53614049f087..41d3889c4483 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -1,5 +1,6 @@ use rustc_ast as ast; use rustc_ast::token::{self, MetaVarKind}; +use rustc_ast::tokenstream::ParserRange; use rustc_ast::{Attribute, attr}; use rustc_errors::codes::*; use rustc_errors::{Diag, PResult}; @@ -8,8 +9,7 @@ use thin_vec::ThinVec; use tracing::debug; use super::{ - AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, ParserRange, PathStyle, Trailing, - UsePreAttrPos, + AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, PathStyle, Trailing, UsePreAttrPos, }; use crate::{errors, exp, fluent_generated as fluent}; diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 6061c9cb4856..44fdf146f9c7 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -1,21 +1,18 @@ use std::borrow::Cow; -use std::{iter, mem}; +use std::mem; -use rustc_ast::token::{Delimiter, Token}; +use rustc_ast::token::Token; use rustc_ast::tokenstream::{ - AttrTokenStream, AttrTokenTree, AttrsTarget, DelimSpacing, DelimSpan, LazyAttrTokenStream, - Spacing, ToAttrTokenStream, + AttrsTarget, LazyAttrTokenStream, NodeRange, ParserRange, Spacing, TokenCursor, }; use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, HasTokens}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::PResult; use rustc_session::parse::ParseSess; -use rustc_span::{DUMMY_SP, Span, sym}; +use rustc_span::{DUMMY_SP, sym}; +use thin_vec::ThinVec; -use super::{ - Capturing, FlatToken, ForceCollect, NodeRange, NodeReplacement, Parser, ParserRange, - TokenCursor, Trailing, -}; +use super::{Capturing, ForceCollect, Parser, Trailing}; // When collecting tokens, this fully captures the start point. Usually its // just after outer attributes, but occasionally it's before. @@ -94,95 +91,6 @@ fn has_cfg_or_cfg_attr(attrs: &[Attribute]) -> bool { }) } -// From a value of this type we can reconstruct the `TokenStream` seen by the -// `f` callback passed to a call to `Parser::collect_tokens`, by -// replaying the getting of the tokens. This saves us producing a `TokenStream` -// if it is never needed, e.g. a captured `macro_rules!` argument that is never -// passed to a proc macro. In practice, token stream creation happens rarely -// compared to calls to `collect_tokens` (see some statistics in #78736) so we -// are doing as little up-front work as possible. -// -// This also makes `Parser` very cheap to clone, since -// there is no intermediate collection buffer to clone. -struct LazyAttrTokenStreamImpl { - start_token: (Token, Spacing), - cursor_snapshot: TokenCursor, - num_calls: u32, - break_last_token: u32, - node_replacements: Box<[NodeReplacement]>, -} - -impl ToAttrTokenStream for LazyAttrTokenStreamImpl { - fn to_attr_token_stream(&self) -> AttrTokenStream { - // The token produced by the final call to `{,inlined_}next` was not - // actually consumed by the callback. The combination of chaining the - // initial token and using `take` produces the desired result - we - // produce an empty `TokenStream` if no calls were made, and omit the - // final token otherwise. - let mut cursor_snapshot = self.cursor_snapshot.clone(); - let tokens = iter::once(FlatToken::Token(self.start_token)) - .chain(iter::repeat_with(|| FlatToken::Token(cursor_snapshot.next()))) - .take(self.num_calls as usize); - - if self.node_replacements.is_empty() { - make_attr_token_stream(tokens, self.break_last_token) - } else { - let mut tokens: Vec<_> = tokens.collect(); - let mut node_replacements = self.node_replacements.to_vec(); - node_replacements.sort_by_key(|(range, _)| range.0.start); - - #[cfg(debug_assertions)] - for [(node_range, tokens), (next_node_range, next_tokens)] in - node_replacements.array_windows() - { - assert!( - node_range.0.end <= next_node_range.0.start - || node_range.0.end >= next_node_range.0.end, - "Node ranges should be disjoint or nested: ({:?}, {:?}) ({:?}, {:?})", - node_range, - tokens, - next_node_range, - next_tokens, - ); - } - - // Process the replace ranges, starting from the highest start - // position and working our way back. If have tokens like: - // - // `#[cfg(FALSE)] struct Foo { #[cfg(FALSE)] field: bool }` - // - // Then we will generate replace ranges for both - // the `#[cfg(FALSE)] field: bool` and the entire - // `#[cfg(FALSE)] struct Foo { #[cfg(FALSE)] field: bool }` - // - // By starting processing from the replace range with the greatest - // start position, we ensure that any (outer) replace range which - // encloses another (inner) replace range will fully overwrite the - // inner range's replacement. - for (node_range, target) in node_replacements.into_iter().rev() { - assert!( - !node_range.0.is_empty(), - "Cannot replace an empty node range: {:?}", - node_range.0 - ); - - // Replace the tokens in range with zero or one `FlatToken::AttrsTarget`s, plus - // enough `FlatToken::Empty`s to fill up the rest of the range. This keeps the - // total length of `tokens` constant throughout the replacement process, allowing - // us to do all replacements without adjusting indices. - let target_len = target.is_some() as usize; - tokens.splice( - (node_range.0.start as usize)..(node_range.0.end as usize), - target.into_iter().map(|target| FlatToken::AttrsTarget(target)).chain( - iter::repeat(FlatToken::Empty).take(node_range.0.len() - target_len), - ), - ); - } - make_attr_token_stream(tokens.into_iter(), self.break_last_token) - } - } -} - impl<'a> Parser<'a> { pub(super) fn collect_pos(&self) -> CollectPos { CollectPos { @@ -387,10 +295,10 @@ impl<'a> Parser<'a> { // This is hot enough for `deep-vector` that checking the conditions for an empty iterator // is measurably faster than actually executing the iterator. - let node_replacements: Box<[_]> = if parser_replacements_start == parser_replacements_end + let node_replacements = if parser_replacements_start == parser_replacements_end && inner_attr_parser_replacements.is_empty() { - Box::new([]) + ThinVec::new() } else { // Grab any replace ranges that occur *inside* the current AST node. Convert them // from `ParserRange` form to `NodeRange` form. We will perform the actual @@ -429,13 +337,13 @@ impl<'a> Parser<'a> { // - `attrs`: includes the outer and the inner attr. // - `tokens`: lazy tokens for `g` (with its inner attr deleted). - let tokens = LazyAttrTokenStream::new(LazyAttrTokenStreamImpl { - start_token: collect_pos.start_token, - cursor_snapshot: collect_pos.cursor_snapshot, + let tokens = LazyAttrTokenStream::new_pending( + collect_pos.start_token, + collect_pos.cursor_snapshot, num_calls, - break_last_token: self.break_last_token, + self.break_last_token, node_replacements, - }); + ); let mut tokens_used = false; // If in "definite capture mode" we need to register a replace range @@ -483,71 +391,6 @@ impl<'a> Parser<'a> { } } -/// Converts a flattened iterator of tokens (including open and close delimiter tokens) into an -/// `AttrTokenStream`, creating an `AttrTokenTree::Delimited` for each matching pair of open and -/// close delims. -fn make_attr_token_stream( - iter: impl Iterator, - break_last_token: u32, -) -> AttrTokenStream { - #[derive(Debug)] - struct FrameData { - // This is `None` for the first frame, `Some` for all others. - open_delim_sp: Option<(Delimiter, Span, Spacing)>, - inner: Vec, - } - // The stack always has at least one element. Storing it separately makes for shorter code. - let mut stack_top = FrameData { open_delim_sp: None, inner: vec![] }; - let mut stack_rest = vec![]; - for flat_token in iter { - match flat_token { - FlatToken::Token((token @ Token { kind, span }, spacing)) => { - if let Some(delim) = kind.open_delim() { - stack_rest.push(mem::replace( - &mut stack_top, - FrameData { open_delim_sp: Some((delim, span, spacing)), inner: vec![] }, - )); - } else if let Some(delim) = kind.close_delim() { - let frame_data = mem::replace(&mut stack_top, stack_rest.pop().unwrap()); - let (open_delim, open_sp, open_spacing) = frame_data.open_delim_sp.unwrap(); - assert!( - open_delim.eq_ignoring_invisible_origin(&delim), - "Mismatched open/close delims: open={open_delim:?} close={span:?}" - ); - let dspan = DelimSpan::from_pair(open_sp, span); - let dspacing = DelimSpacing::new(open_spacing, spacing); - let stream = AttrTokenStream::new(frame_data.inner); - let delimited = AttrTokenTree::Delimited(dspan, dspacing, delim, stream); - stack_top.inner.push(delimited); - } else { - stack_top.inner.push(AttrTokenTree::Token(token, spacing)) - } - } - FlatToken::AttrsTarget(target) => { - stack_top.inner.push(AttrTokenTree::AttrsTarget(target)) - } - FlatToken::Empty => {} - } - } - - if break_last_token > 0 { - let last_token = stack_top.inner.pop().unwrap(); - if let AttrTokenTree::Token(last_token, spacing) = last_token { - let (unglued, _) = last_token.kind.break_two_token_op(break_last_token).unwrap(); - - // Tokens are always ASCII chars, so we can use byte arithmetic here. - let mut first_span = last_token.span.shrink_to_lo(); - first_span = - first_span.with_hi(first_span.lo() + rustc_span::BytePos(break_last_token)); - - stack_top.inner.push(AttrTokenTree::Token(Token::new(unglued, first_span), spacing)); - } else { - panic!("Unexpected last token {last_token:?}") - } - } - AttrTokenStream::new(stack_top.inner) -} - /// Tokens are needed if: /// - any non-single-segment attributes (other than doc comments) are present, /// e.g. `rustfmt::skip`; or @@ -562,14 +405,3 @@ fn needs_tokens(attrs: &[ast::Attribute]) -> bool { } }) } - -// 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!(LazyAttrTokenStreamImpl, 96); - // tidy-alphabetical-end -} diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 48df8b59d55a..968376678f3b 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -12,7 +12,6 @@ pub mod token_type; mod ty; use std::assert_matches::debug_assert_matches; -use std::ops::Range; use std::{fmt, mem, slice}; use attr_wrapper::{AttrWrapper, UsePreAttrPos}; @@ -25,7 +24,9 @@ use rustc_ast::ptr::P; use rustc_ast::token::{ self, IdentIsRaw, InvisibleOrigin, MetaVarKind, NtExprKind, NtPatKind, Token, TokenKind, }; -use rustc_ast::tokenstream::{AttrsTarget, Spacing, TokenStream, TokenTree}; +use rustc_ast::tokenstream::{ + ParserRange, ParserReplacement, Spacing, TokenCursor, TokenStream, TokenTree, TokenTreeCursor, +}; use rustc_ast::util::case::Case; use rustc_ast::{ self as ast, AnonConst, AttrArgs, AttrId, ByRef, Const, CoroutineKind, DUMMY_NODE_ID, @@ -37,7 +38,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, Diag, FatalError, MultiSpan, PResult}; use rustc_index::interval::IntervalSet; use rustc_session::parse::ParseSess; -use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; +use rustc_span::{Ident, Span, Symbol, kw, sym}; use thin_vec::ThinVec; use token_type::TokenTypeSet; pub use token_type::{ExpKeywordPair, ExpTokenPair, TokenType}; @@ -55,19 +56,64 @@ mod tests; mod tokenstream { mod tests; } -#[cfg(test)] -mod mut_visit { - mod tests; -} bitflags::bitflags! { + /// Restrictions applied while parsing. + /// + /// The parser maintains a bitset of restrictions it will honor while + /// parsing. This is essentially used as a way of tracking state of what + /// is being parsed and to change behavior based on that. #[derive(Clone, Copy, Debug)] struct Restrictions: u8 { + /// Restricts expressions for use in statement position. + /// + /// When expressions are used in various places, like statements or + /// match arms, this is used to stop parsing once certain tokens are + /// reached. + /// + /// For example, `if true {} & 1` with `STMT_EXPR` in effect is parsed + /// as two separate expression statements (`if` and a reference to 1). + /// Otherwise it is parsed as a bitwise AND where `if` is on the left + /// and 1 is on the right. const STMT_EXPR = 1 << 0; + /// Do not allow struct literals. + /// + /// There are several places in the grammar where we don't want to + /// allow struct literals because they can require lookahead, or + /// otherwise could be ambiguous or cause confusion. For example, + /// `if Foo {} {}` isn't clear if it is `Foo{}` struct literal, or + /// just `Foo` is the condition, followed by a consequent block, + /// followed by an empty block. + /// + /// See [RFC 92](https://rust-lang.github.io/rfcs/0092-struct-grammar.html). const NO_STRUCT_LITERAL = 1 << 1; + /// Used to provide better error messages for const generic arguments. + /// + /// An un-braced const generic argument is limited to a very small + /// subset of expressions. This is used to detect the situation where + /// an expression outside of that subset is used, and to suggest to + /// wrap the expression in braces. const CONST_EXPR = 1 << 2; + /// Allows `let` expressions. + /// + /// `let pattern = scrutinee` is parsed as an expression, but it is + /// only allowed in let chains (`if` and `while` conditions). + /// Otherwise it is not an expression (note that `let` in statement + /// positions is treated as a `StmtKind::Let` statement, which has a + /// slightly different grammar). const ALLOW_LET = 1 << 3; + /// Used to detect a missing `=>` in a match guard. + /// + /// This is used for error handling in a match guard to give a better + /// error message if the `=>` is missing. It is set when parsing the + /// guard expression. const IN_IF_GUARD = 1 << 4; + /// Used to detect the incorrect use of expressions in patterns. + /// + /// This is used for error handling while parsing a pattern. During + /// error recovery, this will be set to try to parse the pattern as an + /// expression, but halts parsing the expression when reaching certain + /// tokens like `=`. const IS_PAT = 1 << 5; } } @@ -187,57 +233,6 @@ struct ClosureSpans { body: Span, } -/// A token range within a `Parser`'s full token stream. -#[derive(Clone, Debug)] -struct ParserRange(Range); - -/// A token range within an individual AST node's (lazy) token stream, i.e. -/// relative to that node's first token. Distinct from `ParserRange` so the two -/// kinds of range can't be mixed up. -#[derive(Clone, Debug)] -struct NodeRange(Range); - -/// Indicates a range of tokens that should be replaced by an `AttrsTarget` -/// (replacement) or be replaced by nothing (deletion). This is used in two -/// places during token collection. -/// -/// 1. Replacement. During the parsing of an AST node that may have a -/// `#[derive]` attribute, when we parse a nested AST node that has `#[cfg]` -/// or `#[cfg_attr]`, we replace the entire inner AST node with -/// `FlatToken::AttrsTarget`. This lets us perform eager cfg-expansion on an -/// `AttrTokenStream`. -/// -/// 2. Deletion. We delete inner attributes from all collected token streams, -/// and instead track them through the `attrs` field on the AST node. This -/// lets us manipulate them similarly to outer attributes. When we create a -/// `TokenStream`, the inner attributes are inserted into the proper place -/// in the token stream. -/// -/// Each replacement starts off in `ParserReplacement` form but is converted to -/// `NodeReplacement` form when it is attached to a single AST node, via -/// `LazyAttrTokenStreamImpl`. -type ParserReplacement = (ParserRange, Option); - -/// See the comment on `ParserReplacement`. -type NodeReplacement = (NodeRange, Option); - -impl NodeRange { - // Converts a range within a parser's tokens to a range within a - // node's tokens beginning at `start_pos`. - // - // For example, imagine a parser with 50 tokens in its token stream, a - // function that spans `ParserRange(20..40)` and an inner attribute within - // that function that spans `ParserRange(30..35)`. We would find the inner - // attribute's range within the function's tokens by subtracting 20, which - // is the position of the function's start token. This gives - // `NodeRange(10..15)`. - fn new(ParserRange(parser_range): ParserRange, start_pos: u32) -> NodeRange { - assert!(!parser_range.is_empty()); - assert!(parser_range.start >= start_pos); - NodeRange((parser_range.start - start_pos)..(parser_range.end - start_pos)) - } -} - /// Controls how we capture tokens. Capturing can be expensive, /// so we try to avoid performing capturing in cases where /// we will never need an `AttrTokenStream`. @@ -260,104 +255,6 @@ struct CaptureState { seen_attrs: IntervalSet, } -#[derive(Clone, Debug)] -struct TokenTreeCursor { - stream: TokenStream, - /// Points to the current token tree in the stream. In `TokenCursor::curr`, - /// this can be any token tree. In `TokenCursor::stack`, this is always a - /// `TokenTree::Delimited`. - index: usize, -} - -impl TokenTreeCursor { - #[inline] - fn new(stream: TokenStream) -> Self { - TokenTreeCursor { stream, index: 0 } - } - - #[inline] - fn curr(&self) -> Option<&TokenTree> { - self.stream.get(self.index) - } - - fn look_ahead(&self, n: usize) -> Option<&TokenTree> { - self.stream.get(self.index + n) - } - - #[inline] - fn bump(&mut self) { - self.index += 1; - } -} - -/// A `TokenStream` cursor that produces `Token`s. It's a bit odd that -/// we (a) lex tokens into a nice tree structure (`TokenStream`), and then (b) -/// use this type to emit them as a linear sequence. But a linear sequence is -/// what the parser expects, for the most part. -#[derive(Clone, Debug)] -struct TokenCursor { - // Cursor for the current (innermost) token stream. The index within the - // cursor can point to any token tree in the stream (or one past the end). - // The delimiters for this token stream are found in `self.stack.last()`; - // if that is `None` we are in the outermost token stream which never has - // delimiters. - curr: TokenTreeCursor, - - // Token streams surrounding the current one. The index within each cursor - // always points to a `TokenTree::Delimited`. - stack: Vec, -} - -impl TokenCursor { - fn next(&mut self) -> (Token, Spacing) { - self.inlined_next() - } - - /// This always-inlined version should only be used on hot code paths. - #[inline(always)] - fn inlined_next(&mut self) -> (Token, Spacing) { - loop { - // FIXME: we currently don't return `Delimiter::Invisible` open/close delims. To fix - // #67062 we will need to, whereupon the `delim != Delimiter::Invisible` conditions - // below can be removed. - if let Some(tree) = self.curr.curr() { - match tree { - &TokenTree::Token(token, spacing) => { - debug_assert!(!token.kind.is_delim()); - let res = (token, spacing); - self.curr.bump(); - return res; - } - &TokenTree::Delimited(sp, spacing, delim, ref tts) => { - let trees = TokenTreeCursor::new(tts.clone()); - self.stack.push(mem::replace(&mut self.curr, trees)); - if !delim.skip() { - return (Token::new(delim.as_open_token_kind(), sp.open), spacing.open); - } - // No open delimiter to return; continue on to the next iteration. - } - }; - } else if let Some(parent) = self.stack.pop() { - // We have exhausted this token stream. Move back to its parent token stream. - let Some(&TokenTree::Delimited(span, spacing, delim, _)) = parent.curr() else { - panic!("parent should be Delimited") - }; - self.curr = parent; - self.curr.bump(); // move past the `Delimited` - if !delim.skip() { - return (Token::new(delim.as_close_token_kind(), span.close), spacing.close); - } - // No close delimiter to return; continue on to the next iteration. - } else { - // We have exhausted the outermost token stream. The use of - // `Spacing::Alone` is arbitrary and immaterial, because the - // `Eof` token's spacing is never used. - return (Token::new(token::Eof, DUMMY_SP), Spacing::Alone); - } - } - } -} - /// A sequence separator. #[derive(Debug)] struct SeqSep<'a> { @@ -1742,26 +1639,6 @@ impl<'a> Parser<'a> { } } -/// A helper struct used when building an `AttrTokenStream` from -/// a `LazyAttrTokenStream`. Both delimiter and non-delimited tokens -/// are stored as `FlatToken::Token`. A vector of `FlatToken`s -/// is then 'parsed' to build up an `AttrTokenStream` with nested -/// `AttrTokenTree::Delimited` tokens. -#[derive(Debug, Clone)] -enum FlatToken { - /// A token - this holds both delimiter (e.g. '{' and '}') - /// and non-delimiter tokens - Token((Token, Spacing)), - /// Holds the `AttrsTarget` for an AST node. The `AttrsTarget` is inserted - /// directly into the constructed `AttrTokenStream` as an - /// `AttrTokenTree::AttrsTarget`. - AttrsTarget(AttrsTarget), - /// A special 'empty' token that is ignored during the conversion - /// to an `AttrTokenStream`. This is used to simplify the - /// handling of replace ranges. - Empty, -} - // Metavar captures of various kinds. #[derive(Clone, Debug)] pub enum ParseNtResult { diff --git a/compiler/rustc_parse/src/parser/mut_visit/tests.rs b/compiler/rustc_parse/src/parser/mut_visit/tests.rs deleted file mode 100644 index 46c678c39026..000000000000 --- a/compiler/rustc_parse/src/parser/mut_visit/tests.rs +++ /dev/null @@ -1,65 +0,0 @@ -use rustc_ast as ast; -use rustc_ast::mut_visit::MutVisitor; -use rustc_ast_pretty::pprust; -use rustc_span::{Ident, create_default_session_globals_then}; - -use crate::parser::tests::{matches_codepattern, string_to_crate}; - -// This version doesn't care about getting comments or doc-strings in. -fn print_crate_items(krate: &ast::Crate) -> String { - krate.items.iter().map(|i| pprust::item_to_string(i)).collect::>().join(" ") -} - -// Change every identifier to "zz". -struct ToZzIdentMutVisitor; - -impl MutVisitor for ToZzIdentMutVisitor { - const VISIT_TOKENS: bool = true; - - fn visit_ident(&mut self, ident: &mut Ident) { - *ident = Ident::from_str("zz"); - } -} - -macro_rules! assert_matches_codepattern { - ($a:expr , $b:expr) => {{ - let a_val = $a; - let b_val = $b; - if !matches_codepattern(&a_val, &b_val) { - panic!("expected args satisfying `matches_codepattern`, got {} and {}", a_val, b_val); - } - }}; -} - -// Make sure idents get transformed everywhere. -#[test] -fn ident_transformation() { - create_default_session_globals_then(|| { - let mut zz_visitor = ToZzIdentMutVisitor; - let mut krate = - string_to_crate("#[a] mod b {fn c (d : e, f : g) {h!(i,j,k);l;m}}".to_string()); - zz_visitor.visit_crate(&mut krate); - assert_matches_codepattern!( - print_crate_items(&krate), - "#[zz]mod zz{fn zz(zz:zz,zz:zz){zz!(zz,zz,zz);zz;zz}}".to_string() - ); - }) -} - -// Make sure idents get transformed even inside macro defs. -#[test] -fn ident_transformation_in_defs() { - create_default_session_globals_then(|| { - let mut zz_visitor = ToZzIdentMutVisitor; - let mut krate = string_to_crate( - "macro_rules! a {(b $c:expr $(d $e:token)f+ => \ - (g $(d $d $e)+))} " - .to_string(), - ); - zz_visitor.visit_crate(&mut krate); - assert_matches_codepattern!( - print_crate_items(&krate), - "macro_rules! zz{(zz$zz:zz$(zz $zz:zz)zz+=>(zz$(zz$zz$zz)+))}".to_string() - ); - }) -} diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs index 8285070839aa..2a44c90abc17 100644 --- a/compiler/rustc_parse/src/parser/tests.rs +++ b/compiler/rustc_parse/src/parser/tests.rs @@ -95,12 +95,6 @@ pub(crate) fn string_to_stream(source_str: String) -> TokenStream { )) } -/// Parses a string, returns a crate. -pub(crate) fn string_to_crate(source_str: String) -> ast::Crate { - let psess = psess(); - with_error_checking_parse(source_str, &psess, |p| p.parse_crate_mod()) -} - /// Does the given string match the pattern? whitespace in the first string /// may be deleted or replaced with other whitespace to match the pattern. /// This function is relatively Unicode-ignorant; fortunately, the careful design diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 3c329dd0a0e8..b7d8af2c995b 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -234,7 +234,7 @@ pub fn query_system<'a>( } } -rustc_middle::rustc_query_append! { define_queries! } +rustc_middle::rustc_with_all_queries! { define_queries! } pub fn provide(providers: &mut rustc_middle::util::Providers) { providers.hooks.alloc_self_profile_query_strings = alloc_self_profile_query_strings; diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 19ccc5587d6a..d11fa8bad9be 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -575,11 +575,14 @@ where } // NOTE: `$V` isn't used here, but we still need to match on it so it can be passed to other macros -// invoked by `rustc_query_append`. +// invoked by `rustc_with_all_queries`. macro_rules! define_queries { ( - $($(#[$attr:meta])* - [$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => { + $( + $(#[$attr:meta])* + [$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty, + )* + ) => { pub(crate) mod query_impl { $(pub(crate) mod $name { use super::super::*; diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index bae2fdeecafc..faee0e7dd5ff 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -958,6 +958,11 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r self.resolve_anon_const(end, AnonConstKind::ConstArg(IsRepeatExpr::No)); } } + TyPatKind::Or(patterns) => { + for pat in patterns { + self.visit_ty_pat(pat) + } + } TyPatKind::Err(_) => {} } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 4a252a7b5281..d2da3ac7d86f 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -19,6 +19,7 @@ #![feature(iter_intersperse)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] +#![recursion_limit = "256"] // tidy-alphabetical-end use std::cell::{Cell, RefCell}; diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index 76489dd0913c..8bcac4c4678e 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -412,6 +412,7 @@ impl<'tcx> Stable<'tcx> for ty::Pattern<'tcx> { end: Some(end.stable(tables)), include_end: true, }, + ty::PatternKind::Or(_) => todo!(), } } } diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 9f80f8443cbd..f8f2714ee42d 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -253,6 +253,22 @@ impl<'tcx> SymbolMangler<'tcx> { Ok(()) } + + fn print_pat(&mut self, pat: ty::Pattern<'tcx>) -> Result<(), std::fmt::Error> { + Ok(match *pat { + ty::PatternKind::Range { start, end } => { + let consts = [start, end]; + for ct in consts { + Ty::new_array_with_const_len(self.tcx, self.tcx.types.unit, ct).print(self)?; + } + } + ty::PatternKind::Or(patterns) => { + for pat in patterns { + self.print_pat(pat)?; + } + } + }) + } } impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { @@ -469,20 +485,14 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { ty.print(self)?; } - ty::Pat(ty, pat) => match *pat { - ty::PatternKind::Range { start, end } => { - let consts = [start, end]; - // HACK: Represent as tuple until we have something better. - // HACK: constants are used in arrays, even if the types don't match. - self.push("T"); - ty.print(self)?; - for ct in consts { - Ty::new_array_with_const_len(self.tcx, self.tcx.types.unit, ct) - .print(self)?; - } - self.push("E"); - } - }, + ty::Pat(ty, pat) => { + // HACK: Represent as tuple until we have something better. + // HACK: constants are used in arrays, even if the types don't match. + self.push("T"); + ty.print(self)?; + self.print_pat(pat)?; + self.push("E"); + } ty::Array(ty, len) => { self.push("A"); diff --git a/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_gnueabi.rs index 52e786de3ed9..7b93672dbe0f 100644 --- a/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_gnueabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_gnueabi.rs @@ -20,6 +20,7 @@ pub(crate) fn target() -> Target { max_atomic_width: Some(32), mcount: "\u{1}__gnu_mcount_nc".into(), has_thumb_interworking: true, + llvm_mcount_intrinsic: Some("llvm.arm.gnu.eabi.mcount".into()), ..base::linux_gnu::opts() }, } diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs index 3b5a337b4f13..a3b35d658e9d 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs @@ -22,6 +22,7 @@ pub(crate) fn target() -> Target { features: "+v7,+vfp3,-d32,+thumb2,-neon".into(), max_atomic_width: Some(64), mcount: "\u{1}__gnu_mcount_nc".into(), + llvm_mcount_intrinsic: Some("llvm.arm.gnu.eabi.mcount".into()), ..base::linux_gnu::opts() }, } diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index 1c61e23362a8..a5cc8d9ea012 100644 --- a/compiler/rustc_trait_selection/Cargo.toml +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -21,7 +21,6 @@ rustc_parse_format = { path = "../rustc_parse_format" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_transmute = { path = "../rustc_transmute", features = ["rustc"] } -rustc_type_ir = { path = "../rustc_type_ir" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } thin-vec = "0.2" tracing = "0.1" 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 eba195cb99cf..de9a50f19623 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 @@ -15,10 +15,9 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer}; use rustc_middle::ty::{ self, GenericArg, GenericArgKind, GenericArgsRef, InferConst, IsSuggestable, Term, TermKind, - Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeckResults, + Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, TypeckResults, }; use rustc_span::{BytePos, DUMMY_SP, FileName, Ident, Span, sym}; -use rustc_type_ir::TypeVisitableExt; use tracing::{debug, instrument, warn}; use super::nice_region_error::placeholder_error::Highlighted; 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 242469a225a3..b8207c4f8163 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -11,9 +11,10 @@ use rustc_hir::{self as hir, ParamName}; use rustc_middle::bug; use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::error::TypeError; -use rustc_middle::ty::{self, IsSuggestable, Region, Ty, TyCtxt, TypeVisitableExt as _}; +use rustc_middle::ty::{ + self, IsSuggestable, Region, Ty, TyCtxt, TypeVisitableExt as _, Upcast as _, +}; use rustc_span::{BytePos, ErrorGuaranteed, Span, Symbol, kw}; -use rustc_type_ir::Upcast as _; use tracing::{debug, instrument}; use super::ObligationCauseAsDiagArg; 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 c5ed74420d4d..d929ecf68bf3 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs @@ -5,10 +5,9 @@ use rustc_hir::def::Namespace; use rustc_hir::def_id::LOCAL_CRATE; use rustc_infer::traits::{Obligation, PredicateObligation}; use rustc_middle::ty::print::{FmtPrinter, Print}; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, TyCtxt, Upcast}; use rustc_session::Limit; use rustc_span::Span; -use rustc_type_ir::Upcast; use tracing::debug; use crate::error_reporting::TypeErrCtxt; diff --git a/compiler/rustc_trait_selection/src/solve.rs b/compiler/rustc_trait_selection/src/solve.rs index 0c2451a80a70..5a5d16167d28 100644 --- a/compiler/rustc_trait_selection/src/solve.rs +++ b/compiler/rustc_trait_selection/src/solve.rs @@ -11,6 +11,6 @@ pub use fulfill::{FulfillmentCtxt, NextSolverError}; pub(crate) use normalize::deeply_normalize_for_diagnostics; pub use normalize::{ deeply_normalize, deeply_normalize_with_skipped_universes, - deeply_normalize_with_skipped_universes_and_ambiguous_goals, + deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals, }; pub use select::InferCtxtSelectExt; diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index a87c5ad6db96..ef64da131891 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -8,10 +8,10 @@ use rustc_infer::infer::canonical::{ }; use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, TyCtxtInferExt}; use rustc_infer::traits::solve::Goal; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitableExt as _}; +use rustc_middle::traits::query::NoSolution; +use rustc_middle::traits::solve::Certainty; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitableExt as _, TypingMode}; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; -use rustc_type_ir::TypingMode; -use rustc_type_ir::solve::{Certainty, NoSolution}; use crate::traits::{EvaluateConstErr, specialization_graph}; @@ -155,7 +155,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< fn register_hidden_type_in_storage( &self, - opaque_type_key: rustc_type_ir::OpaqueTypeKey, + opaque_type_key: ty::OpaqueTypeKey<'tcx>, hidden_ty: ::Ty, span: ::Span, ) -> Option<::Ty> { diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 1f4fa5aac102..3e1cdac84dfd 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -10,11 +10,10 @@ use rustc_infer::traits::{ FromSolverError, PredicateObligation, PredicateObligations, TraitEngine, }; use rustc_middle::ty::{ - self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, TypingMode, + self, DelayedSet, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, TypingMode, }; use rustc_next_trait_solver::solve::{GenerateProofTree, HasChanged, SolverDelegateEvalExt as _}; use rustc_span::Span; -use rustc_type_ir::data_structures::DelayedSet; use tracing::instrument; use self::derive_errors::*; diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs index a024f432450c..2d445dd07900 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs @@ -7,11 +7,11 @@ use rustc_infer::traits::{ self, MismatchedProjectionTypes, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation, SelectionError, }; +use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_next_trait_solver::solve::{GenerateProofTree, SolverDelegateEvalExt as _}; -use rustc_type_ir::solve::NoSolution; use tracing::{instrument, trace}; use crate::solve::delegate::SolverDelegate; diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index 5f1e63ab225a..d903f94b489d 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -45,9 +45,11 @@ where T: TypeFoldable>, E: FromSolverError<'tcx, NextSolverError<'tcx>>, { - let (value, goals) = - deeply_normalize_with_skipped_universes_and_ambiguous_goals(at, value, universes)?; - assert_eq!(goals, vec![]); + let (value, coroutine_goals) = + deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals( + at, value, universes, + )?; + assert_eq!(coroutine_goals, vec![]); Ok(value) } @@ -59,9 +61,9 @@ where /// entered before passing `value` to the function. This is currently needed for /// `normalize_erasing_regions`, which skips binders as it walks through a type. /// -/// This returns a set of stalled obligations if the typing mode of the underlying infcx -/// has any stalled coroutine def ids. -pub fn deeply_normalize_with_skipped_universes_and_ambiguous_goals<'tcx, T, E>( +/// This returns a set of stalled obligations involving coroutines if the typing mode of +/// the underlying infcx has any stalled coroutine def ids. +pub fn deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals<'tcx, T, E>( at: At<'_, 'tcx>, value: T, universes: Vec>, @@ -71,11 +73,16 @@ where E: FromSolverError<'tcx, NextSolverError<'tcx>>, { let fulfill_cx = FulfillmentCtxt::new(at.infcx); - let mut folder = - NormalizationFolder { at, fulfill_cx, depth: 0, universes, stalled_goals: vec![] }; + let mut folder = NormalizationFolder { + at, + fulfill_cx, + depth: 0, + universes, + stalled_coroutine_goals: vec![], + }; let value = value.try_fold_with(&mut folder)?; let errors = folder.fulfill_cx.select_all_or_error(at.infcx); - if errors.is_empty() { Ok((value, folder.stalled_goals)) } else { Err(errors) } + if errors.is_empty() { Ok((value, folder.stalled_coroutine_goals)) } else { Err(errors) } } struct NormalizationFolder<'me, 'tcx, E> { @@ -83,7 +90,7 @@ struct NormalizationFolder<'me, 'tcx, E> { fulfill_cx: FulfillmentCtxt<'tcx, E>, depth: usize, universes: Vec>, - stalled_goals: Vec>>, + stalled_coroutine_goals: Vec>>, } impl<'tcx, E> NormalizationFolder<'_, 'tcx, E> @@ -182,7 +189,7 @@ where return Err(errors); } - self.stalled_goals.extend( + self.stalled_coroutine_goals.extend( self.fulfill_cx .drain_stalled_obligations_for_coroutines(self.at.infcx) .into_iter() @@ -298,13 +305,13 @@ impl<'tcx> TypeFolder> for DeeplyNormalizeForDiagnosticsFolder<'_, fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { let infcx = self.at.infcx; - let result = - infcx.commit_if_ok(|_| { - deeply_normalize_with_skipped_universes_and_ambiguous_goals::< - _, - ScrubbedTraitError<'tcx>, - >(self.at, ty, vec![None; ty.outer_exclusive_binder().as_usize()]) - }); + let result: Result<_, Vec>> = infcx.commit_if_ok(|_| { + deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals( + self.at, + ty, + vec![None; ty.outer_exclusive_binder().as_usize()], + ) + }); match result { Ok((ty, _)) => ty, Err(_) => ty.super_fold_with(self), @@ -313,13 +320,13 @@ impl<'tcx> TypeFolder> for DeeplyNormalizeForDiagnosticsFolder<'_, fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { let infcx = self.at.infcx; - let result = - infcx.commit_if_ok(|_| { - deeply_normalize_with_skipped_universes_and_ambiguous_goals::< - _, - ScrubbedTraitError<'tcx>, - >(self.at, ct, vec![None; ct.outer_exclusive_binder().as_usize()]) - }); + let result: Result<_, Vec>> = infcx.commit_if_ok(|_| { + deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals( + self.at, + ct, + vec![None; ct.outer_exclusive_binder().as_usize()], + ) + }); match result { Ok((ct, _)) => ct, Err(_) => ct.super_fold_with(self), diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index 519394685a8e..220a847cc230 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -13,9 +13,9 @@ use rustc_middle::query::Providers; use rustc_middle::ty::{ self, EarlyBinder, GenericArgs, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Upcast, + elaborate, }; use rustc_span::Span; -use rustc_type_ir::elaborate; use smallvec::SmallVec; use tracing::{debug, instrument}; diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs index defbafac20b3..cc5861b5a1f5 100644 --- a/compiler/rustc_trait_selection/src/traits/effects.rs +++ b/compiler/rustc_trait_selection/src/traits/effects.rs @@ -4,10 +4,10 @@ use rustc_infer::traits::{ ImplDerivedHostCause, ImplSource, Obligation, ObligationCauseCode, PredicateObligation, }; use rustc_middle::span_bug; +use rustc_middle::traits::query::NoSolution; +use rustc_middle::ty::elaborate::elaborate; use rustc_middle::ty::fast_reject::DeepRejectCtxt; use rustc_middle::ty::{self, TypingMode}; -use rustc_type_ir::elaborate::elaborate; -use rustc_type_ir::solve::NoSolution; use thin_vec::{ThinVec, thin_vec}; use super::SelectionContext; @@ -252,6 +252,9 @@ fn evaluate_host_effect_for_destruct_goal<'tcx>( let self_ty = obligation.predicate.self_ty(); let const_conditions = match *self_ty.kind() { + // `ManuallyDrop` is trivially `~const Destruct` as we do not run any drop glue on it. + ty::Adt(adt_def, _) if adt_def.is_manually_drop() => thin_vec![], + // An ADT is `~const Destruct` only if all of the fields are, // *and* if there is a `Drop` impl, that `Drop` impl is also `~const`. ty::Adt(adt_def, args) => { diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 9f3178f88792..8d6e6b4a6516 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -14,8 +14,8 @@ use rustc_macros::extension; use rustc_middle::arena::ArenaAllocatable; use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::error::TypeError; +use rustc_middle::ty::relate::Relate; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, Upcast, Variance}; -use rustc_type_ir::relate::Relate; use super::{FromSolverError, FulfillmentContext, ScrubbedTraitError, TraitEngine}; use crate::error_reporting::InferCtxtErrorExt; diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index d38ddbc825c4..5f0acd46f86a 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -260,11 +260,14 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx } ty::Projection if !data.has_escaping_bound_vars() => { - // This branch is *mostly* just an optimization: when we don't - // have escaping bound vars, we don't need to replace them with - // placeholders (see branch below). *Also*, we know that we can - // register an obligation to *later* project, since we know - // there won't be bound vars there. + // When we don't have escaping bound vars we can normalize ambig aliases + // to inference variables (done in `normalize_projection_ty`). This would + // be wrong if there were escaping bound vars as even if we instantiated + // the bound vars with placeholders, we wouldn't be able to map them back + // after normalization succeeded. + // + // Also, as an optimization: when we don't have escaping bound vars, we don't + // need to replace them with placeholders (see branch below). let data = data.fold_with(self); let normalized_ty = project::normalize_projection_ty( self.selcx, diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index 1df69932c64d..d9b57f0c67d1 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -6,10 +6,10 @@ use rustc_infer::traits::query::OutlivesBound; use rustc_infer::traits::query::type_op::ImpliedOutlivesBounds; use rustc_middle::infer::canonical::CanonicalQueryResponse; use rustc_middle::traits::ObligationCause; +use rustc_middle::ty::outlives::{Component, push_outlives_components}; use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeVisitable, TypeVisitor}; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::{DUMMY_SP, Span, sym}; -use rustc_type_ir::outlives::{Component, push_outlives_components}; use smallvec::{SmallVec, smallvec}; use crate::traits::query::NoSolution; 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 5d0b9dd41b20..10a2ba049d85 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -14,9 +14,8 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_hir as hir; use rustc_infer::traits::{Obligation, PolyTraitObligation, SelectionError}; use rustc_middle::ty::fast_reject::DeepRejectCtxt; -use rustc_middle::ty::{self, Ty, TypeVisitableExt, TypingMode}; +use rustc_middle::ty::{self, Ty, TypeVisitableExt, TypingMode, elaborate}; use rustc_middle::{bug, span_bug}; -use rustc_type_ir::elaborate; use tracing::{debug, instrument, trace}; use super::SelectionCandidate::*; diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index d71d1e9ae0fa..8008c7e4d342 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -15,10 +15,9 @@ use rustc_hir::lang_items::LangItem; use rustc_infer::infer::{DefineOpaqueTypes, HigherRankedType, InferOk}; use rustc_infer::traits::ObligationCauseCode; use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData}; -use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, Upcast}; +use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, Upcast, elaborate}; use rustc_middle::{bug, span_bug}; use rustc_span::def_id::DefId; -use rustc_type_ir::elaborate; use thin_vec::thin_vec; use tracing::{debug, instrument}; diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index df02a67c2c9b..4ce37db42800 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -28,10 +28,9 @@ use rustc_middle::ty::error::TypeErrorToStringExt; use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths}; use rustc_middle::ty::{ self, GenericArgsRef, PolyProjectionPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, - TypingMode, Upcast, + TypingMode, Upcast, elaborate, }; use rustc_span::{Symbol, sym}; -use rustc_type_ir::elaborate; use tracing::{debug, instrument, trace}; use self::EvaluationResult::*; diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 448ac558cad7..b30fadd3e5b7 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -18,11 +18,11 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_infer::traits::Obligation; use rustc_middle::bug; use rustc_middle::query::LocalCrate; +use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, TypingMode}; use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, sym}; -use rustc_type_ir::solve::NoSolution; use specialization_graph::GraphExt; use tracing::{debug, instrument}; diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 00a4a58a6d86..2e32cda7602e 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -658,6 +658,50 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // ``` } } + + fn add_wf_preds_for_pat_ty(&mut self, base_ty: Ty<'tcx>, pat: ty::Pattern<'tcx>) { + let tcx = self.tcx(); + match *pat { + ty::PatternKind::Range { start, end } => { + let mut check = |c| { + let cause = self.cause(ObligationCauseCode::Misc); + self.out.push(traits::Obligation::with_depth( + tcx, + cause.clone(), + self.recursion_depth, + self.param_env, + ty::Binder::dummy(ty::PredicateKind::Clause( + ty::ClauseKind::ConstArgHasType(c, base_ty), + )), + )); + if !tcx.features().generic_pattern_types() { + if c.has_param() { + if self.span.is_dummy() { + self.tcx() + .dcx() + .delayed_bug("feature error should be reported elsewhere, too"); + } else { + feature_err( + &self.tcx().sess, + sym::generic_pattern_types, + self.span, + "wraparound pattern type ranges cause monomorphization time errors", + ) + .emit(); + } + } + } + }; + check(start); + check(end); + } + ty::PatternKind::Or(patterns) => { + for pat in patterns { + self.add_wf_preds_for_pat_ty(base_ty, pat) + } + } + } + } } impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { @@ -710,43 +754,9 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { )); } - ty::Pat(subty, pat) => { - self.require_sized(subty, ObligationCauseCode::Misc); - match *pat { - ty::PatternKind::Range { start, end } => { - let mut check = |c| { - let cause = self.cause(ObligationCauseCode::Misc); - self.out.push(traits::Obligation::with_depth( - tcx, - cause.clone(), - self.recursion_depth, - self.param_env, - ty::Binder::dummy(ty::PredicateKind::Clause( - ty::ClauseKind::ConstArgHasType(c, subty), - )), - )); - if !tcx.features().generic_pattern_types() { - if c.has_param() { - if self.span.is_dummy() { - self.tcx().dcx().delayed_bug( - "feature error should be reported elsewhere, too", - ); - } else { - feature_err( - &self.tcx().sess, - sym::generic_pattern_types, - self.span, - "wraparound pattern type ranges cause monomorphization time errors", - ) - .emit(); - } - } - } - }; - check(start); - check(end); - } - } + ty::Pat(base_ty, pat) => { + self.require_sized(base_ty, ObligationCauseCode::Misc); + self.add_wf_preds_for_pat_ty(base_ty, pat); } ty::Tuple(tys) => { diff --git a/compiler/rustc_transmute/Cargo.toml b/compiler/rustc_transmute/Cargo.toml index 0250cc0ea078..246b66d3d030 100644 --- a/compiler/rustc_transmute/Cargo.toml +++ b/compiler/rustc_transmute/Cargo.toml @@ -5,7 +5,6 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -itertools = "0.12" rustc_abi = { path = "../rustc_abi", optional = true } rustc_data_structures = { path = "../rustc_data_structures" } rustc_hir = { path = "../rustc_hir", optional = true } @@ -15,6 +14,11 @@ smallvec = "1.8.1" tracing = "0.1" # tidy-alphabetical-end +[dev-dependencies] +# tidy-alphabetical-start +itertools = "0.12" +# tidy-alphabetical-end + [features] rustc = [ "dep:rustc_abi", diff --git a/compiler/rustc_transmute/src/layout/dfa.rs b/compiler/rustc_transmute/src/layout/dfa.rs index d1f58157b696..05afa28db31a 100644 --- a/compiler/rustc_transmute/src/layout/dfa.rs +++ b/compiler/rustc_transmute/src/layout/dfa.rs @@ -1,5 +1,5 @@ use std::fmt; -use std::ops::RangeInclusive; +use std::iter::Peekable; use std::sync::atomic::{AtomicU32, Ordering}; use super::{Byte, Ref, Tree, Uninhabited}; @@ -211,15 +211,15 @@ where let b_transitions = b_src.and_then(|b_src| b.transitions.get(&b_src)).unwrap_or(&empty_transitions); - let byte_transitions = - a_transitions.byte_transitions.union(&b_transitions.byte_transitions); + let byte_transitions = a_transitions.byte_transitions.union( + &b_transitions.byte_transitions, + |a_dst, b_dst| { + assert!(a_dst.is_some() || b_dst.is_some()); - let byte_transitions = byte_transitions.map_states(|(a_dst, b_dst)| { - assert!(a_dst.is_some() || b_dst.is_some()); - - queue.enqueue(a_dst, b_dst); - mapped((a_dst, b_dst)) - }); + queue.enqueue(a_dst, b_dst); + mapped((a_dst, b_dst)) + }, + ); let ref_transitions = a_transitions.ref_transitions.keys().chain(b_transitions.ref_transitions.keys()); @@ -245,18 +245,6 @@ where Self { transitions, start, accept } } - pub(crate) fn states_from( - &self, - state: State, - src_validity: RangeInclusive, - ) -> impl Iterator { - self.transitions - .get(&state) - .map(move |t| t.byte_transitions.states_from(src_validity)) - .into_iter() - .flatten() - } - pub(crate) fn get_uninit_edge_dst(&self, state: State) -> Option { let transitions = self.transitions.get(&state)?; transitions.byte_transitions.get_uninit_edge_dst() @@ -334,95 +322,31 @@ where use edge_set::EdgeSet; mod edge_set { - use std::cmp; - - use run::*; - use smallvec::{SmallVec, smallvec}; + use smallvec::SmallVec; use super::*; - mod run { - use std::ops::{Range, RangeInclusive}; - use super::*; - use crate::layout::Byte; - - /// A logical set of edges. - /// - /// A `Run` encodes one edge for every byte value in `start..=end` - /// pointing to `dst`. - #[derive(Eq, PartialEq, Copy, Clone, Debug)] - pub(super) struct Run { - // `start` and `end` are both inclusive (ie, closed) bounds, as this - // is required in order to be able to store 0..=255. We provide - // setters and getters which operate on closed/open ranges, which - // are more intuitive and easier for performing offset math. - start: u8, - end: u8, - pub(super) dst: S, - } - - impl Run { - pub(super) fn new(range: RangeInclusive, dst: S) -> Self { - Self { start: *range.start(), end: *range.end(), dst } - } - - pub(super) fn from_inclusive_exclusive(range: Range, dst: S) -> Self { - Self { - start: range.start.try_into().unwrap(), - end: (range.end - 1).try_into().unwrap(), - dst, - } - } - - pub(super) fn contains(&self, idx: u16) -> bool { - idx >= u16::from(self.start) && idx <= u16::from(self.end) - } - - pub(super) fn as_inclusive_exclusive(&self) -> (u16, u16) { - (u16::from(self.start), u16::from(self.end) + 1) - } - - pub(super) fn as_byte(&self) -> Byte { - Byte::new(self.start..=self.end) - } - - pub(super) fn map_state(self, f: impl FnOnce(S) -> SS) -> Run { - let Run { start, end, dst } = self; - Run { start, end, dst: f(dst) } - } - - /// Produces a new `Run` whose lower bound is the greater of - /// `self`'s existing lower bound and `lower_bound`. - pub(super) fn clamp_lower(self, lower_bound: u8) -> Self { - let Run { start, end, dst } = self; - Run { start: cmp::max(start, lower_bound), end, dst } - } - } - } - - /// The set of outbound byte edges associated with a DFA node (not including - /// reference edges). + /// The set of outbound byte edges associated with a DFA node. #[derive(Eq, PartialEq, Clone, Debug)] pub(super) struct EdgeSet { - // A sequence of runs stored in ascending order. Since the graph is a - // DFA, these must be non-overlapping with one another. - runs: SmallVec<[Run; 1]>, - // The edge labeled with the uninit byte, if any. + // A sequence of byte edges with contiguous byte values and a common + // destination is stored as a single run. // - // FIXME(@joshlf): Make `State` a `NonZero` so that this is NPO'd. - uninit: Option, + // Runs are non-empty, non-overlapping, and stored in ascending order. + runs: SmallVec<[(Byte, S); 1]>, } impl EdgeSet { - pub(crate) fn new(byte: Byte, dst: S) -> Self { - match byte.range() { - Some(range) => Self { runs: smallvec![Run::new(range, dst)], uninit: None }, - None => Self { runs: SmallVec::new(), uninit: Some(dst) }, + pub(crate) fn new(range: Byte, dst: S) -> Self { + let mut this = Self { runs: SmallVec::new() }; + if !range.is_empty() { + this.runs.push((range, dst)); } + this } pub(crate) fn empty() -> Self { - Self { runs: SmallVec::new(), uninit: None } + Self { runs: SmallVec::new() } } #[cfg(test)] @@ -431,43 +355,23 @@ mod edge_set { S: Ord, { edges.sort(); - Self { - runs: edges - .into_iter() - .map(|(byte, state)| Run::new(byte.range().unwrap(), state)) - .collect(), - uninit: None, - } + Self { runs: edges.into() } } pub(crate) fn iter(&self) -> impl Iterator where S: Copy, { - self.uninit - .map(|dst| (Byte::uninit(), dst)) - .into_iter() - .chain(self.runs.iter().map(|run| (run.as_byte(), run.dst))) - } - - pub(crate) fn states_from( - &self, - byte: RangeInclusive, - ) -> impl Iterator - where - S: Copy, - { - // FIXME(@joshlf): Optimize this. A manual scan over `self.runs` may - // permit us to more efficiently discard runs which will not be - // produced by this iterator. - self.iter().filter(move |(o, _)| Byte::new(byte.clone()).transmutable_into(&o)) + self.runs.iter().copied() } pub(crate) fn get_uninit_edge_dst(&self) -> Option where S: Copy, { - self.uninit + // Uninit is ordered last. + let &(range, dst) = self.runs.last()?; + if range.contains_uninit() { Some(dst) } else { None } } pub(crate) fn map_states(self, mut f: impl FnMut(S) -> SS) -> EdgeSet { @@ -478,95 +382,106 @@ mod edge_set { // allocates the correct number of elements once up-front [1]. // // [1] https://doc.rust-lang.org/1.85.0/src/alloc/vec/spec_from_iter_nested.rs.html#47 - runs: self.runs.into_iter().map(|run| run.map_state(&mut f)).collect(), - uninit: self.uninit.map(f), + runs: self.runs.into_iter().map(|(b, s)| (b, f(s))).collect(), } } /// Unions two edge sets together. /// /// If `u = a.union(b)`, then for each byte value, `u` will have an edge - /// with that byte value and with the destination `(Some(_), None)`, - /// `(None, Some(_))`, or `(Some(_), Some(_))` depending on whether `a`, + /// with that byte value and with the destination `join(Some(_), None)`, + /// `join(None, Some(_))`, or `join(Some(_), Some(_))` depending on whether `a`, /// `b`, or both have an edge with that byte value. /// /// If neither `a` nor `b` have an edge with a particular byte value, /// then no edge with that value will be present in `u`. - pub(crate) fn union(&self, other: &Self) -> EdgeSet<(Option, Option)> + pub(crate) fn union( + &self, + other: &Self, + mut join: impl FnMut(Option, Option) -> S, + ) -> EdgeSet where S: Copy, { - let uninit = match (self.uninit, other.uninit) { - (None, None) => None, - (s, o) => Some((s, o)), - }; - - let mut runs = SmallVec::new(); - - // Iterate over `self.runs` and `other.runs` simultaneously, - // advancing `idx` as we go. At each step, we advance `idx` as far - // as we can without crossing a run boundary in either `self.runs` - // or `other.runs`. - - // INVARIANT: `idx < s[0].end && idx < o[0].end`. - let (mut s, mut o) = (self.runs.as_slice(), other.runs.as_slice()); - let mut idx = 0u16; - while let (Some((s_run, s_rest)), Some((o_run, o_rest))) = - (s.split_first(), o.split_first()) - { - let (s_start, s_end) = s_run.as_inclusive_exclusive(); - let (o_start, o_end) = o_run.as_inclusive_exclusive(); - - // Compute `end` as the end of the current run (which starts - // with `idx`). - let (end, dst) = match (s_run.contains(idx), o_run.contains(idx)) { - // `idx` is in an existing run in both `s` and `o`, so `end` - // is equal to the smallest of the two ends of those runs. - (true, true) => (cmp::min(s_end, o_end), (Some(s_run.dst), Some(o_run.dst))), - // `idx` is in an existing run in `s`, but not in any run in - // `o`. `end` is either the end of the `s` run or the - // beginning of the next `o` run, whichever comes first. - (true, false) => (cmp::min(s_end, o_start), (Some(s_run.dst), None)), - // The inverse of the previous case. - (false, true) => (cmp::min(s_start, o_end), (None, Some(o_run.dst))), - // `idx` is not in a run in either `s` or `o`, so advance it - // to the beginning of the next run. - (false, false) => { - idx = cmp::min(s_start, o_start); - continue; - } - }; - - // FIXME(@joshlf): If this is contiguous with the previous run - // and has the same `dst`, just merge it into that run rather - // than adding a new one. - runs.push(Run::from_inclusive_exclusive(idx..end, dst)); - idx = end; - - if idx >= s_end { - s = s_rest; - } - if idx >= o_end { - o = o_rest; - } - } - - // At this point, either `s` or `o` have been exhausted, so the - // remaining elements in the other slice are guaranteed to be - // non-overlapping. We can add all remaining runs to `runs` with no - // further processing. - if let Ok(idx) = u8::try_from(idx) { - let (slc, map) = if !s.is_empty() { - let map: fn(_) -> _ = |st| (Some(st), None); - (s, map) - } else { - let map: fn(_) -> _ = |st| (None, Some(st)); - (o, map) - }; - runs.extend(slc.iter().map(|run| run.clamp_lower(idx).map_state(map))); - } - - EdgeSet { runs, uninit } + let xs = self.runs.iter().copied(); + let ys = other.runs.iter().copied(); + // FIXME(@joshlf): Merge contiguous runs with common destination. + EdgeSet { runs: union(xs, ys).map(|(range, (x, y))| (range, join(x, y))).collect() } } } } + +/// Merges two sorted sequences into one sorted sequence. +pub(crate) fn union, Y: Iterator>( + xs: X, + ys: Y, +) -> UnionIter { + UnionIter { xs: xs.peekable(), ys: ys.peekable() } +} + +pub(crate) struct UnionIter { + xs: Peekable, + ys: Peekable, +} + +// FIXME(jswrenn) we'd likely benefit from specializing try_fold here. +impl, Y: Iterator> Iterator + for UnionIter +{ + type Item = (Byte, (Option, Option)); + + fn next(&mut self) -> Option { + use std::cmp::{self, Ordering}; + + let ret; + match (self.xs.peek_mut(), self.ys.peek_mut()) { + (None, None) => { + ret = None; + } + (Some(x), None) => { + ret = Some((x.0, (Some(x.1), None))); + self.xs.next(); + } + (None, Some(y)) => { + ret = Some((y.0, (None, Some(y.1)))); + self.ys.next(); + } + (Some(x), Some(y)) => { + let start; + let end; + let dst; + match x.0.start.cmp(&y.0.start) { + Ordering::Less => { + start = x.0.start; + end = cmp::min(x.0.end, y.0.start); + dst = (Some(x.1), None); + } + Ordering::Greater => { + start = y.0.start; + end = cmp::min(x.0.start, y.0.end); + dst = (None, Some(y.1)); + } + Ordering::Equal => { + start = x.0.start; + end = cmp::min(x.0.end, y.0.end); + dst = (Some(x.1), Some(y.1)); + } + } + ret = Some((Byte { start, end }, dst)); + if start == x.0.start { + x.0.start = end; + } + if start == y.0.start { + y.0.start = end; + } + if x.0.is_empty() { + self.xs.next(); + } + if y.0.is_empty() { + self.ys.next(); + } + } + } + ret + } +} diff --git a/compiler/rustc_transmute/src/layout/mod.rs b/compiler/rustc_transmute/src/layout/mod.rs index 4d5f630ae229..c08bf440734e 100644 --- a/compiler/rustc_transmute/src/layout/mod.rs +++ b/compiler/rustc_transmute/src/layout/mod.rs @@ -6,61 +6,61 @@ pub(crate) mod tree; pub(crate) use tree::Tree; pub(crate) mod dfa; -pub(crate) use dfa::Dfa; +pub(crate) use dfa::{Dfa, union}; #[derive(Debug)] pub(crate) struct Uninhabited; -/// A range of byte values, or the uninit byte. +/// A range of byte values (including an uninit byte value). #[derive(Hash, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)] pub(crate) struct Byte { - // An inclusive-inclusive range. We use this instead of `RangeInclusive` - // because `RangeInclusive: !Copy`. + // An inclusive-exclusive range. We use this instead of `Range` because `Range: !Copy`. // - // `None` means uninit. - // - // FIXME(@joshlf): Optimize this representation. Some pairs of values (where - // `lo > hi`) are illegal, and we could use these to represent `None`. - range: Option<(u8, u8)>, + // Uninit byte value is represented by 256. + pub(crate) start: u16, + pub(crate) end: u16, } impl Byte { + const UNINIT: u16 = 256; + + #[inline] fn new(range: RangeInclusive) -> Self { - Self { range: Some((*range.start(), *range.end())) } + let start: u16 = (*range.start()).into(); + let end: u16 = (*range.end()).into(); + Byte { start, end: end + 1 } } + #[inline] fn from_val(val: u8) -> Self { - Self { range: Some((val, val)) } + let val: u16 = val.into(); + Byte { start: val, end: val + 1 } } - pub(crate) fn uninit() -> Byte { - Byte { range: None } + #[inline] + fn uninit() -> Byte { + Byte { start: 0, end: Self::UNINIT + 1 } } - /// Returns `None` if `self` is the uninit byte. - pub(crate) fn range(&self) -> Option> { - self.range.map(|(lo, hi)| lo..=hi) + #[inline] + fn is_empty(&self) -> bool { + self.start == self.end } - /// Are any of the values in `self` transmutable into `other`? - /// - /// Note two special cases: An uninit byte is only transmutable into another - /// uninit byte. Any byte is transmutable into an uninit byte. - pub(crate) fn transmutable_into(&self, other: &Byte) -> bool { - match (self.range, other.range) { - (None, None) => true, - (None, Some(_)) => false, - (Some(_), None) => true, - (Some((slo, shi)), Some((olo, ohi))) => slo <= ohi && olo <= shi, - } + #[inline] + fn contains_uninit(&self) -> bool { + self.start <= Self::UNINIT && Self::UNINIT < self.end } } impl fmt::Debug for Byte { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.range { - None => write!(f, "uninit"), - Some((lo, hi)) => write!(f, "{lo}..={hi}"), + if self.start == Self::UNINIT && self.end == Self::UNINIT + 1 { + write!(f, "uninit") + } else if self.start <= Self::UNINIT && self.end == Self::UNINIT + 1 { + write!(f, "{}..{}|uninit", self.start, self.end - 1) + } else { + write!(f, "{}..{}", self.start, self.end) } } } @@ -72,6 +72,7 @@ impl From> for Byte { } impl From for Byte { + #[inline] fn from(src: u8) -> Self { Self::from_val(src) } diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs index 0a19cccc2ed0..f76abe50ed34 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs @@ -1,14 +1,11 @@ -use std::rc::Rc; -use std::{cmp, iter}; - -use itertools::Either; +use rustc_data_structures::stack::ensure_sufficient_stack; use tracing::{debug, instrument, trace}; pub(crate) mod query_context; #[cfg(test)] mod tests; -use crate::layout::{self, Byte, Def, Dfa, Ref, Tree, dfa}; +use crate::layout::{self, Def, Dfa, Ref, Tree, dfa, union}; use crate::maybe_transmutable::query_context::QueryContext; use crate::{Answer, Condition, Map, Reason}; @@ -153,232 +150,137 @@ where if let Some(answer) = cache.get(&(src_state, dst_state)) { answer.clone() } else { - debug!(?src_state, ?dst_state); - debug!(src = ?self.src); - debug!(dst = ?self.dst); - debug!( - src_transitions_len = self.src.transitions.len(), - dst_transitions_len = self.dst.transitions.len() - ); - let answer = if dst_state == self.dst.accept { - // truncation: `size_of(Src) >= size_of(Dst)` - // - // Why is truncation OK to do? Because even though the Src is bigger, all we care about - // is whether we have enough data for the Dst to be valid in accordance with what its - // type dictates. - // For example, in a u8 to `()` transmutation, we have enough data available from the u8 - // to transmute it to a `()` (though in this case does `()` really need any data to - // begin with? It doesn't). Same thing with u8 to fieldless struct. - // Now then, why is something like u8 to bool not allowed? That is not because the bool - // is smaller in size, but rather because those 2 bits that we are re-interpreting from - // the u8 could introduce invalid states for the bool type. - // - // So, if it's possible to transmute to a smaller Dst by truncating, and we can guarantee - // that none of the actually-used data can introduce an invalid state for Dst's type, we - // are able to safely transmute, even with truncation. - Answer::Yes - } else if src_state == self.src.accept { - // extension: `size_of(Src) <= size_of(Dst)` - if let Some(dst_state_prime) = self.dst.get_uninit_edge_dst(dst_state) { - self.answer_memo(cache, src_state, dst_state_prime) - } else { - Answer::No(Reason::DstIsTooBig) - } - } else { - let src_quantifier = if self.assume.validity { - // if the compiler may assume that the programmer is doing additional validity checks, - // (e.g.: that `src != 3u8` when the destination type is `bool`) - // then there must exist at least one transition out of `src_state` such that the transmute is viable... - Quantifier::ThereExists - } else { - // if the compiler cannot assume that the programmer is doing additional validity checks, - // then for all transitions out of `src_state`, such that the transmute is viable... - // then there must exist at least one transition out of `dst_state` such that the transmute is viable... - Quantifier::ForAll - }; - - let c = &core::cell::RefCell::new(&mut *cache); - let bytes_answer = src_quantifier.apply( - // for each of the byte set transitions out of the `src_state`... - self.src.bytes_from(src_state).flat_map( - move |(src_validity, src_state_prime)| { - // ...find all matching transitions out of `dst_state`. - - let Some(src_validity) = src_validity.range() else { - // NOTE: We construct an iterator here rather - // than just computing the value directly (via - // `self.answer_memo`) so that, if the iterator - // we produce from this branch is - // short-circuited, we don't waste time - // computing `self.answer_memo` unnecessarily. - // That will specifically happen if - // `src_quantifier == Quantifier::ThereExists`, - // since we emit `Answer::Yes` first (before - // chaining `answer_iter`). - let answer_iter = if let Some(dst_state_prime) = - self.dst.get_uninit_edge_dst(dst_state) - { - Either::Left(iter::once_with(move || { - let mut c = c.borrow_mut(); - self.answer_memo(&mut *c, src_state_prime, dst_state_prime) - })) - } else { - Either::Right(iter::once(Answer::No( - Reason::DstIsBitIncompatible, - ))) - }; - - // When `answer == Answer::No(...)`, there are - // two cases to consider: - // - If `assume.validity`, then we should - // succeed because the user is responsible for - // ensuring that the *specific* byte value - // appearing at runtime is valid for the - // destination type. When `assume.validity`, - // `src_quantifier == - // Quantifier::ThereExists`, so adding an - // `Answer::Yes` has the effect of ensuring - // that the "there exists" is always - // satisfied. - // - If `!assume.validity`, then we should fail. - // In this case, `src_quantifier == - // Quantifier::ForAll`, so adding an - // `Answer::Yes` has no effect. - return Either::Left(iter::once(Answer::Yes).chain(answer_iter)); - }; - - #[derive(Copy, Clone, Debug)] - struct Accum { - // The number of matching byte edges that we - // have found in the destination so far. - sum: usize, - found_uninit: bool, - } - - let accum1 = Rc::new(std::cell::Cell::new(Accum { - sum: 0, - found_uninit: false, - })); - let accum2 = Rc::clone(&accum1); - let sv = src_validity.clone(); - let update_accum = move |mut accum: Accum, dst_validity: Byte| { - if let Some(dst_validity) = dst_validity.range() { - // Only add the part of `dst_validity` that - // overlaps with `src_validity`. - let start = cmp::max(*sv.start(), *dst_validity.start()); - let end = cmp::min(*sv.end(), *dst_validity.end()); - - // We add 1 here to account for the fact - // that `end` is an inclusive bound. - accum.sum += 1 + usize::from(end.saturating_sub(start)); - } else { - accum.found_uninit = true; - } - accum - }; - - let answers = self - .dst - .states_from(dst_state, src_validity.clone()) - .map(move |(dst_validity, dst_state_prime)| { - let mut c = c.borrow_mut(); - accum1.set(update_accum(accum1.get(), dst_validity)); - let answer = - self.answer_memo(&mut *c, src_state_prime, dst_state_prime); - answer - }) - .chain( - iter::once_with(move || { - let src_validity_len = usize::from(*src_validity.end()) - - usize::from(*src_validity.start()) - + 1; - let accum = accum2.get(); - - // If this condition is false, then - // there are some byte values in the - // source which have no corresponding - // transition in the destination DFA. In - // that case, we add a `No` to our list - // of answers. When - // `!self.assume.validity`, this will - // cause the query to fail. - if accum.found_uninit || accum.sum == src_validity_len { - None - } else { - Some(Answer::No(Reason::DstIsBitIncompatible)) - } - }) - .flatten(), - ); - Either::Right(answers) - }, - ), - ); - - // The below early returns reflect how this code would behave: - // if self.assume.validity { - // or(bytes_answer, refs_answer) - // } else { - // and(bytes_answer, refs_answer) - // } - // ...if `refs_answer` was computed lazily. The below early - // returns can be deleted without impacting the correctness of - // the algorithm; only its performance. - debug!(?bytes_answer); - match bytes_answer { - Answer::No(_) if !self.assume.validity => return bytes_answer, - Answer::Yes if self.assume.validity => return bytes_answer, - _ => {} - }; - - let refs_answer = src_quantifier.apply( - // for each reference transition out of `src_state`... - self.src.refs_from(src_state).map(|(src_ref, src_state_prime)| { - // ...there exists a reference transition out of `dst_state`... - Quantifier::ThereExists.apply(self.dst.refs_from(dst_state).map( - |(dst_ref, dst_state_prime)| { - if !src_ref.is_mutable() && dst_ref.is_mutable() { - Answer::No(Reason::DstIsMoreUnique) - } else if !self.assume.alignment - && src_ref.min_align() < dst_ref.min_align() - { - Answer::No(Reason::DstHasStricterAlignment { - src_min_align: src_ref.min_align(), - dst_min_align: dst_ref.min_align(), - }) - } else if dst_ref.size() > src_ref.size() { - Answer::No(Reason::DstRefIsTooBig { - src: src_ref, - dst: dst_ref, - }) - } else { - // ...such that `src` is transmutable into `dst`, if - // `src_ref` is transmutability into `dst_ref`. - and( - Answer::If(Condition::IfTransmutable { - src: src_ref, - dst: dst_ref, - }), - self.answer_memo(cache, src_state_prime, dst_state_prime), - ) - } - }, - )) - }), - ); - - if self.assume.validity { - or(bytes_answer, refs_answer) - } else { - and(bytes_answer, refs_answer) - } - }; + let answer = ensure_sufficient_stack(|| self.answer_impl(cache, src_state, dst_state)); if let Some(..) = cache.insert((src_state, dst_state), answer.clone()) { panic!("failed to correctly cache transmutability") } answer } } + + fn answer_impl( + &self, + cache: &mut Map<(dfa::State, dfa::State), Answer<::Ref>>, + src_state: dfa::State, + dst_state: dfa::State, + ) -> Answer<::Ref> { + debug!(?src_state, ?dst_state); + debug!(src = ?self.src); + debug!(dst = ?self.dst); + debug!( + src_transitions_len = self.src.transitions.len(), + dst_transitions_len = self.dst.transitions.len() + ); + if dst_state == self.dst.accept { + // truncation: `size_of(Src) >= size_of(Dst)` + // + // Why is truncation OK to do? Because even though the Src is bigger, all we care about + // is whether we have enough data for the Dst to be valid in accordance with what its + // type dictates. + // For example, in a u8 to `()` transmutation, we have enough data available from the u8 + // to transmute it to a `()` (though in this case does `()` really need any data to + // begin with? It doesn't). Same thing with u8 to fieldless struct. + // Now then, why is something like u8 to bool not allowed? That is not because the bool + // is smaller in size, but rather because those 2 bits that we are re-interpreting from + // the u8 could introduce invalid states for the bool type. + // + // So, if it's possible to transmute to a smaller Dst by truncating, and we can guarantee + // that none of the actually-used data can introduce an invalid state for Dst's type, we + // are able to safely transmute, even with truncation. + Answer::Yes + } else if src_state == self.src.accept { + // extension: `size_of(Src) <= size_of(Dst)` + if let Some(dst_state_prime) = self.dst.get_uninit_edge_dst(dst_state) { + self.answer_memo(cache, src_state, dst_state_prime) + } else { + Answer::No(Reason::DstIsTooBig) + } + } else { + let src_quantifier = if self.assume.validity { + // if the compiler may assume that the programmer is doing additional validity checks, + // (e.g.: that `src != 3u8` when the destination type is `bool`) + // then there must exist at least one transition out of `src_state` such that the transmute is viable... + Quantifier::ThereExists + } else { + // if the compiler cannot assume that the programmer is doing additional validity checks, + // then for all transitions out of `src_state`, such that the transmute is viable... + // then there must exist at least one transition out of `dst_state` such that the transmute is viable... + Quantifier::ForAll + }; + + let bytes_answer = src_quantifier.apply( + union(self.src.bytes_from(src_state), self.dst.bytes_from(dst_state)).filter_map( + |(_range, (src_state_prime, dst_state_prime))| { + match (src_state_prime, dst_state_prime) { + // No matching transitions in `src`. Skip. + (None, _) => None, + // No matching transitions in `dst`. Fail. + (Some(_), None) => Some(Answer::No(Reason::DstIsBitIncompatible)), + // Matching transitions. Continue with successor states. + (Some(src_state_prime), Some(dst_state_prime)) => { + Some(self.answer_memo(cache, src_state_prime, dst_state_prime)) + } + } + }, + ), + ); + + // The below early returns reflect how this code would behave: + // if self.assume.validity { + // or(bytes_answer, refs_answer) + // } else { + // and(bytes_answer, refs_answer) + // } + // ...if `refs_answer` was computed lazily. The below early + // returns can be deleted without impacting the correctness of + // the algorithm; only its performance. + debug!(?bytes_answer); + match bytes_answer { + Answer::No(_) if !self.assume.validity => return bytes_answer, + Answer::Yes if self.assume.validity => return bytes_answer, + _ => {} + }; + + let refs_answer = src_quantifier.apply( + // for each reference transition out of `src_state`... + self.src.refs_from(src_state).map(|(src_ref, src_state_prime)| { + // ...there exists a reference transition out of `dst_state`... + Quantifier::ThereExists.apply(self.dst.refs_from(dst_state).map( + |(dst_ref, dst_state_prime)| { + if !src_ref.is_mutable() && dst_ref.is_mutable() { + Answer::No(Reason::DstIsMoreUnique) + } else if !self.assume.alignment + && src_ref.min_align() < dst_ref.min_align() + { + Answer::No(Reason::DstHasStricterAlignment { + src_min_align: src_ref.min_align(), + dst_min_align: dst_ref.min_align(), + }) + } else if dst_ref.size() > src_ref.size() { + Answer::No(Reason::DstRefIsTooBig { src: src_ref, dst: dst_ref }) + } else { + // ...such that `src` is transmutable into `dst`, if + // `src_ref` is transmutability into `dst_ref`. + and( + Answer::If(Condition::IfTransmutable { + src: src_ref, + dst: dst_ref, + }), + self.answer_memo(cache, src_state_prime, dst_state_prime), + ) + } + }, + )) + }), + ); + + if self.assume.validity { + or(bytes_answer, refs_answer) + } else { + and(bytes_answer, refs_answer) + } + } + } } fn and(lhs: Answer, rhs: Answer) -> Answer diff --git a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs index 992fcb7cc4c8..fbb4639dbd63 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs @@ -400,16 +400,23 @@ mod r#ref { fn should_permit_identity_transmutation() { type Tree = crate::layout::Tree; - let layout = Tree::Seq(vec![Tree::byte(0x00), Tree::Ref([()])]); + for validity in [false, true] { + let layout = Tree::Seq(vec![Tree::byte(0x00), Tree::Ref([()])]); - let answer = crate::maybe_transmutable::MaybeTransmutableQuery::new( - layout.clone(), - layout, - Assume::default(), - UltraMinimal::default(), - ) - .answer(); - assert_eq!(answer, Answer::If(crate::Condition::IfTransmutable { src: [()], dst: [()] })); + let assume = Assume { validity, ..Assume::default() }; + + let answer = crate::maybe_transmutable::MaybeTransmutableQuery::new( + layout.clone(), + layout, + assume, + UltraMinimal::default(), + ) + .answer(); + assert_eq!( + answer, + Answer::If(crate::Condition::IfTransmutable { src: [()], dst: [()] }) + ); + } } } diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 16336ed530a6..908fcb14cb2f 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -259,13 +259,95 @@ fn layout_of_uncached<'tcx>( }; layout.largest_niche = Some(niche); - - tcx.mk_layout(layout) } else { bug!("pattern type with range but not scalar layout: {ty:?}, {layout:?}") } } + ty::PatternKind::Or(variants) => match *variants[0] { + ty::PatternKind::Range { .. } => { + if let BackendRepr::Scalar(scalar) = &mut layout.backend_repr { + let variants: Result, _> = variants + .iter() + .map(|pat| match *pat { + ty::PatternKind::Range { start, end } => Ok(( + extract_const_value(cx, ty, start) + .unwrap() + .try_to_bits(tcx, cx.typing_env) + .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?, + extract_const_value(cx, ty, end) + .unwrap() + .try_to_bits(tcx, cx.typing_env) + .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?, + )), + ty::PatternKind::Or(_) => { + unreachable!("mixed or patterns are not allowed") + } + }) + .collect(); + let mut variants = variants?; + if !scalar.is_signed() { + let guar = tcx.dcx().err(format!( + "only signed integer base types are allowed for or-pattern pattern types at present" + )); + + return Err(error(cx, LayoutError::ReferencesError(guar))); + } + variants.sort(); + if variants.len() != 2 { + let guar = tcx + .dcx() + .err(format!("the only or-pattern types allowed are two range patterns that are directly connected at their overflow site")); + + return Err(error(cx, LayoutError::ReferencesError(guar))); + } + + // first is the one starting at the signed in range min + let mut first = variants[0]; + let mut second = variants[1]; + if second.0 + == layout.size.truncate(layout.size.signed_int_min() as u128) + { + (second, first) = (first, second); + } + + if layout.size.sign_extend(first.1) >= layout.size.sign_extend(second.0) + { + let guar = tcx.dcx().err(format!( + "only non-overlapping pattern type ranges are allowed at present" + )); + + return Err(error(cx, LayoutError::ReferencesError(guar))); + } + if layout.size.signed_int_max() as u128 != second.1 { + let guar = tcx.dcx().err(format!( + "one pattern needs to end at `{ty}::MAX`, but was {} instead", + second.1 + )); + + return Err(error(cx, LayoutError::ReferencesError(guar))); + } + + // Now generate a wrapping range (which aren't allowed in surface syntax). + scalar.valid_range_mut().start = second.0; + scalar.valid_range_mut().end = first.1; + + let niche = Niche { + offset: Size::ZERO, + value: scalar.primitive(), + valid_range: scalar.valid_range(cx), + }; + + layout.largest_niche = Some(niche); + } else { + bug!( + "pattern type with range but not scalar layout: {ty:?}, {layout:?}" + ) + } + } + ty::PatternKind::Or(..) => bug!("patterns cannot have nested or patterns"), + }, } + tcx.mk_layout(layout) } // Basic scalars. diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs index 03d3194f1065..67b67df4b281 100644 --- a/compiler/rustc_type_ir/src/canonical.rs +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -34,7 +34,6 @@ pub struct CanonicalQueryInput { #[derive_where(Eq; I: Interner, V: Eq)] #[derive_where(Debug; I: Interner, V: fmt::Debug)] #[derive_where(Copy; I: Interner, V: Copy)] -#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr( feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) @@ -147,7 +146,6 @@ impl CanonicalVarInfo { /// in the type-theory sense of the term -- i.e., a "meta" type system /// that analyzes type-like values. #[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] -#[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 b37347354fab..7ed0f92b6398 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -304,7 +304,7 @@ impl FlagComputation { ty::Pat(ty, pat) => { self.add_ty(ty); - self.add_flags(pat.flags()); + self.add_ty_pat(pat); } ty::Slice(tt) => self.add_ty(tt), @@ -338,6 +338,10 @@ impl FlagComputation { } } + fn add_ty_pat(&mut self, pat: ::Pat) { + self.add_flags(pat.flags()); + } + fn add_predicate(&mut self, binder: ty::Binder>) { self.bound_computation(binder, |computation, atom| computation.add_predicate_atom(atom)); } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 9758cecaf6ac..6410da1f7409 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -113,6 +113,13 @@ pub trait Interner: + Relate + Flags + IntoKind>; + type PatList: Copy + + Debug + + Hash + + Default + + Eq + + TypeVisitable + + SliceLike; type Safety: Safety; type Abi: Abi; diff --git a/compiler/rustc_type_ir/src/pattern.rs b/compiler/rustc_type_ir/src/pattern.rs index d74a82da1f92..7e56565917c6 100644 --- a/compiler/rustc_type_ir/src/pattern.rs +++ b/compiler/rustc_type_ir/src/pattern.rs @@ -13,4 +13,5 @@ use crate::Interner; )] pub enum PatternKind { Range { start: I::Const, end: I::Const }, + Or(I::PatList), } diff --git a/compiler/rustc_type_ir/src/walk.rs b/compiler/rustc_type_ir/src/walk.rs index 5683e1f1712c..737550eb73e9 100644 --- a/compiler/rustc_type_ir/src/walk.rs +++ b/compiler/rustc_type_ir/src/walk.rs @@ -89,12 +89,7 @@ fn push_inner(stack: &mut TypeWalkerStack, parent: I::GenericArg | ty::Foreign(..) => {} ty::Pat(ty, pat) => { - match pat.kind() { - ty::PatternKind::Range { start, end } => { - stack.push(end.into()); - stack.push(start.into()); - } - } + push_ty_pat::(stack, pat); stack.push(ty.into()); } ty::Array(ty, len) => { @@ -171,3 +166,17 @@ fn push_inner(stack: &mut TypeWalkerStack, parent: I::GenericArg }, } } + +fn push_ty_pat(stack: &mut TypeWalkerStack, pat: I::Pat) { + match pat.kind() { + ty::PatternKind::Range { start, end } => { + stack.push(end.into()); + stack.push(start.into()); + } + ty::PatternKind::Or(pats) => { + for pat in pats.iter() { + push_ty_pat::(stack, pat) + } + } + } +} diff --git a/library/Cargo.lock b/library/Cargo.lock index c21dec14986f..f5c04a3bf48c 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -448,9 +448,9 @@ dependencies = [ [[package]] name = "unwinding" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51f06a05848f650946acef3bf525fe96612226b61f74ae23ffa4e98bfbb8ab3c" +checksum = "8393f2782b6060a807337ff353780c1ca15206f9ba2424df18cb6e733bd7b345" dependencies = [ "compiler_builtins", "gimli", diff --git a/library/alloc/src/macros.rs b/library/alloc/src/macros.rs index 214192b8c9a9..1e6e2ae8c367 100644 --- a/library/alloc/src/macros.rs +++ b/library/alloc/src/macros.rs @@ -105,8 +105,7 @@ macro_rules! vec { macro_rules! format { ($($arg:tt)*) => { $crate::__export::must_use({ - let res = $crate::fmt::format($crate::__export::format_args!($($arg)*)); - res + $crate::fmt::format($crate::__export::format_args!($($arg)*)) }) } } diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs index adcfdd309b7e..e409771362e4 100644 --- a/library/core/src/fmt/rt.rs +++ b/library/core/src/fmt/rt.rs @@ -200,8 +200,15 @@ impl Argument<'_> { /// let f = format_args!("{}", "a"); /// println!("{f}"); /// ``` + /// + /// This function should _not_ be const, to make sure we don't accept + /// format_args!() and panic!() with arguments in const, even when not evaluated: + /// + /// ```compile_fail,E0015 + /// const _: () = if false { panic!("a {}", "a") }; + /// ``` #[inline] - pub const fn none() -> [Self; 0] { + pub fn none() -> [Self; 0] { [] } } diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index bcf34781c8ac..5234fb83eb67 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -484,8 +484,9 @@ impl *const T { /// /// This operation itself is always safe, but using the resulting pointer is not. /// - /// The resulting pointer "remembers" the [allocated object] that `self` points to; it must not - /// be used to read or write other allocated objects. + /// The resulting pointer "remembers" the [allocated object] that `self` points to + /// (this is called "[Provenance](ptr/index.html#provenance)"). + /// The pointer must not be used to read or write other allocated objects. /// /// In other words, `let z = x.wrapping_offset((y as isize) - (x as isize))` does *not* make `z` /// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 6d1a50d84366..31b8d3b572c0 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -482,8 +482,9 @@ impl *mut T { /// /// This operation itself is always safe, but using the resulting pointer is not. /// - /// The resulting pointer "remembers" the [allocated object] that `self` points to; it must not - /// be used to read or write other allocated objects. + /// The resulting pointer "remembers" the [allocated object] that `self` points to + /// (this is called "[Provenance](ptr/index.html#provenance)"). + /// The pointer must not be used to read or write other allocated objects. /// /// In other words, `let z = x.wrapping_offset((y as isize) - (x as isize))` does *not* make `z` /// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 1593969e114a..ce2dc7952207 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -12,9 +12,11 @@ use crate::error::Error; use crate::ffi::{OsStr, OsString}; +use crate::num::NonZero; +use crate::ops::Try; use crate::path::{Path, PathBuf}; use crate::sys::{env as env_imp, os as os_imp}; -use crate::{fmt, io, sys}; +use crate::{array, fmt, io, sys}; /// Returns the current working directory as a [`PathBuf`]. /// @@ -872,19 +874,36 @@ impl !Sync for Args {} #[stable(feature = "env", since = "1.0.0")] impl Iterator for Args { type Item = String; + fn next(&mut self) -> Option { self.inner.next().map(|s| s.into_string().unwrap()) } + + #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + + // Methods which skip args cannot simply delegate to the inner iterator, + // because `env::args` states that we will "panic during iteration if any + // argument to the process is not valid Unicode". + // + // This offers two possible interpretations: + // - a skipped argument is never encountered "during iteration" + // - even a skipped argument is encountered "during iteration" + // + // As a panic can be observed, we err towards validating even skipped + // arguments for now, though this is not explicitly promised by the API. } #[stable(feature = "env", since = "1.0.0")] impl ExactSizeIterator for Args { + #[inline] fn len(&self) -> usize { self.inner.len() } + + #[inline] fn is_empty(&self) -> bool { self.inner.is_empty() } @@ -914,19 +933,65 @@ impl !Sync for ArgsOs {} #[stable(feature = "env", since = "1.0.0")] impl Iterator for ArgsOs { type Item = OsString; + + #[inline] fn next(&mut self) -> Option { self.inner.next() } + + #[inline] + fn next_chunk( + &mut self, + ) -> Result<[OsString; N], array::IntoIter> { + self.inner.next_chunk() + } + + #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + + #[inline] + fn count(self) -> usize { + self.inner.len() + } + + #[inline] + fn last(self) -> Option { + self.inner.last() + } + + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { + self.inner.advance_by(n) + } + + #[inline] + fn try_fold(&mut self, init: B, f: F) -> R + where + F: FnMut(B, Self::Item) -> R, + R: Try, + { + self.inner.try_fold(init, f) + } + + #[inline] + fn fold(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, f) + } } #[stable(feature = "env", since = "1.0.0")] impl ExactSizeIterator for ArgsOs { + #[inline] fn len(&self) -> usize { self.inner.len() } + + #[inline] fn is_empty(&self) -> bool { self.inner.is_empty() } @@ -934,9 +999,15 @@ impl ExactSizeIterator for ArgsOs { #[stable(feature = "env_iterators", since = "1.12.0")] impl DoubleEndedIterator for ArgsOs { + #[inline] fn next_back(&mut self) -> Option { self.inner.next_back() } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { + self.inner.advance_back_by(n) + } } #[stable(feature = "std_debug", since = "1.16.0")] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index ba57ad9bae32..c011f9661ae7 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -301,6 +301,8 @@ #![feature(formatting_options)] #![feature(if_let_guard)] #![feature(intra_doc_pointers)] +#![feature(iter_advance_by)] +#![feature(iter_next_chunk)] #![feature(lang_items)] #![feature(let_chains)] #![feature(link_cfg)] @@ -321,6 +323,7 @@ #![feature(strict_provenance_lints)] #![feature(thread_local)] #![feature(try_blocks)] +#![feature(try_trait_v2)] #![feature(type_alias_impl_trait)] // tidy-alphabetical-end // diff --git a/library/std/src/sys/args/common.rs b/library/std/src/sys/args/common.rs index 43ac5e959234..303b373ccf90 100644 --- a/library/std/src/sys/args/common.rs +++ b/library/std/src/sys/args/common.rs @@ -1,5 +1,7 @@ use crate::ffi::OsString; -use crate::{fmt, vec}; +use crate::num::NonZero; +use crate::ops::Try; +use crate::{array, fmt, vec}; pub struct Args { iter: vec::IntoIter, @@ -9,6 +11,7 @@ impl !Send for Args {} impl !Sync for Args {} impl Args { + #[inline] pub(super) fn new(args: Vec) -> Self { Args { iter: args.into_iter() } } @@ -22,22 +25,77 @@ impl fmt::Debug for Args { impl Iterator for Args { type Item = OsString; + + #[inline] fn next(&mut self) -> Option { self.iter.next() } + + #[inline] + fn next_chunk( + &mut self, + ) -> Result<[OsString; N], array::IntoIter> { + self.iter.next_chunk() + } + + #[inline] fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } -} -impl ExactSizeIterator for Args { - fn len(&self) -> usize { + #[inline] + fn count(self) -> usize { self.iter.len() } + + #[inline] + fn last(mut self) -> Option { + self.iter.next_back() + } + + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { + self.iter.advance_by(n) + } + + #[inline] + fn try_fold(&mut self, init: B, f: F) -> R + where + F: FnMut(B, Self::Item) -> R, + R: Try, + { + self.iter.try_fold(init, f) + } + + #[inline] + fn fold(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, f) + } } impl DoubleEndedIterator for Args { + #[inline] fn next_back(&mut self) -> Option { self.iter.next_back() } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { + self.iter.advance_back_by(n) + } +} + +impl ExactSizeIterator for Args { + #[inline] + fn len(&self) -> usize { + self.iter.len() + } + + #[inline] + fn is_empty(&self) -> bool { + self.iter.is_empty() + } } diff --git a/library/std/src/sys/args/sgx.rs b/library/std/src/sys/args/sgx.rs index 2a4bc76aefb9..f800500c22a8 100644 --- a/library/std/src/sys/args/sgx.rs +++ b/library/std/src/sys/args/sgx.rs @@ -1,6 +1,8 @@ #![allow(fuzzy_provenance_casts)] // FIXME: this module systematically confuses pointers and integers use crate::ffi::OsString; +use crate::num::NonZero; +use crate::ops::Try; use crate::sync::atomic::{Atomic, AtomicUsize, Ordering}; use crate::sys::os_str::Buf; use crate::sys::pal::abi::usercalls::alloc; @@ -28,35 +30,81 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) { pub fn args() -> Args { let args = unsafe { (ARGS.load(Ordering::Relaxed) as *const ArgsStore).as_ref() }; - if let Some(args) = args { Args(args.iter()) } else { Args([].iter()) } + let slice = args.map(|args| args.as_slice()).unwrap_or(&[]); + Args { iter: slice.iter() } } -pub struct Args(slice::Iter<'static, OsString>); +pub struct Args { + iter: slice::Iter<'static, OsString>, +} impl fmt::Debug for Args { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.as_slice().fmt(f) + self.iter.as_slice().fmt(f) } } impl Iterator for Args { type Item = OsString; - fn next(&mut self) -> Option { - self.0.next().cloned() - } - fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() - } -} -impl ExactSizeIterator for Args { - fn len(&self) -> usize { - self.0.len() + fn next(&mut self) -> Option { + self.iter.next().cloned() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + #[inline] + fn count(self) -> usize { + self.iter.len() + } + + fn last(self) -> Option { + self.iter.last().cloned() + } + + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { + self.iter.advance_by(n) + } + + fn try_fold(&mut self, init: B, f: F) -> R + where + F: FnMut(B, Self::Item) -> R, + R: Try, + { + self.iter.by_ref().cloned().try_fold(init, f) + } + + fn fold(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + self.iter.cloned().fold(init, f) } } impl DoubleEndedIterator for Args { fn next_back(&mut self) -> Option { - self.0.next_back().cloned() + self.iter.next_back().cloned() + } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { + self.iter.advance_back_by(n) + } +} + +impl ExactSizeIterator for Args { + #[inline] + fn len(&self) -> usize { + self.iter.len() + } + + #[inline] + fn is_empty(&self) -> bool { + self.iter.is_empty() } } diff --git a/library/std/src/sys/args/unsupported.rs b/library/std/src/sys/args/unsupported.rs index a2d75a619763..ecffc6d26414 100644 --- a/library/std/src/sys/args/unsupported.rs +++ b/library/std/src/sys/args/unsupported.rs @@ -15,22 +15,28 @@ impl fmt::Debug for Args { impl Iterator for Args { type Item = OsString; + + #[inline] fn next(&mut self) -> Option { None } + + #[inline] fn size_hint(&self) -> (usize, Option) { (0, Some(0)) } } -impl ExactSizeIterator for Args { - fn len(&self) -> usize { - 0 - } -} - impl DoubleEndedIterator for Args { + #[inline] fn next_back(&mut self) -> Option { None } } + +impl ExactSizeIterator for Args { + #[inline] + fn len(&self) -> usize { + 0 + } +} diff --git a/library/test/src/test_result.rs b/library/test/src/test_result.rs index a312894c25c4..4cb43fc45fd6 100644 --- a/library/test/src/test_result.rs +++ b/library/test/src/test_result.rs @@ -61,16 +61,15 @@ pub(crate) fn calc_result( } else if let Some(panic_str) = maybe_panic_str { TestResult::TrFailedMsg(format!( r#"panic did not contain expected string - panic message: `{panic_str:?}`, - expected substring: `{msg:?}`"# + panic message: {panic_str:?} + expected substring: {msg:?}"# )) } else { TestResult::TrFailedMsg(format!( r#"expected panic with string value, found non-string value: `{:?}` - expected substring: `{:?}`"#, - (*err).type_id(), - msg + expected substring: {msg:?}"#, + (*err).type_id() )) } } diff --git a/library/test/src/tests.rs b/library/test/src/tests.rs index 47f581fefae1..d986bd74f772 100644 --- a/library/test/src/tests.rs +++ b/library/test/src/tests.rs @@ -200,8 +200,8 @@ fn test_should_panic_bad_message() { } let expected = "foobar"; let failed_msg = r#"panic did not contain expected string - panic message: `"an error message"`, - expected substring: `"foobar"`"#; + panic message: "an error message" + expected substring: "foobar""#; let desc = TestDescAndFn { desc: TestDesc { name: StaticTestName("whatever"), @@ -238,7 +238,7 @@ fn test_should_panic_non_string_message_type() { let failed_msg = format!( r#"expected panic with string value, found non-string value: `{:?}` - expected substring: `"foobar"`"#, + expected substring: "foobar""#, TypeId::of::() ); let desc = TestDescAndFn { diff --git a/library/unwind/Cargo.toml b/library/unwind/Cargo.toml index da60924c2b41..df43e6ae80fb 100644 --- a/library/unwind/Cargo.toml +++ b/library/unwind/Cargo.toml @@ -22,7 +22,7 @@ cfg-if = "1.0" libc = { version = "0.2.140", features = ['rustc-dep-of-std'], default-features = false } [target.'cfg(target_os = "xous")'.dependencies] -unwinding = { version = "0.2.5", features = ['rustc-dep-of-std', 'unwinder', 'fde-custom'], default-features = false } +unwinding = { version = "0.2.6", features = ['rustc-dep-of-std', 'unwinder', 'fde-custom'], default-features = false } [features] diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 1549d4713af2..ac568eab2e8a 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -462,7 +462,7 @@ macro_rules! bootstrap_tool { } } -pub(crate) const COMPILETEST_ALLOW_FEATURES: &str = "test,internal_output_capture"; +pub(crate) const COMPILETEST_ALLOW_FEATURES: &str = "internal_output_capture"; bootstrap_tool!( // This is marked as an external tool because it includes dependencies diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index e4503b264562..36b3c95d638c 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -872,11 +872,15 @@ impl Builder<'_> { } cargo.env( profile_var("DEBUG_ASSERTIONS"), - if mode == Mode::Std { - self.config.std_debug_assertions.to_string() - } else { - self.config.rustc_debug_assertions.to_string() - }, + match mode { + Mode::Std => self.config.std_debug_assertions, + Mode::Rustc => self.config.rustc_debug_assertions, + Mode::Codegen => self.config.rustc_debug_assertions, + Mode::ToolBootstrap => self.config.tools_debug_assertions, + Mode::ToolStd => self.config.tools_debug_assertions, + Mode::ToolRustc => self.config.tools_debug_assertions, + } + .to_string(), ); cargo.env( profile_var("OVERFLOW_CHECKS"), diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 23b623d9bab2..65a3e7667e7f 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -306,6 +306,7 @@ pub struct Config { pub rustc_debug_assertions: bool, pub std_debug_assertions: bool, + pub tools_debug_assertions: bool, pub rust_overflow_checks: bool, pub rust_overflow_checks_std: bool, @@ -1280,6 +1281,7 @@ define_config! { rustc_debug_assertions: Option = "debug-assertions", randomize_layout: Option = "randomize-layout", std_debug_assertions: Option = "debug-assertions-std", + tools_debug_assertions: Option = "debug-assertions-tools", overflow_checks: Option = "overflow-checks", overflow_checks_std: Option = "overflow-checks-std", debug_logging: Option = "debug-logging", @@ -1937,6 +1939,7 @@ impl Config { let mut debug = None; let mut rustc_debug_assertions = None; let mut std_debug_assertions = None; + let mut tools_debug_assertions = None; let mut overflow_checks = None; let mut overflow_checks_std = None; let mut debug_logging = None; @@ -2000,6 +2003,7 @@ impl Config { codegen_units_std, rustc_debug_assertions: rustc_debug_assertions_toml, std_debug_assertions: std_debug_assertions_toml, + tools_debug_assertions: tools_debug_assertions_toml, overflow_checks: overflow_checks_toml, overflow_checks_std: overflow_checks_std_toml, debug_logging: debug_logging_toml, @@ -2084,6 +2088,7 @@ impl Config { debug = debug_toml; rustc_debug_assertions = rustc_debug_assertions_toml; std_debug_assertions = std_debug_assertions_toml; + tools_debug_assertions = tools_debug_assertions_toml; overflow_checks = overflow_checks_toml; overflow_checks_std = overflow_checks_std_toml; debug_logging = debug_logging_toml; @@ -2509,6 +2514,8 @@ impl Config { let default = debug == Some(true); config.rustc_debug_assertions = rustc_debug_assertions.unwrap_or(default); config.std_debug_assertions = std_debug_assertions.unwrap_or(config.rustc_debug_assertions); + config.tools_debug_assertions = + tools_debug_assertions.unwrap_or(config.rustc_debug_assertions); config.rust_overflow_checks = overflow_checks.unwrap_or(default); config.rust_overflow_checks_std = overflow_checks_std.unwrap_or(config.rust_overflow_checks); @@ -3568,6 +3575,7 @@ fn check_incompatible_options_for_ci_rustc( codegen_units_std: _, rustc_debug_assertions: _, std_debug_assertions: _, + tools_debug_assertions: _, overflow_checks: _, overflow_checks_std: _, debuginfo_level: _, diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 3f1885a425f8..d926185ffaf1 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -401,4 +401,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Info, summary: "Added new option `include` to create config extensions.", }, + ChangeInfo { + change_id: 140438, + severity: ChangeSeverity::Info, + summary: "Added a new option `rust.debug-assertions-tools` to control debug asssertions for tools.", + }, ]; diff --git a/src/ci/docker/scripts/rfl-build.sh b/src/ci/docker/scripts/rfl-build.sh index ea8066d95e02..1d280948ebe6 100755 --- a/src/ci/docker/scripts/rfl-build.sh +++ b/src/ci/docker/scripts/rfl-build.sh @@ -2,7 +2,7 @@ set -euo pipefail -LINUX_VERSION=v6.14-rc3 +LINUX_VERSION=v6.15-rc4 # Build rustc, rustdoc, cargo, clippy-driver and rustfmt ../x.py build --stage 2 library rustdoc clippy rustfmt diff --git a/src/doc/rustc-dev-guide/src/tests/ui.md b/src/doc/rustc-dev-guide/src/tests/ui.md index 6232c8bcc0a6..b31c861c947a 100644 --- a/src/doc/rustc-dev-guide/src/tests/ui.md +++ b/src/doc/rustc-dev-guide/src/tests/ui.md @@ -372,9 +372,9 @@ E.g. use `//@ dont-require-annotations: NOTE` to annotate notes selectively. Avoid using this directive for `ERROR`s and `WARN`ings, unless there's a serious reason, like target-dependent compiler output. -Missing diagnostic kinds (`//~ message`) are currently accepted, but are being phased away. -They will match any compiler output kind, but will not force exhaustive annotations for that kind. -Prefer explicit kind and `//@ dont-require-annotations` to achieve the same effect. +Some diagnostics are never required to be line-annotated, regardless of their kind or directives, +for example secondary lines of multiline diagnostics, +or ubiquitous diagnostics like `aborting due to N previous errors`. UI tests use the `-A unused` flag by default to ignore all unused warnings, as unused warnings are usually not the focus of a test. However, simple code diff --git a/src/doc/unstable-book/src/compiler-flags/rustc-bootstrap.md b/src/doc/unstable-book/src/compiler-flags/rustc-bootstrap.md index 6895f2322386..1520b86341b2 100644 --- a/src/doc/unstable-book/src/compiler-flags/rustc-bootstrap.md +++ b/src/doc/unstable-book/src/compiler-flags/rustc-bootstrap.md @@ -23,7 +23,7 @@ Crates can fully opt out of unstable features by using [`#![forbid(unstable_feat In particular, nightly is built with beta, and beta is built with stable. Since the standard library and compiler both use unstable features, `RUSTC_BOOTSTRAP` is required so that we can use the previous version to build them. -## Why is this environment variable so easy to use for people not in the rust project? +## Why is this environment variable so easy to use for people not in the Rust project? Originally, `RUSTC_BOOTSTRAP` required passing in a hash of the previous compiler version, to discourage using it for any purpose other than bootstrapping. That constraint was later relaxed; see for the discussion that happened at that time. diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index fe1fd70a9fa7..17368a7530d7 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -1117,6 +1117,11 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_const_arg(s); self.hash_const_arg(e); }, + TyPatKind::Or(variants) => { + for variant in variants.iter() { + self.hash_ty_pat(variant) + } + }, TyPatKind::Err(_) => {}, } } diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index e0132056d6c4..4f93b4987413 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -413,14 +413,6 @@ pub struct Config { /// cross-compilation scenarios that do not otherwise want/need to `-Zbuild-std`. Used in e.g. /// ABI tests. pub minicore_path: Utf8PathBuf, - - /// If true, disable the "new" executor, and use the older libtest-based - /// executor to run tests instead. This is a temporary fallback, to make - /// manual comparative testing easier if bugs are found in the new executor. - /// - /// FIXME(Zalathar): Eventually remove this flag and remove the libtest - /// dependency. - pub no_new_executor: bool, } impl Config { diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs index 3bb98276bf52..a45f39b036cc 100644 --- a/src/tools/compiletest/src/errors.rs +++ b/src/tools/compiletest/src/errors.rs @@ -30,24 +30,20 @@ impl ErrorKind { /// Either the canonical uppercase string, or some additional versions for compatibility. /// FIXME: consider keeping only the canonical versions here. - fn from_user_str(s: &str) -> Option { - Some(match s { + pub fn from_user_str(s: &str) -> ErrorKind { + match s { "HELP" | "help" => ErrorKind::Help, "ERROR" | "error" => ErrorKind::Error, - "NOTE" | "note" => ErrorKind::Note, + // `MONO_ITEM` makes annotations in `codegen-units` tests syntactically correct, + // but those tests never use the error kind later on. + "NOTE" | "note" | "MONO_ITEM" => ErrorKind::Note, "SUGGESTION" => ErrorKind::Suggestion, "WARN" | "WARNING" | "warn" | "warning" => ErrorKind::Warning, - _ => return None, - }) - } - - pub fn expect_from_user_str(s: &str) -> ErrorKind { - ErrorKind::from_user_str(s).unwrap_or_else(|| { - panic!( + _ => panic!( "unexpected diagnostic kind `{s}`, expected \ `ERROR`, `WARN`, `NOTE`, `HELP` or `SUGGESTION`" - ) - }) + ), + } } } @@ -67,8 +63,7 @@ impl fmt::Display for ErrorKind { pub struct Error { pub line_num: Option, /// What kind of message we expect (e.g., warning, error, suggestion). - /// `None` if not specified or unknown message kind. - pub kind: Option, + pub kind: ErrorKind, pub msg: String, /// For some `Error`s, like secondary lines of multi-line diagnostics, line annotations /// are not mandatory, even if they would otherwise be mandatory for primary errors. @@ -79,12 +74,7 @@ pub struct Error { impl Error { pub fn render_for_expected(&self) -> String { use colored::Colorize; - format!( - "{: <10}line {: >3}: {}", - self.kind.map(|kind| kind.to_string()).unwrap_or_default(), - self.line_num_str(), - self.msg.cyan(), - ) + format!("{: <10}line {: >3}: {}", self.kind, self.line_num_str(), self.msg.cyan()) } pub fn line_num_str(&self) -> String { @@ -173,9 +163,10 @@ fn parse_expected( // Get the part of the comment after the sigil (e.g. `~^^` or ~|). let tag = captures.get(0).unwrap(); let rest = line[tag.end()..].trim_start(); - let (kind_str, _) = rest.split_once(|c: char| !c.is_ascii_alphabetic()).unwrap_or((rest, "")); + let (kind_str, _) = + rest.split_once(|c: char| c != '_' && !c.is_ascii_alphabetic()).unwrap_or((rest, "")); let kind = ErrorKind::from_user_str(kind_str); - let untrimmed_msg = if kind.is_some() { &rest[kind_str.len()..] } else { rest }; + let untrimmed_msg = &rest[kind_str.len()..]; let msg = untrimmed_msg.strip_prefix(':').unwrap_or(untrimmed_msg).trim().to_owned(); let line_num_adjust = &captures["adjust"]; diff --git a/src/tools/compiletest/src/executor.rs b/src/tools/compiletest/src/executor.rs index 990be56ce0c5..e774c5e2047c 100644 --- a/src/tools/compiletest/src/executor.rs +++ b/src/tools/compiletest/src/executor.rs @@ -12,7 +12,6 @@ use crate::common::{Config, TestPaths}; mod deadline; mod json; -pub(crate) mod libtest; pub(crate) fn run_tests(config: &Config, tests: Vec) -> bool { let tests_len = tests.len(); diff --git a/src/tools/compiletest/src/executor/libtest.rs b/src/tools/compiletest/src/executor/libtest.rs deleted file mode 100644 index 032b3f4fa9a8..000000000000 --- a/src/tools/compiletest/src/executor/libtest.rs +++ /dev/null @@ -1,111 +0,0 @@ -//! This submodule encapsulates all of the code that actually interacts with -//! libtest, so that it can be easily removed after the new executor becomes -//! the default. - -use std::borrow::Cow; -use std::io; - -use crate::common::Config; -use crate::executor::{CollectedTest, CollectedTestDesc, ColorConfig, OutputFormat, ShouldPanic}; - -/// Delegates to libtest to run the list of collected tests. -/// -/// Returns `Ok(true)` if all tests passed, or `Ok(false)` if one or more tests failed. -pub(crate) fn execute_tests(config: &Config, tests: Vec) -> io::Result { - let opts = test_opts(config); - let tests = tests.into_iter().map(|t| t.into_libtest()).collect::>(); - - test::run_tests_console(&opts, tests) -} - -impl CollectedTest { - fn into_libtest(self) -> test::TestDescAndFn { - let Self { desc, config, testpaths, revision } = self; - let CollectedTestDesc { name, ignore, ignore_message, should_panic } = desc; - - // Libtest requires the ignore message to be a &'static str, so we might - // have to leak memory to create it. This is fine, as we only do so once - // per test, so the leak won't grow indefinitely. - let ignore_message = ignore_message.map(|msg| match msg { - Cow::Borrowed(s) => s, - Cow::Owned(s) => &*String::leak(s), - }); - - let desc = test::TestDesc { - name: test::DynTestName(name), - ignore, - ignore_message, - source_file: "", - start_line: 0, - start_col: 0, - end_line: 0, - end_col: 0, - should_panic: should_panic.to_libtest(), - compile_fail: false, - no_run: false, - test_type: test::TestType::Unknown, - }; - - // This closure is invoked when libtest returns control to compiletest - // to execute the test. - let testfn = test::DynTestFn(Box::new(move || { - crate::runtest::run(config, &testpaths, revision.as_deref()); - Ok(()) - })); - - test::TestDescAndFn { desc, testfn } - } -} - -impl ColorConfig { - fn to_libtest(self) -> test::ColorConfig { - match self { - Self::AutoColor => test::ColorConfig::AutoColor, - Self::AlwaysColor => test::ColorConfig::AlwaysColor, - Self::NeverColor => test::ColorConfig::NeverColor, - } - } -} - -impl OutputFormat { - fn to_libtest(self) -> test::OutputFormat { - match self { - Self::Pretty => test::OutputFormat::Pretty, - Self::Terse => test::OutputFormat::Terse, - Self::Json => test::OutputFormat::Json, - } - } -} - -impl ShouldPanic { - fn to_libtest(self) -> test::ShouldPanic { - match self { - Self::No => test::ShouldPanic::No, - Self::Yes => test::ShouldPanic::Yes, - } - } -} - -fn test_opts(config: &Config) -> test::TestOpts { - test::TestOpts { - exclude_should_panic: false, - filters: config.filters.clone(), - filter_exact: config.filter_exact, - run_ignored: if config.run_ignored { test::RunIgnored::Yes } else { test::RunIgnored::No }, - format: config.format.to_libtest(), - logfile: None, - run_tests: true, - bench_benchmarks: true, - nocapture: config.nocapture, - color: config.color.to_libtest(), - shuffle: false, - shuffle_seed: None, - test_threads: None, - skip: config.skip.clone(), - list: false, - options: test::Options::new(), - time_options: None, - force_run_in_process: false, - fail_fast: config.fail_fast, - } -} diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 2b203bb309c6..8bee9caacc94 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -593,7 +593,7 @@ impl TestProps { config.parse_name_value_directive(ln, DONT_REQUIRE_ANNOTATIONS) { self.dont_require_annotations - .insert(ErrorKind::expect_from_user_str(err_kind.trim())); + .insert(ErrorKind::from_user_str(err_kind.trim())); } }, ); diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs index 62fe538ee32e..960f5ba58882 100644 --- a/src/tools/compiletest/src/json.rs +++ b/src/tools/compiletest/src/json.rs @@ -229,7 +229,7 @@ fn push_actual_errors( // Convert multi-line messages into multiple errors. // We expect to replace these with something more structured anyhow. let mut message_lines = diagnostic.message.lines(); - let kind = Some(ErrorKind::from_compiler_str(&diagnostic.level)); + let kind = ErrorKind::from_compiler_str(&diagnostic.level); let first_line = message_lines.next().unwrap_or(&diagnostic.message); if primary_spans.is_empty() { static RE: OnceLock = OnceLock::new(); @@ -278,7 +278,7 @@ fn push_actual_errors( for (index, line) in suggested_replacement.lines().enumerate() { errors.push(Error { line_num: Some(span.line_start + index), - kind: Some(ErrorKind::Suggestion), + kind: ErrorKind::Suggestion, msg: line.to_string(), require_annotation: true, }); @@ -297,7 +297,7 @@ fn push_actual_errors( for span in spans_in_this_file.iter().filter(|span| span.label.is_some()) { errors.push(Error { line_num: Some(span.line_start), - kind: Some(ErrorKind::Note), + kind: ErrorKind::Note, msg: span.label.clone().unwrap(), require_annotation: true, }); @@ -317,7 +317,7 @@ fn push_backtrace( if Path::new(&expansion.span.file_name) == Path::new(&file_name) { errors.push(Error { line_num: Some(expansion.span.line_start), - kind: Some(ErrorKind::Note), + kind: ErrorKind::Note, msg: format!("in this expansion of {}", expansion.macro_decl_name), require_annotation: true, }); diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 788bafaa7247..0db4d3f6a410 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -1,11 +1,10 @@ #![crate_name = "compiletest"] -// Needed by the libtest-based test executor. -#![feature(test)] // Needed by the "new" test executor that does not depend on libtest. +// FIXME(Zalathar): We should be able to get rid of `internal_output_capture`, +// by having `runtest` manually capture all of its println-like output instead. +// That would result in compiletest being written entirely in stable Rust! #![feature(internal_output_capture)] -extern crate test; - #[cfg(test)] mod tests; @@ -448,8 +447,6 @@ pub fn parse_config(args: Vec) -> Config { diff_command: matches.opt_str("compiletest-diff-tool"), minicore_path: opt_path(matches, "minicore-path"), - - no_new_executor: matches.opt_present("no-new-executor"), } } @@ -576,12 +573,10 @@ pub fn run_tests(config: Arc) { // Delegate to the executor to filter and run the big list of test structures // created during test discovery. When the executor decides to run a test, // it will return control to the rest of compiletest by calling `runtest::run`. - let res = if !config.no_new_executor { - Ok(executor::run_tests(&config, tests)) - } else { - // FIXME(Zalathar): Eventually remove the libtest executor entirely. - crate::executor::libtest::execute_tests(&config, tests) - }; + // FIXME(Zalathar): Once we're confident that we won't need to revert the + // removal of the libtest-based executor, remove this Result and other + // remnants of the old executor. + let res: io::Result = Ok(executor::run_tests(&config, tests)); // Check the outcome reported by libtest. match res { diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index fe23cce81e90..97cb82c9e363 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -675,9 +675,7 @@ impl<'test> TestCx<'test> { "check_expected_errors: expected_errors={:?} proc_res.status={:?}", expected_errors, proc_res.status ); - if proc_res.status.success() - && expected_errors.iter().any(|x| x.kind == Some(ErrorKind::Error)) - { + if proc_res.status.success() && expected_errors.iter().any(|x| x.kind == ErrorKind::Error) { self.fatal_proc_rec("process did not return an error status", proc_res); } @@ -709,7 +707,7 @@ impl<'test> TestCx<'test> { // if one of them actually occurs in the test. let expected_kinds: HashSet<_> = [ErrorKind::Error, ErrorKind::Warning] .into_iter() - .chain(expected_errors.iter().filter_map(|e| e.kind)) + .chain(expected_errors.iter().map(|e| e.kind)) .collect(); // Parse the JSON output from the compiler and extract out the messages. @@ -723,8 +721,7 @@ impl<'test> TestCx<'test> { expected_errors.iter().enumerate().position(|(index, expected_error)| { !found[index] && actual_error.line_num == expected_error.line_num - && (expected_error.kind.is_none() - || actual_error.kind == expected_error.kind) + && actual_error.kind == expected_error.kind && actual_error.msg.contains(&expected_error.msg) }); @@ -737,19 +734,14 @@ impl<'test> TestCx<'test> { None => { if actual_error.require_annotation - && actual_error.kind.map_or(false, |kind| { - expected_kinds.contains(&kind) - && !self.props.dont_require_annotations.contains(&kind) - }) + && expected_kinds.contains(&actual_error.kind) + && !self.props.dont_require_annotations.contains(&actual_error.kind) { self.error(&format!( "{}:{}: unexpected {}: '{}'", file_name, actual_error.line_num_str(), - actual_error - .kind - .as_ref() - .map_or(String::from("message"), |k| k.to_string()), + actual_error.kind, actual_error.msg )); unexpected.push(actual_error); @@ -766,7 +758,7 @@ impl<'test> TestCx<'test> { "{}:{}: expected {} not found: {}", file_name, expected_error.line_num_str(), - expected_error.kind.as_ref().map_or("message".into(), |k| k.to_string()), + expected_error.kind, expected_error.msg )); not_found.push(expected_error); diff --git a/src/tools/compiletest/src/runtest/ui.rs b/src/tools/compiletest/src/runtest/ui.rs index e87b037cd289..cf0ae14f81bf 100644 --- a/src/tools/compiletest/src/runtest/ui.rs +++ b/src/tools/compiletest/src/runtest/ui.rs @@ -6,8 +6,8 @@ use rustfix::{Filter, apply_suggestions, get_suggestions_from_json}; use tracing::debug; use super::{ - AllowUnused, Emit, ErrorKind, FailMode, LinkToAux, PassMode, TargetLocation, TestCx, - TestOutput, Truncated, UI_FIXED, WillExecute, + AllowUnused, Emit, FailMode, LinkToAux, PassMode, TargetLocation, TestCx, TestOutput, + Truncated, UI_FIXED, WillExecute, }; use crate::{errors, json}; @@ -176,7 +176,7 @@ impl TestCx<'_> { let msg = format!( "line {}: cannot combine `--error-format` with {} annotations; use `error-pattern` instead", expected_errors[0].line_num_str(), - expected_errors[0].kind.unwrap_or(ErrorKind::Error), + expected_errors[0].kind, ); self.fatal(&msg); } diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index 7d60a7e5c489..3334c0b5edf9 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -7,13 +7,13 @@ use rand::Rng; use rustc_abi::Size; use rustc_apfloat::{Float, Round}; use rustc_middle::mir; -use rustc_middle::ty::{self, FloatTy, ScalarInt}; +use rustc_middle::ty::{self, FloatTy}; use rustc_span::{Symbol, sym}; use self::atomic::EvalContextExt as _; use self::helpers::{ToHost, ToSoft, check_intrinsic_arg_count}; use self::simd::EvalContextExt as _; -use crate::math::apply_random_float_error_ulp; +use crate::math::apply_random_float_error_to_imm; use crate::*; impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} @@ -473,26 +473,3 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(EmulateItemResult::NeedsReturn) } } - -/// Applies a random 16ULP floating point error to `val` and returns the new value. -/// Will fail if `val` is not a floating point number. -fn apply_random_float_error_to_imm<'tcx>( - ecx: &mut MiriInterpCx<'tcx>, - val: ImmTy<'tcx>, - ulp_exponent: u32, -) -> InterpResult<'tcx, ImmTy<'tcx>> { - let scalar = val.to_scalar_int()?; - let res: ScalarInt = match val.layout.ty.kind() { - ty::Float(FloatTy::F16) => - apply_random_float_error_ulp(ecx, scalar.to_f16(), ulp_exponent).into(), - ty::Float(FloatTy::F32) => - apply_random_float_error_ulp(ecx, scalar.to_f32(), ulp_exponent).into(), - ty::Float(FloatTy::F64) => - apply_random_float_error_ulp(ecx, scalar.to_f64(), ulp_exponent).into(), - ty::Float(FloatTy::F128) => - apply_random_float_error_ulp(ecx, scalar.to_f128(), ulp_exponent).into(), - _ => bug!("intrinsic called with non-float input type"), - }; - - interp_ok(ImmTy::from_scalar_int(res, val.layout)) -} diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 9859a6bca178..3ee53005a036 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -1198,6 +1198,16 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { ecx.generate_nan(inputs) } + #[inline(always)] + fn apply_float_nondet( + ecx: &mut InterpCx<'tcx, Self>, + val: ImmTy<'tcx>, + ) -> InterpResult<'tcx, ImmTy<'tcx>> { + crate::math::apply_random_float_error_to_imm( + ecx, val, 2 /* log2(4) */ + ) + } + #[inline(always)] fn equal_float_min_max(ecx: &MiriInterpCx<'tcx>, a: F, b: F) -> F { ecx.equal_float_min_max(a, b) diff --git a/src/tools/miri/src/math.rs b/src/tools/miri/src/math.rs index fdd021f85394..2ff29c7ac1aa 100644 --- a/src/tools/miri/src/math.rs +++ b/src/tools/miri/src/math.rs @@ -1,6 +1,9 @@ use rand::Rng as _; use rustc_apfloat::Float as _; use rustc_apfloat::ieee::IeeeFloat; +use rustc_middle::ty::{self, FloatTy, ScalarInt}; + +use crate::*; /// Disturbes a floating-point result by a relative error in the range (-2^scale, 2^scale). /// @@ -43,6 +46,29 @@ pub(crate) fn apply_random_float_error_ulp( apply_random_float_error(ecx, val, err_scale) } +/// Applies a random 16ULP floating point error to `val` and returns the new value. +/// Will fail if `val` is not a floating point number. +pub(crate) fn apply_random_float_error_to_imm<'tcx>( + ecx: &mut MiriInterpCx<'tcx>, + val: ImmTy<'tcx>, + ulp_exponent: u32, +) -> InterpResult<'tcx, ImmTy<'tcx>> { + let scalar = val.to_scalar_int()?; + let res: ScalarInt = match val.layout.ty.kind() { + ty::Float(FloatTy::F16) => + apply_random_float_error_ulp(ecx, scalar.to_f16(), ulp_exponent).into(), + ty::Float(FloatTy::F32) => + apply_random_float_error_ulp(ecx, scalar.to_f32(), ulp_exponent).into(), + ty::Float(FloatTy::F64) => + apply_random_float_error_ulp(ecx, scalar.to_f64(), ulp_exponent).into(), + ty::Float(FloatTy::F128) => + apply_random_float_error_ulp(ecx, scalar.to_f128(), ulp_exponent).into(), + _ => bug!("intrinsic called with non-float input type"), + }; + + interp_ok(ImmTy::from_scalar_int(res, val.layout)) +} + pub(crate) fn sqrt(x: IeeeFloat) -> IeeeFloat { match x.category() { // preserve zero sign diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs index 575d70579a4e..98a88cfd62dc 100644 --- a/src/tools/miri/tests/pass/float.rs +++ b/src/tools/miri/tests/pass/float.rs @@ -1292,8 +1292,7 @@ fn test_non_determinism() { } } // We saw the same thing N times. - // FIXME: temporarily disabled as it breaks std tests. - //panic!("expected non-determinism, got {rounds} times the same result: {first:?}"); + panic!("expected non-determinism, got {rounds} times the same result: {first:?}"); } macro_rules! test_operations_f { @@ -1319,66 +1318,68 @@ fn test_non_determinism() { } pub fn test_operations_f32(a: f32, b: f32) { test_operations_f!(a, b); - ensure_nondet(|| a.log(b)); - ensure_nondet(|| a.exp()); - ensure_nondet(|| 10f32.exp2()); - ensure_nondet(|| f32::consts::E.ln()); - ensure_nondet(|| 1f32.ln_1p()); - ensure_nondet(|| 10f32.log10()); - ensure_nondet(|| 8f32.log2()); - ensure_nondet(|| 27.0f32.cbrt()); - ensure_nondet(|| 3.0f32.hypot(4.0f32)); - ensure_nondet(|| 1f32.sin()); - ensure_nondet(|| 0f32.cos()); - // On i686-pc-windows-msvc , these functions are implemented by calling the `f64` version, - // which means the little rounding errors Miri introduces are discard by the cast down to `f32`. - // Just skip the test for them. - if !cfg!(all(target_os = "windows", target_env = "msvc", target_arch = "x86")) { - ensure_nondet(|| 1.0f32.tan()); - ensure_nondet(|| 1.0f32.asin()); - ensure_nondet(|| 5.0f32.acos()); - ensure_nondet(|| 1.0f32.atan()); - ensure_nondet(|| 1.0f32.atan2(2.0f32)); - ensure_nondet(|| 1.0f32.sinh()); - ensure_nondet(|| 1.0f32.cosh()); - ensure_nondet(|| 1.0f32.tanh()); - } - ensure_nondet(|| 1.0f32.asinh()); - ensure_nondet(|| 2.0f32.acosh()); - ensure_nondet(|| 0.5f32.atanh()); - ensure_nondet(|| 5.0f32.gamma()); - ensure_nondet(|| 5.0f32.ln_gamma()); - ensure_nondet(|| 5.0f32.erf()); - ensure_nondet(|| 5.0f32.erfc()); + // FIXME: temporarily disabled as it breaks std tests. + // ensure_nondet(|| a.log(b)); + // ensure_nondet(|| a.exp()); + // ensure_nondet(|| 10f32.exp2()); + // ensure_nondet(|| f32::consts::E.ln()); + // ensure_nondet(|| 1f32.ln_1p()); + // ensure_nondet(|| 10f32.log10()); + // ensure_nondet(|| 8f32.log2()); + // ensure_nondet(|| 27.0f32.cbrt()); + // ensure_nondet(|| 3.0f32.hypot(4.0f32)); + // ensure_nondet(|| 1f32.sin()); + // ensure_nondet(|| 0f32.cos()); + // // On i686-pc-windows-msvc , these functions are implemented by calling the `f64` version, + // // which means the little rounding errors Miri introduces are discard by the cast down to `f32`. + // // Just skip the test for them. + // if !cfg!(all(target_os = "windows", target_env = "msvc", target_arch = "x86")) { + // ensure_nondet(|| 1.0f32.tan()); + // ensure_nondet(|| 1.0f32.asin()); + // ensure_nondet(|| 5.0f32.acos()); + // ensure_nondet(|| 1.0f32.atan()); + // ensure_nondet(|| 1.0f32.atan2(2.0f32)); + // ensure_nondet(|| 1.0f32.sinh()); + // ensure_nondet(|| 1.0f32.cosh()); + // ensure_nondet(|| 1.0f32.tanh()); + // } + // ensure_nondet(|| 1.0f32.asinh()); + // ensure_nondet(|| 2.0f32.acosh()); + // ensure_nondet(|| 0.5f32.atanh()); + // ensure_nondet(|| 5.0f32.gamma()); + // ensure_nondet(|| 5.0f32.ln_gamma()); + // ensure_nondet(|| 5.0f32.erf()); + // ensure_nondet(|| 5.0f32.erfc()); } pub fn test_operations_f64(a: f64, b: f64) { test_operations_f!(a, b); - ensure_nondet(|| a.log(b)); - ensure_nondet(|| a.exp()); - ensure_nondet(|| 50f64.exp2()); - ensure_nondet(|| 3f64.ln()); - ensure_nondet(|| 1f64.ln_1p()); - ensure_nondet(|| f64::consts::E.log10()); - ensure_nondet(|| f64::consts::E.log2()); - ensure_nondet(|| 27.0f64.cbrt()); - ensure_nondet(|| 3.0f64.hypot(4.0f64)); - ensure_nondet(|| 1f64.sin()); - ensure_nondet(|| 0f64.cos()); - ensure_nondet(|| 1.0f64.tan()); - ensure_nondet(|| 1.0f64.asin()); - ensure_nondet(|| 5.0f64.acos()); - ensure_nondet(|| 1.0f64.atan()); - ensure_nondet(|| 1.0f64.atan2(2.0f64)); - ensure_nondet(|| 1.0f64.sinh()); - ensure_nondet(|| 1.0f64.cosh()); - ensure_nondet(|| 1.0f64.tanh()); - ensure_nondet(|| 1.0f64.asinh()); - ensure_nondet(|| 3.0f64.acosh()); - ensure_nondet(|| 0.5f64.atanh()); - ensure_nondet(|| 5.0f64.gamma()); - ensure_nondet(|| 5.0f64.ln_gamma()); - ensure_nondet(|| 5.0f64.erf()); - ensure_nondet(|| 5.0f64.erfc()); + // FIXME: temporarily disabled as it breaks std tests. + // ensure_nondet(|| a.log(b)); + // ensure_nondet(|| a.exp()); + // ensure_nondet(|| 50f64.exp2()); + // ensure_nondet(|| 3f64.ln()); + // ensure_nondet(|| 1f64.ln_1p()); + // ensure_nondet(|| f64::consts::E.log10()); + // ensure_nondet(|| f64::consts::E.log2()); + // ensure_nondet(|| 27.0f64.cbrt()); + // ensure_nondet(|| 3.0f64.hypot(4.0f64)); + // ensure_nondet(|| 1f64.sin()); + // ensure_nondet(|| 0f64.cos()); + // ensure_nondet(|| 1.0f64.tan()); + // ensure_nondet(|| 1.0f64.asin()); + // ensure_nondet(|| 5.0f64.acos()); + // ensure_nondet(|| 1.0f64.atan()); + // ensure_nondet(|| 1.0f64.atan2(2.0f64)); + // ensure_nondet(|| 1.0f64.sinh()); + // ensure_nondet(|| 1.0f64.cosh()); + // ensure_nondet(|| 1.0f64.tanh()); + // ensure_nondet(|| 1.0f64.asinh()); + // ensure_nondet(|| 3.0f64.acosh()); + // ensure_nondet(|| 0.5f64.atanh()); + // ensure_nondet(|| 5.0f64.gamma()); + // ensure_nondet(|| 5.0f64.ln_gamma()); + // ensure_nondet(|| 5.0f64.erf()); + // ensure_nondet(|| 5.0f64.erfc()); } pub fn test_operations_f128(a: f128, b: f128) { test_operations_f!(a, b); diff --git a/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/bug_report.md b/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/bug_report.md index 0d99d06bcdde..8333cf08929f 100644 --- a/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/bug_report.md +++ b/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/bug_report.md @@ -8,7 +8,7 @@ assignees: '' --- diff --git a/src/tools/rust-analyzer/.github/workflows/ci.yaml b/src/tools/rust-analyzer/.github/workflows/ci.yaml index 7a6b43a05315..79fb7a2d2ea9 100644 --- a/src/tools/rust-analyzer/.github/workflows/ci.yaml +++ b/src/tools/rust-analyzer/.github/workflows/ci.yaml @@ -15,7 +15,6 @@ env: CARGO_NET_RETRY: 10 CI: 1 RUST_BACKTRACE: short - RUSTFLAGS: "-D warnings -D elided_lifetimes_in_paths -D explicit_outlives_requirements -D unsafe_op_in_unsafe_fn -D unused_extern_crates -D unused_lifetimes -D unreachable_pub" RUSTUP_MAX_RETRIES: 10 jobs: @@ -25,7 +24,6 @@ jobs: pull-requests: read outputs: typescript: ${{ steps.filter.outputs.typescript }} - proc_macros: ${{ steps.filter.outputs.proc_macros }} steps: - uses: actions/checkout@v4 - uses: dorny/paths-filter@1441771bbfdd59dcd748680ee64ebd8faab1a242 @@ -34,52 +32,54 @@ jobs: filters: | typescript: - 'editors/code/**' - proc_macros: - - 'crates/tt/**' - - 'crates/proc-macro-api/**' - - 'crates/proc-macro-srv/**' - - 'crates/proc-macro-srv-cli/**' proc-macro-srv: - needs: changes - if: github.repository == 'rust-lang/rust-analyzer' && needs.changes.outputs.proc_macros == 'true' + if: github.repository == 'rust-lang/rust-analyzer' name: proc-macro-srv runs-on: ubuntu-latest + env: + RUSTFLAGS: "-D warnings" + steps: - name: Checkout repository uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} + - name: Install rustup-toolchain-install-master + run: cargo install rustup-toolchain-install-master@1.6.0 + + # Install a pinned rustc commit to avoid surprises - name: Install Rust toolchain run: | - rustup update --no-self-update nightly - rustup default nightly - rustup component add --toolchain nightly rust-src rustfmt + RUSTC_VERSION=`cat rust-version` + rustup-toolchain-install-master ${RUSTC_VERSION} -c rust-src -c rustfmt + rustup default ${RUSTC_VERSION} + + # Emulate a nightly toolchain, because the toolchain installed above does not have "nightly" + # in its version string. + - name: Emulate a nightly toolchain + run: echo "RUSTC_BOOTSTRAP=1" >> $GITHUB_ENV + # https://github.com/actions-rust-lang/setup-rust-toolchain/blob/main/rust.json - name: Install Rust Problem Matcher - if: matrix.os == 'ubuntu-latest' run: echo "::add-matcher::.github/rust.json" - - name: Cache Dependencies - uses: Swatinem/rust-cache@9bdad043e88c75890e36ad3bbc8d27f0090dd609 - - - name: Bump opt-level - if: matrix.os == 'ubuntu-latest' - run: sed -i '/\[profile.dev]/a opt-level=1' Cargo.toml - - name: Test - run: cargo test --features sysroot-abi -p rust-analyzer -p proc-macro-srv -p proc-macro-srv-cli -p proc-macro-api -- --quiet + run: cargo test --features sysroot-abi -p proc-macro-srv -p proc-macro-srv-cli -p proc-macro-api -- --quiet + + - name: Check salsa dependency + run: "! (cargo tree -p proc-macro-srv-cli | grep -q salsa)" rust: if: github.repository == 'rust-lang/rust-analyzer' name: Rust runs-on: ${{ matrix.os }} env: + RUSTFLAGS: "-Dwarnings" CC: deny_c strategy: - fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] @@ -93,7 +93,7 @@ jobs: run: | rustup update --no-self-update stable rustup default stable - rustup component add --toolchain stable rust-src + rustup component add --toolchain stable rust-src clippy # We always use a nightly rustfmt, regardless of channel, because we need # --file-lines. rustup toolchain install nightly --profile minimal --component rustfmt @@ -102,63 +102,46 @@ jobs: if: matrix.os == 'ubuntu-latest' run: echo "::add-matcher::.github/rust.json" - - name: Cache Dependencies - uses: Swatinem/rust-cache@9bdad043e88c75890e36ad3bbc8d27f0090dd609 + # - name: Cache Dependencies + # uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 + # with: + # workspaces: | + # . -> target + # ./crates/proc-macro-srv/proc-macro-test/imp -> target - - name: Bump opt-level - if: matrix.os == 'ubuntu-latest' - run: sed -i '/\[profile.dev]/a opt-level=1' Cargo.toml + - name: Install nextest + uses: taiki-e/install-action@nextest - name: Codegen checks (rust-analyzer) + if: matrix.os == 'ubuntu-latest' run: cargo codegen --check - - name: Compile (tests) - run: cargo test --no-run --locked + - name: Compile tests + run: cargo test --no-run - # It's faster to `test` before `build` ¯\_(ツ)_/¯ - - name: Compile (rust-analyzer) - if: matrix.os == 'ubuntu-latest' - run: cargo build --quiet + - name: Run tests + run: cargo nextest run --no-fail-fast --hide-progress-bar --status-level fail - - name: Test - if: matrix.os == 'ubuntu-latest' || matrix.os == 'windows-latest' || github.event_name == 'push' - run: cargo test -- --quiet - - - name: Switch to stable toolchain + - name: Cancel parallel jobs + if: failure() run: | - rustup update --no-self-update stable - rustup component add --toolchain stable rust-src clippy - rustup default stable + # https://docs.github.com/en/rest/actions/workflow-runs?apiVersion=2022-11-28#cancel-a-workflow-run + curl -L \ + -X POST \ + -H "Accept: application/vnd.github.v3+json" \ + -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + https://api.github.com/repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/cancel - - name: Run analysis-stats on rust-analyzer - if: matrix.os == 'ubuntu-latest' - run: target/${{ matrix.target }}/debug/rust-analyzer analysis-stats . - - - name: Run analysis-stats on the rust standard libraries - if: matrix.os == 'ubuntu-latest' - env: - RUSTC_BOOTSTRAP: 1 - run: target/${{ matrix.target }}/debug/rust-analyzer analysis-stats --with-deps --no-sysroot --no-test $(rustc --print sysroot)/lib/rustlib/src/rust/library/ - - - name: clippy - if: matrix.os == 'windows-latest' + - name: Run Clippy + if: matrix.os == 'macos-latest' run: cargo clippy --all-targets -- -D clippy::disallowed_macros -D clippy::dbg_macro -D clippy::todo -D clippy::print_stdout -D clippy::print_stderr - - name: rustfmt - if: matrix.os == 'ubuntu-latest' - run: cargo fmt -- --check - - # Weird targets to catch non-portable code - rust-cross: + analysis-stats: if: github.repository == 'rust-lang/rust-analyzer' - name: Rust Cross runs-on: ubuntu-latest - env: - targets: "powerpc-unknown-linux-gnu x86_64-unknown-linux-musl" - # The rust-analyzer binary is not expected to compile on WASM, but the IDE - # crate should - targets_ide: "wasm32-unknown-unknown" + RUSTC_BOOTSTRAP: 1 steps: - name: Checkout repository @@ -167,19 +150,91 @@ jobs: - name: Install Rust toolchain run: | rustup update --no-self-update stable - rustup target add ${{ env.targets }} ${{ env.targets_ide }} + rustup default stable + rustup component add rustfmt - - name: Cache Dependencies - uses: Swatinem/rust-cache@9bdad043e88c75890e36ad3bbc8d27f0090dd609 + # - name: Cache Dependencies + # uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 - - name: Check + - name: Bump opt-level + run: sed -i '/\[profile.dev]/a opt-level=1' Cargo.toml + + - run: cargo build -p rust-analyzer + + - name: ./rust-analyzer + run: ./target/debug/rust-analyzer analysis-stats . -q + + - name: sysroot/lib/rustlib/src/rust/library/ + run: ./target/debug/rust-analyzer analysis-stats --with-deps --no-sysroot --no-test $(rustc --print sysroot)/lib/rustlib/src/rust/library/ -q + + rustfmt: + if: github.repository == 'rust-lang/rust-analyzer' + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install Rust toolchain run: | - for target in ${{ env.targets }}; do - cargo check --target=$target --all-targets - done - for target in ${{ env.targets_ide }}; do - cargo check -p ide --target=$target --all-targets - done + rustup update --no-self-update stable + rustup default stable + rustup component add rustfmt + + - run: cargo fmt -- --check + + miri: + if: github.repository == 'rust-lang/rust-analyzer' + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install Rust toolchain + run: | + rustup update --no-self-update nightly + rustup default nightly + rustup component add miri + + # - name: Cache Dependencies + # uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 + + - run: cargo miri test -p intern + + # Weird targets to catch non-portable code + rust-cross: + if: github.repository == 'rust-lang/rust-analyzer' + name: Rust Cross + runs-on: ubuntu-latest + + strategy: + matrix: + target: [powerpc-unknown-linux-gnu, x86_64-unknown-linux-musl, wasm32-unknown-unknown] + include: + # The rust-analyzer binary is not expected to compile on WASM, but the IDE + # crate should + - target: wasm32-unknown-unknown + ide-only: true + env: + RUSTFLAGS: "-Dwarnings" + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install Rust toolchain + run: | + rustup update --no-self-update stable + rustup target add ${{ matrix.target }} + + # - name: Cache Dependencies + # uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 + + - run: cargo check --target=${{ matrix.target }} --all-targets -p ide + if: ${{ matrix.ide-only }} + - run: cargo check --target=${{ matrix.target }} --all-targets + if: ${{ !matrix.ide-only }} typescript: needs: changes @@ -261,7 +316,7 @@ jobs: run: typos conclusion: - needs: [rust, rust-cross, typescript, typo-check, proc-macro-srv] + needs: [rust, rust-cross, typescript, typo-check, proc-macro-srv, miri, rustfmt, analysis-stats] # We need to ensure this job does *not* get skipped if its dependencies fail, # because a skipped job is considered a success by GitHub. So we have to # overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run diff --git a/src/tools/rust-analyzer/.github/workflows/release.yaml b/src/tools/rust-analyzer/.github/workflows/release.yaml index c8e6de72ce98..a758ecfd4679 100644 --- a/src/tools/rust-analyzer/.github/workflows/release.yaml +++ b/src/tools/rust-analyzer/.github/workflows/release.yaml @@ -29,19 +29,25 @@ jobs: - os: windows-latest target: x86_64-pc-windows-msvc code-target: win32-x64 + pgo: clap-rs/clap@v4.5.36 - os: windows-latest target: i686-pc-windows-msvc + pgo: clap-rs/clap@v4.5.36 - os: windows-latest target: aarch64-pc-windows-msvc code-target: win32-arm64 - os: ubuntu-latest target: x86_64-unknown-linux-gnu - zig_target: x86_64-unknown-linux-gnu.2.28 + # Use a container with glibc 2.28 + # Zig is not used because it doesn't work with PGO + container: quay.io/pypa/manylinux_2_28_x86_64 code-target: linux-x64 - - os: ubuntu-latest + pgo: clap-rs/clap@v4.5.36 + - os: ubuntu-24.04-arm target: aarch64-unknown-linux-gnu - zig_target: aarch64-unknown-linux-gnu.2.28 + container: quay.io/pypa/manylinux_2_28_aarch64 code-target: linux-arm64 + pgo: clap-rs/clap@v4.5.36 - os: ubuntu-latest target: arm-unknown-linux-gnueabihf zig_target: arm-unknown-linux-gnueabihf.2.28 @@ -49,9 +55,11 @@ jobs: - os: macos-13 target: x86_64-apple-darwin code-target: darwin-x64 - - os: macos-13 + pgo: clap-rs/clap@v4.5.36 + - os: macos-14 target: aarch64-apple-darwin code-target: darwin-arm64 + pgo: clap-rs/clap@v4.5.36 name: dist (${{ matrix.target }}) runs-on: ${{ matrix.os }} @@ -71,10 +79,17 @@ jobs: with: node-version: 22 + - name: Install rustup + if: ${{ matrix.container }} + run: | + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal + echo "$HOME/.cargo/bin" >> $GITHUB_PATH + - name: Install Rust toolchain run: | rustup update --no-self-update stable - rustup component add rust-src + # llvm-tools contain the llvm-profdata tool which is needed for PGO + rustup component add rust-src ${{ matrix.pgo && 'llvm-tools' || '' }} rustup target add ${{ matrix.target }} - name: Install Zig toolchain @@ -87,11 +102,11 @@ jobs: - name: Dist (plain) if: ${{ !matrix.zig_target }} - run: cargo xtask dist --client-patch-version ${{ github.run_number }} + run: cargo xtask dist --client-patch-version ${{ github.run_number }} ${{ matrix.pgo && format('--pgo {0}', matrix.pgo) || ''}} - name: Dist (using zigbuild) if: ${{ matrix.zig_target }} - run: RA_TARGET=${{ matrix.zig_target}} cargo xtask dist --client-patch-version ${{ github.run_number }} --zig + run: RA_TARGET=${{ matrix.zig_target}} cargo xtask dist --client-patch-version ${{ github.run_number }} --zig ${{ matrix.pgo && format('--pgo {0}', matrix.pgo) || ''}} - run: npm ci working-directory: editors/code diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 2dbb3f5d69ca..9f6b80c63790 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -1,65 +1,77 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" -version = "0.22.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] -name = "always-assert" -version = "0.2.0" +name = "aho-corasick" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1078fa1ce1e34b1872d8611ad921196d76bdd7027e949fbe31231abde201892" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" [[package]] name = "arbitrary" -version = "1.3.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" +dependencies = [ + "derive_arbitrary", +] [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backtrace" -version = "0.3.73" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", "miniz_oxide", - "object 0.36.3", + "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -67,14 +79,14 @@ name = "base-db" version = "0.0.0" dependencies = [ "cfg", + "dashmap", "intern", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lz4_flex", - "rustc-hash 2.0.0", + "query-group-macro", + "rustc-hash 2.1.1", "salsa", "semver", "span", - "stdx", "syntax", "tracing", "triomphe", @@ -95,62 +107,65 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.7.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1be3f42a67d6d345ecd59f675f3f012d6974981560836e938c22b424b85ce1be" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" [[package]] name = "borsh" -version = "1.5.1" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6362ed55def622cddc70a4746a68554d7b687713770de539e59a739b249f8ed" +checksum = "5430e3be710b68d984d1391c854eb431a9d548640711faa54eecb1df93db91cc" dependencies = [ - "cfg_aliases 0.2.1", + "cfg_aliases", ] [[package]] -name = "byteorder" -version = "1.5.0" +name = "boxcar" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +checksum = "6740c6e2fc6360fa57c35214c7493826aee95993926092606f27c983b40837be" +dependencies = [ + "loom", +] [[package]] name = "camino" -version = "1.1.7" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" dependencies = [ "serde", ] [[package]] name = "cargo-platform" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" dependencies = [ "serde", ] [[package]] name = "cargo_metadata" -version = "0.18.1" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" +checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" dependencies = [ "camino", "cargo-platform", "semver", "serde", "serde_json", - "thiserror", + "thiserror 2.0.12", ] [[package]] name = "cc" -version = "1.1.22" +version = "1.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0" +checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" dependencies = [ "shlex", ] @@ -164,7 +179,7 @@ dependencies = [ "expect-test", "intern", "oorandom", - "rustc-hash 2.0.0", + "rustc-hash 2.1.1", "syntax", "syntax-bridge", "tracing", @@ -177,12 +192,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "cfg_aliases" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" - [[package]] name = "cfg_aliases" version = "0.2.1" @@ -191,9 +200,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chalk-derive" -version = "0.100.0" +version = "0.102.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab2d131019373f0d0d1f2af0abd4f719739f6583c1b33965112455f643a910af" +checksum = "feb14e3ff0ebac26d8e58b6ed1417afb60c4a0a44b6425546ee7eb9c75ebb336" dependencies = [ "proc-macro2", "quote", @@ -203,19 +212,19 @@ dependencies = [ [[package]] name = "chalk-ir" -version = "0.100.0" +version = "0.102.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f114996bda14c0213f014a4ef31a7867dcf5f539a3900477fc6b20138e7a17b" +checksum = "72f0a61621a088af69fee8df39ec63cf5b6d0b9ab663a740cdeb376aabf2f244" dependencies = [ - "bitflags 2.7.0", + "bitflags 2.9.0", "chalk-derive", ] [[package]] name = "chalk-recursive" -version = "0.100.0" +version = "0.102.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "551e956e031c09057c7b21f17d48d91de99c9b6b6e34bceaf5e7202d71021268" +checksum = "cbd3415cc540015533aa4a8ad007696d585dd9c5f81e7c099872f1dd4bf14894" dependencies = [ "chalk-derive", "chalk-ir", @@ -226,15 +235,15 @@ dependencies = [ [[package]] name = "chalk-solve" -version = "0.100.0" +version = "0.102.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd7ca50181156ce649efe8e5dd00580f573651554e4dcd11afa4e2ac93f53324" +checksum = "747707b0c082b3ecf4b1ae28d0d8df708a46cddd22a386f9cc85a312a4de25ff" dependencies = [ "chalk-derive", "chalk-ir", "ena", "indexmap", - "itertools", + "itertools 0.12.1", "petgraph", "rustc-hash 1.1.0", "tracing", @@ -263,18 +272,18 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.13" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -290,29 +299,39 @@ dependencies = [ ] [[package]] -name = "crossbeam-utils" -version = "0.8.20" +name = "crossbeam-queue" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "ctrlc" -version = "3.4.4" +version = "3.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "672465ae37dc1bc6380a6547a8883d5dd397b0f1faaad4f265726cc7042a5345" +checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3" dependencies = [ "nix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "dashmap" -version = "5.5.3" +version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" dependencies = [ "cfg-if", - "hashbrown", + "crossbeam-utils", + "hashbrown 0.14.5", "lock_api", "once_cell", "parking_lot_core", @@ -320,18 +339,18 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.11" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" dependencies = [ "powerfmt", ] [[package]] name = "derive_arbitrary" -version = "1.3.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" +checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" dependencies = [ "proc-macro2", "quote", @@ -340,39 +359,50 @@ dependencies = [ [[package]] name = "directories" -version = "5.0.1" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" +checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d" dependencies = [ "dirs-sys", ] [[package]] name = "dirs" -version = "5.0.1" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" dependencies = [ "dirs-sys", ] [[package]] name = "dirs-sys" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.48.0", + "windows-sys 0.59.0", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] name = "dissimilar" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59f8e79d1fbf76bdfbde321e902714bf6c49df88a7dda6fc682fc2979226962d" +checksum = "8975ffdaa0ef3661bfe02dbdcc06c9f829dfafe6a3c474de366a8d5e44276921" [[package]] name = "dot" @@ -392,9 +422,9 @@ version = "0.0.0" [[package]] name = "either" -version = "1.13.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "ena" @@ -407,15 +437,15 @@ dependencies = [ [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "expect-test" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e0be0a561335815e06dab7c62e50353134c796e7a6155402a64bcff66b6a5e0" +checksum = "63af43ff4431e848fb47472a920f14fa71c24de13255a5692e93d4e90302acb0" dependencies = [ "dissimilar", "once_cell", @@ -423,9 +453,9 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.24" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf401df4a4e3872c4fe8151134cf483738e74b67fc934d6532c882b3d24a4550" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" dependencies = [ "cfg-if", "libc", @@ -441,14 +471,20 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.31" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f211bbe8e69bbd0cfdea405084f128ae8b4aaa6b0b522fc8f2b009084797920" +checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc" dependencies = [ "crc32fast", "miniz_oxide", ] +[[package]] +name = "foldhash" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -473,6 +509,19 @@ version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a" +[[package]] +name = "generator" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc6bd114ceda131d3b1d665eba35788690ad37f5916457286b32ab6fd3c438dd" +dependencies = [ + "cfg-if", + "libc", + "log", + "rustversion", + "windows 0.58.0", +] + [[package]] name = "getrandom" version = "0.2.15" @@ -486,9 +535,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.29.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "hashbrown" @@ -497,10 +546,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] -name = "heck" -version = "0.4.1" +name = "hashbrown" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + +[[package]] +name = "hashlink" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +dependencies = [ + "hashbrown 0.15.2", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" @@ -522,8 +591,8 @@ dependencies = [ "hir-ty", "indexmap", "intern", - "itertools", - "rustc-hash 2.0.0", + "itertools 0.14.0", + "rustc-hash 2.1.1", "smallvec", "span", "stdx", @@ -542,26 +611,25 @@ version = "0.0.0" dependencies = [ "arrayvec", "base-db", - "bitflags 2.7.0", + "bitflags 2.9.0", "cfg", "cov-mark", - "dashmap", "drop_bomb", "either", "expect-test", "fst", - "hashbrown", "hir-expand", "indexmap", "intern", - "itertools", + "itertools 0.14.0", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "mbe", + "query-group-macro", "ra-ap-rustc_abi", - "ra-ap-rustc_hashes", "ra-ap-rustc_parse_format", - "rustc-hash 2.0.0", + "rustc-hash 2.1.1", "rustc_apfloat", + "salsa", "smallvec", "span", "stdx", @@ -570,6 +638,7 @@ dependencies = [ "test-fixture", "test-utils", "text-size", + "thin-vec", "tracing", "triomphe", "tt", @@ -584,13 +653,13 @@ dependencies = [ "cov-mark", "either", "expect-test", - "hashbrown", "intern", - "itertools", - "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.14.0", "mbe", "parser", - "rustc-hash 2.0.0", + "query-group-macro", + "rustc-hash 2.1.1", + "salsa", "smallvec", "span", "stdx", @@ -607,7 +676,7 @@ version = "0.0.0" dependencies = [ "arrayvec", "base-db", - "bitflags 2.7.0", + "bitflags 2.9.0", "chalk-derive", "chalk-ir", "chalk-recursive", @@ -620,16 +689,17 @@ dependencies = [ "hir-expand", "indexmap", "intern", - "itertools", + "itertools 0.14.0", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "nohash-hasher", "oorandom", "project-model", + "query-group-macro", "ra-ap-rustc_abi", "ra-ap-rustc_index", "ra-ap-rustc_pattern_analysis", - "rustc-hash 2.0.0", + "rustc-hash 2.1.1", "rustc_apfloat", + "salsa", "scoped-tls", "smallvec", "span", @@ -646,11 +716,129 @@ dependencies = [ [[package]] name = "home" -version = "0.5.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", +] + +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -669,7 +857,7 @@ dependencies = [ "ide-db", "ide-diagnostics", "ide-ssr", - "itertools", + "itertools 0.14.0", "nohash-hasher", "oorandom", "profile", @@ -697,7 +885,7 @@ dependencies = [ "expect-test", "hir", "ide-db", - "itertools", + "itertools 0.14.0", "smallvec", "stdx", "syntax", @@ -715,7 +903,7 @@ dependencies = [ "expect-test", "hir", "ide-db", - "itertools", + "itertools 0.14.0", "smallvec", "stdx", "syntax", @@ -730,7 +918,7 @@ version = "0.0.0" dependencies = [ "arrayvec", "base-db", - "bitflags 2.7.0", + "bitflags 2.9.0", "cov-mark", "crossbeam-channel", "either", @@ -738,14 +926,16 @@ dependencies = [ "fst", "hir", "indexmap", - "itertools", + "itertools 0.14.0", "line-index 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "memchr", "nohash-hasher", "parser", "profile", + "query-group-macro", "rayon", - "rustc-hash 2.0.0", + "rustc-hash 2.1.1", + "salsa", "span", "stdx", "syntax", @@ -753,6 +943,7 @@ dependencies = [ "test-utils", "tracing", "triomphe", + "vfs", ] [[package]] @@ -765,7 +956,7 @@ dependencies = [ "expect-test", "hir", "ide-db", - "itertools", + "itertools 0.14.0", "paths", "serde_json", "stdx", @@ -783,10 +974,8 @@ dependencies = [ "expect-test", "hir", "ide-db", - "itertools", - "nohash-hasher", + "itertools 0.14.0", "parser", - "stdx", "syntax", "test-fixture", "test-utils", @@ -795,22 +984,34 @@ dependencies = [ [[package]] name = "idna" -version = "0.5.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", ] [[package]] name = "indexmap" -version = "2.3.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3fc2e30ba82dd1b3911c8de1ffc143c74a914a14e99514d7637e3099df5ea0" +checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.15.2", + "serde", ] [[package]] @@ -819,7 +1020,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3" dependencies = [ - "bitflags 2.7.0", + "bitflags 2.9.0", "inotify-sys", "libc", ] @@ -838,8 +1039,8 @@ name = "intern" version = "0.0.0" dependencies = [ "dashmap", - "hashbrown", - "rustc-hash 2.0.0", + "hashbrown 0.14.5", + "rustc-hash 2.1.1", "triomphe", ] @@ -853,16 +1054,25 @@ dependencies = [ ] [[package]] -name = "itoa" -version = "1.0.11" +name = "itertools" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jod-thread" -version = "0.1.2" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b23360e99b8717f20aaa4598f5a6541efbe30630039fbc7706cf954a87947ae" +checksum = "a037eddb7d28de1d0fc42411f501b53b75838d313908078d6698d064f3029b24" [[package]] name = "kqueue" @@ -908,9 +1118,9 @@ checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libloading" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", "windows-targets 0.52.6", @@ -918,9 +1128,9 @@ dependencies = [ [[package]] name = "libmimalloc-sys" -version = "0.1.39" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23aa6811d3bd4deb8a84dde645f943476d13b248d818edcf8ce0b2f37f036b44" +checksum = "07d0e07885d6a754b9c7993f2625187ad694ee985d60f23355ff0e7077261502" dependencies = [ "cc", "libc", @@ -932,7 +1142,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.7.0", + "bitflags 2.9.0", "libc", "redox_syscall", ] @@ -957,10 +1167,10 @@ dependencies = [ ] [[package]] -name = "linked-hash-map" -version = "0.5.6" +name = "litemap" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" [[package]] name = "load-cargo" @@ -971,8 +1181,7 @@ dependencies = [ "hir-expand", "ide-db", "intern", - "itertools", - "paths", + "itertools 0.14.0", "proc-macro-api", "project-model", "span", @@ -994,20 +1203,21 @@ dependencies = [ [[package]] name = "log" -version = "0.4.22" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" [[package]] -name = "lsp-server" -version = "0.7.7" +name = "loom" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "550446e84739dcaf6d48a4a093973850669e13e8a34d8f8d64851041be267cd9" +checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" dependencies = [ - "crossbeam-channel", - "log", - "serde", - "serde_json", + "cfg-if", + "generator", + "scoped-tls", + "tracing", + "tracing-subscriber", ] [[package]] @@ -1023,6 +1233,19 @@ dependencies = [ "serde_json", ] +[[package]] +name = "lsp-server" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9462c4dc73e17f971ec1f171d44bfffb72e65a130117233388a0ebc7ec5656f9" +dependencies = [ + "crossbeam-channel", + "log", + "serde", + "serde_derive", + "serde_json", +] + [[package]] name = "lsp-types" version = "0.95.0" @@ -1037,10 +1260,13 @@ dependencies = [ ] [[package]] -name = "lz4_flex" -version = "0.11.3" +name = "matchers" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75761162ae2b0e580d7e7c390558127e5f01b4194debd6221fd8c207fc80e3f5" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] [[package]] name = "mbe" @@ -1052,14 +1278,13 @@ dependencies = [ "intern", "parser", "ra-ap-rustc_lexer", - "rustc-hash 2.0.0", + "rustc-hash 2.1.1", "smallvec", "span", "stdx", "syntax", "syntax-bridge", "test-utils", - "tracing", "tt", ] @@ -1071,9 +1296,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" -version = "0.5.10" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" dependencies = [ "libc", ] @@ -1089,20 +1314,20 @@ dependencies = [ [[package]] name = "mimalloc" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68914350ae34959d83f732418d51e2427a794055d0b9529f48259ac07af65633" +checksum = "99585191385958383e13f6b822e6b6d8d9cf928e7d286ceb092da92b43c87bc1" dependencies = [ "libmimalloc-sys", ] [[package]] name = "miniz_oxide" -version = "0.7.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" dependencies = [ - "adler", + "adler2", ] [[package]] @@ -1128,13 +1353,13 @@ dependencies = [ [[package]] name = "nix" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.7.0", + "bitflags 2.9.0", "cfg-if", - "cfg_aliases 0.1.1", + "cfg_aliases", "libc", ] @@ -1150,7 +1375,7 @@ version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fee8403b3d66ac7b26aee6e40a897d85dc5ce26f44da36b8b73e987cc52e943" dependencies = [ - "bitflags 2.7.0", + "bitflags 2.9.0", "filetime", "fsevent-sys", "inotify", @@ -1169,6 +1394,16 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e0826a989adedc2a244799e823aece04662b66609d96af8dff7ac6df9a8925d" +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "nu-ansi-term" version = "0.50.1" @@ -1205,33 +1440,24 @@ dependencies = [ [[package]] name = "object" -version = "0.33.0" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8dd6c0cdf9429bce006e1362bfce61fa1bfd8c898a643ed8d2b471934701d3d" -dependencies = [ - "memchr", -] - -[[package]] -name = "object" -version = "0.36.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc" [[package]] name = "oorandom" -version = "11.1.4" +version = "11.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" [[package]] name = "option-ext" @@ -1239,6 +1465,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "parking_lot" version = "0.12.3" @@ -1325,9 +1557,15 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "portable-atomic" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" [[package]] name = "powerfmt" @@ -1335,15 +1573,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" -[[package]] -name = "ppv-lite86" -version = "0.2.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" -dependencies = [ - "zerocopy", -] - [[package]] name = "proc-macro-api" version = "0.0.0" @@ -1351,7 +1580,7 @@ dependencies = [ "indexmap", "intern", "paths", - "rustc-hash 2.0.0", + "rustc-hash 2.1.1", "serde", "serde_derive", "serde_json", @@ -1370,12 +1599,11 @@ dependencies = [ "libc", "libloading", "memmap2", - "object 0.33.0", + "object", "paths", "proc-macro-test", "ra-ap-rustc_lexer", "span", - "stdx", "syntax-bridge", "tt", ] @@ -1398,23 +1626,23 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.93" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" dependencies = [ "unicode-ident", ] [[package]] name = "process-wrap" -version = "8.0.2" +version = "8.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38ee68ae331824036479c84060534b18254c864fa73366c58d86db3b7b811619" +checksum = "d35f4dc9988d1326b065b4def5e950c3ed727aa03e3151b86cc9e2aec6b03f54" dependencies = [ "indexmap", "nix", "tracing", - "windows", + "windows 0.59.0", ] [[package]] @@ -1438,10 +1666,10 @@ dependencies = [ "cfg", "expect-test", "intern", - "itertools", + "itertools 0.14.0", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "paths", - "rustc-hash 2.0.0", + "rustc-hash 2.1.1", "semver", "serde", "serde_derive", @@ -1461,7 +1689,7 @@ checksum = "a3a7c64d9bf75b1b8d981124c14c179074e8caa7dfe7b6a12e6222ddcd0c8f72" dependencies = [ "once_cell", "protobuf-support", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -1470,7 +1698,7 @@ version = "3.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b088fd20b938a875ea00843b6faf48579462630015c3788d397ad6a786663252" dependencies = [ - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -1479,7 +1707,7 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" dependencies = [ - "bitflags 2.7.0", + "bitflags 2.9.0", "memchr", "unicase", ] @@ -1493,22 +1721,33 @@ dependencies = [ "pulldown-cmark", ] +[[package]] +name = "query-group-macro" +version = "0.0.0" +dependencies = [ + "expect-test", + "proc-macro2", + "quote", + "salsa", + "syn", +] + [[package]] name = "quote" -version = "1.0.36" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] [[package]] name = "ra-ap-rustc_abi" -version = "0.100.0" +version = "0.110.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1651b0f7e8c3eb7c27a88f39d277e69c32bfe58e3be174d286c1a24d6a7a4d8" +checksum = "912228bd8ed3beff1f6f9e5e2d4b37c0827ba3e2070060bf3858a311d0e29e30" dependencies = [ - "bitflags 2.7.0", + "bitflags 2.9.0", "ra-ap-rustc_hashes", "ra-ap-rustc_index", "tracing", @@ -1516,18 +1755,18 @@ dependencies = [ [[package]] name = "ra-ap-rustc_hashes" -version = "0.100.0" +version = "0.110.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bcd85e93dc0ea850bcfe7957a115957df799ccbc9eea488bdee5ec6780d212b" +checksum = "ba520764daf057a9d963fa769f4762eaf87ac5d4900ae76195eeead64cd35afd" dependencies = [ "rustc-stable-hash", ] [[package]] name = "ra-ap-rustc_index" -version = "0.100.0" +version = "0.110.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b295fc0640cd9fe0ecab872ee4a17a96f90a3998ec9f0c4765e9b8415c12cc" +checksum = "b76b5f9ee55f2d0e5a65bea23f6d738893349ce8d3d17a6720933e647ab04978" dependencies = [ "ra-ap-rustc_index_macros", "smallvec", @@ -1535,9 +1774,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_index_macros" -version = "0.100.0" +version = "0.110.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c675f4257023aa933882906f13802cae287e88cc39ab13cbb96809083db0c801" +checksum = "ddd972eb1face2fcaa0d94c01d97862fb955b5561d4f5932003bce8a6cadd8c6" dependencies = [ "proc-macro2", "quote", @@ -1546,9 +1785,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_lexer" -version = "0.100.0" +version = "0.110.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8358702c2a510ea84ba5801ddc047d9ad9520902cfb0e6173277610cdce2c9c" +checksum = "ba3a9876456fb2521097deef33ddeac1c18260c8eafb68054d986f8b9d6ce9fa" dependencies = [ "memchr", "unicode-properties", @@ -1557,57 +1796,27 @@ dependencies = [ [[package]] name = "ra-ap-rustc_parse_format" -version = "0.100.0" +version = "0.110.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98f402011d46732c35c47bfd111dec0495747fef2ec900ddee7fe15d78449a7" +checksum = "8e85de58dfcc60a5f9d5ec0157a657e3f84abd8f22c8a0c4d707cfb42c9011f4" dependencies = [ - "ra-ap-rustc_index", "ra-ap-rustc_lexer", + "rustc-literal-escaper", ] [[package]] name = "ra-ap-rustc_pattern_analysis" -version = "0.100.0" +version = "0.110.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef3ff73fa4653252ffe1d1e9177a446f49ef46d97140e4816b7ff2dad59ed53" +checksum = "ceadf9db550db67deff7eff2e2765109b860c9d7e5bdfca144863020289c823d" dependencies = [ "ra-ap-rustc_index", - "rustc-hash 2.0.0", + "rustc-hash 2.1.1", "rustc_apfloat", "smallvec", "tracing", ] -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - [[package]] name = "rayon" version = "1.10.0" @@ -1630,24 +1839,68 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.3" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" dependencies = [ - "bitflags 2.7.0", + "bitflags 2.9.0", ] [[package]] name = "redox_users" -version = "0.4.5" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" dependencies = [ "getrandom", "libredox", - "thiserror", + "thiserror 2.0.12", ] +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + [[package]] name = "rowan" version = "0.15.15" @@ -1655,7 +1908,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a58fa8a7ccff2aec4f39cc45bf5f985cec7125ab271cf681c279fd00192b49" dependencies = [ "countme", - "hashbrown", + "hashbrown 0.14.5", "memoffset", "rustc-hash 1.1.0", "text-size", @@ -1665,7 +1918,6 @@ dependencies = [ name = "rust-analyzer" version = "0.0.0" dependencies = [ - "always-assert", "anyhow", "base64", "cargo_metadata", @@ -1681,10 +1933,11 @@ dependencies = [ "ide-completion", "ide-db", "ide-ssr", + "indexmap", "intern", - "itertools", + "itertools 0.14.0", "load-cargo", - "lsp-server 0.7.7", + "lsp-server 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", "lsp-types", "memchr", "mimalloc", @@ -1699,7 +1952,7 @@ dependencies = [ "profile", "project-model", "rayon", - "rustc-hash 2.0.0", + "rustc-hash 2.1.1", "scip", "semver", "serde", @@ -1740,9 +1993,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc-hash" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] name = "rustc-literal-escaper" @@ -1752,54 +2005,72 @@ checksum = "0041b6238913c41fe704213a4a9329e2f685a156d1781998128b4149c230ad04" [[package]] name = "rustc-stable-hash" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2febf9acc5ee5e99d1ad0afcdbccc02d87aa3f857a1f01f825b80eacf8edfcd1" +checksum = "781442f29170c5c93b7185ad559492601acdc71d5bb0706f5868094f45cfcd08" [[package]] name = "rustc_apfloat" -version = "0.2.1+llvm-462a31f5a5ab" +version = "0.2.2+llvm-462a31f5a5ab" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "886d94c63c812a8037c4faca2607453a0fa4cf82f734665266876b022244543f" +checksum = "121e2195ff969977a4e2b5c9965ea867fce7e4cb5aee5b09dee698a7932d574f" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.9.0", "smallvec", ] +[[package]] +name = "rustversion" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" + [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "salsa" -version = "0.0.0" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1be22155f8d9732518b2db2bf379fe6f0b2375e76b08b7c8fe6c1b887d548c24" dependencies = [ - "dissimilar", - "expect-test", + "boxcar", + "crossbeam-queue", + "dashmap", + "hashbrown 0.15.2", + "hashlink", "indexmap", - "itertools", - "linked-hash-map", - "lock_api", - "oorandom", "parking_lot", - "rand", - "rustc-hash 2.0.0", + "portable-atomic", + "rayon", + "rustc-hash 2.1.1", + "salsa-macro-rules", "salsa-macros", "smallvec", + "thin-vec", "tracing", - "triomphe", ] +[[package]] +name = "salsa-macro-rules" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55a7ef0a84e336f7c5f0332d81727f5629fe042d2aa556c75307afebc9f78a5" + [[package]] name = "salsa-macros" -version = "0.0.0" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d0e88a9c0c0d231a63f83dcd1a2c5e5d11044fac4b65bc9ad3b68ab48b0a0ab" dependencies = [ "heck", "proc-macro2", "quote", "syn", + "synstructure", ] [[package]] @@ -1813,9 +2084,9 @@ dependencies = [ [[package]] name = "scip" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dfafd2fa14c6237fa1fc4310f739d02fa915d92977fa069426591f1de046f81" +checksum = "fb2b449a5e4660ce817676a0871cd1b4e2ff1023e33a1ac046670fa594b543a2" dependencies = [ "protobuf", ] @@ -1834,27 +2105,27 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "semver" -version = "1.0.23" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.216" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.216" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", @@ -1863,9 +2134,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.124" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66ad62847a56b3dba58cc891acd13884b9c61138d330c0d7b6181713d4fce38d" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "indexmap", "itoa", @@ -1876,9 +2147,9 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", @@ -1887,9 +2158,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] @@ -1911,9 +2182,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "smallvec" -version = "1.13.2" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" [[package]] name = "smol_str" @@ -1929,9 +2200,9 @@ dependencies = [ name = "span" version = "0.0.0" dependencies = [ - "hashbrown", + "hashbrown 0.14.5", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hash 2.0.0", + "rustc-hash 2.1.1", "salsa", "stdx", "syntax", @@ -1939,13 +2210,19 @@ dependencies = [ "vfs", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "stdx" version = "0.0.0" dependencies = [ "backtrace", "crossbeam-channel", - "itertools", + "itertools 0.14.0", "jod-thread", "libc", "miow", @@ -1955,9 +2232,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.87" +version = "2.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" dependencies = [ "proc-macro2", "quote", @@ -1979,15 +2256,13 @@ dependencies = [ name = "syntax" version = "0.0.0" dependencies = [ - "cov-mark", "either", "expect-test", - "indexmap", - "itertools", + "itertools 0.14.0", "parser", "rayon", "rowan", - "rustc-hash 2.0.0", + "rustc-hash 2.1.1", "rustc-literal-escaper", "rustc_apfloat", "smol_str", @@ -2003,12 +2278,11 @@ version = "0.0.0" dependencies = [ "intern", "parser", - "rustc-hash 2.0.0", + "rustc-hash 2.1.1", "span", "stdx", "syntax", "test-utils", - "tracing", "tt", ] @@ -2026,10 +2300,12 @@ dependencies = [ "cfg", "hir-expand", "intern", - "rustc-hash 2.0.0", + "paths", + "rustc-hash 2.1.1", "span", "stdx", "test-utils", + "triomphe", "tt", ] @@ -2040,10 +2316,9 @@ dependencies = [ "dissimilar", "paths", "profile", - "rustc-hash 2.0.0", + "rustc-hash 2.1.1", "stdx", "text-size", - "tracing", ] [[package]] @@ -2053,19 +2328,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f18aa187839b2bdb1ad2fa35ead8c4c2976b64e4363c386d45ac0f7ee85c9233" [[package]] -name = "thiserror" -version = "1.0.63" +name = "thin-vec" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "144f754d318415ac792f9d69fc87abbbfc043ce2ef041c60f16ad828f638717d" + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl 2.0.12", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", @@ -2115,9 +2416,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.36" +version = "0.3.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +checksum = "9d9c75b47bdff86fa3334a3db91356b8d7d86a9b839dab7d0bdc5c3d3a077618" dependencies = [ "deranged", "itoa", @@ -2132,40 +2433,35 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" [[package]] name = "time-macros" -version = "0.2.18" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +checksum = "29aa485584182073ed57fd5004aa09c371f021325014694e432313345865fd04" dependencies = [ "num-conv", "time-core", ] [[package]] -name = "tinyvec" -version = "1.8.0" +name = "tinystr" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" dependencies = [ - "tinyvec_macros", + "displaydoc", + "zerovec", ] -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - [[package]] name = "toml" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" dependencies = [ "serde", "serde_spanned", @@ -2184,9 +2480,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.20" +version = "0.22.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" dependencies = [ "indexmap", "serde", @@ -2205,9 +2501,9 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "pin-project-lite", "tracing-attributes", @@ -2216,9 +2512,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", @@ -2227,9 +2523,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", "valuable", @@ -2248,24 +2544,30 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" dependencies = [ + "matchers", + "nu-ansi-term 0.46.0", + "once_cell", + "regex", "sharded-slab", + "smallvec", "thread_local", "time", + "tracing", "tracing-core", "tracing-log", ] [[package]] name = "tracing-tree" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b56c62d2c80033cb36fae448730a2f2ef99410fe3ecbffc916681a32f6807dbe" +checksum = "f459ca79f1b0d5f71c54ddfde6debfc59c8b6eeb46808ae492077f739dc7b49c" dependencies = [ - "nu-ansi-term", + "nu-ansi-term 0.50.1", "tracing-core", "tracing-log", "tracing-subscriber", @@ -2302,51 +2604,33 @@ checksum = "a3e5df347f0bf3ec1d670aad6ca5c6a1859cd9ea61d2113125794654ccced68f" [[package]] name = "unicase" -version = "2.7.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-normalization" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" -dependencies = [ - "tinyvec", -] +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-properties" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291" +checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "url" -version = "2.5.2" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", @@ -2355,16 +2639,22 @@ dependencies = [ ] [[package]] -name = "valuable" -version = "0.1.0" +name = "utf16_iter" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" [[package]] -name = "version_check" -version = "0.9.5" +name = "utf8_iter" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] name = "vfs" @@ -2375,7 +2665,7 @@ dependencies = [ "indexmap", "nohash-hasher", "paths", - "rustc-hash 2.0.0", + "rustc-hash 2.1.1", "stdx", "tracing", ] @@ -2388,7 +2678,7 @@ dependencies = [ "notify", "paths", "rayon", - "rustc-hash 2.0.0", + "rustc-hash 2.1.1", "stdx", "tracing", "vfs", @@ -2411,6 +2701,22 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + [[package]] name = "winapi-util" version = "0.1.9" @@ -2421,32 +2727,73 @@ dependencies = [ ] [[package]] -name = "windows" -version = "0.56.0" +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1de69df01bdf1ead2f4ac895dc77c9351aefff65b2f3db429a343f9cbf05e132" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" dependencies = [ - "windows-core", + "windows-core 0.58.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f919aee0a93304be7f62e8e5027811bbba96bcb1de84d6618be56e43f8a32a1" +dependencies = [ + "windows-core 0.59.0", + "windows-targets 0.53.0", +] + +[[package]] +name = "windows-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +dependencies = [ + "windows-implement 0.58.0", + "windows-interface 0.58.0", + "windows-result 0.2.0", + "windows-strings 0.1.0", "windows-targets 0.52.6", ] [[package]] name = "windows-core" -version = "0.56.0" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4698e52ed2d08f8658ab0c39512a7c00ee5fe2688c65f8c0a4f06750d729f2a6" +checksum = "810ce18ed2112484b0d4e15d022e5f598113e220c53e373fb31e67e21670c1ce" dependencies = [ - "windows-implement", - "windows-interface", - "windows-result", - "windows-targets 0.52.6", + "windows-implement 0.59.0", + "windows-interface 0.59.0", + "windows-result 0.3.1", + "windows-strings 0.3.1", + "windows-targets 0.53.0", ] [[package]] name = "windows-implement" -version = "0.56.0" +version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-implement" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83577b051e2f49a058c308f17f273b570a6a758386fc291b5f6a934dd84e48c1" dependencies = [ "proc-macro2", "quote", @@ -2455,9 +2802,9 @@ dependencies = [ [[package]] name = "windows-interface" -version = "0.56.0" +version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" dependencies = [ "proc-macro2", "quote", @@ -2465,14 +2812,59 @@ dependencies = [ ] [[package]] -name = "windows-result" -version = "0.1.2" +name = "windows-interface" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" +checksum = "cb26fd936d991781ea39e87c3a27285081e3c0da5ca0fcbc02d368cc6f52ff01" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3" + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-result" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06374efe858fab7e4f881500e6e86ec8bc28f9462c47e5a9941a0142ad86b189" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result 0.2.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -2524,13 +2916,29 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -2543,6 +2951,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -2555,6 +2969,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -2567,12 +2987,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -2585,6 +3017,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -2597,6 +3035,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -2609,6 +3053,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -2622,10 +3072,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] -name = "winnow" -version = "0.6.18" +name = "windows_x86_64_msvc" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + +[[package]] +name = "winnow" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7f4ea97f6f78012141bcdb6a216b2609f0979ada50b20ca5b52dde2eac2bb1" dependencies = [ "memchr", ] @@ -2636,6 +3092,18 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23f6174b2566cc4a74f95e1367ec343e7fa80c93cc8087f5c4a3d6a1088b2118" +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + [[package]] name = "xflags" version = "0.3.2" @@ -2675,7 +3143,7 @@ dependencies = [ "edition", "either", "flate2", - "itertools", + "itertools 0.14.0", "proc-macro2", "quote", "stdx", @@ -2688,20 +3156,66 @@ dependencies = [ ] [[package]] -name = "zerocopy" -version = "0.7.35" +name = "yoke" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" dependencies = [ - "byteorder", - "zerocopy-derive", + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", ] [[package]] -name = "zerocopy-derive" -version = "0.7.35" +name = "yoke-derive" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", @@ -2710,13 +3224,17 @@ dependencies = [ [[package]] name = "zip" -version = "0.6.6" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" +checksum = "fabe6324e908f85a1c52063ce7aa26b68dcb7eb6dbc83a2d148403c9bc3eba50" dependencies = [ - "byteorder", + "arbitrary", "crc32fast", "crossbeam-utils", + "displaydoc", "flate2", + "indexmap", + "memchr", + "thiserror 2.0.12", "time", ] diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index e22191397655..6fa171702dd4 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -4,8 +4,8 @@ exclude = ["crates/proc-macro-srv/proc-macro-test/imp"] resolver = "2" [workspace.package] -rust-version = "1.84" -edition = "2021" +rust-version = "1.86" +edition = "2024" license = "MIT OR Apache-2.0" authors = ["rust-analyzer team"] repository = "https://github.com/rust-lang/rust-analyzer" @@ -46,7 +46,7 @@ debug = 2 # ungrammar = { path = "../ungrammar" } -# rust-analyzer-salsa = { path = "../salsa" } +# salsa = { path = "../salsa" } [workspace.dependencies] # local crates @@ -72,7 +72,7 @@ proc-macro-srv = { path = "./crates/proc-macro-srv", version = "0.0.0" } proc-macro-srv-cli = { path = "./crates/proc-macro-srv-cli", version = "0.0.0" } profile = { path = "./crates/profile", version = "0.0.0" } project-model = { path = "./crates/project-model", version = "0.0.0" } -ra-salsa = { path = "./crates/ra-salsa", package = "salsa", version = "0.0.0" } +query-group = { package = "query-group-macro", path = "./crates/query-group-macro", version = "0.0.0" } span = { path = "./crates/span", version = "0.0.0" } stdx = { path = "./crates/stdx", version = "0.0.0" } syntax = { path = "./crates/syntax", version = "0.0.0" } @@ -85,72 +85,69 @@ vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" } vfs = { path = "./crates/vfs", version = "0.0.0" } edition = { path = "./crates/edition", version = "0.0.0" } -ra-ap-rustc_hashes = { version = "0.100", default-features = false } -ra-ap-rustc_lexer = { version = "0.100", default-features = false } -ra-ap-rustc_parse_format = { version = "0.100", default-features = false } -ra-ap-rustc_index = { version = "0.100", default-features = false } -ra-ap-rustc_abi = { version = "0.100", default-features = false } -ra-ap-rustc_pattern_analysis = { version = "0.100", default-features = false } +ra-ap-rustc_lexer = { version = "0.110", default-features = false } +ra-ap-rustc_parse_format = { version = "0.110", default-features = false } +ra-ap-rustc_index = { version = "0.110", default-features = false } +ra-ap-rustc_abi = { version = "0.110", default-features = false } +ra-ap-rustc_pattern_analysis = { version = "0.110", default-features = false } # local crates that aren't published to crates.io. These should not have versions. # in-tree crates that are published separately and follow semver. See lib/README.md line-index = { version = "0.1.2" } la-arena = { version = "0.3.1" } -lsp-server = { version = "0.7.6" } +lsp-server = { version = "0.7.8" } # non-local crates -anyhow = "1.0.75" -arrayvec = "0.7.4" -bitflags = "2.4.1" -cargo_metadata = "0.18.1" -camino = "1.1.6" -chalk-solve = { version = "0.100.0", default-features = false } -chalk-ir = "0.100.0" -chalk-recursive = { version = "0.100.0", default-features = false } -chalk-derive = "0.100.0" -crossbeam-channel = "0.5.8" -dissimilar = "1.0.7" +anyhow = "1.0.97" +arrayvec = "0.7.6" +bitflags = "2.9.0" +cargo_metadata = "0.19.2" +camino = "1.1.9" +chalk-solve = { version = "0.102.0", default-features = false } +chalk-ir = "0.102.0" +chalk-recursive = { version = "0.102.0", default-features = false } +chalk-derive = "0.102.0" +crossbeam-channel = "0.5.15" +dissimilar = "1.0.10" dot = "0.1.4" -either = "1.9.0" -expect-test = "1.4.0" -hashbrown = { version = "0.14", features = [ - "inline-more", -], default-features = false } -indexmap = "2.1.0" -itertools = "0.12.0" -libc = "0.2.150" -libloading = "0.8.0" -memmap2 = "0.5.4" +either = "1.15.0" +expect-test = "1.5.1" +indexmap = { version = "2.8.0", features = ["serde"] } +itertools = "0.14.0" +libc = "0.2.171" +libloading = "0.8.6" +memmap2 = "0.9.5" nohash-hasher = "0.2.0" -oorandom = "11.1.3" -object = { version = "0.33.0", default-features = false, features = [ +oorandom = "11.1.5" +object = { version = "0.36.7", default-features = false, features = [ "std", "read_core", "elf", "macho", "pe", ] } -process-wrap = { version = "8.0.2", features = ["std"] } +process-wrap = { version = "8.2.0", features = ["std"] } pulldown-cmark-to-cmark = "10.0.4" -pulldown-cmark = { version = "0.9.0", default-features = false } -rayon = "1.8.0" -rustc-hash = "2.0.0" +pulldown-cmark = { version = "0.9.6", default-features = false } +rayon = "1.10.0" +salsa = "0.20.0" +semver = "1.0.26" +serde = { version = "1.0.219" } +serde_derive = { version = "1.0.219" } +serde_json = "1.0.140" +rustc-hash = "2.1.1" rustc-literal-escaper = "0.0.2" -semver = "1.0.14" -serde = { version = "1.0.192" } -serde_derive = { version = "1.0.192" } -serde_json = "1.0.108" -smallvec = { version = "1.10.0", features = [ +smallvec = { version = "1.14.0", features = [ "const_new", "union", "const_generics", ] } smol_str = "0.3.2" text-size = "1.1.1" -tracing = "0.1.40" -tracing-tree = "0.3.0" -tracing-subscriber = { version = "0.3.18", default-features = false, features = [ +tracing = "0.1.41" +tracing-tree = "0.4.0" +tracing-subscriber = { version = "0.3.19", default-features = false, features = [ "registry", "fmt", "local-time", @@ -159,12 +156,15 @@ tracing-subscriber = { version = "0.3.18", default-features = false, features = "tracing-log", ] } triomphe = { version = "0.1.14", default-features = false, features = ["std"] } -url = "2.3.1" -xshell = "0.2.5" - +url = "2.5.4" +xshell = "0.2.7" # We need to freeze the version of the crate, as the raw-api feature is considered unstable -dashmap = { version = "=5.5.3", features = ["raw-api"] } +dashmap = { version = "=6.1.0", features = ["raw-api", "inline"] } +# We need to freeze the version of the crate, as it needs to match with dashmap +hashbrown = { version = "0.14.0", features = [ + "inline-more", +], default-features = false } [workspace.lints.rust] # remember to update RUSTFLAGS in ci.yml if you add something here @@ -172,6 +172,7 @@ dashmap = { version = "=5.5.3", features = ["raw-api"] } elided_lifetimes_in_paths = "warn" explicit_outlives_requirements = "warn" unsafe_op_in_unsafe_fn = "warn" +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(bootstrap)'] } unused_extern_crates = "warn" unused_lifetimes = "warn" unreachable_pub = "warn" diff --git a/src/tools/rust-analyzer/bench_data/numerous_macro_rules b/src/tools/rust-analyzer/bench_data/numerous_macro_rules index 7610a3ae1e3c..60997065b240 100644 --- a/src/tools/rust-analyzer/bench_data/numerous_macro_rules +++ b/src/tools/rust-analyzer/bench_data/numerous_macro_rules @@ -528,7 +528,7 @@ macro_rules! __ra_macro_fixture526 {($expr : expr )=>{|| -> _ { Some ($expr )}( macro_rules! __ra_macro_fixture527 {($($arg : tt )*)=>($crate :: io :: _print ($crate :: format_args ! ($($arg )*))); } macro_rules! __ra_macro_fixture528 {($fmt : literal , $($tt : tt ),*)=>{ mbe :: ExpandError :: ProcMacroError ( tt :: ExpansionError :: Unknown ( format ! ($fmt , $($tt ),*)))}; ($fmt : literal )=>{ mbe :: ExpandError :: ProcMacroError ( tt :: ExpansionError :: Unknown ($fmt . to_string ()))}} macro_rules! __ra_macro_fixture529 {($($tt : tt )* )=>{$crate :: quote :: IntoTt :: to_subtree ($crate :: __quote ! ($($tt )*))}} -macro_rules! __ra_macro_fixture530 {()=>{ Vec ::< tt :: TokenTree >:: new ()}; (@ SUBTREE $delim : ident $($tt : tt )* )=>{{ let children = $crate :: __quote ! ($($tt )*); tt :: Subtree { delimiter : Some ( tt :: Delimiter { kind : tt :: DelimiterKind ::$delim , id : tt :: TokenId :: unspecified (), }), token_trees : $crate :: quote :: IntoTt :: to_tokens ( children ), }}}; (@ PUNCT $first : literal )=>{{ vec ! [ tt :: Leaf :: Punct ( tt :: Punct { char : $first , spacing : tt :: Spacing :: Alone , id : tt :: TokenId :: unspecified (), }). into ()]}}; (@ PUNCT $first : literal , $sec : literal )=>{{ vec ! [ tt :: Leaf :: Punct ( tt :: Punct { char : $first , spacing : tt :: Spacing :: Joint , id : tt :: TokenId :: unspecified (), }). into (), tt :: Leaf :: Punct ( tt :: Punct { char : $sec , spacing : tt :: Spacing :: Alone , id : tt :: TokenId :: unspecified (), }). into ()]}}; (# $first : ident $($tail : tt )* )=>{{ let token = $crate :: quote :: ToTokenTree :: to_token ($first ); let mut tokens = vec ! [ token . into ()]; let mut tail_tokens = $crate :: quote :: IntoTt :: to_tokens ($crate :: __quote ! ($($tail )*)); tokens . append (& mut tail_tokens ); tokens }}; (## $first : ident $($tail : tt )* )=>{{ let mut tokens = $first . into_iter (). map ($crate :: quote :: ToTokenTree :: to_token ). collect ::< Vec < tt :: TokenTree >> (); let mut tail_tokens = $crate :: quote :: IntoTt :: to_tokens ($crate :: __quote ! ($($tail )*)); tokens . append (& mut tail_tokens ); tokens }}; ({$($tt : tt )* })=>{$crate :: __quote ! (@ SUBTREE Brace $($tt )*)}; ([$($tt : tt )* ])=>{$crate :: __quote ! (@ SUBTREE Bracket $($tt )*)}; (($($tt : tt )* ))=>{$crate :: __quote ! (@ SUBTREE Parenthesis $($tt )*)}; ($tt : literal )=>{ vec ! [$crate :: quote :: ToTokenTree :: to_token ($tt ). into ()]}; ($tt : ident )=>{ vec ! [{ tt :: Leaf :: Ident ( tt :: Ident { text : stringify ! ($tt ). into (), id : tt :: TokenId :: unspecified (), }). into ()}]}; (-> )=>{$crate :: __quote ! (@ PUNCT '-' , '>' )}; (& )=>{$crate :: __quote ! (@ PUNCT '&' )}; (, )=>{$crate :: __quote ! (@ PUNCT ',' )}; (: )=>{$crate :: __quote ! (@ PUNCT ':' )}; (; )=>{$crate :: __quote ! (@ PUNCT ';' )}; (:: )=>{$crate :: __quote ! (@ PUNCT ':' , ':' )}; (. )=>{$crate :: __quote ! (@ PUNCT '.' )}; (< )=>{$crate :: __quote ! (@ PUNCT '<' )}; (> )=>{$crate :: __quote ! (@ PUNCT '>' )}; ($first : tt $($tail : tt )+ )=>{{ let mut tokens = $crate :: quote :: IntoTt :: to_tokens ($crate :: __quote ! ($first )); let mut tail_tokens = $crate :: quote :: IntoTt :: to_tokens ($crate :: __quote ! ($($tail )*)); tokens . append (& mut tail_tokens ); tokens }}; } +macro_rules! __ra_macro_fixture530 {()=>{ Vec ::< tt :: TokenTree >:: new ()}; (@ SUBTREE $delim : ident $($tt : tt )* )=>{{ let children = $crate :: __quote ! ($($tt )*); tt :: Subtree { delimiter : Some ( tt :: Delimiter { kind : tt :: DelimiterKind ::$delim , id : tt :: TokenId :: unspecified (), }), token_trees : $crate :: quote :: IntoTt :: to_tokens ( children ), }}}; (@ PUNCT $first : literal )=>{{ vec ! [ tt :: Leaf :: Punct ( tt :: Punct { char : $first , spacing : tt :: Spacing :: Alone , id : tt :: TokenId :: unspecified (), }). into ()]}}; (@ PUNCT $first : literal , $sec : literal )=>{{ vec ! [ tt :: Leaf :: Punct ( tt :: Punct { char : $first , spacing : tt :: Spacing :: Joint , id : tt :: TokenId :: unspecified (), }). into (), tt :: Leaf :: Punct ( tt :: Punct { char : $sec , spacing : tt :: Spacing :: Alone , id : tt :: TokenId :: unspecified (), }). into ()]}}; (# $first : ident $($tail : tt )* )=>{{ let token = $crate :: quote :: ToTokenTree :: to_token ($first ); let mut tokens = vec ! [ token . into ()]; let mut tail_tokens = $crate :: quote :: IntoTt :: to_tokens ($crate :: __quote ! ($($tail )*)); tokens . append (& mut tail_tokens ); tokens }}; (# # $first : ident $($tail : tt )* )=>{{ let mut tokens = $first . into_iter (). map ($crate :: quote :: ToTokenTree :: to_token ). collect ::< Vec < tt :: TokenTree >> (); let mut tail_tokens = $crate :: quote :: IntoTt :: to_tokens ($crate :: __quote ! ($($tail )*)); tokens . append (& mut tail_tokens ); tokens }}; ({$($tt : tt )* })=>{$crate :: __quote ! (@ SUBTREE Brace $($tt )*)}; ([$($tt : tt )* ])=>{$crate :: __quote ! (@ SUBTREE Bracket $($tt )*)}; (($($tt : tt )* ))=>{$crate :: __quote ! (@ SUBTREE Parenthesis $($tt )*)}; ($tt : literal )=>{ vec ! [$crate :: quote :: ToTokenTree :: to_token ($tt ). into ()]}; ($tt : ident )=>{ vec ! [{ tt :: Leaf :: Ident ( tt :: Ident { text : stringify ! ($tt ). into (), id : tt :: TokenId :: unspecified (), }). into ()}]}; (-> )=>{$crate :: __quote ! (@ PUNCT '-' , '>' )}; (& )=>{$crate :: __quote ! (@ PUNCT '&' )}; (, )=>{$crate :: __quote ! (@ PUNCT ',' )}; (: )=>{$crate :: __quote ! (@ PUNCT ':' )}; (; )=>{$crate :: __quote ! (@ PUNCT ';' )}; (:: )=>{$crate :: __quote ! (@ PUNCT ':' , ':' )}; (. )=>{$crate :: __quote ! (@ PUNCT '.' )}; (< )=>{$crate :: __quote ! (@ PUNCT '<' )}; (> )=>{$crate :: __quote ! (@ PUNCT '>' )}; ($first : tt $($tail : tt )+ )=>{{ let mut tokens = $crate :: quote :: IntoTt :: to_tokens ($crate :: __quote ! ($first )); let mut tail_tokens = $crate :: quote :: IntoTt :: to_tokens ($crate :: __quote ! ($($tail )*)); tokens . append (& mut tail_tokens ); tokens }}; } macro_rules! __ra_macro_fixture531 {($($name : ident )*)=>{$(if let Some ( it )= & self .$name { f . field ( stringify ! ($name ), it ); })*}} macro_rules! __ra_macro_fixture532 {($fmt : expr )=>{ RenameError ( format ! ($fmt ))}; ($fmt : expr , $($arg : tt )+)=>{ RenameError ( format ! ($fmt , $($arg )+))}} macro_rules! __ra_macro_fixture533 {($($tokens : tt )*)=>{ return Err ( format_err ! ($($tokens )*))}} diff --git a/src/tools/rust-analyzer/crates/base-db/Cargo.toml b/src/tools/rust-analyzer/crates/base-db/Cargo.toml index 042dd36488aa..441434504c29 100644 --- a/src/tools/rust-analyzer/crates/base-db/Cargo.toml +++ b/src/tools/rust-analyzer/crates/base-db/Cargo.toml @@ -12,10 +12,10 @@ rust-version.workspace = true [lib] [dependencies] -lz4_flex = { version = "0.11", default-features = false } - la-arena.workspace = true -ra-salsa.workspace = true +dashmap.workspace = true +salsa.workspace = true +query-group.workspace = true rustc-hash.workspace = true triomphe.workspace = true semver.workspace = true @@ -23,7 +23,6 @@ tracing.workspace = true # local deps cfg.workspace = true -stdx.workspace = true syntax.workspace = true vfs.workspace = true span.workspace = true diff --git a/src/tools/rust-analyzer/crates/base-db/src/change.rs b/src/tools/rust-analyzer/crates/base-db/src/change.rs index 7e40f5408f14..da2fb27571c2 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/change.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/change.rs @@ -3,23 +3,18 @@ use std::fmt; -use ra_salsa::Durability; -use rustc_hash::FxHashMap; +use salsa::Durability; use triomphe::Arc; use vfs::FileId; -use crate::{ - CrateGraph, CrateId, CrateWorkspaceData, SourceDatabaseFileInputExt, SourceRoot, - SourceRootDatabase, SourceRootId, -}; +use crate::{CrateGraphBuilder, CratesIdMap, RootQueryDb, SourceRoot, SourceRootId}; /// Encapsulate a bunch of raw `.set` calls on the database. #[derive(Default)] pub struct FileChange { pub roots: Option>, pub files_changed: Vec<(FileId, Option)>, - pub crate_graph: Option, - pub ws_data: Option>>, + pub crate_graph: Option, } impl fmt::Debug for FileChange { @@ -39,10 +34,6 @@ impl fmt::Debug for FileChange { } impl FileChange { - pub fn new() -> Self { - FileChange::default() - } - pub fn set_roots(&mut self, roots: Vec) { self.roots = Some(roots); } @@ -51,48 +42,45 @@ impl FileChange { self.files_changed.push((file_id, new_text)) } - pub fn set_crate_graph(&mut self, graph: CrateGraph) { + pub fn set_crate_graph(&mut self, graph: CrateGraphBuilder) { self.crate_graph = Some(graph); } - pub fn set_ws_data(&mut self, data: FxHashMap>) { - self.ws_data = Some(data); - } - - pub fn apply(self, db: &mut dyn SourceRootDatabase) { + pub fn apply(self, db: &mut dyn RootQueryDb) -> Option { let _p = tracing::info_span!("FileChange::apply").entered(); if let Some(roots) = self.roots { for (idx, root) in roots.into_iter().enumerate() { let root_id = SourceRootId(idx as u32); - let durability = durability(&root); + let durability = source_root_durability(&root); for file_id in root.iter() { db.set_file_source_root_with_durability(file_id, root_id, durability); } + db.set_source_root_with_durability(root_id, Arc::new(root), durability); } } for (file_id, text) in self.files_changed { let source_root_id = db.file_source_root(file_id); - let source_root = db.source_root(source_root_id); - let durability = durability(&source_root); + let source_root = db.source_root(source_root_id.source_root_id(db)); + + let durability = file_text_durability(&source_root.source_root(db)); // XXX: can't actually remove the file, just reset the text let text = text.unwrap_or_default(); db.set_file_text_with_durability(file_id, &text, durability) } + if let Some(crate_graph) = self.crate_graph { - db.set_crate_graph_with_durability(Arc::new(crate_graph), Durability::HIGH); - } - if let Some(data) = self.ws_data { - db.set_crate_workspace_data_with_durability(Arc::new(data), Durability::HIGH); + return Some(crate_graph.set_in_db(db)); } + None } } -fn durability(source_root: &SourceRoot) -> Durability { - if source_root.is_library { - Durability::HIGH - } else { - Durability::LOW - } +fn source_root_durability(source_root: &SourceRoot) -> Durability { + if source_root.is_library { Durability::MEDIUM } else { Durability::LOW } +} + +fn file_text_durability(source_root: &SourceRoot) -> Durability { + if source_root.is_library { Durability::HIGH } else { Durability::LOW } } diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs index bd08387b5821..499c9b3716b2 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/input.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs @@ -6,17 +6,23 @@ //! actual IO. See `vfs` and `project_model` in the `rust-analyzer` crate for how //! actual IO is done and lowered to input. +use std::hash::BuildHasherDefault; use std::{fmt, mem, ops}; -use cfg::CfgOptions; +use cfg::{CfgOptions, HashableCfgOptions}; +use dashmap::DashMap; +use dashmap::mapref::entry::Entry; use intern::Symbol; use la_arena::{Arena, Idx, RawIdx}; -use rustc_hash::{FxHashMap, FxHashSet}; -use span::{Edition, EditionedFileId}; +use rustc_hash::{FxHashMap, FxHashSet, FxHasher}; +use salsa::{Durability, Setter}; +use span::Edition; use triomphe::Arc; -use vfs::{file_set::FileSet, AbsPathBuf, AnchoredPath, FileId, VfsPath}; +use vfs::{AbsPathBuf, AnchoredPath, FileId, VfsPath, file_set::FileSet}; -pub type ProcMacroPaths = FxHashMap>; +use crate::{CrateWorkspaceData, EditionedFileId, RootQueryDb}; + +pub type ProcMacroPaths = FxHashMap>; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct SourceRootId(pub u32); @@ -64,30 +70,31 @@ impl SourceRoot { } } -/// `CrateGraph` is a bit of information which turns a set of text files into a -/// number of Rust crates. -/// -/// Each crate is defined by the `FileId` of its root module, the set of enabled -/// `cfg` flags and the set of dependencies. -/// -/// Note that, due to cfg's, there might be several crates for a single `FileId`! -/// -/// For the purposes of analysis, a crate does not have a name. Instead, names -/// are specified on dependency edges. That is, a crate might be known under -/// different names in different dependent crates. -/// -/// Note that `CrateGraph` is build-system agnostic: it's a concept of the Rust -/// language proper, not a concept of the build system. In practice, we get -/// `CrateGraph` by lowering `cargo metadata` output. -/// -/// `CrateGraph` is `!Serialize` by design, see -/// -#[derive(Clone, Default)] -pub struct CrateGraph { - arena: Arena, +#[derive(Default, Clone)] +pub struct CrateGraphBuilder { + arena: Arena, } -impl fmt::Debug for CrateGraph { +pub type CrateBuilderId = Idx; + +impl ops::Index for CrateGraphBuilder { + type Output = CrateBuilder; + + fn index(&self, index: CrateBuilderId) -> &Self::Output { + &self.arena[index] + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct CrateBuilder { + pub basic: CrateDataBuilder, + pub extra: ExtraCrateData, + pub cfg_options: CfgOptions, + pub env: Env, + ws_data: Arc, +} + +impl fmt::Debug for CrateGraphBuilder { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_map() .entries(self.arena.iter().map(|(id, data)| (u32::from(id.into_raw()), data))) @@ -95,8 +102,6 @@ impl fmt::Debug for CrateGraph { } } -pub type CrateId = Idx; - #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct CrateName(Symbol); @@ -105,11 +110,7 @@ impl CrateName { /// Dashes are not allowed in the crate names, /// hence the input string is returned as `Err` for those cases. pub fn new(name: &str) -> Result { - if name.contains('-') { - Err(name) - } else { - Ok(Self(Symbol::intern(name))) - } + if name.contains('-') { Err(name) } else { Ok(Self(Symbol::intern(name))) } } /// Creates a crate name, unconditionally replacing the dashes with underscores. @@ -272,10 +273,49 @@ impl ReleaseChannel { } } -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct CrateData { +/// The crate data from which we derive the `Crate`. +/// +/// We want this to contain as little data as possible, because if it contains dependencies and +/// something changes, this crate and all of its dependencies ids are invalidated, which causes +/// pretty much everything to be recomputed. If the crate id is not invalidated, only this crate's +/// information needs to be recomputed. +/// +/// *Most* different crates have different root files (actually, pretty much all of them). +/// Still, it is possible to have crates distinguished by other factors (e.g. dependencies). +/// So we store only the root file - unless we find that this crate has the same root file as +/// another crate, in which case we store all data for one of them (if one is a dependency of +/// the other, we store for it, because it has more dependencies to be invalidated). +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct UniqueCrateData { + root_file_id: FileId, + disambiguator: Option>, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct CrateData { pub root_file_id: FileId, pub edition: Edition, + /// The dependencies of this crate. + /// + /// Note that this may contain more dependencies than the crate actually uses. + /// A common example is the test crate which is included but only actually is active when + /// declared in source via `extern crate test`. + pub dependencies: Vec>, + pub origin: CrateOrigin, + pub is_proc_macro: bool, + /// The working directory to run proc-macros in invoked in the context of this crate. + /// This is the workspace root of the cargo workspace for workspace members, the crate manifest + /// dir otherwise. + // FIXME: This ought to be a `VfsPath` or something opaque. + pub proc_macro_cwd: Arc, +} + +pub type CrateDataBuilder = CrateData; +pub type BuiltCrateData = CrateData; + +/// Crate data unrelated to analysis. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ExtraCrateData { pub version: Option, /// A name used in the package's project declaration: for Cargo projects, /// its `[package].name` can be different for other project types or even @@ -284,21 +324,8 @@ pub struct CrateData { /// For purposes of analysis, crates are anonymous (only names in /// `Dependency` matters), this name should only be used for UI. pub display_name: Option, - pub cfg_options: Arc, /// The cfg options that could be used by the crate - pub potential_cfg_options: Option>, - pub env: Env, - /// The dependencies of this crate. - /// - /// Note that this may contain more dependencies than the crate actually uses. - /// A common example is the test crate which is included but only actually is active when - /// declared in source via `extern crate test`. - pub dependencies: Vec, - pub origin: CrateOrigin, - pub is_proc_macro: bool, - /// The working directory to run proc-macros in. This is the workspace root of the cargo workspace - /// for workspace members, the crate manifest dir otherwise. - pub proc_macro_cwd: Option, + pub potential_cfg_options: Option, } #[derive(Default, Clone, PartialEq, Eq)] @@ -326,22 +353,32 @@ impl fmt::Debug for Env { } #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Dependency { - pub crate_id: CrateId, +pub struct Dependency { + pub crate_id: Id, pub name: CrateName, prelude: bool, sysroot: bool, } -impl Dependency { - pub fn new(name: CrateName, crate_id: CrateId) -> Self { +pub type DependencyBuilder = Dependency; +pub type BuiltDependency = Dependency; + +impl DependencyBuilder { + pub fn new(name: CrateName, crate_id: CrateBuilderId) -> Self { Self { name, crate_id, prelude: true, sysroot: false } } - pub fn with_prelude(name: CrateName, crate_id: CrateId, prelude: bool, sysroot: bool) -> Self { + pub fn with_prelude( + name: CrateName, + crate_id: CrateBuilderId, + prelude: bool, + sysroot: bool, + ) -> Self { Self { name, crate_id, prelude, sysroot } } +} +impl BuiltDependency { /// Whether this dependency is to be added to the depending crate's extern prelude. pub fn is_prelude(&self) -> bool { self.prelude @@ -353,41 +390,71 @@ impl Dependency { } } -impl CrateGraph { +pub type CratesIdMap = FxHashMap; + +#[salsa::input] +#[derive(Debug)] +pub struct Crate { + #[return_ref] + pub data: BuiltCrateData, + /// Crate data that is not needed for analysis. + /// + /// This is split into a separate field to increase incrementality. + #[return_ref] + pub extra_data: ExtraCrateData, + // This is in `Arc` because it is shared for all crates in a workspace. + #[return_ref] + pub workspace_data: Arc, + #[return_ref] + pub cfg_options: CfgOptions, + #[return_ref] + pub env: Env, +} + +/// The mapping from [`UniqueCrateData`] to their [`Crate`] input. +#[derive(Debug, Default)] +pub struct CratesMap(DashMap>); + +impl CrateGraphBuilder { pub fn add_crate_root( &mut self, root_file_id: FileId, edition: Edition, display_name: Option, version: Option, - cfg_options: Arc, - potential_cfg_options: Option>, + mut cfg_options: CfgOptions, + mut potential_cfg_options: Option, mut env: Env, origin: CrateOrigin, is_proc_macro: bool, - proc_macro_cwd: Option, - ) -> CrateId { + proc_macro_cwd: Arc, + ws_data: Arc, + ) -> CrateBuilderId { env.entries.shrink_to_fit(); - let data = CrateData { - root_file_id, - edition, - version, - display_name, + cfg_options.shrink_to_fit(); + if let Some(potential_cfg_options) = &mut potential_cfg_options { + potential_cfg_options.shrink_to_fit(); + } + self.arena.alloc(CrateBuilder { + basic: CrateData { + root_file_id, + edition, + dependencies: Vec::new(), + origin, + is_proc_macro, + proc_macro_cwd, + }, + extra: ExtraCrateData { version, display_name, potential_cfg_options }, cfg_options, - potential_cfg_options, env, - dependencies: Vec::new(), - origin, - is_proc_macro, - proc_macro_cwd, - }; - self.arena.alloc(data) + ws_data, + }) } pub fn add_dep( &mut self, - from: CrateId, - dep: Dependency, + from: CrateBuilderId, + dep: DependencyBuilder, ) -> Result<(), CyclicDependenciesError> { let _p = tracing::info_span!("add_dep").entered(); @@ -395,37 +462,154 @@ impl CrateGraph { // that out, look for a path in the *opposite* direction, from `to` to // `from`. if let Some(path) = self.find_path(&mut FxHashSet::default(), dep.crate_id, from) { - let path = path.into_iter().map(|it| (it, self[it].display_name.clone())).collect(); + let path = + path.into_iter().map(|it| (it, self[it].extra.display_name.clone())).collect(); let err = CyclicDependenciesError { path }; assert!(err.from().0 == from && err.to().0 == dep.crate_id); return Err(err); } - self.arena[from].add_dep(dep); + self.arena[from].basic.dependencies.push(dep); Ok(()) } - pub fn is_empty(&self) -> bool { - self.arena.is_empty() + pub fn set_in_db(self, db: &mut dyn RootQueryDb) -> CratesIdMap { + let mut all_crates = Vec::with_capacity(self.arena.len()); + let mut visited = FxHashMap::default(); + let mut visited_root_files = FxHashSet::default(); + + let old_all_crates = db.all_crates(); + + let crates_map = db.crates_map(); + // salsa doesn't compare new input to old input to see if they are the same, so here we are doing all the work ourselves. + for krate in self.iter() { + go( + &self, + db, + &crates_map, + &mut visited, + &mut visited_root_files, + &mut all_crates, + krate, + ); + } + + if **old_all_crates != *all_crates { + db.set_all_crates_with_durability( + Arc::new(all_crates.into_boxed_slice()), + Durability::MEDIUM, + ); + } + + return visited; + + fn go( + graph: &CrateGraphBuilder, + db: &mut dyn RootQueryDb, + crates_map: &CratesMap, + visited: &mut FxHashMap, + visited_root_files: &mut FxHashSet, + all_crates: &mut Vec, + source: CrateBuilderId, + ) -> Crate { + if let Some(&crate_id) = visited.get(&source) { + return crate_id; + } + let krate = &graph[source]; + let dependencies = krate + .basic + .dependencies + .iter() + .map(|dep| BuiltDependency { + crate_id: go( + graph, + db, + crates_map, + visited, + visited_root_files, + all_crates, + dep.crate_id, + ), + name: dep.name.clone(), + prelude: dep.prelude, + sysroot: dep.sysroot, + }) + .collect::>(); + let crate_data = BuiltCrateData { + dependencies, + edition: krate.basic.edition, + is_proc_macro: krate.basic.is_proc_macro, + origin: krate.basic.origin.clone(), + root_file_id: krate.basic.root_file_id, + proc_macro_cwd: krate.basic.proc_macro_cwd.clone(), + }; + let disambiguator = if visited_root_files.insert(krate.basic.root_file_id) { + None + } else { + Some(Box::new((crate_data.clone(), krate.cfg_options.to_hashable()))) + }; + + let unique_crate_data = + UniqueCrateData { root_file_id: krate.basic.root_file_id, disambiguator }; + let crate_input = match crates_map.0.entry(unique_crate_data) { + Entry::Occupied(entry) => { + let old_crate = *entry.get(); + if crate_data != *old_crate.data(db) { + old_crate.set_data(db).with_durability(Durability::MEDIUM).to(crate_data); + } + if krate.extra != *old_crate.extra_data(db) { + old_crate + .set_extra_data(db) + .with_durability(Durability::MEDIUM) + .to(krate.extra.clone()); + } + if krate.cfg_options != *old_crate.cfg_options(db) { + old_crate + .set_cfg_options(db) + .with_durability(Durability::MEDIUM) + .to(krate.cfg_options.clone()); + } + if krate.env != *old_crate.env(db) { + old_crate + .set_env(db) + .with_durability(Durability::MEDIUM) + .to(krate.env.clone()); + } + if krate.ws_data != *old_crate.workspace_data(db) { + old_crate + .set_workspace_data(db) + .with_durability(Durability::MEDIUM) + .to(krate.ws_data.clone()); + } + old_crate + } + Entry::Vacant(entry) => { + let input = Crate::builder( + crate_data, + krate.extra.clone(), + krate.ws_data.clone(), + krate.cfg_options.clone(), + krate.env.clone(), + ) + .durability(Durability::MEDIUM) + .new(db); + entry.insert(input); + input + } + }; + all_crates.push(crate_input); + visited.insert(source, crate_input); + crate_input + } } - pub fn len(&self) -> usize { - self.arena.len() - } - - pub fn iter(&self) -> impl Iterator + '_ { + pub fn iter(&self) -> impl Iterator + '_ { self.arena.iter().map(|(idx, _)| idx) } - // FIXME: used for fixing up the toolchain sysroot, should be removed and done differently - #[doc(hidden)] - pub fn iter_mut(&mut self) -> impl Iterator + '_ { - self.arena.iter_mut() - } - /// Returns an iterator over all transitive dependencies of the given crate, /// including the crate itself. - pub fn transitive_deps(&self, of: CrateId) -> impl Iterator { + pub fn transitive_deps(&self, of: CrateBuilderId) -> impl Iterator { let mut worklist = vec![of]; let mut deps = FxHashSet::default(); @@ -434,42 +618,15 @@ impl CrateGraph { continue; } - worklist.extend(self[krate].dependencies.iter().map(|dep| dep.crate_id)); + worklist.extend(self[krate].basic.dependencies.iter().map(|dep| dep.crate_id)); } deps.into_iter() } - /// Returns all transitive reverse dependencies of the given crate, - /// including the crate itself. - pub fn transitive_rev_deps(&self, of: CrateId) -> impl Iterator { - let mut worklist = vec![of]; - let mut rev_deps = FxHashSet::default(); - rev_deps.insert(of); - - let mut inverted_graph = FxHashMap::<_, Vec<_>>::default(); - self.arena.iter().for_each(|(krate, data)| { - data.dependencies - .iter() - .for_each(|dep| inverted_graph.entry(dep.crate_id).or_default().push(krate)) - }); - - while let Some(krate) = worklist.pop() { - if let Some(krate_rev_deps) = inverted_graph.get(&krate) { - krate_rev_deps - .iter() - .copied() - .filter(|&rev_dep| rev_deps.insert(rev_dep)) - .for_each(|rev_dep| worklist.push(rev_dep)); - } - } - - rev_deps.into_iter() - } - /// Returns all crates in the graph, sorted in topological order (ie. dependencies of a crate /// come before the crate itself). - pub fn crates_in_topological_order(&self) -> Vec { + fn crates_in_topological_order(&self) -> Vec { let mut res = Vec::new(); let mut visited = FxHashSet::default(); @@ -480,15 +637,15 @@ impl CrateGraph { return res; fn go( - graph: &CrateGraph, - visited: &mut FxHashSet, - res: &mut Vec, - source: CrateId, + graph: &CrateGraphBuilder, + visited: &mut FxHashSet, + res: &mut Vec, + source: CrateBuilderId, ) { if !visited.insert(source) { return; } - for dep in graph[source].dependencies.iter() { + for dep in graph[source].basic.dependencies.iter() { go(graph, visited, res, dep.crate_id) } res.push(source) @@ -504,23 +661,27 @@ impl CrateGraph { /// Returns a map mapping `other`'s IDs to the new IDs in `self`. pub fn extend( &mut self, - mut other: CrateGraph, + mut other: CrateGraphBuilder, proc_macros: &mut ProcMacroPaths, - ) -> FxHashMap { + ) -> FxHashMap { // Sorting here is a bit pointless because the input is likely already sorted. // However, the overhead is small and it makes the `extend` method harder to misuse. self.arena .iter_mut() - .for_each(|(_, data)| data.dependencies.sort_by_key(|dep| dep.crate_id)); + .for_each(|(_, data)| data.basic.dependencies.sort_by_key(|dep| dep.crate_id)); - let m = self.len(); + let m = self.arena.len(); let topo = other.crates_in_topological_order(); - let mut id_map: FxHashMap = FxHashMap::default(); + let mut id_map: FxHashMap = FxHashMap::default(); for topo in topo { let crate_data = &mut other.arena[topo]; - crate_data.dependencies.iter_mut().for_each(|dep| dep.crate_id = id_map[&dep.crate_id]); - crate_data.dependencies.sort_by_key(|dep| dep.crate_id); + crate_data + .basic + .dependencies + .iter_mut() + .for_each(|dep| dep.crate_id = id_map[&dep.crate_id]); + crate_data.basic.dependencies.sort_by_key(|dep| dep.crate_id); let find = self.arena.iter().take(m).find_map(|(k, v)| (v == crate_data).then_some(k)); let new_id = find.unwrap_or_else(|| self.arena.alloc(crate_data.clone())); @@ -534,10 +695,10 @@ impl CrateGraph { fn find_path( &self, - visited: &mut FxHashSet, - from: CrateId, - to: CrateId, - ) -> Option> { + visited: &mut FxHashSet, + from: CrateBuilderId, + to: CrateBuilderId, + ) -> Option> { if !visited.insert(from) { return None; } @@ -546,7 +707,7 @@ impl CrateGraph { return Some(vec![to]); } - for dep in &self[from].dependencies { + for dep in &self[from].basic.dependencies { let crate_id = dep.crate_id; if let Some(mut path) = self.find_path(visited, crate_id, to) { path.push(from); @@ -559,7 +720,10 @@ impl CrateGraph { /// Removes all crates from this crate graph except for the ones in `to_keep` and fixes up the dependencies. /// Returns a mapping from old crate ids to new crate ids. - pub fn remove_crates_except(&mut self, to_keep: &[CrateId]) -> Vec> { + pub fn remove_crates_except( + &mut self, + to_keep: &[CrateBuilderId], + ) -> Vec> { let mut id_map = vec![None; self.arena.len()]; self.arena = std::mem::take(&mut self.arena) .into_iter() @@ -567,12 +731,12 @@ impl CrateGraph { .enumerate() .map(|(new_id, (id, data))| { id_map[id.into_raw().into_u32() as usize] = - Some(CrateId::from_raw(RawIdx::from_u32(new_id as u32))); + Some(CrateBuilderId::from_raw(RawIdx::from_u32(new_id as u32))); data }) .collect(); for (_, data) in self.arena.iter_mut() { - data.dependencies.iter_mut().for_each(|dep| { + data.basic.dependencies.iter_mut().for_each(|dep| { dep.crate_id = id_map[dep.crate_id.into_raw().into_u32() as usize].expect("crate was filtered") }); @@ -585,22 +749,36 @@ impl CrateGraph { } } -impl ops::Index for CrateGraph { - type Output = CrateData; - fn index(&self, crate_id: CrateId) -> &CrateData { - &self.arena[crate_id] +pub(crate) fn transitive_rev_deps(db: &dyn RootQueryDb, of: Crate) -> FxHashSet { + let mut worklist = vec![of]; + let mut rev_deps = FxHashSet::default(); + rev_deps.insert(of); + + let mut inverted_graph = FxHashMap::<_, Vec<_>>::default(); + db.all_crates().iter().for_each(|&krate| { + krate + .data(db) + .dependencies + .iter() + .for_each(|dep| inverted_graph.entry(dep.crate_id).or_default().push(krate)) + }); + + while let Some(krate) = worklist.pop() { + if let Some(crate_rev_deps) = inverted_graph.get(&krate) { + crate_rev_deps + .iter() + .copied() + .filter(|&rev_dep| rev_deps.insert(rev_dep)) + .for_each(|rev_dep| worklist.push(rev_dep)); + } } + + rev_deps } -impl CrateData { - /// Add a dependency to `self` without checking if the dependency - // is existent among `self.dependencies`. - fn add_dep(&mut self, dep: Dependency) { - self.dependencies.push(dep) - } - - pub fn root_file_id(&self) -> EditionedFileId { - EditionedFileId::new(self.root_file_id, self.edition) +impl BuiltCrateData { + pub fn root_file_id(&self, db: &dyn salsa::Database) -> EditionedFileId { + EditionedFileId::new(db, self.root_file_id, self.edition) } } @@ -657,21 +835,21 @@ impl<'a> IntoIterator for &'a Env { #[derive(Debug)] pub struct CyclicDependenciesError { - path: Vec<(CrateId, Option)>, + path: Vec<(CrateBuilderId, Option)>, } impl CyclicDependenciesError { - fn from(&self) -> &(CrateId, Option) { + fn from(&self) -> &(CrateBuilderId, Option) { self.path.first().unwrap() } - fn to(&self) -> &(CrateId, Option) { + fn to(&self) -> &(CrateBuilderId, Option) { self.path.last().unwrap() } } impl fmt::Display for CyclicDependenciesError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let render = |(id, name): &(CrateId, Option)| match name { + let render = |(id, name): &(CrateBuilderId, Option)| match name { Some(it) => format!("{it}({id:?})"), None => format!("{id:?}"), }; @@ -688,13 +866,20 @@ impl fmt::Display for CyclicDependenciesError { #[cfg(test)] mod tests { - use crate::CrateOrigin; + use triomphe::Arc; + use vfs::AbsPathBuf; - use super::{CrateGraph, CrateName, Dependency, Edition::Edition2018, Env, FileId}; + use crate::{CrateWorkspaceData, DependencyBuilder}; + + use super::{CrateGraphBuilder, CrateName, CrateOrigin, Edition::Edition2018, Env, FileId}; + + fn empty_ws_data() -> Arc { + Arc::new(CrateWorkspaceData { data_layout: Err("".into()), toolchain: None }) + } #[test] fn detect_cyclic_dependency_indirect() { - let mut graph = CrateGraph::default(); + let mut graph = CrateGraphBuilder::default(); let crate1 = graph.add_crate_root( FileId::from_raw(1u32), Edition2018, @@ -705,7 +890,8 @@ mod tests { Env::default(), CrateOrigin::Local { repo: None, name: None }, false, - None, + Arc::new(AbsPathBuf::assert_utf8(std::env::current_dir().unwrap())), + empty_ws_data(), ); let crate2 = graph.add_crate_root( FileId::from_raw(2u32), @@ -717,7 +903,8 @@ mod tests { Env::default(), CrateOrigin::Local { repo: None, name: None }, false, - None, + Arc::new(AbsPathBuf::assert_utf8(std::env::current_dir().unwrap())), + empty_ws_data(), ); let crate3 = graph.add_crate_root( FileId::from_raw(3u32), @@ -729,22 +916,29 @@ mod tests { Env::default(), CrateOrigin::Local { repo: None, name: None }, false, - None, + Arc::new(AbsPathBuf::assert_utf8(std::env::current_dir().unwrap())), + empty_ws_data(), + ); + assert!( + graph + .add_dep(crate1, DependencyBuilder::new(CrateName::new("crate2").unwrap(), crate2,)) + .is_ok() + ); + assert!( + graph + .add_dep(crate2, DependencyBuilder::new(CrateName::new("crate3").unwrap(), crate3,)) + .is_ok() + ); + assert!( + graph + .add_dep(crate3, DependencyBuilder::new(CrateName::new("crate1").unwrap(), crate1,)) + .is_err() ); - assert!(graph - .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2,)) - .is_ok()); - assert!(graph - .add_dep(crate2, Dependency::new(CrateName::new("crate3").unwrap(), crate3,)) - .is_ok()); - assert!(graph - .add_dep(crate3, Dependency::new(CrateName::new("crate1").unwrap(), crate1,)) - .is_err()); } #[test] fn detect_cyclic_dependency_direct() { - let mut graph = CrateGraph::default(); + let mut graph = CrateGraphBuilder::default(); let crate1 = graph.add_crate_root( FileId::from_raw(1u32), Edition2018, @@ -755,7 +949,8 @@ mod tests { Env::default(), CrateOrigin::Local { repo: None, name: None }, false, - None, + Arc::new(AbsPathBuf::assert_utf8(std::env::current_dir().unwrap())), + empty_ws_data(), ); let crate2 = graph.add_crate_root( FileId::from_raw(2u32), @@ -767,19 +962,24 @@ mod tests { Env::default(), CrateOrigin::Local { repo: None, name: None }, false, - None, + Arc::new(AbsPathBuf::assert_utf8(std::env::current_dir().unwrap())), + empty_ws_data(), + ); + assert!( + graph + .add_dep(crate1, DependencyBuilder::new(CrateName::new("crate2").unwrap(), crate2,)) + .is_ok() + ); + assert!( + graph + .add_dep(crate2, DependencyBuilder::new(CrateName::new("crate2").unwrap(), crate2,)) + .is_err() ); - assert!(graph - .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2,)) - .is_ok()); - assert!(graph - .add_dep(crate2, Dependency::new(CrateName::new("crate2").unwrap(), crate2,)) - .is_err()); } #[test] fn it_works() { - let mut graph = CrateGraph::default(); + let mut graph = CrateGraphBuilder::default(); let crate1 = graph.add_crate_root( FileId::from_raw(1u32), Edition2018, @@ -790,7 +990,8 @@ mod tests { Env::default(), CrateOrigin::Local { repo: None, name: None }, false, - None, + Arc::new(AbsPathBuf::assert_utf8(std::env::current_dir().unwrap())), + empty_ws_data(), ); let crate2 = graph.add_crate_root( FileId::from_raw(2u32), @@ -802,7 +1003,8 @@ mod tests { Env::default(), CrateOrigin::Local { repo: None, name: None }, false, - None, + Arc::new(AbsPathBuf::assert_utf8(std::env::current_dir().unwrap())), + empty_ws_data(), ); let crate3 = graph.add_crate_root( FileId::from_raw(3u32), @@ -814,19 +1016,24 @@ mod tests { Env::default(), CrateOrigin::Local { repo: None, name: None }, false, - None, + Arc::new(AbsPathBuf::assert_utf8(std::env::current_dir().unwrap())), + empty_ws_data(), + ); + assert!( + graph + .add_dep(crate1, DependencyBuilder::new(CrateName::new("crate2").unwrap(), crate2,)) + .is_ok() + ); + assert!( + graph + .add_dep(crate2, DependencyBuilder::new(CrateName::new("crate3").unwrap(), crate3,)) + .is_ok() ); - assert!(graph - .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2,)) - .is_ok()); - assert!(graph - .add_dep(crate2, Dependency::new(CrateName::new("crate3").unwrap(), crate3,)) - .is_ok()); } #[test] fn dashes_are_normalized() { - let mut graph = CrateGraph::default(); + let mut graph = CrateGraphBuilder::default(); let crate1 = graph.add_crate_root( FileId::from_raw(1u32), Edition2018, @@ -837,7 +1044,8 @@ mod tests { Env::default(), CrateOrigin::Local { repo: None, name: None }, false, - None, + Arc::new(AbsPathBuf::assert_utf8(std::env::current_dir().unwrap())), + empty_ws_data(), ); let crate2 = graph.add_crate_root( FileId::from_raw(2u32), @@ -849,17 +1057,25 @@ mod tests { Env::default(), CrateOrigin::Local { repo: None, name: None }, false, - None, + Arc::new(AbsPathBuf::assert_utf8(std::env::current_dir().unwrap())), + empty_ws_data(), + ); + assert!( + graph + .add_dep( + crate1, + DependencyBuilder::new( + CrateName::normalize_dashes("crate-name-with-dashes"), + crate2, + ) + ) + .is_ok() ); - assert!(graph - .add_dep( - crate1, - Dependency::new(CrateName::normalize_dashes("crate-name-with-dashes"), crate2,) - ) - .is_ok()); assert_eq!( - graph[crate1].dependencies, - vec![Dependency::new(CrateName::new("crate_name_with_dashes").unwrap(), crate2,)] + graph.arena[crate1].basic.dependencies, + vec![ + DependencyBuilder::new(CrateName::new("crate_name_with_dashes").unwrap(), crate2,) + ] ); } } diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs index eed8c8868395..7f7a712577e4 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs @@ -3,83 +3,311 @@ mod change; mod input; -use std::panic; - -use ra_salsa::Durability; -use rustc_hash::FxHashMap; -use span::EditionedFileId; -use syntax::{ast, Parse, SourceFile, SyntaxError}; -use triomphe::Arc; -use vfs::FileId; +use std::hash::BuildHasherDefault; pub use crate::{ change::FileChange, input::{ - CrateData, CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Env, - LangCrateOrigin, ProcMacroPaths, ReleaseChannel, SourceRoot, SourceRootId, - TargetLayoutLoadResult, + BuiltCrateData, BuiltDependency, Crate, CrateBuilder, CrateBuilderId, CrateDataBuilder, + CrateDisplayName, CrateGraphBuilder, CrateName, CrateOrigin, CratesIdMap, CratesMap, + DependencyBuilder, Env, ExtraCrateData, LangCrateOrigin, ProcMacroPaths, ReleaseChannel, + SourceRoot, SourceRootId, TargetLayoutLoadResult, UniqueCrateData, }, }; -pub use ra_salsa::{self, Cancelled}; -pub use vfs::{file_set::FileSet, AnchoredPath, AnchoredPathBuf, VfsPath}; - +use dashmap::{DashMap, mapref::entry::Entry}; +pub use query_group::{self}; +use rustc_hash::{FxHashSet, FxHasher}; +pub use salsa::{self}; +use salsa::{Durability, Setter}; pub use semver::{BuildMetadata, Prerelease, Version, VersionReq}; +use span::Edition; +use syntax::{Parse, SyntaxError, ast}; +use triomphe::Arc; +pub use vfs::{AnchoredPath, AnchoredPathBuf, FileId, VfsPath, file_set::FileSet}; #[macro_export] macro_rules! impl_intern_key { - ($name:ident) => { - impl $crate::ra_salsa::InternKey for $name { - fn from_intern_id(v: $crate::ra_salsa::InternId) -> Self { - $name(v) - } - fn as_intern_id(&self) -> $crate::ra_salsa::InternId { - self.0 + ($id:ident, $loc:ident) => { + #[salsa::interned(no_lifetime)] + pub struct $id { + pub loc: $loc, + } + + // If we derive this salsa prints the values recursively, and this causes us to blow. + impl ::std::fmt::Debug for $id { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + f.debug_tuple(stringify!($id)) + .field(&format_args!("{:04x}", self.0.as_u32())) + .finish() } } }; } -pub trait Upcast { - fn upcast(&self) -> &T; -} - pub const DEFAULT_FILE_TEXT_LRU_CAP: u16 = 16; pub const DEFAULT_PARSE_LRU_CAP: u16 = 128; pub const DEFAULT_BORROWCK_LRU_CAP: u16 = 2024; -pub trait FileLoader { - fn resolve_path(&self, path: AnchoredPath<'_>) -> Option; - /// Crates whose root's source root is the same as the source root of `file_id` - fn relevant_crates(&self, file_id: FileId) -> Arc<[CrateId]>; +#[derive(Debug, Default)] +pub struct Files { + files: Arc>>, + source_roots: Arc>>, + file_source_roots: Arc>>, +} + +impl Files { + pub fn file_text(&self, file_id: vfs::FileId) -> FileText { + *self.files.get(&file_id).expect("Unable to fetch file; this is a bug") + } + + pub fn set_file_text(&self, db: &mut dyn SourceDatabase, file_id: vfs::FileId, text: &str) { + match self.files.entry(file_id) { + Entry::Occupied(mut occupied) => { + occupied.get_mut().set_text(db).to(Arc::from(text)); + } + Entry::Vacant(vacant) => { + let text = FileText::new(db, Arc::from(text), file_id); + vacant.insert(text); + } + }; + } + + pub fn set_file_text_with_durability( + &self, + db: &mut dyn SourceDatabase, + file_id: vfs::FileId, + text: &str, + durability: Durability, + ) { + match self.files.entry(file_id) { + Entry::Occupied(mut occupied) => { + occupied.get_mut().set_text(db).with_durability(durability).to(Arc::from(text)); + } + Entry::Vacant(vacant) => { + let text = + FileText::builder(Arc::from(text), file_id).durability(durability).new(db); + vacant.insert(text); + } + }; + } + + /// Source root of the file. + pub fn source_root(&self, source_root_id: SourceRootId) -> SourceRootInput { + let source_root = self + .source_roots + .get(&source_root_id) + .expect("Unable to fetch source root id; this is a bug"); + + *source_root + } + + pub fn set_source_root_with_durability( + &self, + db: &mut dyn SourceDatabase, + source_root_id: SourceRootId, + source_root: Arc, + durability: Durability, + ) { + match self.source_roots.entry(source_root_id) { + Entry::Occupied(mut occupied) => { + occupied.get_mut().set_source_root(db).with_durability(durability).to(source_root); + } + Entry::Vacant(vacant) => { + let source_root = + SourceRootInput::builder(source_root).durability(durability).new(db); + vacant.insert(source_root); + } + }; + } + + pub fn file_source_root(&self, id: vfs::FileId) -> FileSourceRootInput { + let file_source_root = self + .file_source_roots + .get(&id) + .expect("Unable to fetch FileSourceRootInput; this is a bug"); + *file_source_root + } + + pub fn set_file_source_root_with_durability( + &self, + db: &mut dyn SourceDatabase, + id: vfs::FileId, + source_root_id: SourceRootId, + durability: Durability, + ) { + match self.file_source_roots.entry(id) { + Entry::Occupied(mut occupied) => { + occupied + .get_mut() + .set_source_root_id(db) + .with_durability(durability) + .to(source_root_id); + } + Entry::Vacant(vacant) => { + let file_source_root = + FileSourceRootInput::builder(source_root_id).durability(durability).new(db); + vacant.insert(file_source_root); + } + }; + } +} + +#[salsa::interned(no_lifetime, debug, constructor=from_span)] +pub struct EditionedFileId { + pub editioned_file_id: span::EditionedFileId, +} + +impl EditionedFileId { + // Salsa already uses the name `new`... + #[inline] + pub fn new(db: &dyn salsa::Database, file_id: FileId, edition: Edition) -> Self { + EditionedFileId::from_span(db, span::EditionedFileId::new(file_id, edition)) + } + + #[inline] + pub fn current_edition(db: &dyn salsa::Database, file_id: FileId) -> Self { + EditionedFileId::new(db, file_id, Edition::CURRENT) + } + + #[inline] + pub fn file_id(self, db: &dyn salsa::Database) -> vfs::FileId { + let id = self.editioned_file_id(db); + id.file_id() + } + + #[inline] + pub fn unpack(self, db: &dyn salsa::Database) -> (vfs::FileId, span::Edition) { + let id = self.editioned_file_id(db); + (id.file_id(), id.edition()) + } + + #[inline] + pub fn edition(self, db: &dyn SourceDatabase) -> Edition { + self.editioned_file_id(db).edition() + } +} + +#[salsa::input(debug)] +pub struct FileText { + pub text: Arc, + pub file_id: vfs::FileId, +} + +#[salsa::input(debug)] +pub struct FileSourceRootInput { + pub source_root_id: SourceRootId, +} + +#[salsa::input(debug)] +pub struct SourceRootInput { + pub source_root: Arc, } /// Database which stores all significant input facts: source code and project /// model. Everything else in rust-analyzer is derived from these queries. -#[ra_salsa::query_group(SourceDatabaseStorage)] -pub trait SourceDatabase: FileLoader + std::fmt::Debug { - #[ra_salsa::input] - fn compressed_file_text(&self, file_id: FileId) -> Arc<[u8]>; - - /// Text of the file. - #[ra_salsa::lru] - fn file_text(&self, file_id: FileId) -> Arc; - +#[query_group::query_group] +pub trait RootQueryDb: SourceDatabase + salsa::Database { /// Parses the file into the syntax tree. - #[ra_salsa::lru] + #[salsa::invoke(parse)] + #[salsa::lru(128)] fn parse(&self, file_id: EditionedFileId) -> Parse; /// Returns the set of errors obtained from parsing the file including validation errors. - fn parse_errors(&self, file_id: EditionedFileId) -> Option>; + #[salsa::transparent] + fn parse_errors(&self, file_id: EditionedFileId) -> Option<&[SyntaxError]>; - /// The crate graph. - #[ra_salsa::input] - fn crate_graph(&self) -> Arc; + #[salsa::transparent] + fn toolchain_channel(&self, krate: Crate) -> Option; - #[ra_salsa::input] - fn crate_workspace_data(&self) -> Arc>>; + /// Crates whose root file is in `id`. + #[salsa::invoke_interned(source_root_crates)] + fn source_root_crates(&self, id: SourceRootId) -> Arc<[Crate]>; - #[ra_salsa::transparent] - fn toolchain_channel(&self, krate: CrateId) -> Option; + #[salsa::transparent] + fn relevant_crates(&self, file_id: FileId) -> Arc<[Crate]>; + + /// Returns the crates in topological order. + /// + /// **Warning**: do not use this query in `hir-*` crates! It kills incrementality across crate metadata modifications. + #[salsa::input] + fn all_crates(&self) -> Arc>; + + /// Returns an iterator over all transitive dependencies of the given crate, + /// including the crate itself. + /// + /// **Warning**: do not use this query in `hir-*` crates! It kills incrementality across crate metadata modifications. + #[salsa::transparent] + fn transitive_deps(&self, crate_id: Crate) -> FxHashSet; + + /// Returns all transitive reverse dependencies of the given crate, + /// including the crate itself. + /// + /// **Warning**: do not use this query in `hir-*` crates! It kills incrementality across crate metadata modifications. + #[salsa::invoke(input::transitive_rev_deps)] + #[salsa::transparent] + fn transitive_rev_deps(&self, of: Crate) -> FxHashSet; +} + +pub fn transitive_deps(db: &dyn SourceDatabase, crate_id: Crate) -> FxHashSet { + // There is a bit of duplication here and in `CrateGraphBuilder` in the same method, but it's not terrible + // and removing that is a bit difficult. + let mut worklist = vec![crate_id]; + let mut deps = FxHashSet::default(); + + while let Some(krate) = worklist.pop() { + if !deps.insert(krate) { + continue; + } + + worklist.extend(krate.data(db).dependencies.iter().map(|dep| dep.crate_id)); + } + + deps +} + +#[salsa::db] +pub trait SourceDatabase: salsa::Database { + /// Text of the file. + fn file_text(&self, file_id: vfs::FileId) -> FileText; + + fn set_file_text(&mut self, file_id: vfs::FileId, text: &str); + + fn set_file_text_with_durability( + &mut self, + file_id: vfs::FileId, + text: &str, + durability: Durability, + ); + + /// Contents of the source root. + fn source_root(&self, id: SourceRootId) -> SourceRootInput; + + fn file_source_root(&self, id: vfs::FileId) -> FileSourceRootInput; + + fn set_file_source_root_with_durability( + &mut self, + id: vfs::FileId, + source_root_id: SourceRootId, + durability: Durability, + ); + + /// Source root of the file. + fn set_source_root_with_durability( + &mut self, + source_root_id: SourceRootId, + source_root: Arc, + durability: Durability, + ); + + fn resolve_path(&self, path: AnchoredPath<'_>) -> Option { + // FIXME: this *somehow* should be platform agnostic... + let source_root = self.file_source_root(path.anchor); + let source_root = self.source_root(source_root.source_root_id(self)); + source_root.source_root(self).resolve_path(path) + } + + #[doc(hidden)] + fn crates_map(&self) -> Arc; } /// Crate related data shared by the whole workspace. @@ -91,113 +319,57 @@ pub struct CrateWorkspaceData { pub toolchain: Option, } -fn toolchain_channel(db: &dyn SourceDatabase, krate: CrateId) -> Option { - db.crate_workspace_data() - .get(&krate)? - .toolchain - .as_ref() - .and_then(|v| ReleaseChannel::from_str(&v.pre)) +impl CrateWorkspaceData { + pub fn is_atleast_187(&self) -> bool { + const VERSION_187: Version = Version { + major: 1, + minor: 87, + patch: 0, + pre: Prerelease::EMPTY, + build: BuildMetadata::EMPTY, + }; + self.toolchain.as_ref().map_or(false, |v| *v >= VERSION_187) + } } -fn parse(db: &dyn SourceDatabase, file_id: EditionedFileId) -> Parse { +fn toolchain_channel(db: &dyn RootQueryDb, krate: Crate) -> Option { + krate.workspace_data(db).toolchain.as_ref().and_then(|v| ReleaseChannel::from_str(&v.pre)) +} + +fn parse(db: &dyn RootQueryDb, file_id: EditionedFileId) -> Parse { let _p = tracing::info_span!("parse", ?file_id).entered(); - let (file_id, edition) = file_id.unpack(); - let text = db.file_text(file_id); - SourceFile::parse(&text, edition) + let (file_id, edition) = file_id.unpack(db.as_dyn_database()); + let text = db.file_text(file_id).text(db); + ast::SourceFile::parse(&text, edition) } -fn parse_errors(db: &dyn SourceDatabase, file_id: EditionedFileId) -> Option> { - let errors = db.parse(file_id).errors(); - match &*errors { - [] => None, - [..] => Some(errors.into()), +fn parse_errors(db: &dyn RootQueryDb, file_id: EditionedFileId) -> Option<&[SyntaxError]> { + #[salsa::tracked(return_ref)] + fn parse_errors(db: &dyn RootQueryDb, file_id: EditionedFileId) -> Option> { + let errors = db.parse(file_id).errors(); + match &*errors { + [] => None, + [..] => Some(errors.into()), + } } + parse_errors(db, file_id).as_ref().map(|it| &**it) } -fn file_text(db: &dyn SourceDatabase, file_id: FileId) -> Arc { - let bytes = db.compressed_file_text(file_id); - let bytes = - lz4_flex::decompress_size_prepended(&bytes).expect("lz4 decompression should not fail"); - let text = std::str::from_utf8(&bytes).expect("file contents should be valid UTF-8"); - Arc::from(text) -} - -/// We don't want to give HIR knowledge of source roots, hence we extract these -/// methods into a separate DB. -#[ra_salsa::query_group(SourceRootDatabaseStorage)] -pub trait SourceRootDatabase: SourceDatabase { - /// Path to a file, relative to the root of its source root. - /// Source root of the file. - #[ra_salsa::input] - fn file_source_root(&self, file_id: FileId) -> SourceRootId; - /// Contents of the source root. - #[ra_salsa::input] - fn source_root(&self, id: SourceRootId) -> Arc; - - /// Crates whose root file is in `id`. - fn source_root_crates(&self, id: SourceRootId) -> Arc<[CrateId]>; -} - -pub trait SourceDatabaseFileInputExt { - fn set_file_text(&mut self, file_id: FileId, text: &str) { - self.set_file_text_with_durability(file_id, text, Durability::LOW); - } - - fn set_file_text_with_durability( - &mut self, - file_id: FileId, - text: &str, - durability: Durability, - ); -} - -impl SourceDatabaseFileInputExt for Db { - fn set_file_text_with_durability( - &mut self, - file_id: FileId, - text: &str, - durability: Durability, - ) { - let bytes = text.as_bytes(); - let compressed = lz4_flex::compress_prepend_size(bytes); - self.set_compressed_file_text_with_durability( - file_id, - Arc::from(compressed.as_slice()), - durability, - ) - } -} - -fn source_root_crates(db: &dyn SourceRootDatabase, id: SourceRootId) -> Arc<[CrateId]> { - let graph = db.crate_graph(); - let mut crates = graph +fn source_root_crates(db: &dyn RootQueryDb, id: SourceRootId) -> Arc<[Crate]> { + let crates = db.all_crates(); + crates .iter() + .copied() .filter(|&krate| { - let root_file = graph[krate].root_file_id; - db.file_source_root(root_file) == id + let root_file = krate.data(db).root_file_id; + db.file_source_root(root_file).source_root_id(db) == id }) - .collect::>(); - crates.sort(); - crates.dedup(); - crates.into_iter().collect() + .collect() } -// FIXME: Would be nice to get rid of this somehow -/// Silly workaround for cyclic deps due to the SourceRootDatabase and SourceDatabase split -/// regarding FileLoader -pub struct FileLoaderDelegate(pub T); +fn relevant_crates(db: &dyn RootQueryDb, file_id: FileId) -> Arc<[Crate]> { + let _p = tracing::info_span!("relevant_crates").entered(); -impl FileLoader for FileLoaderDelegate<&'_ T> { - fn resolve_path(&self, path: AnchoredPath<'_>) -> Option { - // FIXME: this *somehow* should be platform agnostic... - let source_root = self.0.file_source_root(path.anchor); - let source_root = self.0.source_root(source_root); - source_root.resolve_path(path) - } - - fn relevant_crates(&self, file_id: FileId) -> Arc<[CrateId]> { - let _p = tracing::info_span!("relevant_crates").entered(); - let source_root = self.0.file_source_root(file_id); - self.0.source_root_crates(source_root) - } + let source_root = db.file_source_root(file_id); + db.source_root_crates(source_root.source_root_id(db)) } diff --git a/src/tools/rust-analyzer/crates/cfg/Cargo.toml b/src/tools/rust-analyzer/crates/cfg/Cargo.toml index e887368ef28f..d7764a16c044 100644 --- a/src/tools/rust-analyzer/crates/cfg/Cargo.toml +++ b/src/tools/rust-analyzer/crates/cfg/Cargo.toml @@ -20,13 +20,13 @@ tt = { workspace = true, optional = true } intern.workspace = true [dev-dependencies] -expect-test = "1.4.1" -oorandom = "11.1.3" +expect-test = "1.5.1" +oorandom = "11.1.5" # We depend on both individually instead of using `features = ["derive"]` to microoptimize the # build graph: if the feature was enabled, syn would be built early on in the graph if `smolstr` # supports `arbitrary`. This way, we avoid feature unification. -arbitrary = "1.3.2" -derive_arbitrary = "1.3.2" +arbitrary = "1.4.1" +derive_arbitrary = "1.4.1" # local deps syntax-bridge.workspace = true diff --git a/src/tools/rust-analyzer/crates/cfg/src/lib.rs b/src/tools/rust-analyzer/crates/cfg/src/lib.rs index 08545b685119..906106ca5db0 100644 --- a/src/tools/rust-analyzer/crates/cfg/src/lib.rs +++ b/src/tools/rust-analyzer/crates/cfg/src/lib.rs @@ -9,7 +9,7 @@ use std::fmt; use rustc_hash::FxHashSet; -use intern::{sym, Symbol}; +use intern::{Symbol, sym}; pub use cfg_expr::{CfgAtom, CfgExpr}; pub use dnf::DnfExpr; @@ -31,7 +31,7 @@ pub struct CfgOptions { impl Default for CfgOptions { fn default() -> Self { - Self { enabled: FxHashSet::from_iter([CfgAtom::Flag(sym::true_.clone())]) } + Self { enabled: FxHashSet::from_iter([CfgAtom::Flag(sym::true_)]) } } } @@ -104,6 +104,17 @@ impl CfgOptions { _ => None, }) } + + pub fn to_hashable(&self) -> HashableCfgOptions { + let mut enabled = self.enabled.iter().cloned().collect::>(); + enabled.sort_unstable(); + HashableCfgOptions { _enabled: enabled } + } + + #[inline] + pub fn shrink_to_fit(&mut self) { + self.enabled.shrink_to_fit(); + } } impl Extend for CfgOptions { @@ -256,3 +267,9 @@ impl fmt::Display for InactiveReason { Ok(()) } } + +/// A `CfgOptions` that implements `Hash`, for the sake of hashing only. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct HashableCfgOptions { + _enabled: Box<[CfgAtom]>, +} diff --git a/src/tools/rust-analyzer/crates/cfg/src/tests.rs b/src/tools/rust-analyzer/crates/cfg/src/tests.rs index 6d87d83ad930..6766748097f0 100644 --- a/src/tools/rust-analyzer/crates/cfg/src/tests.rs +++ b/src/tools/rust-analyzer/crates/cfg/src/tests.rs @@ -1,10 +1,11 @@ use arbitrary::{Arbitrary, Unstructured}; -use expect_test::{expect, Expect}; +use expect_test::{Expect, expect}; use intern::Symbol; -use syntax::{ast, AstNode, Edition}; +use syntax::{AstNode, Edition, ast}; use syntax_bridge::{ - dummy_test_span_utils::{DummyTestSpanMap, DUMMY}, - syntax_node_to_token_tree, DocCommentDesugarMode, + DocCommentDesugarMode, + dummy_test_span_utils::{DUMMY, DummyTestSpanMap}, + syntax_node_to_token_tree, }; use crate::{CfgAtom, CfgExpr, CfgOptions, DnfExpr}; diff --git a/src/tools/rust-analyzer/crates/edition/src/lib.rs b/src/tools/rust-analyzer/crates/edition/src/lib.rs index 7e9c94af408c..f1a1fe596493 100644 --- a/src/tools/rust-analyzer/crates/edition/src/lib.rs +++ b/src/tools/rust-analyzer/crates/edition/src/lib.rs @@ -15,9 +15,19 @@ pub enum Edition { impl Edition { pub const DEFAULT: Edition = Edition::Edition2015; pub const LATEST: Edition = Edition::Edition2024; - pub const CURRENT: Edition = Edition::Edition2021; + pub const CURRENT: Edition = Edition::Edition2024; /// The current latest stable edition, note this is usually not the right choice in code. - pub const CURRENT_FIXME: Edition = Edition::Edition2021; + pub const CURRENT_FIXME: Edition = Edition::Edition2024; + + pub fn from_u32(u32: u32) -> Edition { + match u32 { + 0 => Edition::Edition2015, + 1 => Edition::Edition2018, + 2 => Edition::Edition2021, + 3 => Edition::Edition2024, + _ => panic!("invalid edition"), + } + } pub fn at_least_2024(self) -> bool { self >= Edition::Edition2024 @@ -31,6 +41,15 @@ impl Edition { self >= Edition::Edition2018 } + pub fn number(&self) -> usize { + match self { + Edition::Edition2015 => 2015, + Edition::Edition2018 => 2018, + Edition::Edition2021 => 2021, + Edition::Edition2024 => 2024, + } + } + pub fn iter() -> impl Iterator { [Edition::Edition2015, Edition::Edition2018, Edition::Edition2021, Edition::Edition2024] .iter() diff --git a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml index a22961c26c84..f97597ffe5a6 100644 --- a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml @@ -14,8 +14,7 @@ rust-version.workspace = true [dependencies] arrayvec.workspace = true bitflags.workspace = true -cov-mark = "2.0.0-pre.1" -dashmap.workspace = true +cov-mark = "2.0.0" drop_bomb = "0.1.5" either.workspace = true fst = { version = "0.4.7", default-features = false } @@ -25,12 +24,12 @@ la-arena.workspace = true rustc-hash.workspace = true tracing.workspace = true smallvec.workspace = true -hashbrown.workspace = true triomphe.workspace = true -rustc_apfloat = "0.2.0" +rustc_apfloat = "0.2.2" text-size.workspace = true +salsa.workspace = true +query-group.workspace = true -ra-ap-rustc_hashes.workspace = true ra-ap-rustc_parse_format.workspace = true ra-ap-rustc_abi.workspace = true @@ -44,7 +43,7 @@ mbe.workspace = true cfg.workspace = true tt.workspace = true span.workspace = true - +thin-vec = "0.2.14" [dev-dependencies] expect-test.workspace = true @@ -53,6 +52,7 @@ expect-test.workspace = true test-utils.workspace = true test-fixture.workspace = true syntax-bridge.workspace = true + [features] in-rust-tree = ["hir-expand/in-rust-tree"] diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs index 710bffcefe90..a80313aba3e4 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs @@ -2,31 +2,32 @@ use std::{borrow::Cow, hash::Hash, ops}; -use base_db::CrateId; +use base_db::Crate; use cfg::{CfgExpr, CfgOptions}; use either::Either; use hir_expand::{ - attrs::{collect_attrs, Attr, AttrId, RawAttrs}, HirFileId, InFile, + attrs::{Attr, AttrId, RawAttrs, collect_attrs}, }; -use intern::{sym, Symbol}; +use intern::{Symbol, sym}; use la_arena::{ArenaMap, Idx, RawIdx}; use mbe::DelimiterKind; +use rustc_abi::ReprOptions; use syntax::{ - ast::{self, HasAttrs}, AstPtr, + ast::{self, HasAttrs}, }; use triomphe::Arc; use tt::iter::{TtElement, TtIter}; use crate::{ + AdtId, AttrDefId, GenericParamId, HasModule, ItemTreeLoc, LocalFieldId, Lookup, MacroId, + VariantId, db::DefDatabase, item_tree::{AttrOwner, FieldParent, ItemTreeNode}, lang_item::LangItem, nameres::{ModuleOrigin, ModuleSource}, src::{HasChildSource, HasSource}, - AdtId, AttrDefId, GenericParamId, HasModule, ItemTreeLoc, LocalFieldId, Lookup, MacroId, - VariantId, }; /// Desugared attributes of an item post `cfg_attr` expansion. @@ -44,8 +45,8 @@ impl Attrs { (**self).iter().find(|attr| attr.id == id) } - pub(crate) fn filter(db: &dyn DefDatabase, krate: CrateId, raw_attrs: RawAttrs) -> Attrs { - Attrs(raw_attrs.filter(db.upcast(), krate)) + pub(crate) fn filter(db: &dyn DefDatabase, krate: Crate, raw_attrs: RawAttrs) -> Attrs { + Attrs(raw_attrs.filter(db, krate)) } } @@ -75,8 +76,6 @@ impl Attrs { let _p = tracing::info_span!("fields_attrs_query").entered(); // FIXME: There should be some proper form of mapping between item tree field ids and hir field ids let mut res = ArenaMap::default(); - - let crate_graph = db.crate_graph(); let item_tree; let (parent, fields, krate) = match v { VariantId::EnumVariantId(it) => { @@ -84,7 +83,7 @@ impl Attrs { let krate = loc.parent.lookup(db).container.krate; item_tree = loc.id.item_tree(db); let variant = &item_tree[loc.id.value]; - (FieldParent::Variant(loc.id.value), &variant.fields, krate) + (FieldParent::EnumVariant(loc.id.value), &variant.fields, krate) } VariantId::StructId(it) => { let loc = it.lookup(db); @@ -102,7 +101,7 @@ impl Attrs { } }; - let cfg_options = &crate_graph[krate].cfg_options; + let cfg_options = krate.cfg_options(db); let mut idx = 0; for (id, _field) in fields.iter().enumerate() { @@ -118,17 +117,20 @@ impl Attrs { } impl Attrs { - pub fn by_key<'attrs>(&'attrs self, key: &'attrs Symbol) -> AttrQuery<'attrs> { + #[inline] + pub fn by_key(&self, key: Symbol) -> AttrQuery<'_> { AttrQuery { attrs: self, key } } + #[inline] pub fn rust_analyzer_tool(&self) -> impl Iterator { self.iter() .filter(|&attr| attr.path.segments().first().is_some_and(|s| *s == sym::rust_analyzer)) } + #[inline] pub fn cfg(&self) -> Option { - let mut cfgs = self.by_key(&sym::cfg).tt_values().map(CfgExpr::parse); + let mut cfgs = self.by_key(sym::cfg).tt_values().map(CfgExpr::parse); let first = cfgs.next()?; match cfgs.next() { Some(second) => { @@ -139,10 +141,12 @@ impl Attrs { } } + #[inline] pub fn cfgs(&self) -> impl Iterator + '_ { - self.by_key(&sym::cfg).tt_values().map(CfgExpr::parse) + self.by_key(sym::cfg).tt_values().map(CfgExpr::parse) } + #[inline] pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> bool { match self.cfg() { None => true, @@ -150,78 +154,225 @@ impl Attrs { } } + #[inline] pub fn lang(&self) -> Option<&Symbol> { - self.by_key(&sym::lang).string_value() + self.by_key(sym::lang).string_value() } + #[inline] pub fn lang_item(&self) -> Option { - self.by_key(&sym::lang).string_value().and_then(LangItem::from_symbol) + self.by_key(sym::lang).string_value().and_then(LangItem::from_symbol) } + #[inline] pub fn has_doc_hidden(&self) -> bool { - self.by_key(&sym::doc).tt_values().any(|tt| { + self.by_key(sym::doc).tt_values().any(|tt| { tt.top_subtree().delimiter.kind == DelimiterKind::Parenthesis && matches!(tt.token_trees().flat_tokens(), [tt::TokenTree::Leaf(tt::Leaf::Ident(ident))] if ident.sym == sym::hidden) }) } + #[inline] pub fn has_doc_notable_trait(&self) -> bool { - self.by_key(&sym::doc).tt_values().any(|tt| { + self.by_key(sym::doc).tt_values().any(|tt| { tt.top_subtree().delimiter.kind == DelimiterKind::Parenthesis && matches!(tt.token_trees().flat_tokens(), [tt::TokenTree::Leaf(tt::Leaf::Ident(ident))] if ident.sym == sym::notable_trait) }) } + #[inline] pub fn doc_exprs(&self) -> impl Iterator + '_ { - self.by_key(&sym::doc).tt_values().map(DocExpr::parse) + self.by_key(sym::doc).tt_values().map(DocExpr::parse) } + #[inline] pub fn doc_aliases(&self) -> impl Iterator + '_ { self.doc_exprs().flat_map(|doc_expr| doc_expr.aliases().to_vec()) } + #[inline] pub fn export_name(&self) -> Option<&Symbol> { - self.by_key(&sym::export_name).string_value() + self.by_key(sym::export_name).string_value() } + #[inline] pub fn is_proc_macro(&self) -> bool { - self.by_key(&sym::proc_macro).exists() + self.by_key(sym::proc_macro).exists() } + #[inline] pub fn is_proc_macro_attribute(&self) -> bool { - self.by_key(&sym::proc_macro_attribute).exists() + self.by_key(sym::proc_macro_attribute).exists() } + #[inline] pub fn is_proc_macro_derive(&self) -> bool { - self.by_key(&sym::proc_macro_derive).exists() + self.by_key(sym::proc_macro_derive).exists() } + #[inline] pub fn is_test(&self) -> bool { self.iter().any(|it| { it.path() .segments() .iter() .rev() - .zip( - [sym::core.clone(), sym::prelude.clone(), sym::v1.clone(), sym::test.clone()] - .iter() - .rev(), - ) + .zip([sym::core, sym::prelude, sym::v1, sym::test].iter().rev()) .all(|it| it.0 == it.1) }) } + #[inline] pub fn is_ignore(&self) -> bool { - self.by_key(&sym::ignore).exists() + self.by_key(sym::ignore).exists() } + #[inline] pub fn is_bench(&self) -> bool { - self.by_key(&sym::bench).exists() + self.by_key(sym::bench).exists() } + #[inline] pub fn is_unstable(&self) -> bool { - self.by_key(&sym::unstable).exists() + self.by_key(sym::unstable).exists() } + + #[inline] + pub fn rustc_legacy_const_generics(&self) -> Option>> { + self.by_key(sym::rustc_legacy_const_generics) + .tt_values() + .next() + .map(parse_rustc_legacy_const_generics) + .filter(|it| !it.is_empty()) + .map(Box::new) + } + + #[inline] + pub fn repr(&self) -> Option { + self.by_key(sym::repr).tt_values().filter_map(parse_repr_tt).fold(None, |acc, repr| { + acc.map_or(Some(repr), |mut acc| { + merge_repr(&mut acc, repr); + Some(acc) + }) + }) + } +} + +fn parse_rustc_legacy_const_generics(tt: &crate::tt::TopSubtree) -> Box<[u32]> { + let mut indices = Vec::new(); + let mut iter = tt.iter(); + while let (Some(first), second) = (iter.next(), iter.next()) { + match first { + TtElement::Leaf(tt::Leaf::Literal(lit)) => match lit.symbol.as_str().parse() { + Ok(index) => indices.push(index), + Err(_) => break, + }, + _ => break, + } + + if let Some(comma) = second { + match comma { + TtElement::Leaf(tt::Leaf::Punct(punct)) if punct.char == ',' => {} + _ => break, + } + } + } + + indices.into_boxed_slice() +} + +fn merge_repr(this: &mut ReprOptions, other: ReprOptions) { + let ReprOptions { int, align, pack, flags, field_shuffle_seed: _ } = this; + flags.insert(other.flags); + *align = (*align).max(other.align); + *pack = match (*pack, other.pack) { + (Some(pack), None) | (None, Some(pack)) => Some(pack), + _ => (*pack).min(other.pack), + }; + if other.int.is_some() { + *int = other.int; + } +} + +fn parse_repr_tt(tt: &crate::tt::TopSubtree) -> Option { + use crate::builtin_type::{BuiltinInt, BuiltinUint}; + use rustc_abi::{Align, Integer, IntegerType, ReprFlags, ReprOptions}; + + match tt.top_subtree().delimiter { + tt::Delimiter { kind: DelimiterKind::Parenthesis, .. } => {} + _ => return None, + } + + let mut acc = ReprOptions::default(); + let mut tts = tt.iter(); + while let Some(tt) = tts.next() { + let TtElement::Leaf(tt::Leaf::Ident(ident)) = tt else { + continue; + }; + let repr = match &ident.sym { + s if *s == sym::packed => { + let pack = if let Some(TtElement::Subtree(_, mut tt_iter)) = tts.peek() { + tts.next(); + if let Some(TtElement::Leaf(tt::Leaf::Literal(lit))) = tt_iter.next() { + lit.symbol.as_str().parse().unwrap_or_default() + } else { + 0 + } + } else { + 0 + }; + let pack = Some(Align::from_bytes(pack).unwrap_or(Align::ONE)); + ReprOptions { pack, ..Default::default() } + } + s if *s == sym::align => { + let mut align = None; + if let Some(TtElement::Subtree(_, mut tt_iter)) = tts.peek() { + tts.next(); + if let Some(TtElement::Leaf(tt::Leaf::Literal(lit))) = tt_iter.next() { + if let Ok(a) = lit.symbol.as_str().parse() { + align = Align::from_bytes(a).ok(); + } + } + } + ReprOptions { align, ..Default::default() } + } + s if *s == sym::C => ReprOptions { flags: ReprFlags::IS_C, ..Default::default() }, + s if *s == sym::transparent => { + ReprOptions { flags: ReprFlags::IS_TRANSPARENT, ..Default::default() } + } + s if *s == sym::simd => ReprOptions { flags: ReprFlags::IS_SIMD, ..Default::default() }, + repr => { + let mut int = None; + if let Some(builtin) = BuiltinInt::from_suffix_sym(repr) + .map(Either::Left) + .or_else(|| BuiltinUint::from_suffix_sym(repr).map(Either::Right)) + { + int = Some(match builtin { + Either::Left(bi) => match bi { + BuiltinInt::Isize => IntegerType::Pointer(true), + BuiltinInt::I8 => IntegerType::Fixed(Integer::I8, true), + BuiltinInt::I16 => IntegerType::Fixed(Integer::I16, true), + BuiltinInt::I32 => IntegerType::Fixed(Integer::I32, true), + BuiltinInt::I64 => IntegerType::Fixed(Integer::I64, true), + BuiltinInt::I128 => IntegerType::Fixed(Integer::I128, true), + }, + Either::Right(bu) => match bu { + BuiltinUint::Usize => IntegerType::Pointer(false), + BuiltinUint::U8 => IntegerType::Fixed(Integer::I8, false), + BuiltinUint::U16 => IntegerType::Fixed(Integer::I16, false), + BuiltinUint::U32 => IntegerType::Fixed(Integer::I32, false), + BuiltinUint::U64 => IntegerType::Fixed(Integer::I64, false), + BuiltinUint::U128 => IntegerType::Fixed(Integer::I128, false), + }, + }); + } + ReprOptions { int, ..Default::default() } + } + }; + merge_repr(&mut acc, repr); + } + + Some(acc) } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -373,7 +524,7 @@ impl AttrsWithOwner { // FIXME: We should be never getting `None` here. match src.value.get(it.local_id()) { Some(val) => RawAttrs::from_attrs_owner( - db.upcast(), + db, src.with_value(val), db.span_map(src.file_id).as_ref(), ), @@ -385,7 +536,7 @@ impl AttrsWithOwner { // FIXME: We should be never getting `None` here. match src.value.get(it.local_id()) { Some(val) => RawAttrs::from_attrs_owner( - db.upcast(), + db, src.with_value(val), db.span_map(src.file_id).as_ref(), ), @@ -397,7 +548,7 @@ impl AttrsWithOwner { // FIXME: We should be never getting `None` here. match src.value.get(it.local_id) { Some(val) => RawAttrs::from_attrs_owner( - db.upcast(), + db, src.with_value(val), db.span_map(src.file_id).as_ref(), ), @@ -410,7 +561,7 @@ impl AttrsWithOwner { AttrDefId::UseId(it) => attrs_from_item_tree_loc(db, it), }; - let attrs = raw_attrs.filter(db.upcast(), def.krate(db)); + let attrs = raw_attrs.filter(db, def.krate(db)); Attrs(attrs) } @@ -547,36 +698,42 @@ impl AttrSourceMap { } } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone)] pub struct AttrQuery<'attr> { attrs: &'attr Attrs, - key: &'attr Symbol, + key: Symbol, } impl<'attr> AttrQuery<'attr> { + #[inline] pub fn tt_values(self) -> impl Iterator { self.attrs().filter_map(|attr| attr.token_tree_value()) } + #[inline] pub fn string_value(self) -> Option<&'attr Symbol> { self.attrs().find_map(|attr| attr.string_value()) } + #[inline] pub fn string_value_with_span(self) -> Option<(&'attr Symbol, span::Span)> { self.attrs().find_map(|attr| attr.string_value_with_span()) } + #[inline] pub fn string_value_unescape(self) -> Option> { self.attrs().find_map(|attr| attr.string_value_unescape()) } + #[inline] pub fn exists(self) -> bool { self.attrs().next().is_some() } + #[inline] pub fn attrs(self) -> impl Iterator + Clone { let key = self.key; - self.attrs.iter().filter(move |attr| attr.path.as_ident().is_some_and(|s| *s == *key)) + self.attrs.iter().filter(move |attr| attr.path.as_ident().is_some_and(|s| *s == key)) } /// Find string value for a specific key inside token tree @@ -585,10 +742,11 @@ impl<'attr> AttrQuery<'attr> { /// #[doc(html_root_url = "url")] /// ^^^^^^^^^^^^^ key /// ``` - pub fn find_string_value_in_tt(self, key: &'attr Symbol) -> Option<&'attr str> { + #[inline] + pub fn find_string_value_in_tt(self, key: Symbol) -> Option<&'attr str> { self.tt_values().find_map(|tt| { let name = tt.iter() - .skip_while(|tt| !matches!(tt, TtElement::Leaf(tt::Leaf::Ident(tt::Ident { sym, ..} )) if *sym == *key)) + .skip_while(|tt| !matches!(tt, TtElement::Leaf(tt::Leaf::Ident(tt::Ident { sym, ..} )) if *sym == key)) .nth(2); match name { @@ -601,17 +759,14 @@ impl<'attr> AttrQuery<'attr> { fn any_has_attrs<'db>( db: &(dyn DefDatabase + 'db), - id: impl Lookup< - Database<'db> = dyn DefDatabase + 'db, - Data = impl HasSource, - >, + id: impl Lookup>, ) -> InFile { id.lookup(db).source(db).map(ast::AnyHasAttrs::new) } fn attrs_from_item_tree_loc<'db, N: ItemTreeNode>( db: &(dyn DefDatabase + 'db), - lookup: impl Lookup = dyn DefDatabase + 'db, Data = impl ItemTreeLoc>, + lookup: impl Lookup>, ) -> RawAttrs { let id = lookup.lookup(db).item_tree_id(); let tree = id.item_tree(db); @@ -649,8 +804,8 @@ mod tests { use hir_expand::span_map::{RealSpanMap, SpanMap}; use span::FileId; - use syntax::{ast, AstNode, TextRange}; - use syntax_bridge::{syntax_node_to_token_tree, DocCommentDesugarMode}; + use syntax::{AstNode, TextRange, ast}; + use syntax_bridge::{DocCommentDesugarMode, syntax_node_to_token_tree}; use crate::attr::{DocAtom, DocExpr}; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/builtin_type.rs b/src/tools/rust-analyzer/crates/hir-def/src/builtin_type.rs index 14b9af84e6ff..8b61c6a9f034 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/builtin_type.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/builtin_type.rs @@ -6,7 +6,7 @@ use std::fmt; use hir_expand::name::{AsName, Name}; -use intern::{sym, Symbol}; +use intern::{Symbol, sym}; /// Different signed int types. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum BuiltinInt { @@ -51,28 +51,28 @@ impl BuiltinType { #[rustfmt::skip] pub fn all_builtin_types() -> [(Name, BuiltinType); 19] { [ - (Name::new_symbol_root(sym::char.clone()), BuiltinType::Char), - (Name::new_symbol_root(sym::bool.clone()), BuiltinType::Bool), - (Name::new_symbol_root(sym::str.clone()), BuiltinType::Str), + (Name::new_symbol_root(sym::char), BuiltinType::Char), + (Name::new_symbol_root(sym::bool), BuiltinType::Bool), + (Name::new_symbol_root(sym::str), BuiltinType::Str), - (Name::new_symbol_root(sym::isize.clone()), BuiltinType::Int(BuiltinInt::Isize)), - (Name::new_symbol_root(sym::i8.clone()), BuiltinType::Int(BuiltinInt::I8)), - (Name::new_symbol_root(sym::i16.clone()), BuiltinType::Int(BuiltinInt::I16)), - (Name::new_symbol_root(sym::i32.clone()), BuiltinType::Int(BuiltinInt::I32)), - (Name::new_symbol_root(sym::i64.clone()), BuiltinType::Int(BuiltinInt::I64)), - (Name::new_symbol_root(sym::i128.clone()), BuiltinType::Int(BuiltinInt::I128)), + (Name::new_symbol_root(sym::isize), BuiltinType::Int(BuiltinInt::Isize)), + (Name::new_symbol_root(sym::i8), BuiltinType::Int(BuiltinInt::I8)), + (Name::new_symbol_root(sym::i16), BuiltinType::Int(BuiltinInt::I16)), + (Name::new_symbol_root(sym::i32), BuiltinType::Int(BuiltinInt::I32)), + (Name::new_symbol_root(sym::i64), BuiltinType::Int(BuiltinInt::I64)), + (Name::new_symbol_root(sym::i128), BuiltinType::Int(BuiltinInt::I128)), - (Name::new_symbol_root(sym::usize.clone()), BuiltinType::Uint(BuiltinUint::Usize)), - (Name::new_symbol_root(sym::u8.clone()), BuiltinType::Uint(BuiltinUint::U8)), - (Name::new_symbol_root(sym::u16.clone()), BuiltinType::Uint(BuiltinUint::U16)), - (Name::new_symbol_root(sym::u32.clone()), BuiltinType::Uint(BuiltinUint::U32)), - (Name::new_symbol_root(sym::u64.clone()), BuiltinType::Uint(BuiltinUint::U64)), - (Name::new_symbol_root(sym::u128.clone()), BuiltinType::Uint(BuiltinUint::U128)), + (Name::new_symbol_root(sym::usize), BuiltinType::Uint(BuiltinUint::Usize)), + (Name::new_symbol_root(sym::u8), BuiltinType::Uint(BuiltinUint::U8)), + (Name::new_symbol_root(sym::u16), BuiltinType::Uint(BuiltinUint::U16)), + (Name::new_symbol_root(sym::u32), BuiltinType::Uint(BuiltinUint::U32)), + (Name::new_symbol_root(sym::u64), BuiltinType::Uint(BuiltinUint::U64)), + (Name::new_symbol_root(sym::u128), BuiltinType::Uint(BuiltinUint::U128)), - (Name::new_symbol_root(sym::f16.clone()), BuiltinType::Float(BuiltinFloat::F16)), - (Name::new_symbol_root(sym::f32.clone()), BuiltinType::Float(BuiltinFloat::F32)), - (Name::new_symbol_root(sym::f64.clone()), BuiltinType::Float(BuiltinFloat::F64)), - (Name::new_symbol_root(sym::f128.clone()), BuiltinType::Float(BuiltinFloat::F128)), + (Name::new_symbol_root(sym::f16), BuiltinType::Float(BuiltinFloat::F16)), + (Name::new_symbol_root(sym::f32), BuiltinType::Float(BuiltinFloat::F32)), + (Name::new_symbol_root(sym::f64), BuiltinType::Float(BuiltinFloat::F64)), + (Name::new_symbol_root(sym::f128), BuiltinType::Float(BuiltinFloat::F128)), ] } @@ -86,30 +86,30 @@ impl BuiltinType { impl AsName for BuiltinType { fn as_name(&self) -> Name { match self { - BuiltinType::Char => Name::new_symbol_root(sym::char.clone()), - BuiltinType::Bool => Name::new_symbol_root(sym::bool.clone()), - BuiltinType::Str => Name::new_symbol_root(sym::str.clone()), + BuiltinType::Char => Name::new_symbol_root(sym::char), + BuiltinType::Bool => Name::new_symbol_root(sym::bool), + BuiltinType::Str => Name::new_symbol_root(sym::str), BuiltinType::Int(it) => match it { - BuiltinInt::Isize => Name::new_symbol_root(sym::isize.clone()), - BuiltinInt::I8 => Name::new_symbol_root(sym::i8.clone()), - BuiltinInt::I16 => Name::new_symbol_root(sym::i16.clone()), - BuiltinInt::I32 => Name::new_symbol_root(sym::i32.clone()), - BuiltinInt::I64 => Name::new_symbol_root(sym::i64.clone()), - BuiltinInt::I128 => Name::new_symbol_root(sym::i128.clone()), + BuiltinInt::Isize => Name::new_symbol_root(sym::isize), + BuiltinInt::I8 => Name::new_symbol_root(sym::i8), + BuiltinInt::I16 => Name::new_symbol_root(sym::i16), + BuiltinInt::I32 => Name::new_symbol_root(sym::i32), + BuiltinInt::I64 => Name::new_symbol_root(sym::i64), + BuiltinInt::I128 => Name::new_symbol_root(sym::i128), }, BuiltinType::Uint(it) => match it { - BuiltinUint::Usize => Name::new_symbol_root(sym::usize.clone()), - BuiltinUint::U8 => Name::new_symbol_root(sym::u8.clone()), - BuiltinUint::U16 => Name::new_symbol_root(sym::u16.clone()), - BuiltinUint::U32 => Name::new_symbol_root(sym::u32.clone()), - BuiltinUint::U64 => Name::new_symbol_root(sym::u64.clone()), - BuiltinUint::U128 => Name::new_symbol_root(sym::u128.clone()), + BuiltinUint::Usize => Name::new_symbol_root(sym::usize), + BuiltinUint::U8 => Name::new_symbol_root(sym::u8), + BuiltinUint::U16 => Name::new_symbol_root(sym::u16), + BuiltinUint::U32 => Name::new_symbol_root(sym::u32), + BuiltinUint::U64 => Name::new_symbol_root(sym::u64), + BuiltinUint::U128 => Name::new_symbol_root(sym::u128), }, BuiltinType::Float(it) => match it { - BuiltinFloat::F16 => Name::new_symbol_root(sym::f16.clone()), - BuiltinFloat::F32 => Name::new_symbol_root(sym::f32.clone()), - BuiltinFloat::F64 => Name::new_symbol_root(sym::f64.clone()), - BuiltinFloat::F128 => Name::new_symbol_root(sym::f128.clone()), + BuiltinFloat::F16 => Name::new_symbol_root(sym::f16), + BuiltinFloat::F32 => Name::new_symbol_root(sym::f32), + BuiltinFloat::F64 => Name::new_symbol_root(sym::f64), + BuiltinFloat::F128 => Name::new_symbol_root(sym::f128), }, } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs deleted file mode 100644 index bec662787728..000000000000 --- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs +++ /dev/null @@ -1,843 +0,0 @@ -//! Contains basic data about various HIR declarations. - -pub mod adt; - -use base_db::CrateId; -use hir_expand::{ - name::Name, AstId, ExpandResult, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefKind, -}; -use intern::{sym, Symbol}; -use la_arena::{Idx, RawIdx}; -use smallvec::SmallVec; -use syntax::{ast, Parse}; -use triomphe::Arc; -use tt::iter::TtElement; - -use crate::{ - db::DefDatabase, - expander::{Expander, Mark}, - item_tree::{self, AssocItem, FnFlags, ItemTree, ItemTreeId, MacroCall, ModItem, TreeId}, - macro_call_as_call_id, - nameres::{ - attr_resolution::ResolvedAttr, - diagnostics::{DefDiagnostic, DefDiagnostics}, - proc_macro::{parse_macro_name_and_helper_attrs, ProcMacroKind}, - DefMap, MacroSubNs, - }, - path::ImportAlias, - type_ref::{TraitRef, TypeBound, TypeRefId, TypesMap}, - visibility::RawVisibility, - AssocItemId, AstIdWithPath, ConstId, ConstLoc, ExternCrateId, FunctionId, FunctionLoc, - HasModule, ImplId, Intern, ItemContainerId, ItemLoc, Lookup, Macro2Id, MacroRulesId, ModuleId, - ProcMacroId, StaticId, TraitAliasId, TraitId, TypeAliasId, TypeAliasLoc, -}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct FunctionData { - pub name: Name, - pub params: Box<[TypeRefId]>, - pub ret_type: TypeRefId, - pub visibility: RawVisibility, - pub abi: Option, - pub legacy_const_generics_indices: Option>>, - pub rustc_allow_incoherent_impl: bool, - pub types_map: Arc, - flags: FnFlags, -} - -impl FunctionData { - pub(crate) fn fn_data_query(db: &dyn DefDatabase, func: FunctionId) -> Arc { - let loc = func.lookup(db); - let krate = loc.container.module(db).krate; - let item_tree = loc.id.item_tree(db); - let func = &item_tree[loc.id.value]; - let visibility = if let ItemContainerId::TraitId(trait_id) = loc.container { - trait_vis(db, trait_id) - } else { - item_tree[func.visibility].clone() - }; - - let crate_graph = db.crate_graph(); - let cfg_options = &crate_graph[krate].cfg_options; - let attr_owner = |idx| { - item_tree::AttrOwner::Param(loc.id.value, Idx::from_raw(RawIdx::from(idx as u32))) - }; - - let mut flags = func.flags; - if flags.contains(FnFlags::HAS_SELF_PARAM) { - // If there's a self param in the syntax, but it is cfg'd out, remove the flag. - let is_cfgd_out = - !item_tree.attrs(db, krate, attr_owner(0usize)).is_cfg_enabled(cfg_options); - if is_cfgd_out { - cov_mark::hit!(cfgd_out_self_param); - flags.remove(FnFlags::HAS_SELF_PARAM); - } - } - if flags.contains(FnFlags::IS_VARARGS) { - if let Some((_, param)) = func.params.iter().enumerate().rev().find(|&(idx, _)| { - item_tree.attrs(db, krate, attr_owner(idx)).is_cfg_enabled(cfg_options) - }) { - if param.type_ref.is_some() { - flags.remove(FnFlags::IS_VARARGS); - } - } else { - flags.remove(FnFlags::IS_VARARGS); - } - } - - let attrs = item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()); - let legacy_const_generics_indices = attrs - .by_key(&sym::rustc_legacy_const_generics) - .tt_values() - .next() - .map(parse_rustc_legacy_const_generics) - .filter(|it| !it.is_empty()) - .map(Box::new); - let rustc_allow_incoherent_impl = attrs.by_key(&sym::rustc_allow_incoherent_impl).exists(); - if flags.contains(FnFlags::HAS_UNSAFE_KW) - && attrs.by_key(&sym::rustc_deprecated_safe_2024).exists() - { - flags.remove(FnFlags::HAS_UNSAFE_KW); - flags.insert(FnFlags::DEPRECATED_SAFE_2024); - } - - if attrs.by_key(&sym::target_feature).exists() { - flags.insert(FnFlags::HAS_TARGET_FEATURE); - } - - Arc::new(FunctionData { - name: func.name.clone(), - params: func - .params - .iter() - .enumerate() - .filter(|&(idx, _)| { - item_tree.attrs(db, krate, attr_owner(idx)).is_cfg_enabled(cfg_options) - }) - .filter_map(|(_, param)| param.type_ref) - .collect(), - ret_type: func.ret_type, - visibility, - abi: func.abi.clone(), - legacy_const_generics_indices, - types_map: func.types_map.clone(), - flags, - rustc_allow_incoherent_impl, - }) - } - - pub fn has_body(&self) -> bool { - self.flags.contains(FnFlags::HAS_BODY) - } - - /// True if the first param is `self`. This is relevant to decide whether this - /// can be called as a method. - pub fn has_self_param(&self) -> bool { - self.flags.contains(FnFlags::HAS_SELF_PARAM) - } - - pub fn is_default(&self) -> bool { - self.flags.contains(FnFlags::HAS_DEFAULT_KW) - } - - pub fn is_const(&self) -> bool { - self.flags.contains(FnFlags::HAS_CONST_KW) - } - - pub fn is_async(&self) -> bool { - self.flags.contains(FnFlags::HAS_ASYNC_KW) - } - - pub fn is_unsafe(&self) -> bool { - self.flags.contains(FnFlags::HAS_UNSAFE_KW) - } - - pub fn is_deprecated_safe_2024(&self) -> bool { - self.flags.contains(FnFlags::DEPRECATED_SAFE_2024) - } - - pub fn is_safe(&self) -> bool { - self.flags.contains(FnFlags::HAS_SAFE_KW) - } - - pub fn is_varargs(&self) -> bool { - self.flags.contains(FnFlags::IS_VARARGS) - } - - pub fn has_target_feature(&self) -> bool { - self.flags.contains(FnFlags::HAS_TARGET_FEATURE) - } -} - -fn parse_rustc_legacy_const_generics(tt: &crate::tt::TopSubtree) -> Box<[u32]> { - let mut indices = Vec::new(); - let mut iter = tt.iter(); - while let (Some(first), second) = (iter.next(), iter.next()) { - match first { - TtElement::Leaf(tt::Leaf::Literal(lit)) => match lit.symbol.as_str().parse() { - Ok(index) => indices.push(index), - Err(_) => break, - }, - _ => break, - } - - if let Some(comma) = second { - match comma { - TtElement::Leaf(tt::Leaf::Punct(punct)) if punct.char == ',' => {} - _ => break, - } - } - } - - indices.into_boxed_slice() -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct TypeAliasData { - pub name: Name, - pub type_ref: Option, - pub visibility: RawVisibility, - pub is_extern: bool, - pub rustc_has_incoherent_inherent_impls: bool, - pub rustc_allow_incoherent_impl: bool, - /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl). - pub bounds: Box<[TypeBound]>, - pub types_map: Arc, -} - -impl TypeAliasData { - pub(crate) fn type_alias_data_query( - db: &dyn DefDatabase, - typ: TypeAliasId, - ) -> Arc { - let loc = typ.lookup(db); - let item_tree = loc.id.item_tree(db); - let typ = &item_tree[loc.id.value]; - let visibility = if let ItemContainerId::TraitId(trait_id) = loc.container { - trait_vis(db, trait_id) - } else { - item_tree[typ.visibility].clone() - }; - - let attrs = item_tree.attrs( - db, - loc.container.module(db).krate(), - ModItem::from(loc.id.value).into(), - ); - let rustc_has_incoherent_inherent_impls = - attrs.by_key(&sym::rustc_has_incoherent_inherent_impls).exists(); - let rustc_allow_incoherent_impl = attrs.by_key(&sym::rustc_allow_incoherent_impl).exists(); - - Arc::new(TypeAliasData { - name: typ.name.clone(), - type_ref: typ.type_ref, - visibility, - is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)), - rustc_has_incoherent_inherent_impls, - rustc_allow_incoherent_impl, - bounds: typ.bounds.clone(), - types_map: typ.types_map.clone(), - }) - } -} - -bitflags::bitflags! { - #[derive(Debug, Clone, Copy, Eq, PartialEq, Default)] - pub struct TraitFlags: u8 { - const IS_AUTO = 1 << 0; - const IS_UNSAFE = 1 << 1; - const IS_FUNDAMENTAL = 1 << 2; - const RUSTC_HAS_INCOHERENT_INHERENT_IMPLS = 1 << 3; - const SKIP_ARRAY_DURING_METHOD_DISPATCH = 1 << 4; - const SKIP_BOXED_SLICE_DURING_METHOD_DISPATCH = 1 << 5; - const RUSTC_PAREN_SUGAR = 1 << 6; - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct TraitData { - pub name: Name, - pub items: Box<[(Name, AssocItemId)]>, - pub flags: TraitFlags, - pub visibility: RawVisibility, - // box it as the vec is usually empty anyways - pub macro_calls: Option, MacroCallId)>>>, -} - -impl TraitData { - #[inline] - pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc { - db.trait_data_with_diagnostics(tr).0 - } - - pub(crate) fn trait_data_with_diagnostics_query( - db: &dyn DefDatabase, - tr: TraitId, - ) -> (Arc, DefDiagnostics) { - let ItemLoc { container: module_id, id: tree_id } = tr.lookup(db); - let item_tree = tree_id.item_tree(db); - let tr_def = &item_tree[tree_id.value]; - let name = tr_def.name.clone(); - let visibility = item_tree[tr_def.visibility].clone(); - let attrs = item_tree.attrs(db, module_id.krate(), ModItem::from(tree_id.value).into()); - - let mut flags = TraitFlags::empty(); - - if tr_def.is_auto { - flags |= TraitFlags::IS_AUTO; - } - if tr_def.is_unsafe { - flags |= TraitFlags::IS_UNSAFE; - } - if attrs.by_key(&sym::fundamental).exists() { - flags |= TraitFlags::IS_FUNDAMENTAL; - } - if attrs.by_key(&sym::rustc_has_incoherent_inherent_impls).exists() { - flags |= TraitFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS; - } - if attrs.by_key(&sym::rustc_paren_sugar).exists() { - flags |= TraitFlags::RUSTC_PAREN_SUGAR; - } - - let mut skip_array_during_method_dispatch = - attrs.by_key(&sym::rustc_skip_array_during_method_dispatch).exists(); - let mut skip_boxed_slice_during_method_dispatch = false; - for tt in attrs.by_key(&sym::rustc_skip_during_method_dispatch).tt_values() { - for tt in tt.iter() { - if let tt::iter::TtElement::Leaf(tt::Leaf::Ident(ident)) = tt { - skip_array_during_method_dispatch |= ident.sym == sym::array; - skip_boxed_slice_during_method_dispatch |= ident.sym == sym::boxed_slice; - } - } - } - - if skip_array_during_method_dispatch { - flags |= TraitFlags::SKIP_ARRAY_DURING_METHOD_DISPATCH; - } - if skip_boxed_slice_during_method_dispatch { - flags |= TraitFlags::SKIP_BOXED_SLICE_DURING_METHOD_DISPATCH; - } - - let mut collector = - AssocItemCollector::new(db, module_id, tree_id.file_id(), ItemContainerId::TraitId(tr)); - collector.collect(&item_tree, tree_id.tree_id(), &tr_def.items); - let (items, macro_calls, diagnostics) = collector.finish(); - - ( - Arc::new(TraitData { name, macro_calls, items, visibility, flags }), - DefDiagnostics::new(diagnostics), - ) - } - - pub fn associated_types(&self) -> impl Iterator + '_ { - self.items.iter().filter_map(|(_name, item)| match item { - AssocItemId::TypeAliasId(t) => Some(*t), - _ => None, - }) - } - - pub fn associated_type_by_name(&self, name: &Name) -> Option { - self.items.iter().find_map(|(item_name, item)| match item { - AssocItemId::TypeAliasId(t) if item_name == name => Some(*t), - _ => None, - }) - } - - pub fn method_by_name(&self, name: &Name) -> Option { - self.items.iter().find_map(|(item_name, item)| match item { - AssocItemId::FunctionId(t) if item_name == name => Some(*t), - _ => None, - }) - } - - pub fn attribute_calls(&self) -> impl Iterator, MacroCallId)> + '_ { - self.macro_calls.iter().flat_map(|it| it.iter()).copied() - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct TraitAliasData { - pub name: Name, - pub visibility: RawVisibility, -} - -impl TraitAliasData { - pub(crate) fn trait_alias_query(db: &dyn DefDatabase, id: TraitAliasId) -> Arc { - let loc = id.lookup(db); - let item_tree = loc.id.item_tree(db); - let alias = &item_tree[loc.id.value]; - let visibility = item_tree[alias.visibility].clone(); - - Arc::new(TraitAliasData { name: alias.name.clone(), visibility }) - } -} - -#[derive(Debug, PartialEq, Eq)] -pub struct ImplData { - pub target_trait: Option, - pub self_ty: TypeRefId, - pub items: Box<[(Name, AssocItemId)]>, - pub is_negative: bool, - pub is_unsafe: bool, - // box it as the vec is usually empty anyways - pub macro_calls: Option, MacroCallId)>>>, - pub types_map: Arc, -} - -impl ImplData { - #[inline] - pub(crate) fn impl_data_query(db: &dyn DefDatabase, id: ImplId) -> Arc { - db.impl_data_with_diagnostics(id).0 - } - - pub(crate) fn impl_data_with_diagnostics_query( - db: &dyn DefDatabase, - id: ImplId, - ) -> (Arc, DefDiagnostics) { - let _p = tracing::info_span!("impl_data_with_diagnostics_query").entered(); - let ItemLoc { container: module_id, id: tree_id } = id.lookup(db); - - let item_tree = tree_id.item_tree(db); - let impl_def = &item_tree[tree_id.value]; - let target_trait = impl_def.target_trait; - let self_ty = impl_def.self_ty; - let is_negative = impl_def.is_negative; - let is_unsafe = impl_def.is_unsafe; - - let mut collector = - AssocItemCollector::new(db, module_id, tree_id.file_id(), ItemContainerId::ImplId(id)); - collector.collect(&item_tree, tree_id.tree_id(), &impl_def.items); - - let (items, macro_calls, diagnostics) = collector.finish(); - - ( - Arc::new(ImplData { - target_trait, - self_ty, - items, - is_negative, - is_unsafe, - macro_calls, - types_map: impl_def.types_map.clone(), - }), - DefDiagnostics::new(diagnostics), - ) - } - - pub fn attribute_calls(&self) -> impl Iterator, MacroCallId)> + '_ { - self.macro_calls.iter().flat_map(|it| it.iter()).copied() - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Macro2Data { - pub name: Name, - pub visibility: RawVisibility, - // It's a bit wasteful as currently this is only for builtin `Default` derive macro, but macro2 - // are rarely used in practice so I think it's okay for now. - /// Derive helpers, if this is a derive rustc_builtin_macro - pub helpers: Option>, -} - -impl Macro2Data { - pub(crate) fn macro2_data_query(db: &dyn DefDatabase, makro: Macro2Id) -> Arc { - let loc = makro.lookup(db); - let item_tree = loc.id.item_tree(db); - let makro = &item_tree[loc.id.value]; - - let helpers = item_tree - .attrs(db, loc.container.krate(), ModItem::from(loc.id.value).into()) - .by_key(&sym::rustc_builtin_macro) - .tt_values() - .next() - .and_then(parse_macro_name_and_helper_attrs) - .map(|(_, helpers)| helpers); - - Arc::new(Macro2Data { - name: makro.name.clone(), - visibility: item_tree[makro.visibility].clone(), - helpers, - }) - } -} -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct MacroRulesData { - pub name: Name, - pub macro_export: bool, -} - -impl MacroRulesData { - pub(crate) fn macro_rules_data_query( - db: &dyn DefDatabase, - makro: MacroRulesId, - ) -> Arc { - let loc = makro.lookup(db); - let item_tree = loc.id.item_tree(db); - let makro = &item_tree[loc.id.value]; - - let macro_export = item_tree - .attrs(db, loc.container.krate(), ModItem::from(loc.id.value).into()) - .by_key(&sym::macro_export) - .exists(); - - Arc::new(MacroRulesData { name: makro.name.clone(), macro_export }) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ProcMacroData { - pub name: Name, - /// Derive helpers, if this is a derive - pub helpers: Option>, -} - -impl ProcMacroData { - pub(crate) fn proc_macro_data_query( - db: &dyn DefDatabase, - makro: ProcMacroId, - ) -> Arc { - let loc = makro.lookup(db); - let item_tree = loc.id.item_tree(db); - let makro = &item_tree[loc.id.value]; - - let (name, helpers) = if let Some(def) = item_tree - .attrs(db, loc.container.krate(), ModItem::from(loc.id.value).into()) - .parse_proc_macro_decl(&makro.name) - { - ( - def.name, - match def.kind { - ProcMacroKind::Derive { helpers } => Some(helpers), - ProcMacroKind::Bang | ProcMacroKind::Attr => None, - }, - ) - } else { - // eeeh... - stdx::never!("proc macro declaration is not a proc macro"); - (makro.name.clone(), None) - }; - Arc::new(ProcMacroData { name, helpers }) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ExternCrateDeclData { - pub name: Name, - pub alias: Option, - pub visibility: RawVisibility, - pub crate_id: Option, -} - -impl ExternCrateDeclData { - pub(crate) fn extern_crate_decl_data_query( - db: &dyn DefDatabase, - extern_crate: ExternCrateId, - ) -> Arc { - let loc = extern_crate.lookup(db); - let item_tree = loc.id.item_tree(db); - let extern_crate = &item_tree[loc.id.value]; - - let name = extern_crate.name.clone(); - let krate = loc.container.krate(); - let crate_id = if name == sym::self_.clone() { - Some(krate) - } else { - db.crate_graph()[krate].dependencies.iter().find_map(|dep| { - if dep.name.symbol() == name.symbol() { - Some(dep.crate_id) - } else { - None - } - }) - }; - - Arc::new(Self { - name, - visibility: item_tree[extern_crate.visibility].clone(), - alias: extern_crate.alias.clone(), - crate_id, - }) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ConstData { - /// `None` for `const _: () = ();` - pub name: Option, - pub type_ref: TypeRefId, - pub visibility: RawVisibility, - pub rustc_allow_incoherent_impl: bool, - pub has_body: bool, - pub types_map: Arc, -} - -impl ConstData { - pub(crate) fn const_data_query(db: &dyn DefDatabase, konst: ConstId) -> Arc { - let loc = konst.lookup(db); - let item_tree = loc.id.item_tree(db); - let konst = &item_tree[loc.id.value]; - let visibility = if let ItemContainerId::TraitId(trait_id) = loc.container { - trait_vis(db, trait_id) - } else { - item_tree[konst.visibility].clone() - }; - - let rustc_allow_incoherent_impl = item_tree - .attrs(db, loc.container.module(db).krate(), ModItem::from(loc.id.value).into()) - .by_key(&sym::rustc_allow_incoherent_impl) - .exists(); - - Arc::new(ConstData { - name: konst.name.clone(), - type_ref: konst.type_ref, - visibility, - rustc_allow_incoherent_impl, - has_body: konst.has_body, - types_map: konst.types_map.clone(), - }) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct StaticData { - pub name: Name, - pub type_ref: TypeRefId, - pub visibility: RawVisibility, - pub mutable: bool, - pub is_extern: bool, - pub has_safe_kw: bool, - pub has_unsafe_kw: bool, - pub types_map: Arc, -} - -impl StaticData { - pub(crate) fn static_data_query(db: &dyn DefDatabase, konst: StaticId) -> Arc { - let loc = konst.lookup(db); - let item_tree = loc.id.item_tree(db); - let statik = &item_tree[loc.id.value]; - - Arc::new(StaticData { - name: statik.name.clone(), - type_ref: statik.type_ref, - visibility: item_tree[statik.visibility].clone(), - mutable: statik.mutable, - is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)), - has_safe_kw: statik.has_safe_kw, - has_unsafe_kw: statik.has_unsafe_kw, - types_map: statik.types_map.clone(), - }) - } -} - -struct AssocItemCollector<'a> { - db: &'a dyn DefDatabase, - module_id: ModuleId, - def_map: Arc, - diagnostics: Vec, - container: ItemContainerId, - expander: Expander, - - items: Vec<(Name, AssocItemId)>, - macro_calls: Vec<(AstId, MacroCallId)>, -} - -impl<'a> AssocItemCollector<'a> { - fn new( - db: &'a dyn DefDatabase, - module_id: ModuleId, - file_id: HirFileId, - container: ItemContainerId, - ) -> Self { - Self { - db, - module_id, - def_map: module_id.def_map(db), - container, - expander: Expander::new(db, file_id, module_id), - items: Vec::new(), - macro_calls: Vec::new(), - diagnostics: Vec::new(), - } - } - - fn finish( - self, - ) -> ( - Box<[(Name, AssocItemId)]>, - Option, MacroCallId)>>>, - Vec, - ) { - ( - self.items.into_boxed_slice(), - if self.macro_calls.is_empty() { None } else { Some(Box::new(self.macro_calls)) }, - self.diagnostics, - ) - } - - fn collect(&mut self, item_tree: &ItemTree, tree_id: TreeId, assoc_items: &[AssocItem]) { - let container = self.container; - self.items.reserve(assoc_items.len()); - - 'items: for &item in assoc_items { - let attrs = item_tree.attrs(self.db, self.module_id.krate, ModItem::from(item).into()); - if !attrs.is_cfg_enabled(self.expander.cfg_options()) { - self.diagnostics.push(DefDiagnostic::unconfigured_code( - self.module_id.local_id, - tree_id, - ModItem::from(item).into(), - attrs.cfg().unwrap(), - self.expander.cfg_options().clone(), - )); - continue; - } - - 'attrs: for attr in &*attrs { - let ast_id = - AstId::new(self.expander.current_file_id(), item.ast_id(item_tree).upcast()); - let ast_id_with_path = AstIdWithPath { path: attr.path.clone(), ast_id }; - - match self.def_map.resolve_attr_macro( - self.db, - self.module_id.local_id, - ast_id_with_path, - attr, - ) { - Ok(ResolvedAttr::Macro(call_id)) => { - let loc = self.db.lookup_intern_macro_call(call_id); - if let MacroDefKind::ProcMacro(_, exp, _) = loc.def.kind { - // If there's no expander for the proc macro (e.g. the - // proc macro is ignored, or building the proc macro - // crate failed), skip expansion like we would if it was - // disabled. This is analogous to the handling in - // `DefCollector::collect_macros`. - if let Some(err) = exp.as_expand_error(self.module_id.krate) { - self.diagnostics.push(DefDiagnostic::macro_error( - self.module_id.local_id, - ast_id, - (*attr.path).clone(), - err, - )); - continue 'attrs; - } - } - - self.macro_calls.push((ast_id, call_id)); - let res = - self.expander.enter_expand_id::(self.db, call_id); - self.collect_macro_items(res); - continue 'items; - } - Ok(_) => (), - Err(_) => { - self.diagnostics.push(DefDiagnostic::unresolved_macro_call( - self.module_id.local_id, - MacroCallKind::Attr { - ast_id, - attr_args: None, - invoc_attr_index: attr.id, - }, - attr.path().clone(), - )); - } - } - } - - self.collect_item(item_tree, tree_id, container, item); - } - } - - fn collect_item( - &mut self, - item_tree: &ItemTree, - tree_id: TreeId, - container: ItemContainerId, - item: AssocItem, - ) { - match item { - AssocItem::Function(id) => { - let item = &item_tree[id]; - let def = - FunctionLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db); - self.items.push((item.name.clone(), def.into())); - } - AssocItem::TypeAlias(id) => { - let item = &item_tree[id]; - let def = - TypeAliasLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db); - self.items.push((item.name.clone(), def.into())); - } - AssocItem::Const(id) => { - let item = &item_tree[id]; - let Some(name) = item.name.clone() else { return }; - let def = ConstLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db); - self.items.push((name, def.into())); - } - AssocItem::MacroCall(call) => { - let file_id = self.expander.current_file_id(); - let MacroCall { ast_id, expand_to, ctxt, ref path } = item_tree[call]; - let module = self.expander.module.local_id; - - let resolver = |path: &_| { - self.def_map - .resolve_path( - self.db, - module, - path, - crate::item_scope::BuiltinShadowMode::Other, - Some(MacroSubNs::Bang), - ) - .0 - .take_macros() - .map(|it| self.db.macro_def(it)) - }; - match macro_call_as_call_id( - self.db.upcast(), - &AstIdWithPath::new(file_id, ast_id, Clone::clone(path)), - ctxt, - expand_to, - self.expander.krate(), - resolver, - ) { - Ok(Some(call_id)) => { - let res = - self.expander.enter_expand_id::(self.db, call_id); - self.macro_calls.push((InFile::new(file_id, ast_id.upcast()), call_id)); - self.collect_macro_items(res); - } - Ok(None) => (), - Err(_) => { - self.diagnostics.push(DefDiagnostic::unresolved_macro_call( - self.module_id.local_id, - MacroCallKind::FnLike { - ast_id: InFile::new(file_id, ast_id), - expand_to, - eager: None, - }, - Clone::clone(path), - )); - } - } - } - } - } - - fn collect_macro_items(&mut self, res: ExpandResult)>>) { - let Some((mark, _parse)) = res.value else { return }; - - let tree_id = item_tree::TreeId::new(self.expander.current_file_id(), None); - let item_tree = tree_id.item_tree(self.db); - let iter: SmallVec<[_; 2]> = - item_tree.top_level_items().iter().filter_map(ModItem::as_assoc_item).collect(); - - self.collect(&item_tree, tree_id, &iter); - - self.expander.exit(mark); - } -} - -fn trait_vis(db: &dyn DefDatabase, trait_id: TraitId) -> RawVisibility { - let ItemLoc { id: tree_id, .. } = trait_id.lookup(db); - let item_tree = tree_id.item_tree(db); - let tr_def = &item_tree[tree_id.value]; - item_tree[tr_def.visibility].clone() -} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs deleted file mode 100644 index c94622016d35..000000000000 --- a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs +++ /dev/null @@ -1,489 +0,0 @@ -//! Defines hir-level representation of structs, enums and unions - -use base_db::CrateId; -use bitflags::bitflags; -use cfg::CfgOptions; -use either::Either; - -use hir_expand::name::Name; -use intern::sym; -use la_arena::Arena; -use rustc_abi::{Align, Integer, IntegerType, ReprFlags, ReprOptions}; -use rustc_hashes::Hash64; -use triomphe::Arc; -use tt::iter::TtElement; - -use crate::{ - builtin_type::{BuiltinInt, BuiltinUint}, - db::DefDatabase, - hir::Expr, - item_tree::{ - AttrOwner, Field, FieldParent, FieldsShape, ItemTree, ModItem, RawVisibilityId, TreeId, - }, - lang_item::LangItem, - nameres::diagnostics::{DefDiagnostic, DefDiagnostics}, - tt::{Delimiter, DelimiterKind, Leaf, TopSubtree}, - type_ref::{TypeRefId, TypesMap}, - visibility::RawVisibility, - EnumId, EnumVariantId, LocalFieldId, LocalModuleId, Lookup, StructId, UnionId, VariantId, -}; - -/// Note that we use `StructData` for unions as well! -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct StructData { - pub name: Name, - pub variant_data: Arc, - pub repr: Option, - pub visibility: RawVisibility, - pub flags: StructFlags, -} - -bitflags! { - #[derive(Debug, Copy, Clone, PartialEq, Eq)] - pub struct StructFlags: u8 { - const NO_FLAGS = 0; - /// Indicates whether the struct is `PhantomData`. - const IS_PHANTOM_DATA = 1 << 2; - /// Indicates whether the struct has a `#[fundamental]` attribute. - const IS_FUNDAMENTAL = 1 << 3; - // FIXME: should this be a flag? - /// Indicates whether the struct has a `#[rustc_has_incoherent_inherent_impls]` attribute. - const IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPL = 1 << 4; - /// Indicates whether this struct is `Box`. - const IS_BOX = 1 << 5; - /// Indicates whether this struct is `ManuallyDrop`. - const IS_MANUALLY_DROP = 1 << 6; - /// Indicates whether this struct is `UnsafeCell`. - const IS_UNSAFE_CELL = 1 << 7; - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct EnumData { - pub name: Name, - pub variants: Box<[(EnumVariantId, Name)]>, - pub repr: Option, - pub visibility: RawVisibility, - pub rustc_has_incoherent_inherent_impls: bool, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct EnumVariantData { - pub name: Name, - pub variant_data: Arc, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum VariantData { - Record { fields: Arena, types_map: Arc }, - Tuple { fields: Arena, types_map: Arc }, - Unit, -} - -/// A single field of an enum variant or struct -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct FieldData { - pub name: Name, - pub type_ref: TypeRefId, - pub visibility: RawVisibility, -} - -fn repr_from_value( - db: &dyn DefDatabase, - krate: CrateId, - item_tree: &ItemTree, - of: AttrOwner, -) -> Option { - item_tree.attrs(db, krate, of).by_key(&sym::repr).tt_values().find_map(parse_repr_tt) -} - -fn parse_repr_tt(tt: &TopSubtree) -> Option { - match tt.top_subtree().delimiter { - Delimiter { kind: DelimiterKind::Parenthesis, .. } => {} - _ => return None, - } - - let mut flags = ReprFlags::empty(); - let mut int = None; - let mut max_align: Option = None; - let mut min_pack: Option = None; - - let mut tts = tt.iter(); - while let Some(tt) = tts.next() { - if let TtElement::Leaf(Leaf::Ident(ident)) = tt { - flags.insert(match &ident.sym { - s if *s == sym::packed => { - let pack = if let Some(TtElement::Subtree(_, mut tt_iter)) = tts.peek() { - tts.next(); - if let Some(TtElement::Leaf(Leaf::Literal(lit))) = tt_iter.next() { - lit.symbol.as_str().parse().unwrap_or_default() - } else { - 0 - } - } else { - 0 - }; - let pack = Align::from_bytes(pack).unwrap_or(Align::ONE); - min_pack = - Some(if let Some(min_pack) = min_pack { min_pack.min(pack) } else { pack }); - ReprFlags::empty() - } - s if *s == sym::align => { - if let Some(TtElement::Subtree(_, mut tt_iter)) = tts.peek() { - tts.next(); - if let Some(TtElement::Leaf(Leaf::Literal(lit))) = tt_iter.next() { - if let Ok(align) = lit.symbol.as_str().parse() { - let align = Align::from_bytes(align).ok(); - max_align = max_align.max(align); - } - } - } - ReprFlags::empty() - } - s if *s == sym::C => ReprFlags::IS_C, - s if *s == sym::transparent => ReprFlags::IS_TRANSPARENT, - s if *s == sym::simd => ReprFlags::IS_SIMD, - repr => { - if let Some(builtin) = BuiltinInt::from_suffix_sym(repr) - .map(Either::Left) - .or_else(|| BuiltinUint::from_suffix_sym(repr).map(Either::Right)) - { - int = Some(match builtin { - Either::Left(bi) => match bi { - BuiltinInt::Isize => IntegerType::Pointer(true), - BuiltinInt::I8 => IntegerType::Fixed(Integer::I8, true), - BuiltinInt::I16 => IntegerType::Fixed(Integer::I16, true), - BuiltinInt::I32 => IntegerType::Fixed(Integer::I32, true), - BuiltinInt::I64 => IntegerType::Fixed(Integer::I64, true), - BuiltinInt::I128 => IntegerType::Fixed(Integer::I128, true), - }, - Either::Right(bu) => match bu { - BuiltinUint::Usize => IntegerType::Pointer(false), - BuiltinUint::U8 => IntegerType::Fixed(Integer::I8, false), - BuiltinUint::U16 => IntegerType::Fixed(Integer::I16, false), - BuiltinUint::U32 => IntegerType::Fixed(Integer::I32, false), - BuiltinUint::U64 => IntegerType::Fixed(Integer::I64, false), - BuiltinUint::U128 => IntegerType::Fixed(Integer::I128, false), - }, - }); - } - ReprFlags::empty() - } - }) - } - } - - Some(ReprOptions { - int, - align: max_align, - pack: min_pack, - flags, - field_shuffle_seed: Hash64::ZERO, - }) -} - -impl StructData { - #[inline] - pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc { - db.struct_data_with_diagnostics(id).0 - } - - pub(crate) fn struct_data_with_diagnostics_query( - db: &dyn DefDatabase, - id: StructId, - ) -> (Arc, DefDiagnostics) { - let loc = id.lookup(db); - let krate = loc.container.krate; - let item_tree = loc.id.item_tree(db); - let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into()); - let attrs = item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()); - - let mut flags = StructFlags::NO_FLAGS; - if attrs.by_key(&sym::rustc_has_incoherent_inherent_impls).exists() { - flags |= StructFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPL; - } - if attrs.by_key(&sym::fundamental).exists() { - flags |= StructFlags::IS_FUNDAMENTAL; - } - if let Some(lang) = attrs.lang_item() { - match lang { - LangItem::PhantomData => flags |= StructFlags::IS_PHANTOM_DATA, - LangItem::OwnedBox => flags |= StructFlags::IS_BOX, - LangItem::ManuallyDrop => flags |= StructFlags::IS_MANUALLY_DROP, - LangItem::UnsafeCell => flags |= StructFlags::IS_UNSAFE_CELL, - _ => (), - } - } - - let strukt = &item_tree[loc.id.value]; - let (fields, diagnostics) = lower_fields( - db, - krate, - loc.container.local_id, - loc.id.tree_id(), - &item_tree, - &db.crate_graph()[krate].cfg_options, - FieldParent::Struct(loc.id.value), - &strukt.fields, - None, - ); - let types_map = strukt.types_map.clone(); - ( - Arc::new(StructData { - name: strukt.name.clone(), - variant_data: Arc::new(match strukt.shape { - FieldsShape::Record => VariantData::Record { fields, types_map }, - FieldsShape::Tuple => VariantData::Tuple { fields, types_map }, - FieldsShape::Unit => VariantData::Unit, - }), - repr, - visibility: item_tree[strukt.visibility].clone(), - flags, - }), - DefDiagnostics::new(diagnostics), - ) - } - - #[inline] - pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc { - db.union_data_with_diagnostics(id).0 - } - - pub(crate) fn union_data_with_diagnostics_query( - db: &dyn DefDatabase, - id: UnionId, - ) -> (Arc, DefDiagnostics) { - let loc = id.lookup(db); - let krate = loc.container.krate; - let item_tree = loc.id.item_tree(db); - let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into()); - let attrs = item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()); - let mut flags = StructFlags::NO_FLAGS; - if attrs.by_key(&sym::rustc_has_incoherent_inherent_impls).exists() { - flags |= StructFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPL; - } - if attrs.by_key(&sym::fundamental).exists() { - flags |= StructFlags::IS_FUNDAMENTAL; - } - - let union = &item_tree[loc.id.value]; - let (fields, diagnostics) = lower_fields( - db, - krate, - loc.container.local_id, - loc.id.tree_id(), - &item_tree, - &db.crate_graph()[krate].cfg_options, - FieldParent::Union(loc.id.value), - &union.fields, - None, - ); - let types_map = union.types_map.clone(); - ( - Arc::new(StructData { - name: union.name.clone(), - variant_data: Arc::new(VariantData::Record { fields, types_map }), - repr, - visibility: item_tree[union.visibility].clone(), - flags, - }), - DefDiagnostics::new(diagnostics), - ) - } -} - -impl EnumData { - pub(crate) fn enum_data_query(db: &dyn DefDatabase, e: EnumId) -> Arc { - let loc = e.lookup(db); - let krate = loc.container.krate; - let item_tree = loc.id.item_tree(db); - let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into()); - let rustc_has_incoherent_inherent_impls = item_tree - .attrs(db, loc.container.krate, ModItem::from(loc.id.value).into()) - .by_key(&sym::rustc_has_incoherent_inherent_impls) - .exists(); - - let enum_ = &item_tree[loc.id.value]; - - Arc::new(EnumData { - name: enum_.name.clone(), - variants: loc.container.def_map(db).enum_definitions[&e] - .iter() - .map(|&id| (id, item_tree[id.lookup(db).id.value].name.clone())) - .collect(), - repr, - visibility: item_tree[enum_.visibility].clone(), - rustc_has_incoherent_inherent_impls, - }) - } - - pub fn variant(&self, name: &Name) -> Option { - let &(id, _) = self.variants.iter().find(|(_id, n)| n == name)?; - Some(id) - } - - pub fn variant_body_type(&self) -> IntegerType { - match self.repr { - Some(ReprOptions { int: Some(builtin), .. }) => builtin, - _ => IntegerType::Pointer(true), - } - } - - // [Adopted from rustc](https://github.com/rust-lang/rust/blob/bd53aa3bf7a24a70d763182303bd75e5fc51a9af/compiler/rustc_middle/src/ty/adt.rs#L446-L448) - pub fn is_payload_free(&self, db: &dyn DefDatabase) -> bool { - self.variants.iter().all(|(v, _)| { - // The condition check order is slightly modified from rustc - // to improve performance by early returning with relatively fast checks - let variant = &db.enum_variant_data(*v).variant_data; - if !variant.fields().is_empty() { - return false; - } - // The outer if condition is whether this variant has const ctor or not - if !matches!(variant.kind(), StructKind::Unit) { - let body = db.body((*v).into()); - // A variant with explicit discriminant - if body.exprs[body.body_expr] != Expr::Missing { - return false; - } - } - true - }) - } -} - -impl EnumVariantData { - #[inline] - pub(crate) fn enum_variant_data_query( - db: &dyn DefDatabase, - e: EnumVariantId, - ) -> Arc { - db.enum_variant_data_with_diagnostics(e).0 - } - - pub(crate) fn enum_variant_data_with_diagnostics_query( - db: &dyn DefDatabase, - e: EnumVariantId, - ) -> (Arc, DefDiagnostics) { - let loc = e.lookup(db); - let container = loc.parent.lookup(db).container; - let krate = container.krate; - let item_tree = loc.id.item_tree(db); - let variant = &item_tree[loc.id.value]; - - let (fields, diagnostics) = lower_fields( - db, - krate, - container.local_id, - loc.id.tree_id(), - &item_tree, - &db.crate_graph()[krate].cfg_options, - FieldParent::Variant(loc.id.value), - &variant.fields, - Some(item_tree[loc.parent.lookup(db).id.value].visibility), - ); - let types_map = variant.types_map.clone(); - - ( - Arc::new(EnumVariantData { - name: variant.name.clone(), - variant_data: Arc::new(match variant.shape { - FieldsShape::Record => VariantData::Record { fields, types_map }, - FieldsShape::Tuple => VariantData::Tuple { fields, types_map }, - FieldsShape::Unit => VariantData::Unit, - }), - }), - DefDiagnostics::new(diagnostics), - ) - } -} - -impl VariantData { - pub fn fields(&self) -> &Arena { - const EMPTY: &Arena = &Arena::new(); - match &self { - VariantData::Record { fields, .. } | VariantData::Tuple { fields, .. } => fields, - _ => EMPTY, - } - } - - pub fn types_map(&self) -> &TypesMap { - match &self { - VariantData::Record { types_map, .. } | VariantData::Tuple { types_map, .. } => { - types_map - } - VariantData::Unit => TypesMap::EMPTY, - } - } - - // FIXME: Linear lookup - pub fn field(&self, name: &Name) -> Option { - self.fields().iter().find_map(|(id, data)| if &data.name == name { Some(id) } else { None }) - } - - pub fn kind(&self) -> StructKind { - match self { - VariantData::Record { .. } => StructKind::Record, - VariantData::Tuple { .. } => StructKind::Tuple, - VariantData::Unit => StructKind::Unit, - } - } - - #[allow(clippy::self_named_constructors)] - pub(crate) fn variant_data(db: &dyn DefDatabase, id: VariantId) -> Arc { - match id { - VariantId::StructId(it) => db.struct_data(it).variant_data.clone(), - VariantId::EnumVariantId(it) => db.enum_variant_data(it).variant_data.clone(), - VariantId::UnionId(it) => db.union_data(it).variant_data.clone(), - } - } -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum StructKind { - Tuple, - Record, - Unit, -} - -fn lower_fields( - db: &dyn DefDatabase, - krate: CrateId, - container: LocalModuleId, - tree_id: TreeId, - item_tree: &ItemTree, - cfg_options: &CfgOptions, - parent: FieldParent, - fields: &[Field], - override_visibility: Option, -) -> (Arena, Vec) { - let mut diagnostics = Vec::new(); - let mut arena = Arena::new(); - for (idx, field) in fields.iter().enumerate() { - let attr_owner = AttrOwner::make_field_indexed(parent, idx); - let attrs = item_tree.attrs(db, krate, attr_owner); - if attrs.is_cfg_enabled(cfg_options) { - arena.alloc(lower_field(item_tree, field, override_visibility)); - } else { - diagnostics.push(DefDiagnostic::unconfigured_code( - container, - tree_id, - attr_owner, - attrs.cfg().unwrap(), - cfg_options.clone(), - )) - } - } - (arena, diagnostics) -} - -fn lower_field( - item_tree: &ItemTree, - field: &Field, - override_visibility: Option, -) -> FieldData { - FieldData { - name: field.name.clone(), - type_ref: field.type_ref, - visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(), - } -} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs index 598a850898bb..34cf42d02bdb 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs @@ -1,273 +1,373 @@ //! Defines database & queries for name resolution. -use base_db::{ra_salsa, CrateId, SourceDatabase, Upcast}; +use base_db::{Crate, RootQueryDb, SourceDatabase}; use either::Either; -use hir_expand::{db::ExpandDatabase, HirFileId, MacroDefId}; +use hir_expand::{EditionedFileId, HirFileId, MacroCallId, MacroDefId, db::ExpandDatabase}; use intern::sym; use la_arena::ArenaMap; -use span::{EditionedFileId, MacroCallId}; -use syntax::{ast, AstPtr}; +use syntax::{AstPtr, ast}; +use thin_vec::ThinVec; use triomphe::Arc; use crate::{ + AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, EnumVariantId, + EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId, + FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalFieldId, Macro2Id, Macro2Loc, MacroId, + MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, ProcMacroLoc, StaticId, + StaticLoc, StructId, StructLoc, TraitAliasId, TraitAliasLoc, TraitId, TraitLoc, TypeAliasId, + TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc, VariantId, attr::{Attrs, AttrsWithOwner}, - data::{ - adt::{EnumData, EnumVariantData, StructData, VariantData}, - ConstData, ExternCrateDeclData, FunctionData, ImplData, Macro2Data, MacroRulesData, - ProcMacroData, StaticData, TraitAliasData, TraitData, TypeAliasData, + expr_store::{ + Body, BodySourceMap, ExpressionStore, ExpressionStoreSourceMap, scope::ExprScopes, }, - expr_store::{scope::ExprScopes, Body, BodySourceMap}, - generics::GenericParams, + hir::generics::GenericParams, import_map::ImportMap, - item_tree::{AttrOwner, ItemTree, ItemTreeSourceMaps}, + item_tree::{AttrOwner, ItemTree}, lang_item::{self, LangItem, LangItemTarget, LangItems}, - nameres::{diagnostics::DefDiagnostics, DefMap}, + nameres::{ + DefMap, LocalDefMap, + assoc::{ImplItems, TraitItems}, + diagnostics::DefDiagnostics, + }, + signatures::{ + ConstSignature, EnumSignature, EnumVariants, FunctionSignature, ImplSignature, + InactiveEnumVariantCode, StaticSignature, StructSignature, TraitAliasSignature, + TraitSignature, TypeAliasSignature, UnionSignature, VariantFields, + }, tt, - type_ref::TypesSourceMap, visibility::{self, Visibility}, - AttrDefId, BlockId, BlockLoc, ConstBlockId, ConstBlockLoc, ConstId, ConstLoc, DefWithBodyId, - EnumId, EnumLoc, EnumVariantId, EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, - ExternCrateLoc, FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, InTypeConstId, - InTypeConstLoc, LocalFieldId, Macro2Id, Macro2Loc, MacroId, MacroRulesId, MacroRulesLoc, - MacroRulesLocFlags, ProcMacroId, ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc, - TraitAliasId, TraitAliasLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, - UseId, UseLoc, VariantId, }; -#[ra_salsa::query_group(InternDatabaseStorage)] -pub trait InternDatabase: SourceDatabase { - // region: items - #[ra_salsa::interned] - fn intern_use(&self, loc: UseLoc) -> UseId; - #[ra_salsa::interned] - fn intern_extern_crate(&self, loc: ExternCrateLoc) -> ExternCrateId; - #[ra_salsa::interned] - fn intern_function(&self, loc: FunctionLoc) -> FunctionId; - #[ra_salsa::interned] - fn intern_struct(&self, loc: StructLoc) -> StructId; - #[ra_salsa::interned] - fn intern_union(&self, loc: UnionLoc) -> UnionId; - #[ra_salsa::interned] - fn intern_enum(&self, loc: EnumLoc) -> EnumId; - #[ra_salsa::interned] - fn intern_enum_variant(&self, loc: EnumVariantLoc) -> EnumVariantId; - #[ra_salsa::interned] - fn intern_const(&self, loc: ConstLoc) -> ConstId; - #[ra_salsa::interned] - fn intern_static(&self, loc: StaticLoc) -> StaticId; - #[ra_salsa::interned] - fn intern_trait(&self, loc: TraitLoc) -> TraitId; - #[ra_salsa::interned] - fn intern_trait_alias(&self, loc: TraitAliasLoc) -> TraitAliasId; - #[ra_salsa::interned] - fn intern_type_alias(&self, loc: TypeAliasLoc) -> TypeAliasId; - #[ra_salsa::interned] - fn intern_impl(&self, loc: ImplLoc) -> ImplId; - #[ra_salsa::interned] - fn intern_extern_block(&self, loc: ExternBlockLoc) -> ExternBlockId; - #[ra_salsa::interned] - fn intern_macro2(&self, loc: Macro2Loc) -> Macro2Id; - #[ra_salsa::interned] - fn intern_proc_macro(&self, loc: ProcMacroLoc) -> ProcMacroId; - #[ra_salsa::interned] - fn intern_macro_rules(&self, loc: MacroRulesLoc) -> MacroRulesId; - // endregion: items +use salsa::plumbing::AsId; - #[ra_salsa::interned] +#[query_group::query_group(InternDatabaseStorage)] +pub trait InternDatabase: RootQueryDb { + // region: items + #[salsa::interned] + fn intern_use(&self, loc: UseLoc) -> UseId; + + #[salsa::interned] + fn intern_extern_crate(&self, loc: ExternCrateLoc) -> ExternCrateId; + + #[salsa::interned] + fn intern_function(&self, loc: FunctionLoc) -> FunctionId; + + #[salsa::interned] + fn intern_struct(&self, loc: StructLoc) -> StructId; + + #[salsa::interned] + fn intern_union(&self, loc: UnionLoc) -> UnionId; + + #[salsa::interned] + fn intern_enum(&self, loc: EnumLoc) -> EnumId; + + #[salsa::interned] + fn intern_enum_variant(&self, loc: EnumVariantLoc) -> EnumVariantId; + + #[salsa::interned] + fn intern_const(&self, loc: ConstLoc) -> ConstId; + + #[salsa::interned] + fn intern_static(&self, loc: StaticLoc) -> StaticId; + + #[salsa::interned] + fn intern_trait(&self, loc: TraitLoc) -> TraitId; + + #[salsa::interned] + fn intern_trait_alias(&self, loc: TraitAliasLoc) -> TraitAliasId; + + #[salsa::interned] + fn intern_type_alias(&self, loc: TypeAliasLoc) -> TypeAliasId; + + #[salsa::interned] + fn intern_impl(&self, loc: ImplLoc) -> ImplId; + + #[salsa::interned] + fn intern_extern_block(&self, loc: ExternBlockLoc) -> ExternBlockId; + + #[salsa::interned] + fn intern_macro2(&self, loc: Macro2Loc) -> Macro2Id; + + #[salsa::interned] + fn intern_proc_macro(&self, loc: ProcMacroLoc) -> ProcMacroId; + + #[salsa::interned] + fn intern_macro_rules(&self, loc: MacroRulesLoc) -> MacroRulesId; + // // endregion: items + + #[salsa::interned] fn intern_block(&self, loc: BlockLoc) -> BlockId; - #[ra_salsa::interned] - fn intern_anonymous_const(&self, id: ConstBlockLoc) -> ConstBlockId; - #[ra_salsa::interned] - fn intern_in_type_const(&self, id: InTypeConstLoc) -> InTypeConstId; } -#[ra_salsa::query_group(DefDatabaseStorage)] -pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast { +#[query_group::query_group] +pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase { /// Whether to expand procedural macros during name resolution. - #[ra_salsa::input] + #[salsa::input] fn expand_proc_attr_macros(&self) -> bool; /// Computes an [`ItemTree`] for the given file or macro expansion. - #[ra_salsa::invoke(ItemTree::file_item_tree_query)] + #[salsa::invoke(ItemTree::file_item_tree_query)] fn file_item_tree(&self, file_id: HirFileId) -> Arc; - #[ra_salsa::invoke(ItemTree::block_item_tree_query)] + #[salsa::invoke(ItemTree::block_item_tree_query)] fn block_item_tree(&self, block_id: BlockId) -> Arc; - #[ra_salsa::invoke(ItemTree::file_item_tree_with_source_map_query)] - fn file_item_tree_with_source_map( - &self, - file_id: HirFileId, - ) -> (Arc, Arc); + #[salsa::invoke(DefMap::crate_local_def_map_query)] + fn crate_local_def_map(&self, krate: Crate) -> (Arc, Arc); - #[ra_salsa::invoke(ItemTree::block_item_tree_with_source_map_query)] - fn block_item_tree_with_source_map( - &self, - block_id: BlockId, - ) -> (Arc, Arc); - - #[ra_salsa::invoke(DefMap::crate_def_map_query)] - fn crate_def_map(&self, krate: CrateId) -> Arc; + #[salsa::invoke(DefMap::crate_def_map_query)] + fn crate_def_map(&self, krate: Crate) -> Arc; /// Computes the block-level `DefMap`. - #[ra_salsa::invoke(DefMap::block_def_map_query)] + #[salsa::invoke(DefMap::block_def_map_query)] fn block_def_map(&self, block: BlockId) -> Arc; /// Turns a MacroId into a MacroDefId, describing the macro's definition post name resolution. + #[salsa::invoke(macro_def)] fn macro_def(&self, m: MacroId) -> MacroDefId; // region:data - #[ra_salsa::transparent] - #[ra_salsa::invoke(StructData::struct_data_query)] - fn struct_data(&self, id: StructId) -> Arc; - - #[ra_salsa::invoke(StructData::struct_data_with_diagnostics_query)] - fn struct_data_with_diagnostics(&self, id: StructId) -> (Arc, DefDiagnostics); - - #[ra_salsa::transparent] - #[ra_salsa::invoke(StructData::union_data_query)] - fn union_data(&self, id: UnionId) -> Arc; - - #[ra_salsa::invoke(StructData::union_data_with_diagnostics_query)] - fn union_data_with_diagnostics(&self, id: UnionId) -> (Arc, DefDiagnostics); - - #[ra_salsa::invoke(EnumData::enum_data_query)] - fn enum_data(&self, e: EnumId) -> Arc; - - #[ra_salsa::transparent] - #[ra_salsa::invoke(EnumVariantData::enum_variant_data_query)] - fn enum_variant_data(&self, id: EnumVariantId) -> Arc; - - #[ra_salsa::invoke(EnumVariantData::enum_variant_data_with_diagnostics_query)] - fn enum_variant_data_with_diagnostics( + #[salsa::invoke(VariantFields::query)] + fn variant_fields_with_source_map( &self, - id: EnumVariantId, - ) -> (Arc, DefDiagnostics); + id: VariantId, + ) -> (Arc, Arc); - #[ra_salsa::transparent] - #[ra_salsa::invoke(VariantData::variant_data)] - fn variant_data(&self, id: VariantId) -> Arc; - #[ra_salsa::transparent] - #[ra_salsa::invoke(ImplData::impl_data_query)] - fn impl_data(&self, e: ImplId) -> Arc; + #[salsa::tracked] + fn enum_variants(&self, id: EnumId) -> Arc { + self.enum_variants_with_diagnostics(id).0 + } - #[ra_salsa::invoke(ImplData::impl_data_with_diagnostics_query)] - fn impl_data_with_diagnostics(&self, e: ImplId) -> (Arc, DefDiagnostics); + #[salsa::invoke(EnumVariants::enum_variants_query)] + fn enum_variants_with_diagnostics( + &self, + id: EnumId, + ) -> (Arc, Option>>); - #[ra_salsa::transparent] - #[ra_salsa::invoke(TraitData::trait_data_query)] - fn trait_data(&self, e: TraitId) -> Arc; + #[salsa::transparent] + #[salsa::invoke(ImplItems::impl_items_query)] + fn impl_items(&self, e: ImplId) -> Arc; - #[ra_salsa::invoke(TraitData::trait_data_with_diagnostics_query)] - fn trait_data_with_diagnostics(&self, tr: TraitId) -> (Arc, DefDiagnostics); + #[salsa::invoke(ImplItems::impl_items_with_diagnostics_query)] + fn impl_items_with_diagnostics(&self, e: ImplId) -> (Arc, DefDiagnostics); - #[ra_salsa::invoke(TraitAliasData::trait_alias_query)] - fn trait_alias_data(&self, e: TraitAliasId) -> Arc; + #[salsa::transparent] + #[salsa::invoke(TraitItems::trait_items_query)] + fn trait_items(&self, e: TraitId) -> Arc; - #[ra_salsa::invoke(TypeAliasData::type_alias_data_query)] - fn type_alias_data(&self, e: TypeAliasId) -> Arc; + #[salsa::invoke(TraitItems::trait_items_with_diagnostics_query)] + fn trait_items_with_diagnostics(&self, tr: TraitId) -> (Arc, DefDiagnostics); - #[ra_salsa::invoke(FunctionData::fn_data_query)] - fn function_data(&self, func: FunctionId) -> Arc; + #[salsa::tracked] + fn variant_fields(&self, id: VariantId) -> Arc { + self.variant_fields_with_source_map(id).0 + } - #[ra_salsa::invoke(ConstData::const_data_query)] - fn const_data(&self, konst: ConstId) -> Arc; + #[salsa::tracked] + fn trait_signature(&self, trait_: TraitId) -> Arc { + self.trait_signature_with_source_map(trait_).0 + } - #[ra_salsa::invoke(StaticData::static_data_query)] - fn static_data(&self, statik: StaticId) -> Arc; + #[salsa::tracked] + fn impl_signature(&self, impl_: ImplId) -> Arc { + self.impl_signature_with_source_map(impl_).0 + } - #[ra_salsa::invoke(Macro2Data::macro2_data_query)] - fn macro2_data(&self, makro: Macro2Id) -> Arc; + #[salsa::tracked] + fn struct_signature(&self, struct_: StructId) -> Arc { + self.struct_signature_with_source_map(struct_).0 + } - #[ra_salsa::invoke(MacroRulesData::macro_rules_data_query)] - fn macro_rules_data(&self, makro: MacroRulesId) -> Arc; + #[salsa::tracked] + fn union_signature(&self, union_: UnionId) -> Arc { + self.union_signature_with_source_map(union_).0 + } - #[ra_salsa::invoke(ProcMacroData::proc_macro_data_query)] - fn proc_macro_data(&self, makro: ProcMacroId) -> Arc; + #[salsa::tracked] + fn enum_signature(&self, e: EnumId) -> Arc { + self.enum_signature_with_source_map(e).0 + } - #[ra_salsa::invoke(ExternCrateDeclData::extern_crate_decl_data_query)] - fn extern_crate_decl_data(&self, extern_crate: ExternCrateId) -> Arc; + #[salsa::tracked] + fn const_signature(&self, e: ConstId) -> Arc { + self.const_signature_with_source_map(e).0 + } + + #[salsa::tracked] + fn static_signature(&self, e: StaticId) -> Arc { + self.static_signature_with_source_map(e).0 + } + + #[salsa::tracked] + fn function_signature(&self, e: FunctionId) -> Arc { + self.function_signature_with_source_map(e).0 + } + + #[salsa::tracked] + fn trait_alias_signature(&self, e: TraitAliasId) -> Arc { + self.trait_alias_signature_with_source_map(e).0 + } + + #[salsa::tracked] + fn type_alias_signature(&self, e: TypeAliasId) -> Arc { + self.type_alias_signature_with_source_map(e).0 + } + + #[salsa::invoke(TraitSignature::query)] + fn trait_signature_with_source_map( + &self, + trait_: TraitId, + ) -> (Arc, Arc); + + #[salsa::invoke(ImplSignature::query)] + fn impl_signature_with_source_map( + &self, + impl_: ImplId, + ) -> (Arc, Arc); + + #[salsa::invoke(StructSignature::query)] + fn struct_signature_with_source_map( + &self, + struct_: StructId, + ) -> (Arc, Arc); + + #[salsa::invoke(UnionSignature::query)] + fn union_signature_with_source_map( + &self, + union_: UnionId, + ) -> (Arc, Arc); + + #[salsa::invoke(EnumSignature::query)] + fn enum_signature_with_source_map( + &self, + e: EnumId, + ) -> (Arc, Arc); + + #[salsa::invoke(ConstSignature::query)] + fn const_signature_with_source_map( + &self, + e: ConstId, + ) -> (Arc, Arc); + + #[salsa::invoke(StaticSignature::query)] + fn static_signature_with_source_map( + &self, + e: StaticId, + ) -> (Arc, Arc); + + #[salsa::invoke(FunctionSignature::query)] + fn function_signature_with_source_map( + &self, + e: FunctionId, + ) -> (Arc, Arc); + + #[salsa::invoke(TraitAliasSignature::query)] + fn trait_alias_signature_with_source_map( + &self, + e: TraitAliasId, + ) -> (Arc, Arc); + + #[salsa::invoke(TypeAliasSignature::query)] + fn type_alias_signature_with_source_map( + &self, + e: TypeAliasId, + ) -> (Arc, Arc); // endregion:data - #[ra_salsa::invoke(Body::body_with_source_map_query)] - #[ra_salsa::lru] + #[salsa::invoke(Body::body_with_source_map_query)] + #[salsa::lru(512)] fn body_with_source_map(&self, def: DefWithBodyId) -> (Arc, Arc); - #[ra_salsa::invoke(Body::body_query)] + #[salsa::invoke(Body::body_query)] fn body(&self, def: DefWithBodyId) -> Arc; - #[ra_salsa::invoke(ExprScopes::expr_scopes_query)] + #[salsa::invoke(ExprScopes::expr_scopes_query)] fn expr_scopes(&self, def: DefWithBodyId) -> Arc; - #[ra_salsa::invoke(GenericParams::generic_params_query)] + #[salsa::transparent] + #[salsa::invoke(GenericParams::new)] fn generic_params(&self, def: GenericDefId) -> Arc; - /// If this returns `None` for the source map, that means it is the same as with the item tree. - #[ra_salsa::invoke(GenericParams::generic_params_with_source_map_query)] - fn generic_params_with_source_map( + #[salsa::transparent] + #[salsa::invoke(GenericParams::generic_params_and_store)] + fn generic_params_and_store( &self, def: GenericDefId, - ) -> (Arc, Option>); + ) -> (Arc, Arc); + + #[salsa::transparent] + #[salsa::invoke(GenericParams::generic_params_and_store_and_source_map)] + fn generic_params_and_store_and_source_map( + &self, + def: GenericDefId, + ) -> (Arc, Arc, Arc); // region:attrs - #[ra_salsa::invoke(Attrs::fields_attrs_query)] + #[salsa::invoke(Attrs::fields_attrs_query)] fn fields_attrs(&self, def: VariantId) -> Arc>; // should this really be a query? - #[ra_salsa::invoke(crate::attr::fields_attrs_source_map)] + #[salsa::invoke(crate::attr::fields_attrs_source_map)] fn fields_attrs_source_map( &self, def: VariantId, ) -> Arc>>>; - #[ra_salsa::invoke(AttrsWithOwner::attrs_query)] + // FIXME: Make this a non-interned query. + #[salsa::invoke_interned(AttrsWithOwner::attrs_query)] fn attrs(&self, def: AttrDefId) -> Attrs; - #[ra_salsa::transparent] - #[ra_salsa::invoke(lang_item::lang_attr)] + #[salsa::transparent] + #[salsa::invoke(lang_item::lang_attr)] fn lang_attr(&self, def: AttrDefId) -> Option; // endregion:attrs - #[ra_salsa::invoke(LangItems::lang_item_query)] - fn lang_item(&self, start_crate: CrateId, item: LangItem) -> Option; + #[salsa::invoke(LangItems::lang_item_query)] + fn lang_item(&self, start_crate: Crate, item: LangItem) -> Option; - #[ra_salsa::invoke(ImportMap::import_map_query)] - fn import_map(&self, krate: CrateId) -> Arc; + #[salsa::invoke(ImportMap::import_map_query)] + fn import_map(&self, krate: Crate) -> Arc; // region:visibilities - #[ra_salsa::invoke(visibility::field_visibilities_query)] + #[salsa::invoke(visibility::field_visibilities_query)] fn field_visibilities(&self, var: VariantId) -> Arc>; // FIXME: unify function_visibility and const_visibility? - #[ra_salsa::invoke(visibility::function_visibility_query)] + + #[salsa::invoke(visibility::function_visibility_query)] fn function_visibility(&self, def: FunctionId) -> Visibility; - #[ra_salsa::invoke(visibility::const_visibility_query)] + #[salsa::invoke(visibility::const_visibility_query)] fn const_visibility(&self, def: ConstId) -> Visibility; + #[salsa::invoke(visibility::type_alias_visibility_query)] + fn type_alias_visibility(&self, def: TypeAliasId) -> Visibility; + // endregion:visibilities - #[ra_salsa::invoke(LangItems::crate_lang_items_query)] - fn crate_lang_items(&self, krate: CrateId) -> Option>; + #[salsa::invoke(LangItems::crate_lang_items_query)] + fn crate_lang_items(&self, krate: Crate) -> Option>; - #[ra_salsa::invoke(crate::lang_item::notable_traits_in_deps)] - fn notable_traits_in_deps(&self, krate: CrateId) -> Arc<[Arc<[TraitId]>]>; - #[ra_salsa::invoke(crate::lang_item::crate_notable_traits)] - fn crate_notable_traits(&self, krate: CrateId) -> Option>; + #[salsa::invoke(crate::lang_item::notable_traits_in_deps)] + fn notable_traits_in_deps(&self, krate: Crate) -> Arc<[Arc<[TraitId]>]>; + #[salsa::invoke(crate::lang_item::crate_notable_traits)] + fn crate_notable_traits(&self, krate: Crate) -> Option>; - fn crate_supports_no_std(&self, crate_id: CrateId) -> bool; + #[salsa::invoke(crate_supports_no_std)] + fn crate_supports_no_std(&self, crate_id: Crate) -> bool; - fn include_macro_invoc(&self, crate_id: CrateId) -> Arc<[(MacroCallId, EditionedFileId)]>; + #[salsa::invoke(include_macro_invoc)] + fn include_macro_invoc(&self, crate_id: Crate) -> Arc<[(MacroCallId, EditionedFileId)]>; } // return: macro call id and include file id fn include_macro_invoc( db: &dyn DefDatabase, - krate: CrateId, + krate: Crate, ) -> Arc<[(MacroCallId, EditionedFileId)]> { db.crate_def_map(krate) .modules @@ -275,20 +375,20 @@ fn include_macro_invoc( .flat_map(|m| m.scope.iter_macro_invoc()) .filter_map(|invoc| { db.lookup_intern_macro_call(*invoc.1) - .include_file_id(db.upcast(), *invoc.1) + .include_file_id(db, *invoc.1) .map(|x| (*invoc.1, x)) }) .collect() } -fn crate_supports_no_std(db: &dyn DefDatabase, crate_id: CrateId) -> bool { - let file = db.crate_graph()[crate_id].root_file_id(); +fn crate_supports_no_std(db: &dyn DefDatabase, crate_id: Crate) -> bool { + let file = crate_id.data(db).root_file_id(db); let item_tree = db.file_item_tree(file.into()); let attrs = item_tree.raw_attrs(AttrOwner::TopLevel); for attr in &**attrs { match attr.path().as_ident() { - Some(ident) if *ident == sym::no_std.clone() => return true, - Some(ident) if *ident == sym::cfg_attr.clone() => {} + Some(ident) if *ident == sym::no_std => return true, + Some(ident) if *ident == sym::cfg_attr => {} _ => continue, } @@ -304,7 +404,7 @@ fn crate_supports_no_std(db: &dyn DefDatabase, crate_id: CrateId) -> bool { for output in segments.skip(1) { match output.flat_tokens() { [tt::TokenTree::Leaf(tt::Leaf::Ident(ident))] if ident.sym == sym::no_std => { - return true + return true; } _ => {} } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/dyn_map.rs b/src/tools/rust-analyzer/crates/hir-def/src/dyn_map.rs index 8868bc0cd95b..eed1490a7af6 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/dyn_map.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/dyn_map.rs @@ -27,15 +27,15 @@ pub mod keys { use std::marker::PhantomData; - use hir_expand::{attrs::AttrId, MacroCallId}; + use hir_expand::{MacroCallId, attrs::AttrId}; use rustc_hash::FxHashMap; - use syntax::{ast, AstNode, AstPtr}; + use syntax::{AstNode, AstPtr, ast}; use crate::{ - dyn_map::{DynMap, Policy}, BlockId, ConstId, EnumId, EnumVariantId, ExternBlockId, ExternCrateId, FieldId, FunctionId, ImplId, LifetimeParamId, Macro2Id, MacroRulesId, ProcMacroId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, TypeOrConstParamId, UnionId, UseId, + dyn_map::{DynMap, Policy}, }; pub type Key = crate::dyn_map::Key, V, AstPtrPolicy>; @@ -112,6 +112,10 @@ pub struct Key { } impl Key { + #[allow( + clippy::new_without_default, + reason = "this a const fn, so it can't be default yet. See " + )] pub(crate) const fn new() -> Key { Key { _phantom: PhantomData } } @@ -148,16 +152,11 @@ impl Policy for (K, V) { } } +#[derive(Default)] pub struct DynMap { pub(crate) map: Map, } -impl Default for DynMap { - fn default() -> Self { - DynMap { map: Map::new() } - } -} - #[repr(transparent)] pub struct KeyMap { map: DynMap, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs deleted file mode 100644 index a1b3123c9914..000000000000 --- a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs +++ /dev/null @@ -1,243 +0,0 @@ -//! Macro expansion utilities. - -use std::cell::OnceCell; - -use base_db::CrateId; -use cfg::CfgOptions; -use drop_bomb::DropBomb; -use hir_expand::{ - attrs::RawAttrs, mod_path::ModPath, span_map::SpanMap, ExpandError, ExpandErrorKind, - ExpandResult, HirFileId, InFile, Lookup, MacroCallId, -}; -use span::{Edition, SyntaxContextId}; -use syntax::{ast, Parse}; -use triomphe::Arc; - -use crate::type_ref::{TypesMap, TypesSourceMap}; -use crate::{ - attr::Attrs, db::DefDatabase, lower::LowerCtx, path::Path, AsMacroCall, MacroId, ModuleId, - UnresolvedMacro, -}; - -#[derive(Debug)] -pub struct Expander { - cfg_options: Arc, - span_map: OnceCell, - current_file_id: HirFileId, - pub(crate) module: ModuleId, - /// `recursion_depth == usize::MAX` indicates that the recursion limit has been reached. - recursion_depth: u32, - recursion_limit: usize, -} - -impl Expander { - pub fn new(db: &dyn DefDatabase, current_file_id: HirFileId, module: ModuleId) -> Expander { - let recursion_limit = module.def_map(db).recursion_limit() as usize; - let recursion_limit = if cfg!(test) { - // Without this, `body::tests::your_stack_belongs_to_me` stack-overflows in debug - std::cmp::min(32, recursion_limit) - } else { - recursion_limit - }; - Expander { - current_file_id, - module, - recursion_depth: 0, - recursion_limit, - cfg_options: db.crate_graph()[module.krate].cfg_options.clone(), - span_map: OnceCell::new(), - } - } - - pub(crate) fn span_map(&self, db: &dyn DefDatabase) -> &SpanMap { - self.span_map.get_or_init(|| db.span_map(self.current_file_id)) - } - - pub fn krate(&self) -> CrateId { - self.module.krate - } - - pub fn syntax_context(&self) -> SyntaxContextId { - // FIXME: - SyntaxContextId::root(Edition::CURRENT) - } - - pub fn enter_expand( - &mut self, - db: &dyn DefDatabase, - macro_call: ast::MacroCall, - resolver: impl Fn(&ModPath) -> Option, - ) -> Result)>>, UnresolvedMacro> { - // FIXME: within_limit should support this, instead of us having to extract the error - let mut unresolved_macro_err = None; - - let result = self.within_limit(db, |this| { - let macro_call = this.in_file(¯o_call); - match macro_call.as_call_id_with_errors(db.upcast(), this.module.krate(), |path| { - resolver(path).map(|it| db.macro_def(it)) - }) { - Ok(call_id) => call_id, - Err(resolve_err) => { - unresolved_macro_err = Some(resolve_err); - ExpandResult { value: None, err: None } - } - } - }); - - if let Some(err) = unresolved_macro_err { - Err(err) - } else { - Ok(result) - } - } - - pub fn enter_expand_id( - &mut self, - db: &dyn DefDatabase, - call_id: MacroCallId, - ) -> ExpandResult)>> { - self.within_limit(db, |_this| ExpandResult::ok(Some(call_id))) - } - - pub fn exit(&mut self, mut mark: Mark) { - self.span_map = mark.span_map; - self.current_file_id = mark.file_id; - if self.recursion_depth == u32::MAX { - // Recursion limit has been reached somewhere in the macro expansion tree. Reset the - // depth only when we get out of the tree. - if !self.current_file_id.is_macro() { - self.recursion_depth = 0; - } - } else { - self.recursion_depth -= 1; - } - mark.bomb.defuse(); - } - - pub fn ctx<'a>( - &self, - db: &'a dyn DefDatabase, - types_map: &'a mut TypesMap, - types_source_map: &'a mut TypesSourceMap, - ) -> LowerCtx<'a> { - LowerCtx::with_span_map_cell( - db, - self.current_file_id, - self.span_map.clone(), - types_map, - types_source_map, - ) - } - - pub(crate) fn in_file(&self, value: T) -> InFile { - InFile { file_id: self.current_file_id, value } - } - - pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> Attrs { - Attrs::filter( - db, - self.krate(), - RawAttrs::new( - db.upcast(), - owner, - self.span_map.get_or_init(|| db.span_map(self.current_file_id)).as_ref(), - ), - ) - } - - pub(crate) fn cfg_options(&self) -> &CfgOptions { - &self.cfg_options - } - - pub fn current_file_id(&self) -> HirFileId { - self.current_file_id - } - - pub(crate) fn parse_path( - &mut self, - db: &dyn DefDatabase, - path: ast::Path, - types_map: &mut TypesMap, - types_source_map: &mut TypesSourceMap, - ) -> Option { - let mut ctx = LowerCtx::with_span_map_cell( - db, - self.current_file_id, - self.span_map.clone(), - types_map, - types_source_map, - ); - Path::from_src(&mut ctx, path) - } - - fn within_limit( - &mut self, - db: &dyn DefDatabase, - op: F, - ) -> ExpandResult)>> - where - F: FnOnce(&mut Self) -> ExpandResult>, - { - if self.recursion_depth == u32::MAX { - // Recursion limit has been reached somewhere in the macro expansion tree. We should - // stop expanding other macro calls in this tree, or else this may result in - // exponential number of macro expansions, leading to a hang. - // - // The overflow error should have been reported when it occurred (see the next branch), - // so don't return overflow error here to avoid diagnostics duplication. - cov_mark::hit!(overflow_but_not_me); - return ExpandResult::ok(None); - } - - let ExpandResult { value, err } = op(self); - let Some(call_id) = value else { - return ExpandResult { value: None, err }; - }; - if self.recursion_depth as usize > self.recursion_limit { - self.recursion_depth = u32::MAX; - cov_mark::hit!(your_stack_belongs_to_me); - return ExpandResult::only_err(ExpandError::new( - db.macro_arg_considering_derives(call_id, &call_id.lookup(db.upcast()).kind).2, - ExpandErrorKind::RecursionOverflow, - )); - } - - let macro_file = call_id.as_macro_file(); - let res = db.parse_macro_expansion(macro_file); - - let err = err.or(res.err); - ExpandResult { - value: match &err { - // If proc-macro is disabled or unresolved, we want to expand to a missing expression - // instead of an empty tree which might end up in an empty block. - Some(e) if matches!(e.kind(), ExpandErrorKind::MissingProcMacroExpander(_)) => None, - _ => (|| { - let parse = res.value.0.cast::()?; - - self.recursion_depth += 1; - let old_span_map = OnceCell::new(); - if let Some(prev) = self.span_map.take() { - _ = old_span_map.set(prev); - }; - _ = self.span_map.set(SpanMap::ExpansionSpanMap(res.value.1)); - let old_file_id = - std::mem::replace(&mut self.current_file_id, macro_file.into()); - let mark = Mark { - file_id: old_file_id, - span_map: old_span_map, - bomb: DropBomb::new("expansion mark dropped"), - }; - Some((mark, parse)) - })(), - }, - err, - } - } -} - -#[derive(Debug)] -pub struct Mark { - file_id: HirFileId, - span_map: OnceCell, - bomb: DropBomb, -} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs index 5ff6a7ffe566..e3775c4931ae 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs @@ -1,10 +1,11 @@ //! Defines `ExpressionStore`: a lowered representation of functions, statics and //! consts. -mod body; -mod lower; -mod pretty; +pub mod body; +mod expander; +pub mod lower; +pub mod path; +pub mod pretty; pub mod scope; - #[cfg(test)] mod tests; @@ -12,45 +13,49 @@ use std::ops::{Deref, Index}; use cfg::{CfgExpr, CfgOptions}; use either::Either; -use hir_expand::{name::Name, ExpandError, InFile}; +use hir_expand::{ExpandError, InFile, MacroCallId, mod_path::ModPath, name::Name}; use la_arena::{Arena, ArenaMap}; use rustc_hash::FxHashMap; use smallvec::SmallVec; -use span::{Edition, MacroFileId, SyntaxContextData}; -use syntax::{ast, AstPtr, SyntaxNodePtr}; +use span::{Edition, SyntaxContext}; +use syntax::{AstPtr, SyntaxNodePtr, ast}; use triomphe::Arc; use tt::TextRange; use crate::{ + BlockId, SyntheticSyntax, db::DefDatabase, + expr_store::path::Path, hir::{ Array, AsmOperand, Binding, BindingId, Expr, ExprId, ExprOrPatId, Label, LabelId, Pat, PatId, RecordFieldPat, Statement, }, nameres::DefMap, - path::{ModPath, Path}, - type_ref::{TypeRef, TypeRefId, TypesMap, TypesSourceMap}, - BlockId, DefWithBodyId, Lookup, SyntheticSyntax, + type_ref::{LifetimeRef, LifetimeRefId, PathId, TypeRef, TypeRefId}, }; pub use self::body::{Body, BodySourceMap}; +pub use self::lower::{ + hir_assoc_type_binding_to_ast, hir_generic_arg_to_ast, hir_segment_to_ast_segment, +}; /// A wrapper around [`span::SyntaxContextId`] that is intended only for comparisons. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct HygieneId(span::SyntaxContextId); +pub struct HygieneId(span::SyntaxContext); impl HygieneId { // The edition doesn't matter here, we only use this for comparisons and to lookup the macro. - pub const ROOT: Self = Self(span::SyntaxContextId::root(Edition::Edition2015)); + pub const ROOT: Self = Self(span::SyntaxContext::root(Edition::Edition2015)); - pub fn new(mut ctx: span::SyntaxContextId) -> Self { + pub fn new(mut ctx: span::SyntaxContext) -> Self { // See `Name` for why we're doing that. ctx.remove_root_edition(); Self(ctx) } - pub(crate) fn lookup(self, db: &dyn DefDatabase) -> SyntaxContextData { - db.lookup_intern_syntax_context(self.0) + // FIXME: Inline this + pub(crate) fn lookup(self) -> SyntaxContext { + self.0 } pub(crate) fn is_root(self) -> bool { @@ -79,27 +84,26 @@ pub type ExprOrPatSource = InFile; pub type SelfParamPtr = AstPtr; pub type MacroCallPtr = AstPtr; +pub type TypePtr = AstPtr; +pub type TypeSource = InFile; + +pub type LifetimePtr = AstPtr; +pub type LifetimeSource = InFile; + #[derive(Debug, Eq, PartialEq)] pub struct ExpressionStore { pub exprs: Arena, pub pats: Arena, pub bindings: Arena, pub labels: Arena