diff options
Diffstat (limited to 'compiler')
56 files changed, 693 insertions, 508 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index f5c4affdce2..75ccbc92be1 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1616,7 +1616,7 @@ pub enum StrStyle { /// A raw string, like `r##"foo"##`. /// /// The value is the number of `#` symbols used. - Raw(u16), + Raw(u8), } /// An AST literal. diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 7df385873c1..2132cdfc001 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -59,9 +59,9 @@ pub enum LitKind { Integer, Float, Str, - StrRaw(u16), // raw string delimited by `n` hash symbols + StrRaw(u8), // raw string delimited by `n` hash symbols ByteStr, - ByteStrRaw(u16), // raw byte string delimited by `n` hash symbols + ByteStrRaw(u8), // raw byte string delimited by `n` hash symbols Err, } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index d64f1a05712..9442e0f1a1f 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -618,9 +618,9 @@ impl<'hir> LoweringContext<'_, 'hir> { /// Desugar `<expr>.await` into: /// ```rust /// match ::std::future::IntoFuture::into_future(<expr>) { - /// mut pinned => loop { + /// mut __awaitee => loop { /// match unsafe { ::std::future::Future::poll( - /// <::std::pin::Pin>::new_unchecked(&mut pinned), + /// <::std::pin::Pin>::new_unchecked(&mut __awaitee), /// ::std::future::get_context(task_context), /// ) } { /// ::std::task::Poll::Ready(result) => break result, @@ -657,21 +657,24 @@ impl<'hir> LoweringContext<'_, 'hir> { let expr = self.lower_expr_mut(expr); let expr_hir_id = expr.hir_id; - let pinned_ident = Ident::with_dummy_span(sym::pinned); - let (pinned_pat, pinned_pat_hid) = - self.pat_ident_binding_mode(span, pinned_ident, hir::BindingAnnotation::Mutable); + // Note that the name of this binding must not be changed to something else because + // debuggers and debugger extensions expect it to be called `__awaitee`. They use + // this name to identify what is being awaited by a suspended async functions. + let awaitee_ident = Ident::with_dummy_span(sym::__awaitee); + let (awaitee_pat, awaitee_pat_hid) = + self.pat_ident_binding_mode(span, awaitee_ident, hir::BindingAnnotation::Mutable); let task_context_ident = Ident::with_dummy_span(sym::_task_context); // unsafe { // ::std::future::Future::poll( - // ::std::pin::Pin::new_unchecked(&mut pinned), + // ::std::pin::Pin::new_unchecked(&mut __awaitee), // ::std::future::get_context(task_context), // ) // } let poll_expr = { - let pinned = self.expr_ident(span, pinned_ident, pinned_pat_hid); - let ref_mut_pinned = self.expr_mut_addr_of(span, pinned); + let awaitee = self.expr_ident(span, awaitee_ident, awaitee_pat_hid); + let ref_mut_awaitee = self.expr_mut_addr_of(span, awaitee); let task_context = if let Some(task_context_hid) = self.task_context { self.expr_ident_mut(span, task_context_ident, task_context_hid) } else { @@ -681,7 +684,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let new_unchecked = self.expr_call_lang_item_fn_mut( span, hir::LangItem::PinNewUnchecked, - arena_vec![self; ref_mut_pinned], + arena_vec![self; ref_mut_awaitee], Some(expr_hir_id), ); let get_context = self.expr_call_lang_item_fn_mut( @@ -782,8 +785,8 @@ impl<'hir> LoweringContext<'_, 'hir> { span: self.lower_span(span), }); - // mut pinned => loop { ... } - let pinned_arm = self.arm(pinned_pat, loop_expr); + // mut __awaitee => loop { ... } + let awaitee_arm = self.arm(awaitee_pat, loop_expr); // `match ::std::future::IntoFuture::into_future(<expr>) { ... }` let into_future_span = self.mark_span_with_reason( @@ -799,11 +802,11 @@ impl<'hir> LoweringContext<'_, 'hir> { ); // match <into_future_expr> { - // mut pinned => loop { .. } + // mut __awaitee => loop { .. } // } hir::ExprKind::Match( into_future_expr, - arena_vec![self; pinned_arm], + arena_vec![self; awaitee_arm], hir::MatchSource::AwaitDesugar, ) } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 5b6147c7223..a778d8c5470 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -387,13 +387,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { if attr.has_name(sym::link) { for nested_meta in attr.meta_item_list().unwrap_or_default() { if nested_meta.has_name(sym::modifiers) { - gate_feature_post!( - self, - native_link_modifiers, - nested_meta.span(), - "native link modifiers are experimental" - ); - if let Some(modifiers) = nested_meta.value_str() { for modifier in modifiers.as_str().split(',') { if let Some(modifier) = modifier.strip_prefix(&['+', '-']) { @@ -412,7 +405,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_modifier!( "bundle" => native_link_modifiers_bundle "verbatim" => native_link_modifiers_verbatim - "whole-archive" => native_link_modifiers_whole_archive "as-needed" => native_link_modifiers_as_needed ); } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index a8fd5bb50a6..0007d8026e6 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -156,7 +156,6 @@ fn do_mir_borrowck<'a, 'tcx>( let tcx = infcx.tcx; let param_env = tcx.param_env(def.did); - let id = tcx.hir().local_def_id_to_hir_id(def.did); let mut local_names = IndexVec::from_elem(None, &input_body.local_decls); for var_debug_info in &input_body.var_debug_info { @@ -226,7 +225,7 @@ fn do_mir_borrowck<'a, 'tcx>( .iterate_to_fixpoint() .into_results_cursor(&body); - let locals_are_invalidated_at_exit = tcx.hir().body_owner_kind(id).is_fn_or_closure(); + let locals_are_invalidated_at_exit = tcx.hir().body_owner_kind(def.did).is_fn_or_closure(); let borrow_set = Rc::new(BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &mdpe.move_data)); @@ -289,8 +288,9 @@ fn do_mir_borrowck<'a, 'tcx>( .pass_name("borrowck") .iterate_to_fixpoint(); + let def_hir_id = tcx.hir().local_def_id_to_hir_id(def.did); let movable_generator = !matches!( - tcx.hir().get(id), + tcx.hir().get(def_hir_id), Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(.., Some(hir::Movability::Static)), .. @@ -385,7 +385,7 @@ fn do_mir_borrowck<'a, 'tcx>( let scope = mbcx.body.source_info(location).scope; let lint_root = match &mbcx.body.source_scopes[scope].local_data { ClearCrossCrate::Set(data) => data.lint_root, - _ => id, + _ => def_hir_id, }; // Span and message don't matter; we overwrite them below anyway diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index e9c64049817..0bf2eb17d1b 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -524,7 +524,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let tcx = self.infcx.tcx; let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.did.to_def_id()); - match tcx.hir().body_owner_kind(self.mir_hir_id) { + match tcx.hir().body_owner_kind(self.mir_def.did) { BodyOwnerKind::Closure | BodyOwnerKind::Fn => { let defining_ty = if self.mir_def.did.to_def_id() == typeck_root_def_id { tcx.type_of(typeck_root_def_id) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index dbbbbd5ecc0..548ae0e411d 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1844,7 +1844,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( // This change is somewhat breaking in practice due to local static libraries being linked // as whole-archive (#85144), so removing whole-archive may be a pre-requisite. if sess.opts.debugging_opts.link_native_libraries { - add_local_native_libraries(cmd, sess, codegen_results); + add_local_native_libraries(cmd, sess, codegen_results, crate_type); } // Upstream rust libraries and their nobundle static libraries @@ -2016,6 +2016,16 @@ fn add_order_independent_options( add_rpath_args(cmd, sess, codegen_results, out_filename); } +// A dylib may reexport symbols from the linked rlib or native static library. +// Even if some symbol is reexported it's still not necessarily counted as used and may be +// dropped, at least with `ld`-like ELF linkers. So we have to link some rlibs and static +// libraries as whole-archive to avoid losing reexported symbols. +// FIXME: Find a way to mark reexported symbols as used and avoid this use of whole-archive. +fn default_to_whole_archive(sess: &Session, crate_type: CrateType, cmd: &dyn Linker) -> bool { + crate_type == CrateType::Dylib + && !(sess.target.limit_rdylib_exports && cmd.exported_symbol_means_used_symbol()) +} + /// # Native library linking /// /// User-supplied library search paths (-L on the command line). These are the same paths used to @@ -2029,6 +2039,7 @@ fn add_local_native_libraries( cmd: &mut dyn Linker, sess: &Session, codegen_results: &CodegenResults, + crate_type: CrateType, ) { let filesearch = sess.target_filesearch(PathKind::All); for search_path in filesearch.search_paths() { @@ -2046,14 +2057,18 @@ fn add_local_native_libraries( codegen_results.crate_info.used_libraries.iter().filter(|l| relevant_lib(sess, l)); let search_path = OnceCell::new(); - let mut last = (NativeLibKind::Unspecified, None); + let mut last = (None, NativeLibKind::Unspecified, None); for lib in relevant_libs { let Some(name) = lib.name else { continue; }; // Skip if this library is the same as the last. - last = if (lib.kind, lib.name) == last { continue } else { (lib.kind, lib.name) }; + last = if (lib.name, lib.kind, lib.verbatim) == last { + continue; + } else { + (lib.name, lib.kind, lib.verbatim) + }; let verbatim = lib.verbatim.unwrap_or(false); match lib.kind { @@ -2064,15 +2079,19 @@ fn add_local_native_libraries( NativeLibKind::Framework { as_needed } => { cmd.link_framework(name, as_needed.unwrap_or(true)) } - NativeLibKind::Static { bundle: None | Some(true), .. } - | NativeLibKind::Static { whole_archive: Some(true), .. } => { - cmd.link_whole_staticlib( - name, - verbatim, - &search_path.get_or_init(|| archive_search_paths(sess)), - ); + NativeLibKind::Static { whole_archive, .. } => { + if whole_archive == Some(true) + || (whole_archive == None && default_to_whole_archive(sess, crate_type, cmd)) + { + cmd.link_whole_staticlib( + name, + verbatim, + &search_path.get_or_init(|| archive_search_paths(sess)), + ); + } else { + cmd.link_staticlib(name, verbatim) + } } - NativeLibKind::Static { .. } => cmd.link_staticlib(name, verbatim), NativeLibKind::RawDylib => { // FIXME(#58713): Proper handling for raw dylibs. bug!("raw_dylib feature not yet implemented"); @@ -2197,34 +2216,37 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( // external build system already has the native dependencies defined, and it // will provide them to the linker itself. if sess.opts.debugging_opts.link_native_libraries { - let mut last = None; + let mut last = (None, NativeLibKind::Unspecified, None); for lib in &codegen_results.crate_info.native_libraries[&cnum] { + let Some(name) = lib.name else { + continue; + }; if !relevant_lib(sess, lib) { - // Skip libraries if they are disabled by `#[link(cfg=...)]` continue; } // Skip if this library is the same as the last. - if last == lib.name { + last = if (lib.name, lib.kind, lib.verbatim) == last { continue; - } - - if let Some(static_lib_name) = lib.name { - if let NativeLibKind::Static { bundle: Some(false), whole_archive } = - lib.kind + } else { + (lib.name, lib.kind, lib.verbatim) + }; + + if let NativeLibKind::Static { bundle: Some(false), whole_archive } = + lib.kind + { + let verbatim = lib.verbatim.unwrap_or(false); + if whole_archive == Some(true) + || (whole_archive == None + && default_to_whole_archive(sess, crate_type, cmd)) { - let verbatim = lib.verbatim.unwrap_or(false); - if whole_archive == Some(true) { - cmd.link_whole_staticlib( - static_lib_name, - verbatim, - search_path.get_or_init(|| archive_search_paths(sess)), - ); - } else { - cmd.link_staticlib(static_lib_name, verbatim); - } - - last = lib.name; + cmd.link_whole_staticlib( + name, + verbatim, + search_path.get_or_init(|| archive_search_paths(sess)), + ); + } else { + cmd.link_staticlib(name, verbatim); } } } @@ -2282,15 +2304,10 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( let cratepath = &src.rlib.as_ref().unwrap().0; let mut link_upstream = |path: &Path| { - // If we're creating a dylib, then we need to include the - // whole of each object in our archive into that artifact. This is - // because a `dylib` can be reused as an intermediate artifact. - // - // Note, though, that we don't want to include the whole of a - // compiler-builtins crate (e.g., compiler-rt) because it'll get - // repeatedly linked anyway. + // We don't want to include the whole compiler-builtins crate (e.g., compiler-rt) + // regardless of the default because it'll get repeatedly linked anyway. let path = fix_windows_verbatim_for_gcc(path); - if crate_type == CrateType::Dylib + if default_to_whole_archive(sess, crate_type, cmd) && codegen_results.crate_info.compiler_builtins != Some(cnum) { cmd.link_whole_rlib(&path); @@ -2401,7 +2418,7 @@ fn add_upstream_native_libraries( sess: &Session, codegen_results: &CodegenResults, ) { - let mut last = (NativeLibKind::Unspecified, None); + let mut last = (None, NativeLibKind::Unspecified, None); for &cnum in &codegen_results.crate_info.used_crates { for lib in codegen_results.crate_info.native_libraries[&cnum].iter() { let Some(name) = lib.name else { @@ -2412,7 +2429,11 @@ fn add_upstream_native_libraries( } // Skip if this library is the same as the last. - last = if (lib.kind, lib.name) == last { continue } else { (lib.kind, lib.name) }; + last = if (lib.name, lib.kind, lib.verbatim) == last { + continue; + } else { + (lib.name, lib.kind, lib.verbatim) + }; let verbatim = lib.verbatim.unwrap_or(false); match lib.kind { diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index a838787381d..3a66bfafaf3 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -186,6 +186,9 @@ pub trait Linker { fn no_crt_objects(&mut self); fn no_default_libraries(&mut self); fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]); + fn exported_symbol_means_used_symbol(&self) -> bool { + true + } fn subsystem(&mut self, subsystem: &str); fn group_start(&mut self); fn group_end(&mut self); @@ -724,6 +727,10 @@ impl<'a> Linker for GccLinker<'a> { } } + fn exported_symbol_means_used_symbol(&self) -> bool { + self.sess.target.is_like_windows || self.sess.target.is_like_osx + } + fn subsystem(&mut self, subsystem: &str) { self.linker_arg("--subsystem"); self.linker_arg(&subsystem); @@ -1471,6 +1478,10 @@ impl<'a> Linker for L4Bender<'a> { return; } + fn exported_symbol_means_used_symbol(&self) -> bool { + false + } + fn subsystem(&mut self, subsystem: &str) { self.cmd.arg(&format!("--subsystem {}", subsystem)); } diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index df809e82701..946546263ea 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -38,7 +38,7 @@ fn eval_body_using_ecx<'mir, 'tcx>( || matches!( ecx.tcx.def_kind(cid.instance.def_id()), DefKind::Const - | DefKind::Static + | DefKind::Static(_) | DefKind::ConstParam | DefKind::AnonConst | DefKind::InlineConst diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 5a6a2b2c57b..18302ffdb8e 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -6,7 +6,7 @@ //! //! (In order to prevent the pathological case, we'd need to lazily construct the resulting //! `NamedMatch`es at the very end. It'd be a pain, and require more memory to keep around old -//! items, but it would also save overhead) +//! matcher positions, but it would also save overhead) //! //! We don't say this parser uses the Earley algorithm, because it's unnecessarily inaccurate. //! The macro parser restricts itself to the features of finite state automata. Earley parsers @@ -14,19 +14,19 @@ //! //! Quick intro to how the parser works: //! -//! A 'position' is a dot in the middle of a matcher, usually represented as a -//! dot. For example `· a $( a )* a b` is a position, as is `a $( · a )* a b`. +//! A "matcher position" (a.k.a. "position" or "mp") is a dot in the middle of a matcher, usually +//! written as a `·`. For example `· a $( a )* a b` is one, as is `a $( · a )* a b`. //! //! The parser walks through the input a character at a time, maintaining a list -//! of threads consistent with the current position in the input string: `cur_items`. +//! of threads consistent with the current position in the input string: `cur_mps`. //! -//! As it processes them, it fills up `eof_items` with threads that would be valid if -//! the macro invocation is now over, `bb_items` with threads that are waiting on -//! a Rust non-terminal like `$e:expr`, and `next_items` with threads that are waiting +//! As it processes them, it fills up `eof_mps` with threads that would be valid if +//! the macro invocation is now over, `bb_mps` with threads that are waiting on +//! a Rust non-terminal like `$e:expr`, and `next_mps` with threads that are waiting //! on a particular token. Most of the logic concerns moving the · through the //! repetitions indicated by Kleene stars. The rules for moving the · without //! consuming any input are called epsilon transitions. It only advances or calls -//! out to the real Rust parser when no `cur_items` threads remain. +//! out to the real Rust parser when no `cur_mps` threads remain. //! //! Example: //! @@ -40,28 +40,28 @@ //! //! Remaining input: a a a b //! cur: [a · $( a )* a b] -//! Descend/Skip (first item). +//! Descend/Skip (first position). //! next: [a $( · a )* a b] [a $( a )* · a b]. //! //! - - - Advance over an a. - - - //! //! Remaining input: a a b //! cur: [a $( a · )* a b] [a $( a )* a · b] -//! Follow epsilon transition: Finish/Repeat (first item) +//! Follow epsilon transition: Finish/Repeat (first position) //! next: [a $( a )* · a b] [a $( · a )* a b] [a $( a )* a · b] //! //! - - - Advance over an a. - - - (this looks exactly like the last step) //! //! Remaining input: a b //! cur: [a $( a · )* a b] [a $( a )* a · b] -//! Follow epsilon transition: Finish/Repeat (first item) +//! Follow epsilon transition: Finish/Repeat (first position) //! next: [a $( a )* · a b] [a $( · a )* a b] [a $( a )* a · b] //! //! - - - Advance over an a. - - - (this looks exactly like the last step) //! //! Remaining input: b //! cur: [a $( a · )* a b] [a $( a )* a · b] -//! Follow epsilon transition: Finish/Repeat (first item) +//! Follow epsilon transition: Finish/Repeat (first position) //! next: [a $( a )* · a b] [a $( · a )* a b] [a $( a )* a · b] //! //! - - - Advance over a b. - - - @@ -89,15 +89,13 @@ use std::borrow::Cow; use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::mem; -/// An unzipping of `TokenTree`s... see the `stack` field of `MatcherPos`. -/// /// This is used by `parse_tt_inner` to keep track of delimited submatchers that we have /// descended into. #[derive(Clone)] -struct MatcherTtFrame<'tt> { - /// The "parent" matcher that we are descending into. - elts: &'tt [TokenTree], - /// The position of the "dot" in `elts` at the time we descended. +struct MatcherPosFrame<'tt> { + /// The "parent" matcher that we have descended from. + tts: &'tt [TokenTree], + /// The position of the "dot" in `tt` at the time we descended. idx: usize, } @@ -110,128 +108,135 @@ type NamedMatchVec = SmallVec<[NamedMatch; 1]>; #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] rustc_data_structures::static_assert_size!(NamedMatchVec, 48); -/// Represents a single "position" (aka "matcher position", aka "item"), as -/// described in the module documentation. +/// A single matcher position, which could be within the top-level matcher, a submatcher, a +/// subsubmatcher, etc. For example: +/// ```text +/// macro_rules! m { $id:ident ( $($e:expr),* ) } => { ... } +/// <----------> second submatcher; one tt, one metavar +/// <--------------> first submatcher; three tts, zero metavars +/// <--------------------------> top-level matcher; two tts, one metavar +/// ``` #[derive(Clone)] struct MatcherPos<'tt> { - /// The token or slice of tokens that make up the matcher. `elts` is short for "elements". - top_elts: &'tt [TokenTree], + /// The tokens that make up the current matcher. When we are within a `Sequence` or `Delimited` + /// submatcher, this is just the contents of that submatcher. + tts: &'tt [TokenTree], - /// The position of the "dot" in this matcher + /// The "dot" position within the current submatcher, i.e. the index into `tts`. idx: usize, - /// For each named metavar in the matcher, we keep track of token trees matched against the - /// metavar by the black box parser. In particular, there may be more than one match per - /// metavar if we are in a repetition (each repetition matches each of the variables). - /// Moreover, matchers and repetitions can be nested; the `matches` field is shared (hence the - /// `Rc`) among all "nested" matchers. `match_lo`, `match_cur`, and `match_hi` keep track of - /// the current position of the `self` matcher position in the shared `matches` list. - /// - /// Also, note that while we are descending into a sequence, matchers are given their own - /// `matches` vector. Only once we reach the end of a full repetition of the sequence do we add - /// all bound matches from the submatcher into the shared top-level `matches` vector. If `sep` - /// and `up` are `Some`, then `matches` is _not_ the shared top-level list. Instead, if one - /// wants the shared `matches`, one should use `up.matches`. - matches: Box<[Lrc<NamedMatchVec>]>, - /// The position in `matches` corresponding to the first metavar in this matcher's sequence of - /// token trees. In other words, the first metavar in the first token of `top_elts` corresponds - /// to `matches[match_lo]`. + /// This vector ends up with one element per metavar in the *top-level* matcher, even when this + /// `MatcherPos` is for a submatcher. Each element records token trees matched against the + /// relevant metavar by the black box parser. The element will be a `MatchedSeq` if the + /// corresponding metavar is within a sequence. + matches: Lrc<NamedMatchVec>, + + /// The number of sequences this mp is within. + seq_depth: usize, + + /// The position in `matches` of the first metavar in this (sub)matcher. Zero if there are + /// no metavars. match_lo: usize, - /// The position in `matches` corresponding to the metavar we are currently trying to match - /// against the source token stream. `match_lo <= match_cur <= match_hi`. + + /// The position in `matches` of the next metavar to be matched against the source token + /// stream. Should not be used if there are no metavars. match_cur: usize, - /// Similar to `match_lo` except `match_hi` is the position in `matches` of the _last_ metavar - /// in this matcher. - match_hi: usize, - /// This field is only used if we are matching a repetition. - repetition: Option<MatcherPosRepetition<'tt>>, + /// This field is only used if we are matching a sequence. + sequence: Option<MatcherPosSequence<'tt>>, - /// Specifically used to "unzip" token trees. By "unzip", we mean to unwrap the delimiters from - /// a delimited token tree (e.g., something wrapped in `(` `)`) or to get the contents of a doc - /// comment... - /// - /// When matching against matchers with nested delimited submatchers (e.g., `pat ( pat ( .. ) - /// pat ) pat`), we need to keep track of the matchers we are descending into. This stack does - /// that where the bottom of the stack is the outermost matcher. - /// Also, throughout the comments, this "descent" is often referred to as "unzipping"... - stack: SmallVec<[MatcherTtFrame<'tt>; 1]>, + /// When we are within a `Delimited` submatcher (or subsubmatcher), this tracks the parent + /// matcher(s). The bottom of the stack is the top-level matcher. + stack: SmallVec<[MatcherPosFrame<'tt>; 1]>, } // This type is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(MatcherPos<'_>, 112); +rustc_data_structures::static_assert_size!(MatcherPos<'_>, 104); impl<'tt> MatcherPos<'tt> { - /// `len` `Vec`s (initially shared and empty) that will store matches of metavars. - fn create_matches(len: usize) -> Box<[Lrc<NamedMatchVec>]> { - if len == 0 { - vec![] - } else { - let empty_matches = Lrc::new(SmallVec::new()); - vec![empty_matches; len] - } - .into_boxed_slice() - } - - /// Generates the top-level matcher position in which the "dot" is before the first token of - /// the matcher `ms`. - fn new(ms: &'tt [TokenTree]) -> Self { - let match_idx_hi = count_names(ms); + fn top_level(matcher: &'tt [TokenTree], empty_matches: Lrc<NamedMatchVec>) -> Self { MatcherPos { - // Start with the top level matcher given to us. - top_elts: ms, - - // The "dot" is before the first token of the matcher. + tts: matcher, idx: 0, - - // Initialize `matches` to a bunch of empty `Vec`s -- one for each metavar in - // `top_elts`. `match_lo` for `top_elts` is 0 and `match_hi` is `match_idx_hi`. - // `match_cur` is 0 since we haven't actually matched anything yet. - matches: Self::create_matches(match_idx_hi), + matches: empty_matches, + seq_depth: 0, match_lo: 0, match_cur: 0, - match_hi: match_idx_hi, - - // Haven't descended into any delimiters, so this is empty. stack: smallvec![], - - // Haven't descended into any sequences, so this is `None`. - repetition: None, + sequence: None, } } - fn repetition(up: Box<MatcherPos<'tt>>, seq: &'tt SequenceRepetition) -> Self { - MatcherPos { - top_elts: &seq.tts, + fn sequence( + parent: Box<MatcherPos<'tt>>, + seq: &'tt SequenceRepetition, + empty_matches: Lrc<NamedMatchVec>, + ) -> Self { + let mut mp = MatcherPos { + tts: &seq.tts, idx: 0, - matches: Self::create_matches(up.matches.len()), - match_lo: up.match_cur, - match_cur: up.match_cur, - match_hi: up.match_cur + seq.num_captures, - repetition: Some(MatcherPosRepetition { up, seq }), + matches: parent.matches.clone(), + seq_depth: parent.seq_depth, + match_lo: parent.match_cur, + match_cur: parent.match_cur, + sequence: Some(MatcherPosSequence { parent, seq }), stack: smallvec![], + }; + // Start with an empty vec for each metavar within the sequence. Note that `mp.seq_depth` + // must have the parent's depth at this point for these `push_match` calls to work. + for idx in mp.match_lo..mp.match_lo + seq.num_captures { + mp.push_match(idx, MatchedSeq(empty_matches.clone())); } + mp.seq_depth += 1; + mp } /// Adds `m` as a named match for the `idx`-th metavar. fn push_match(&mut self, idx: usize, m: NamedMatch) { - let matches = Lrc::make_mut(&mut self.matches[idx]); - matches.push(m); + let matches = Lrc::make_mut(&mut self.matches); + match self.seq_depth { + 0 => { + // We are not within a sequence. Just append `m`. + assert_eq!(idx, matches.len()); + matches.push(m); + } + _ => { + // We are within a sequence. Find the final `MatchedSeq` at the appropriate depth + // and append `m` to its vector. + let mut curr = &mut matches[idx]; + for _ in 0..self.seq_depth - 1 { + match curr { + MatchedSeq(seq) => { + let seq = Lrc::make_mut(seq); + curr = seq.last_mut().unwrap(); + } + _ => unreachable!(), + } + } + match curr { + MatchedSeq(seq) => { + let seq = Lrc::make_mut(seq); + seq.push(m); + } + _ => unreachable!(), + } + } + } } } #[derive(Clone)] -struct MatcherPosRepetition<'tt> { - /// The "parent" matcher position. That is, the matcher position just before we enter the - /// sequence. - up: Box<MatcherPos<'tt>>, +struct MatcherPosSequence<'tt> { + /// The parent matcher position. Effectively gives a linked list of matches all the way to the + /// top-level matcher. + parent: Box<MatcherPos<'tt>>, /// The sequence itself. seq: &'tt SequenceRepetition, } -enum EofItems<'tt> { +enum EofMatcherPositions<'tt> { None, One(Box<MatcherPos<'tt>>), Multiple, @@ -254,24 +259,24 @@ crate enum ParseResult<T> { /// of metavars to the token trees they bind to. crate type NamedParseResult = ParseResult<FxHashMap<MacroRulesNormalizedIdent, NamedMatch>>; -/// Count how many metavars are named in the given matcher `ms`. -pub(super) fn count_names(ms: &[TokenTree]) -> usize { - ms.iter().fold(0, |count, elt| { - count - + match elt { - TokenTree::Delimited(_, delim) => count_names(delim.inner_tts()), +/// Count how many metavars declarations are in `matcher`. +pub(super) fn count_metavar_decls(matcher: &[TokenTree]) -> usize { + matcher + .iter() + .map(|tt| { + match tt { + TokenTree::Delimited(_, delim) => count_metavar_decls(delim.inner_tts()), TokenTree::MetaVar(..) => 0, TokenTree::MetaVarDecl(..) => 1, - // Panicking here would abort execution because `parse_tree` makes use of this - // function. In other words, RHS meta-variable expressions eventually end-up here. - // - // `0` is still returned to inform that no meta-variable was found. `Meta-variables - // != Meta-variable expressions` + // RHS meta-variable expressions eventually end-up here. `0` is returned to inform + // that no meta-variable was found, because "meta-variables" != "meta-variable + // expressions". TokenTree::MetaVarExpr(..) => 0, TokenTree::Sequence(_, seq) => seq.num_captures, TokenTree::Token(..) => 0, } - }) + }) + .sum() } /// `NamedMatch` is a pattern-match result for a single metavar. All @@ -331,11 +336,9 @@ crate enum NamedMatch { MatchedNonterminal(Lrc<Nonterminal>), } -/// Takes a slice of token trees `ms` representing a matcher which successfully matched input -/// and an iterator of items that matched input and produces a `NamedParseResult`. fn nameize<I: Iterator<Item = NamedMatch>>( sess: &ParseSess, - ms: &[TokenTree], + matcher: &[TokenTree], mut res: I, ) -> NamedParseResult { // Recursively descend into each type of matcher (e.g., sequences, delimited, metavars) and make @@ -344,11 +347,11 @@ fn nameize<I: Iterator<Item = NamedMatch>>( // `NamedParseResult`. fn n_rec<I: Iterator<Item = NamedMatch>>( sess: &ParseSess, - m: &TokenTree, + tt: &TokenTree, res: &mut I, ret_val: &mut FxHashMap<MacroRulesNormalizedIdent, NamedMatch>, ) -> Result<(), (rustc_span::Span, String)> { - match *m { + match *tt { TokenTree::Sequence(_, ref seq) => { for next_m in &seq.tts { n_rec(sess, next_m, res.by_ref(), ret_val)? @@ -380,8 +383,8 @@ fn nameize<I: Iterator<Item = NamedMatch>>( } let mut ret_val = FxHashMap::default(); - for m in ms { - match n_rec(sess, m, res.by_ref(), &mut ret_val) { + for tt in matcher { + match n_rec(sess, tt, res.by_ref(), &mut ret_val) { Ok(_) => {} Err((sp, msg)) => return Error(sp, msg), } @@ -401,86 +404,96 @@ fn token_name_eq(t1: &Token, t2: &Token) -> bool { } } -// Note: the item vectors could be created and dropped within `parse_tt`, but to avoid excess +// Note: the position vectors could be created and dropped within `parse_tt`, but to avoid excess // allocations we have a single vector fo each kind that is cleared and reused repeatedly. pub struct TtParser<'tt> { macro_name: Ident, - /// The set of current items to be processed. This should be empty by the end of a successful + /// The set of current mps to be processed. This should be empty by the end of a successful /// execution of `parse_tt_inner`. - cur_items: Vec<Box<MatcherPos<'tt>>>, + cur_mps: Vec<Box<MatcherPos<'tt>>>, - /// The set of newly generated items. These are used to replenish `cur_items` in the function + /// The set of newly generated mps. These are used to replenish `cur_mps` in the function /// `parse_tt`. - next_items: Vec<Box<MatcherPos<'tt>>>, + next_mps: Vec<Box<MatcherPos<'tt>>>, - /// The set of items that are waiting for the black-box parser. - bb_items: Vec<Box<MatcherPos<'tt>>>, + /// The set of mps that are waiting for the black-box parser. + bb_mps: Vec<Box<MatcherPos<'tt>>>, + + /// Pre-allocate an empty match array, so it can be cloned cheaply for macros with many rules + /// that have no metavars. + empty_matches: Lrc<NamedMatchVec>, } impl<'tt> TtParser<'tt> { pub(super) fn new(macro_name: Ident) -> TtParser<'tt> { - TtParser { macro_name, cur_items: vec![], next_items: vec![], bb_items: vec![] } + TtParser { + macro_name, + cur_mps: vec![], + next_mps: vec![], + bb_mps: vec![], + empty_matches: Lrc::new(smallvec![]), + } } - /// Process the matcher positions of `cur_items` until it is empty. In the process, this will - /// produce more items in `next_items` and `bb_items`. - /// - /// For more info about the how this happens, see the module-level doc comments and the inline - /// comments of this function. + /// Process the matcher positions of `cur_mps` until it is empty. In the process, this will + /// produce more mps in `next_mps` and `bb_mps`. /// /// # Returns /// /// `Some(result)` if everything is finished, `None` otherwise. Note that matches are kept - /// track of through the items generated. + /// track of through the mps generated. fn parse_tt_inner( &mut self, sess: &ParseSess, - ms: &[TokenTree], + matcher: &[TokenTree], token: &Token, ) -> Option<NamedParseResult> { // Matcher positions that would be valid if the macro invocation was over now. Only // modified if `token == Eof`. - let mut eof_items = EofItems::None; - - while let Some(mut item) = self.cur_items.pop() { - // When unzipped trees end, remove them. This corresponds to backtracking out of a - // delimited submatcher into which we already descended. When backtracking out again, we - // need to advance the "dot" past the delimiters in the outer matcher. - while item.idx >= item.top_elts.len() { - match item.stack.pop() { - Some(MatcherTtFrame { elts, idx }) => { - item.top_elts = elts; - item.idx = idx + 1; + let mut eof_mps = EofMatcherPositions::None; + + while let Some(mut mp) = self.cur_mps.pop() { + // Backtrack out of delimited submatcher when necessary. When backtracking out again, + // we need to advance the "dot" past the delimiters in the parent matcher(s). + while mp.idx >= mp.tts.len() { + match mp.stack.pop() { + Some(MatcherPosFrame { tts, idx }) => { + mp.tts = tts; + mp.idx = idx + 1; } None => break, } } - // Get the current position of the "dot" (`idx`) in `item` and the number of token + // Get the current position of the "dot" (`idx`) in `mp` and the number of token // trees in the matcher (`len`). - let idx = item.idx; - let len = item.top_elts.len(); + let idx = mp.idx; + let len = mp.tts.len(); if idx < len { // We are in the middle of a matcher. Compare the matcher's current tt against // `token`. - match &item.top_elts[idx] { + match &mp.tts[idx] { TokenTree::Sequence(_sp, seq) => { let op = seq.kleene.op; if op == mbe::KleeneOp::ZeroOrMore || op == mbe::KleeneOp::ZeroOrOne { // Allow for the possibility of zero matches of this sequence. - let mut new_item = item.clone(); - new_item.match_cur += seq.num_captures; - new_item.idx += 1; - for idx in item.match_cur..item.match_cur + seq.num_captures { - new_item.push_match(idx, MatchedSeq(Lrc::new(smallvec![]))); + let mut new_mp = mp.clone(); + new_mp.match_cur += seq.num_captures; + new_mp.idx += 1; + for idx in mp.match_cur..mp.match_cur + seq.num_captures { + new_mp.push_match(idx, MatchedSeq(self.empty_matches.clone())); } - self.cur_items.push(new_item); + self.cur_mps.push(new_mp); } // Allow for the possibility of one or more matches of this sequence. - self.cur_items.push(box MatcherPos::repetition(item, &seq)); + self.cur_mps.push(box MatcherPos::sequence( + mp, + &seq, + self.empty_matches.clone(), + )); } &TokenTree::MetaVarDecl(span, _, None) => { @@ -497,61 +510,63 @@ impl<'tt> TtParser<'tt> { // We use the span of the metavariable declaration to determine any // edition-specific matching behavior for non-terminals. if Parser::nonterminal_may_begin_with(kind, token) { - self.bb_items.push(item); + self.bb_mps.push(mp); } } TokenTree::Delimited(_, delimited) => { // To descend into a delimited submatcher, we push the current matcher onto - // a stack and push a new item containing the submatcher onto `cur_items`. + // a stack and push a new mp containing the submatcher onto `cur_mps`. // // At the beginning of the loop, if we reach the end of the delimited // submatcher, we pop the stack to backtrack out of the descent. Note that // we use `all_tts` to include the open and close delimiter tokens. - let lower_elts = mem::replace(&mut item.top_elts, &delimited.all_tts); - let idx = item.idx; - item.stack.push(MatcherTtFrame { elts: lower_elts, idx }); - item.idx = 0; - self.cur_items.push(item); + let tts = mem::replace(&mut mp.tts, &delimited.all_tts); + let idx = mp.idx; + mp.stack.push(MatcherPosFrame { tts, idx }); + mp.idx = 0; + self.cur_mps.push(mp); } TokenTree::Token(t) => { // If it's a doc comment, we just ignore it and move on to the next tt in - // the matcher. If the token matches, we can just advance the parser. + // the matcher. This is a bug, but #95267 showed that existing programs + // rely on this behaviour, and changing it would require some care and a + // transition period. + // + // If the token matches, we can just advance the parser. + // // Otherwise, this match has failed, there is nothing to do, and hopefully - // another item in `cur_items` will match. + // another mp in `cur_mps` will match. if matches!(t, Token { kind: DocComment(..), .. }) { - item.idx += 1; - self.cur_items.push(item); + mp.idx += 1; + self.cur_mps.push(mp); } else if token_name_eq(&t, token) { - item.idx += 1; - self.next_items.push(item); + mp.idx += 1; + self.next_mps.push(mp); } } // These cannot appear in a matcher. TokenTree::MetaVar(..) | TokenTree::MetaVarExpr(..) => unreachable!(), } - } else if let Some(repetition) = &item.repetition { - // We are past the end of a repetition. + } else if let Some(sequence) = &mp.sequence { + // We are past the end of a sequence. debug_assert!(idx <= len + 1); if idx == len { - // Add all matches from the sequence to `up`, and move the "dot" past the - // repetition in `up`. This allows for the case where the sequence matching is - // finished. - let mut new_pos = repetition.up.clone(); - for idx in item.match_lo..item.match_hi { - let sub = item.matches[idx].clone(); - new_pos.push_match(idx, MatchedSeq(sub)); - } - new_pos.match_cur = item.match_hi; - new_pos.idx += 1; - self.cur_items.push(new_pos); + // Add all matches from the sequence to `parent`, and move the "dot" past the + // sequence in `parent`. This allows for the case where the sequence matching + // is finished. + let mut new_mp = sequence.parent.clone(); + new_mp.matches = mp.matches.clone(); + new_mp.match_cur = mp.match_lo + sequence.seq.num_captures; + new_mp.idx += 1; + self.cur_mps.push(new_mp); } - if idx == len && repetition.seq.separator.is_some() { - if repetition + if idx == len && sequence.seq.separator.is_some() { + if sequence .seq .separator .as_ref() @@ -559,25 +574,27 @@ impl<'tt> TtParser<'tt> { { // The matcher has a separator, and it matches the current token. We can // advance past the separator token. - item.idx += 1; - self.next_items.push(item); + mp.idx += 1; + self.next_mps.push(mp); } - } else if repetition.seq.kleene.op != mbe::KleeneOp::ZeroOrOne { + } else if sequence.seq.kleene.op != mbe::KleeneOp::ZeroOrOne { // We don't need a separator. Move the "dot" back to the beginning of the // matcher and try to match again UNLESS we are only allowed to have _one_ // repetition. - item.match_cur = item.match_lo; - item.idx = 0; - self.cur_items.push(item); + mp.match_cur = mp.match_lo; + mp.idx = 0; + self.cur_mps.push(mp); } } else { - // We are past the end of the matcher, and not in a repetition. Look for end of + // We are past the end of the matcher, and not in a sequence. Look for end of // input. debug_assert_eq!(idx, len); if *token == token::Eof { - eof_items = match eof_items { - EofItems::None => EofItems::One(item), - EofItems::One(_) | EofItems::Multiple => EofItems::Multiple, + eof_mps = match eof_mps { + EofMatcherPositions::None => EofMatcherPositions::One(mp), + EofMatcherPositions::One(_) | EofMatcherPositions::Multiple => { + EofMatcherPositions::Multiple + } } } } @@ -586,16 +603,18 @@ impl<'tt> TtParser<'tt> { // If we reached the end of input, check that there is EXACTLY ONE possible matcher. // Otherwise, either the parse is ambiguous (which is an error) or there is a syntax error. if *token == token::Eof { - Some(match eof_items { - EofItems::One(mut eof_item) => { - let matches = - eof_item.matches.iter_mut().map(|dv| Lrc::make_mut(dv).pop().unwrap()); - nameize(sess, ms, matches) + Some(match eof_mps { + EofMatcherPositions::One(mut eof_mp) => { + assert_eq!(eof_mp.matches.len(), count_metavar_decls(matcher)); + // Need to take ownership of the matches from within the `Lrc`. + Lrc::make_mut(&mut eof_mp.matches); + let matches = Lrc::try_unwrap(eof_mp.matches).unwrap().into_iter(); + nameize(sess, matcher, matches) } - EofItems::Multiple => { + EofMatcherPositions::Multiple => { Error(token.span, "ambiguity: multiple successful parses".to_string()) } - EofItems::None => Failure( + EofMatcherPositions::None => Failure( Token::new( token::Eof, if token.span.is_dummy() { token.span } else { token.span.shrink_to_hi() }, @@ -608,36 +627,35 @@ impl<'tt> TtParser<'tt> { } } - /// Use the given slice of token trees (`ms`) as a matcher. Match the token stream from the - /// given `parser` against it and return the match. + /// Match the token stream from `parser` against `matcher`. pub(super) fn parse_tt( &mut self, parser: &mut Cow<'_, Parser<'_>>, - ms: &'tt [TokenTree], + matcher: &'tt [TokenTree], ) -> NamedParseResult { // A queue of possible matcher positions. We initialize it with the matcher position in - // which the "dot" is before the first token of the first token tree in `ms`. + // which the "dot" is before the first token of the first token tree in `matcher`. // `parse_tt_inner` then processes all of these possible matcher positions and produces - // possible next positions into `next_items`. After some post-processing, the contents of - // `next_items` replenish `cur_items` and we start over again. - self.cur_items.clear(); - self.cur_items.push(box MatcherPos::new(ms)); + // possible next positions into `next_mps`. After some post-processing, the contents of + // `next_mps` replenish `cur_mps` and we start over again. + self.cur_mps.clear(); + self.cur_mps.push(box MatcherPos::top_level(matcher, self.empty_matches.clone())); loop { - self.next_items.clear(); - self.bb_items.clear(); + self.next_mps.clear(); + self.bb_mps.clear(); - // Process `cur_items` until either we have finished the input or we need to get some + // Process `cur_mps` until either we have finished the input or we need to get some // parsing from the black-box parser done. - if let Some(result) = self.parse_tt_inner(parser.sess, ms, &parser.token) { + if let Some(result) = self.parse_tt_inner(parser.sess, matcher, &parser.token) { return result; } - // `parse_tt_inner` handled all cur_items, so it's empty. - assert!(self.cur_items.is_empty()); + // `parse_tt_inner` handled all of `cur_mps`, so it's empty. + assert!(self.cur_mps.is_empty()); // Error messages here could be improved with links to original rules. - match (self.next_items.len(), self.bb_items.len()) { + match (self.next_mps.len(), self.bb_mps.len()) { (0, 0) => { // There are no possible next positions AND we aren't waiting for the black-box // parser: syntax error. @@ -648,17 +666,17 @@ impl<'tt> TtParser<'tt> { } (_, 0) => { - // Dump all possible `next_items` into `cur_items` for the next iteration. Then + // Dump all possible `next_mps` into `cur_mps` for the next iteration. Then // process the next token. - self.cur_items.extend(self.next_items.drain(..)); + self.cur_mps.extend(self.next_mps.drain(..)); parser.to_mut().bump(); } (0, 1) => { // We need to call the black-box parser to get some nonterminal. - let mut item = self.bb_items.pop().unwrap(); - if let TokenTree::MetaVarDecl(span, _, Some(kind)) = item.top_elts[item.idx] { - let match_cur = item.match_cur; + let mut mp = self.bb_mps.pop().unwrap(); + if let TokenTree::MetaVarDecl(span, _, Some(kind)) = mp.tts[mp.idx] { + let match_cur = mp.match_cur; // We use the span of the metavariable declaration to determine any // edition-specific matching behavior for non-terminals. let nt = match parser.to_mut().parse_nonterminal(kind) { @@ -678,13 +696,13 @@ impl<'tt> TtParser<'tt> { NtOrTt::Nt(nt) => MatchedNonterminal(Lrc::new(nt)), NtOrTt::Tt(tt) => MatchedTokenTree(tt), }; - item.push_match(match_cur, m); - item.idx += 1; - item.match_cur += 1; + mp.push_match(match_cur, m); + mp.idx += 1; + mp.match_cur += 1; } else { unreachable!() } - self.cur_items.push(item); + self.cur_mps.push(mp); } (_, _) => { @@ -693,15 +711,15 @@ impl<'tt> TtParser<'tt> { } } - assert!(!self.cur_items.is_empty()); + assert!(!self.cur_mps.is_empty()); } } fn ambiguity_error(&self, token_span: rustc_span::Span) -> NamedParseResult { let nts = self - .bb_items + .bb_mps .iter() - .map(|item| match item.top_elts[item.idx] { + .map(|mp| match mp.tts[mp.idx] { TokenTree::MetaVarDecl(_, bind, Some(kind)) => { format!("{} ('{}')", kind, bind) } @@ -715,7 +733,7 @@ impl<'tt> TtParser<'tt> { format!( "local ambiguity when calling macro `{}`: multiple parsing options: {}", self.macro_name, - match self.next_items.len() { + match self.next_mps.len() { 0 => format!("built-in NTs {}.", nts), 1 => format!("built-in NTs {} or 1 other option.", nts), n => format!("built-in NTs {} or {} other options.", nts, n), diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index b3ed6b8e4db..d91871c7e57 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -211,7 +211,7 @@ fn parse_tree( let (separator, kleene) = parse_sep_and_kleene_op(&mut trees, delim_span.entire(), sess); // Count the number of captured "names" (i.e., named metavars) - let name_captures = macro_parser::count_names(&sequence); + let name_captures = macro_parser::count_metavar_decls(&sequence); TokenTree::Sequence( delim_span, Lrc::new(SequenceRepetition { diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index ace0c9df58d..e37251c9c24 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -215,6 +215,10 @@ declare_features! ( /// Allows patterns with concurrent by-move and by-ref bindings. /// For example, you can write `Foo(a, ref b)` where `a` is by-move and `b` is by-ref. (accepted, move_ref_pattern, "1.49.0", Some(68354), None), + /// Allows specifying modifiers in the link attribute: `#[link(modifiers = "...")]` + (accepted, native_link_modifiers, "1.61.0", Some(81490), None), + /// Allows specifying the whole-archive link modifier + (accepted, native_link_modifiers_whole_archive, "1.61.0", Some(81490), None), /// Allows using `#![no_std]`. (accepted, no_std, "1.6.0", None, None), /// Allows defining identifiers beyond ASCII. diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index feef7295254..28466315c86 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -400,6 +400,8 @@ declare_features! ( (active, generic_arg_infer, "1.55.0", Some(85077), None), /// Allows associated types to be generic, e.g., `type Foo<T>;` (RFC 1598). (active, generic_associated_types, "1.23.0", Some(44265), None), + /// An extension to the `generic_associated_types` feature, allowing incomplete features. + (incomplete, generic_associated_types_extended, "1.61.0", Some(95451), None), /// Allows non-trivial generic constants which have to have wfness manually propagated to callers (incomplete, generic_const_exprs, "1.56.0", Some(76560), None), /// Allows using `..X`, `..=X`, `...X`, and `X..` as a pattern. @@ -446,16 +448,12 @@ declare_features! ( (active, must_not_suspend, "1.57.0", Some(83310), None), /// Allows using `#[naked]` on functions. (active, naked_functions, "1.9.0", Some(32408), None), - /// Allows specifying modifiers in the link attribute: `#[link(modifiers = "...")]` - (active, native_link_modifiers, "1.53.0", Some(81490), None), /// Allows specifying the as-needed link modifier (active, native_link_modifiers_as_needed, "1.53.0", Some(81490), None), /// Allows specifying the bundle link modifier (active, native_link_modifiers_bundle, "1.53.0", Some(81490), None), /// Allows specifying the verbatim link modifier (active, native_link_modifiers_verbatim, "1.53.0", Some(81490), None), - /// Allows specifying the whole-archive link modifier - (active, native_link_modifiers_whole_archive, "1.53.0", Some(81490), None), /// Allow negative trait implementations. (active, negative_impls, "1.44.0", Some(68318), None), /// Allows the `!` type. Does not imply 'exhaustive_patterns' (below) any more. diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index a2f97f65708..352f369f0d4 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -78,7 +78,7 @@ pub enum DefKind { Const, /// Constant generic parameter: `struct Foo<const N: usize> { ... }` ConstParam, - Static, + Static(ast::Mutability), /// Refers to the struct or enum variant's constructor. /// /// The reason `Ctor` exists in addition to [`DefKind::Struct`] and @@ -128,7 +128,7 @@ impl DefKind { "crate" } DefKind::Mod => "module", - DefKind::Static => "static", + DefKind::Static(..) => "static", DefKind::Enum => "enum", DefKind::Variant => "variant", DefKind::Ctor(CtorOf::Variant, CtorKind::Fn) => "tuple variant", @@ -202,7 +202,7 @@ impl DefKind { DefKind::Fn | DefKind::Const | DefKind::ConstParam - | DefKind::Static + | DefKind::Static(..) | DefKind::Ctor(..) | DefKind::AssocFn | DefKind::AssocConst => Some(Namespace::ValueNS), diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 19fc77fb74b..10871df3ab9 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1530,7 +1530,7 @@ impl Expr<'_> { pub fn is_place_expr(&self, mut allow_projections_from: impl FnMut(&Self) -> bool) -> bool { match self.kind { ExprKind::Path(QPath::Resolved(_, ref path)) => { - matches!(path.res, Res::Local(..) | Res::Def(DefKind::Static, _) | Res::Err) + matches!(path.res, Res::Local(..) | Res::Def(DefKind::Static(_), _) | Res::Err) } // Type ascription inherits its place expression kind from its diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index 5b8300ab530..a41e0374f41 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -161,15 +161,15 @@ pub enum LiteralKind { /// "b"abc"", "b"abc" ByteStr { terminated: bool }, /// "r"abc"", "r#"abc"#", "r####"ab"###"c"####", "r#"a" - RawStr { n_hashes: u16, err: Option<RawStrError> }, + RawStr { n_hashes: u8, err: Option<RawStrError> }, /// "br"abc"", "br#"abc"#", "br####"ab"###"c"####", "br#"a" - RawByteStr { n_hashes: u16, err: Option<RawStrError> }, + RawByteStr { n_hashes: u8, err: Option<RawStrError> }, } /// Error produced validating a raw string. Represents cases like: /// - `r##~"abcde"##`: `InvalidStarter` /// - `r###"abcde"##`: `NoTerminator { expected: 3, found: 2, possible_terminator_offset: Some(11)` -/// - Too many `#`s (>65535): `TooManyDelimiters` +/// - Too many `#`s (>255): `TooManyDelimiters` // perf note: It doesn't matter that this makes `Token` 36 bytes bigger. See #77629 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum RawStrError { @@ -178,7 +178,7 @@ pub enum RawStrError { /// The string was never terminated. `possible_terminator_offset` is the number of characters after `r` or `br` where they /// may have intended to terminate it. NoTerminator { expected: usize, found: usize, possible_terminator_offset: Option<usize> }, - /// More than 65535 `#`s exist. + /// More than 255 `#`s exist. TooManyDelimiters { found: usize }, } @@ -698,12 +698,12 @@ impl Cursor<'_> { } /// Eats the double-quoted string and returns `n_hashes` and an error if encountered. - fn raw_double_quoted_string(&mut self, prefix_len: usize) -> (u16, Option<RawStrError>) { + fn raw_double_quoted_string(&mut self, prefix_len: usize) -> (u8, Option<RawStrError>) { // Wrap the actual function to handle the error with too many hashes. // This way, it eats the whole raw string. let (n_hashes, err) = self.raw_string_unvalidated(prefix_len); - // Only up to 65535 `#`s are allowed in raw strings - match u16::try_from(n_hashes) { + // Only up to 255 `#`s are allowed in raw strings + match u8::try_from(n_hashes) { Ok(num) => (num, err), // We lie about the number of hashes here :P Err(_) => (0, Some(RawStrError::TooManyDelimiters { found: n_hashes })), diff --git a/compiler/rustc_lexer/src/tests.rs b/compiler/rustc_lexer/src/tests.rs index 548de67449a..07daee06f0f 100644 --- a/compiler/rustc_lexer/src/tests.rs +++ b/compiler/rustc_lexer/src/tests.rs @@ -2,7 +2,7 @@ use super::*; use expect_test::{expect, Expect}; -fn check_raw_str(s: &str, expected_hashes: u16, expected_err: Option<RawStrError>) { +fn check_raw_str(s: &str, expected_hashes: u8, expected_err: Option<RawStrError>) { let s = &format!("r{}", s); let mut cursor = Cursor::new(s); cursor.bump(); @@ -68,13 +68,13 @@ fn test_unterminated_no_pound() { #[test] fn test_too_many_hashes() { - let max_count = u16::MAX; + let max_count = u8::MAX; let mut hashes: String = "#".repeat(max_count.into()); - // Valid number of hashes (65535 = 2^16 - 1), but invalid string. + // Valid number of hashes (255 = 2^8 - 1 = u8::MAX), but invalid string. check_raw_str(&hashes, max_count, Some(RawStrError::InvalidStarter { bad_char: '\u{0}' })); - // One more hash sign (65536 = 2^16) becomes too many. + // One more hash sign (256 = 2^8) becomes too many. hashes.push('#'); check_raw_str( &hashes, diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs index 8476c2bfcc4..0324ac3641e 100644 --- a/compiler/rustc_llvm/src/lib.rs +++ b/compiler/rustc_llvm/src/lib.rs @@ -1,5 +1,5 @@ #![feature(nll)] -#![feature(native_link_modifiers)] +#![cfg_attr(bootstrap, feature(native_link_modifiers))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] // NOTE: This crate only exists to allow linking on mingw targets. diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index c3a76112391..1cbfb0bd554 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -125,13 +125,18 @@ impl<'tcx> ItemLikeVisitor<'tcx> for Collector<'tcx> { // Do this outside the above loop so we don't depend on modifiers coming // after kinds - if let Some(item) = items.iter().find(|item| item.has_name(sym::modifiers)) { + let mut modifiers_count = 0; + for item in items.iter().filter(|item| item.has_name(sym::modifiers)) { if let Some(modifiers) = item.value_str() { + modifiers_count += 1; let span = item.name_value_literal_span().unwrap(); + let mut has_duplicate_modifiers = false; for modifier in modifiers.as_str().split(',') { let (modifier, value) = match modifier.strip_prefix(&['+', '-']) { Some(m) => (m, modifier.starts_with('+')), None => { + // Note: this error also excludes the case with empty modifier + // string, like `modifiers = ""`. sess.span_err( span, "invalid linking modifier syntax, expected '+' or '-' prefix \ @@ -143,6 +148,9 @@ impl<'tcx> ItemLikeVisitor<'tcx> for Collector<'tcx> { match (modifier, &mut lib.kind) { ("bundle", NativeLibKind::Static { bundle, .. }) => { + if bundle.is_some() { + has_duplicate_modifiers = true; + } *bundle = Some(value); } ("bundle", _) => { @@ -153,9 +161,17 @@ impl<'tcx> ItemLikeVisitor<'tcx> for Collector<'tcx> { ); } - ("verbatim", _) => lib.verbatim = Some(value), + ("verbatim", _) => { + if lib.verbatim.is_some() { + has_duplicate_modifiers = true; + } + lib.verbatim = Some(value); + } ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => { + if whole_archive.is_some() { + has_duplicate_modifiers = true; + } *whole_archive = Some(value); } ("whole-archive", _) => { @@ -168,6 +184,9 @@ impl<'tcx> ItemLikeVisitor<'tcx> for Collector<'tcx> { ("as-needed", NativeLibKind::Dylib { as_needed }) | ("as-needed", NativeLibKind::Framework { as_needed }) => { + if as_needed.is_some() { + has_duplicate_modifiers = true; + } *as_needed = Some(value); } ("as-needed", _) => { @@ -190,12 +209,22 @@ impl<'tcx> ItemLikeVisitor<'tcx> for Collector<'tcx> { } } } + if has_duplicate_modifiers { + let msg = + "same modifier is used multiple times in a single `modifiers` argument"; + sess.span_err(item.span(), msg); + } } else { let msg = "must be of the form `#[link(modifiers = \"...\")]`"; sess.span_err(item.span(), msg); } } + if modifiers_count > 1 { + let msg = "multiple `modifiers` arguments in a single `#[link]` attribute"; + sess.span_err(m.span, msg); + } + // In general we require #[link(name = "...")] but we allow // #[link(wasm_import_module = "...")] without the `name`. let requires_name = kind_specified || lib.wasm_import_module.is_none(); @@ -349,6 +378,15 @@ impl Collector<'_> { .drain_filter(|lib| { if let Some(lib_name) = lib.name { if lib_name.as_str() == passed_lib.name { + // FIXME: This whole logic is questionable, whether modifiers are + // involved or not, library reordering and kind overriding without + // explicit `:rename` in particular. + if lib.has_modifiers() || passed_lib.has_modifiers() { + self.tcx.sess.span_err( + self.tcx.def_span(lib.foreign_module.unwrap()), + "overriding linking modifiers from command line is not supported" + ); + } if passed_lib.kind != NativeLibKind::Unspecified { lib.kind = passed_lib.kind; } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index e88ef68c722..8c765249007 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1464,21 +1464,11 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { fn is_foreign_item(self, id: DefIndex) -> bool { match self.kind(id) { - EntryKind::ForeignImmStatic | EntryKind::ForeignMutStatic | EntryKind::ForeignFn(_) => { - true - } + EntryKind::ForeignStatic | EntryKind::ForeignFn(_) => true, _ => false, } } - fn static_mutability(self, id: DefIndex) -> Option<hir::Mutability> { - match self.kind(id) { - EntryKind::ImmStatic | EntryKind::ForeignImmStatic => Some(hir::Mutability::Not), - EntryKind::MutStatic | EntryKind::ForeignMutStatic => Some(hir::Mutability::Mut), - _ => None, - } - } - #[inline] fn def_key(self, index: DefIndex) -> DefKey { *self diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 70358ae0e22..5a2c59b4601 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -165,7 +165,6 @@ provide! { <'tcx> tcx, def_id, other, cdata, inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) } is_const_fn_raw => { cdata.is_const_fn_raw(def_id.index) } is_foreign_item => { cdata.is_foreign_item(def_id.index) } - static_mutability => { cdata.static_mutability(def_id.index) } item_attrs => { tcx.arena.alloc_from_iter(cdata.get_item_attrs(def_id.index, tcx.sess)) } trait_of_item => { cdata.get_trait_of_item(def_id.index) } is_mir_available => { cdata.is_item_mir_available(def_id.index) } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index a219b9eb2be..4541cf2c059 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -797,7 +797,7 @@ fn should_encode_visibility(def_kind: DefKind) -> bool { | DefKind::AssocTy | DefKind::Fn | DefKind::Const - | DefKind::Static + | DefKind::Static(..) | DefKind::Ctor(..) | DefKind::AssocFn | DefKind::AssocConst @@ -831,7 +831,7 @@ fn should_encode_stability(def_kind: DefKind) -> bool { | DefKind::AssocConst | DefKind::TyParam | DefKind::ConstParam - | DefKind::Static + | DefKind::Static(..) | DefKind::Const | DefKind::Fn | DefKind::ForeignMod @@ -875,7 +875,7 @@ fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) { DefKind::AnonConst | DefKind::InlineConst | DefKind::AssocConst - | DefKind::Static + | DefKind::Static(..) | DefKind::Const => (true, false), // Full-fledged functions DefKind::AssocFn | DefKind::Fn => { @@ -920,7 +920,7 @@ fn should_encode_variances(def_kind: DefKind) -> bool { | DefKind::AssocConst | DefKind::TyParam | DefKind::ConstParam - | DefKind::Static + | DefKind::Static(..) | DefKind::Const | DefKind::ForeignMod | DefKind::TyAlias @@ -954,7 +954,7 @@ fn should_encode_generics(def_kind: DefKind) -> bool { | DefKind::AssocTy | DefKind::Fn | DefKind::Const - | DefKind::Static + | DefKind::Static(..) | DefKind::Ctor(..) | DefKind::AssocFn | DefKind::AssocConst @@ -1390,8 +1390,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.encode_ident_span(def_id, item.ident); let entry_kind = match item.kind { - hir::ItemKind::Static(_, hir::Mutability::Mut, _) => EntryKind::MutStatic, - hir::ItemKind::Static(_, hir::Mutability::Not, _) => EntryKind::ImmStatic, + hir::ItemKind::Static(..) => EntryKind::Static, hir::ItemKind::Const(_, body_id) => { let qualifs = self.tcx.at(item.span).mir_const_qualif(def_id); let const_data = self.encode_rendered_const_for_body(body_id); @@ -1906,11 +1905,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }; record!(self.tables.kind[def_id] <- EntryKind::ForeignFn(self.lazy(data))); } - hir::ForeignItemKind::Static(_, hir::Mutability::Mut) => { - record!(self.tables.kind[def_id] <- EntryKind::ForeignMutStatic); - } - hir::ForeignItemKind::Static(_, hir::Mutability::Not) => { - record!(self.tables.kind[def_id] <- EntryKind::ForeignImmStatic); + hir::ForeignItemKind::Static(..) => { + record!(self.tables.kind[def_id] <- EntryKind::ForeignStatic); } hir::ForeignItemKind::Type => { record!(self.tables.kind[def_id] <- EntryKind::ForeignType); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 204284ffaa3..06581033129 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -338,10 +338,8 @@ define_tables! { enum EntryKind { AnonConst, Const, - ImmStatic, - MutStatic, - ForeignImmStatic, - ForeignMutStatic, + Static, + ForeignStatic, ForeignMod, ForeignType, GlobalAsm, diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 8afa6e70e41..f9d24b68634 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -228,7 +228,7 @@ impl<'hir> Map<'hir> { let hir_id = self.local_def_id_to_hir_id(local_def_id); let def_kind = match self.find(hir_id)? { Node::Item(item) => match item.kind { - ItemKind::Static(..) => DefKind::Static, + ItemKind::Static(_, mt, _) => DefKind::Static(mt), ItemKind::Const(..) => DefKind::Const, ItemKind::Fn(..) => DefKind::Fn, ItemKind::Macro(_, macro_kind) => DefKind::Macro(macro_kind), @@ -248,7 +248,7 @@ impl<'hir> Map<'hir> { }, Node::ForeignItem(item) => match item.kind { ForeignItemKind::Fn(..) => DefKind::Fn, - ForeignItemKind::Static(..) => DefKind::Static, + ForeignItemKind::Static(_, mt) => DefKind::Static(mt), ForeignItemKind::Type => DefKind::ForeignTy, }, Node::TraitItem(item) => match item.kind { @@ -471,19 +471,15 @@ impl<'hir> Map<'hir> { /// Returns the `BodyOwnerKind` of this `LocalDefId`. /// /// Panics if `LocalDefId` does not have an associated body. - pub fn body_owner_kind(self, id: HirId) -> BodyOwnerKind { - match self.get(id) { - Node::Item(&Item { kind: ItemKind::Const(..), .. }) - | Node::TraitItem(&TraitItem { kind: TraitItemKind::Const(..), .. }) - | Node::ImplItem(&ImplItem { kind: ImplItemKind::Const(..), .. }) - | Node::AnonConst(_) => BodyOwnerKind::Const, - Node::Ctor(..) - | Node::Item(&Item { kind: ItemKind::Fn(..), .. }) - | Node::TraitItem(&TraitItem { kind: TraitItemKind::Fn(..), .. }) - | Node::ImplItem(&ImplItem { kind: ImplItemKind::Fn(..), .. }) => BodyOwnerKind::Fn, - Node::Item(&Item { kind: ItemKind::Static(_, m, _), .. }) => BodyOwnerKind::Static(m), - Node::Expr(&Expr { kind: ExprKind::Closure(..), .. }) => BodyOwnerKind::Closure, - node => bug!("{:#?} is not a body node", node), + pub fn body_owner_kind(self, def_id: LocalDefId) -> BodyOwnerKind { + match self.tcx.def_kind(def_id) { + DefKind::Const | DefKind::AssocConst | DefKind::InlineConst | DefKind::AnonConst => { + BodyOwnerKind::Const + } + DefKind::Ctor(..) | DefKind::Fn | DefKind::AssocFn => BodyOwnerKind::Fn, + DefKind::Closure | DefKind::Generator => BodyOwnerKind::Closure, + DefKind::Static(mt) => BodyOwnerKind::Static(mt), + dk => bug!("{:?} is not a body node: {:?}", def_id, dk), } } @@ -494,16 +490,17 @@ impl<'hir> Map<'hir> { /// This should only be used for determining the context of a body, a return /// value of `Some` does not always suggest that the owner of the body is `const`, /// just that it has to be checked as if it were. - pub fn body_const_context(self, did: LocalDefId) -> Option<ConstContext> { - let hir_id = self.local_def_id_to_hir_id(did); - let ccx = match self.body_owner_kind(hir_id) { + pub fn body_const_context(self, def_id: LocalDefId) -> Option<ConstContext> { + let ccx = match self.body_owner_kind(def_id) { BodyOwnerKind::Const => ConstContext::Const, BodyOwnerKind::Static(mt) => ConstContext::Static(mt), - BodyOwnerKind::Fn if self.tcx.is_constructor(did.to_def_id()) => return None, - BodyOwnerKind::Fn if self.tcx.is_const_fn_raw(did.to_def_id()) => ConstContext::ConstFn, + BodyOwnerKind::Fn if self.tcx.is_constructor(def_id.to_def_id()) => return None, + BodyOwnerKind::Fn if self.tcx.is_const_fn_raw(def_id.to_def_id()) => { + ConstContext::ConstFn + } BodyOwnerKind::Fn - if self.tcx.has_attr(did.to_def_id(), sym::default_method_body_is_const) => + if self.tcx.has_attr(def_id.to_def_id(), sym::default_method_body_is_const) => { ConstContext::ConstFn } diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 50d9c8e98b9..b2dd67fb16d 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -950,9 +950,8 @@ fn write_mir_sig(tcx: TyCtxt<'_>, body: &Body<'_>, w: &mut dyn Write) -> io::Res match (kind, body.source.promoted) { (_, Some(i)) => write!(w, "{:?} in ", i)?, (DefKind::Const | DefKind::AssocConst, _) => write!(w, "const ")?, - (DefKind::Static, _) => { - write!(w, "static {}", if tcx.is_mutable_static(def_id) { "mut " } else { "" })? - } + (DefKind::Static(hir::Mutability::Not), _) => write!(w, "static ")?, + (DefKind::Static(hir::Mutability::Mut), _) => write!(w, "static mut ")?, (_, _) if is_function => write!(w, "fn ")?, (DefKind::AnonConst | DefKind::InlineConst, _) => {} // things like anon const, not an item _ => bug!("Unexpected def kind {:?}", kind), diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 6d7e7ef0cb0..bf45269e06f 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -586,12 +586,6 @@ rustc_queries! { separate_provide_extern } - /// Returns `Some(mutability)` if the node pointed to by `def_id` is a static item. - query static_mutability(def_id: DefId) -> Option<hir::Mutability> { - desc { |tcx| "looking up static mutability of `{}`", tcx.def_path_str(def_id) } - separate_provide_extern - } - /// Returns `Some(generator_kind)` if the node pointed to by `def_id` is a generator. query generator_kind(def_id: DefId) -> Option<hir::GeneratorKind> { desc { |tcx| "looking up generator kind of `{}`", tcx.def_path_str(def_id) } diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 388109e6512..075928c889d 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -1379,3 +1379,50 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { ControlFlow::CONTINUE } } + +/// Finds the max universe present +pub struct MaxUniverse { + max_universe: ty::UniverseIndex, +} + +impl MaxUniverse { + pub fn new() -> Self { + MaxUniverse { max_universe: ty::UniverseIndex::ROOT } + } + + pub fn max_universe(self) -> ty::UniverseIndex { + self.max_universe + } +} + +impl<'tcx> TypeVisitor<'tcx> for MaxUniverse { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { + if let ty::Placeholder(placeholder) = t.kind() { + self.max_universe = ty::UniverseIndex::from_u32( + self.max_universe.as_u32().max(placeholder.universe.as_u32()), + ); + } + + t.super_visit_with(self) + } + + fn visit_const(&mut self, c: ty::consts::Const<'tcx>) -> ControlFlow<Self::BreakTy> { + if let ty::ConstKind::Placeholder(placeholder) = c.val() { + self.max_universe = ty::UniverseIndex::from_u32( + self.max_universe.as_u32().max(placeholder.universe.as_u32()), + ); + } + + c.super_visit_with(self) + } + + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { + if let ty::RePlaceholder(placeholder) = *r { + self.max_universe = ty::UniverseIndex::from_u32( + self.max_universe.as_u32().max(placeholder.universe.as_u32()), + ); + } + + ControlFlow::CONTINUE + } +} diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index dfc405b1195..7b12ec50b0d 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2147,7 +2147,7 @@ impl<'tcx> TyCtxt<'tcx> { match instance { ty::InstanceDef::Item(def) => match self.def_kind(def.did) { DefKind::Const - | DefKind::Static + | DefKind::Static(..) | DefKind::AssocConst | DefKind::Ctor(..) | DefKind::AnonConst diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index fecc5d805fc..21650fbb75d 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -912,12 +912,25 @@ pub trait PrettyPrinter<'tcx>: } for (assoc_item_def_id, term) in assoc_items { - // Skip printing `<[generator@] as Generator<_>>::Return` from async blocks - if let Some(ty) = term.skip_binder().ty() && - let ty::Projection(ty::ProjectionTy { item_def_id, .. }) = ty.kind() && - Some(*item_def_id) == self.tcx().lang_items().generator_return() { - continue; - } + // Skip printing `<[generator@] as Generator<_>>::Return` from async blocks, + // unless we can find out what generator return type it comes from. + let term = if let Some(ty) = term.skip_binder().ty() + && let ty::Projection(ty::ProjectionTy { item_def_id, substs }) = ty.kind() + && Some(*item_def_id) == self.tcx().lang_items().generator_return() + { + if let ty::Generator(_, substs, _) = substs.type_at(0).kind() { + let return_ty = substs.as_generator().return_ty(); + if !return_ty.is_ty_infer() { + return_ty.into() + } else { + continue; + } + } else { + continue; + } + } else { + term.skip_binder() + }; if first { p!("<"); @@ -928,7 +941,7 @@ pub trait PrettyPrinter<'tcx>: p!(write("{} = ", self.tcx().associated_item(assoc_item_def_id).name)); - match term.skip_binder() { + match term { Term::Ty(ty) => { p!(print(ty)) } @@ -1188,7 +1201,7 @@ pub trait PrettyPrinter<'tcx>: } ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted: None }) => { match self.tcx().def_kind(def.did) { - DefKind::Static | DefKind::Const | DefKind::AssocConst => { + DefKind::Static(..) | DefKind::Const | DefKind::AssocConst => { p!(print_value_path(def.did, substs)) } _ => { diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 1b07dc6eb37..7d9a917d04c 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -533,8 +533,14 @@ impl<'tcx> TyCtxt<'tcx> { } /// Returns `true` if the node pointed to by `def_id` is a `static` item. + #[inline] pub fn is_static(self, def_id: DefId) -> bool { - self.static_mutability(def_id).is_some() + matches!(self.def_kind(def_id), DefKind::Static(_)) + } + + #[inline] + pub fn static_mutability(self, def_id: DefId) -> Option<hir::Mutability> { + if let DefKind::Static(mt) = self.def_kind(def_id) { Some(mt) } else { None } } /// Returns `true` if this is a `static` item with the `#[thread_local]` attribute. @@ -543,6 +549,7 @@ impl<'tcx> TyCtxt<'tcx> { } /// Returns `true` if the node pointed to by `def_id` is a mutable `static` item. + #[inline] pub fn is_mutable_static(self, def_id: DefId) -> bool { self.static_mutability(def_id) == Some(hir::Mutability::Mut) } diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index ab3dc8f020c..901635dc488 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -41,7 +41,7 @@ crate fn mir_built<'tcx>( /// Construct the MIR for a given `DefId`. fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_> { let id = tcx.hir().local_def_id_to_hir_id(def.did); - let body_owner_kind = tcx.hir().body_owner_kind(id); + let body_owner_kind = tcx.hir().body_owner_kind(def.did); let typeck_results = tcx.typeck_opt_const_arg(def); // Ensure unsafeck and abstract const building is ran before we steal the THIR. @@ -802,7 +802,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { check_overflow |= tcx.sess.overflow_checks(); // Constants always need overflow checks. check_overflow |= matches!( - tcx.hir().body_owner_kind(hir_id), + tcx.hir().body_owner_kind(def.did), hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) ); diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index cab5fcd179b..e6afc89baa0 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -523,7 +523,7 @@ impl<'tcx> Cx<'tcx> { } } - Res::Def(DefKind::Static, def_id) => { + Res::Def(DefKind::Static(_), def_id) => { InlineAsmOperand::SymStatic { def_id } } @@ -901,7 +901,7 @@ impl<'tcx> Cx<'tcx> { // We encode uses of statics as a `*&STATIC` where the `&STATIC` part is // a constant reference (or constant raw pointer for `static mut`) in MIR - Res::Def(DefKind::Static, id) => { + Res::Def(DefKind::Static(_), id) => { let ty = self.tcx.static_ptr_ty(id); let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id); let kind = if self.tcx.is_thread_local_static(id) { diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index d21fbb9edff..57aec867856 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -420,7 +420,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { _ => { let pattern_error = match res { Res::Def(DefKind::ConstParam, _) => PatternError::ConstParamInPattern(span), - Res::Def(DefKind::Static, _) => PatternError::StaticInPattern(span), + Res::Def(DefKind::Static(_), _) => PatternError::StaticInPattern(span), _ => PatternError::NonConstPath(span), }; self.errors.push(pattern_error); diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 23e5f0b4f30..b6bb56990ed 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -59,11 +59,10 @@ impl<'tcx> MirPass<'tcx> for Inline { } fn inline<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool { - let def_id = body.source.def_id(); - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + let def_id = body.source.def_id().expect_local(); // Only do inlining into fn bodies. - if !tcx.hir().body_owner_kind(hir_id).is_fn_or_closure() { + if !tcx.hir().body_owner_kind(def_id).is_fn_or_closure() { return false; } if body.source.promoted.is_some() { @@ -77,9 +76,10 @@ fn inline<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool { } let param_env = tcx.param_env_reveal_all_normalized(def_id); + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let param_env = rustc_trait_selection::traits::normalize_param_env_or_error( tcx, - def_id, + def_id.to_def_id(), param_env, ObligationCause::misc(body.span, hir_id), ); diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index 48b6951f10e..c6a99aae588 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -158,7 +158,7 @@ fn mark_used_by_default_parameters<'tcx>( | DefKind::Fn | DefKind::Const | DefKind::ConstParam - | DefKind::Static + | DefKind::Static(_) | DefKind::Ctor(_, _) | DefKind::AssocFn | DefKind::AssocConst diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 92c5d329f6e..5ab412dc777 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -597,15 +597,13 @@ impl<'a> StringReader<'a> { } } - /// Note: It was decided to not add a test case, because it would be too big. - /// <https://github.com/rust-lang/rust/pull/50296#issuecomment-392135180> fn report_too_many_hashes(&self, start: BytePos, found: usize) -> ! { self.fatal_span_( start, self.pos, &format!( "too many `#` symbols: raw strings may be delimited \ - by up to 65535 `#` symbols, but found {}", + by up to 255 `#` symbols, but found {}", found ), ) diff --git a/compiler/rustc_passes/src/region.rs b/compiler/rustc_passes/src/region.rs index fdf93e58932..7b21ab32f4f 100644 --- a/compiler/rustc_passes/src/region.rs +++ b/compiler/rustc_passes/src/region.rs @@ -734,7 +734,7 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> { fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) { let body_id = body.id(); - let owner_id = self.tcx.hir().body_owner(body_id); + let owner_id = self.tcx.hir().body_owner_def_id(body_id); debug!( "visit_body(id={:?}, span={:?}, body.id={:?}, cx.parent={:?})", diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 1f286d557ca..85168aad1c3 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -553,7 +553,7 @@ impl<'tcx> EmbargoVisitor<'tcx> { } match def_kind { // No type privacy, so can be directly marked as reachable. - DefKind::Const | DefKind::Static | DefKind::TraitAlias | DefKind::TyAlias => { + DefKind::Const | DefKind::Static(_) | DefKind::TraitAlias | DefKind::TyAlias => { if vis.is_accessible_from(module.to_def_id(), self.tcx) { self.update(def_id, level); } @@ -1243,12 +1243,12 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { let def = def.filter(|(kind, _)| { matches!( kind, - DefKind::AssocFn | DefKind::AssocConst | DefKind::AssocTy | DefKind::Static + DefKind::AssocFn | DefKind::AssocConst | DefKind::AssocTy | DefKind::Static(_) ) }); if let Some((kind, def_id)) = def { let is_local_static = - if let DefKind::Static = kind { def_id.is_local() } else { false }; + if let DefKind::Static(_) = kind { def_id.is_local() } else { false }; if !self.item_is_accessible(def_id) && !is_local_static { let sess = self.tcx.sess; let sm = sess.source_map(); diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 34218e87b51..b706547f7fc 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -701,8 +701,8 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { } // These items live in the value namespace. - ItemKind::Static(..) => { - let res = Res::Def(DefKind::Static, def_id); + ItemKind::Static(_, mt, _) => { + let res = Res::Def(DefKind::Static(mt), def_id); self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion)); } ItemKind::Const(..) => { @@ -907,7 +907,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { let def_id = local_def_id.to_def_id(); let (def_kind, ns) = match item.kind { ForeignItemKind::Fn(..) => (DefKind::Fn, ValueNS), - ForeignItemKind::Static(..) => (DefKind::Static, ValueNS), + ForeignItemKind::Static(_, mt, _) => (DefKind::Static(mt), ValueNS), ForeignItemKind::TyAlias(..) => (DefKind::ForeignTy, TypeNS), ForeignItemKind::MacCall(_) => unreachable!(), }; @@ -963,7 +963,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { Res::Def( DefKind::Fn | DefKind::AssocFn - | DefKind::Static + | DefKind::Static(_) | DefKind::Const | DefKind::AssocConst | DefKind::Ctor(..), diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index bb05a3d7510..400adf20cba 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -300,7 +300,7 @@ impl<'a> PathSource<'a> { Res::Def( DefKind::Ctor(_, CtorKind::Const | CtorKind::Fn) | DefKind::Const - | DefKind::Static + | DefKind::Static(_) | DefKind::Fn | DefKind::AssocFn | DefKind::AssocConst @@ -1830,7 +1830,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } Some(res) } - Res::Def(DefKind::Ctor(..) | DefKind::Const | DefKind::Static, _) => { + Res::Def(DefKind::Ctor(..) | DefKind::Const | DefKind::Static(_), _) => { // This is unambiguously a fresh binding, either syntactically // (e.g., `IDENT @ PAT` or `ref IDENT`) or because `IDENT` resolves // to something unusable as a pattern (e.g., constructor function), diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs index d071d66ffa6..08a990c65ff 100644 --- a/compiler/rustc_save_analysis/src/lib.rs +++ b/compiler/rustc_save_analysis/src/lib.rs @@ -701,7 +701,7 @@ impl<'tcx> SaveContext<'tcx> { let parent_def_id = self.tcx.parent(def_id).unwrap(); Some(Ref { kind: RefKind::Type, span, ref_id: id_from_def_id(parent_def_id) }) } - Res::Def(HirDefKind::Static | HirDefKind::Const | HirDefKind::AssocConst, _) => { + Res::Def(HirDefKind::Static(_) | HirDefKind::Const | HirDefKind::AssocConst, _) => { Some(Ref { kind: RefKind::Variable, span, ref_id: id_from_def_id(res.def_id()) }) } Res::Def(HirDefKind::AssocFn, decl_id) => { diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 44a2e2bdc85..856436e44db 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1948,9 +1948,6 @@ fn parse_native_lib_kind( kind: &str, error_format: ErrorOutputType, ) -> (NativeLibKind, Option<bool>) { - let is_nightly = nightly_options::match_is_nightly_build(matches); - let enable_unstable = nightly_options::is_unstable_enabled(matches); - let (kind, modifiers) = match kind.split_once(':') { None => (kind, None), Some((kind, modifiers)) => (kind, Some(modifiers)), @@ -1972,7 +1969,7 @@ fn parse_native_lib_kind( "linking modifier can't be used with library kind `static-nobundle`", ) } - if !is_nightly { + if !nightly_options::match_is_nightly_build(matches) { early_error( error_format, "library kind `static-nobundle` are currently unstable and only accepted on \ @@ -1988,23 +1985,7 @@ fn parse_native_lib_kind( }; match modifiers { None => (kind, None), - Some(modifiers) => { - if !is_nightly { - early_error( - error_format, - "linking modifiers are currently unstable and only accepted on \ - the nightly compiler", - ); - } - if !enable_unstable { - early_error( - error_format, - "linking modifiers are currently unstable, \ - the `-Z unstable-options` flag must also be passed to use it", - ) - } - parse_native_lib_modifiers(kind, modifiers, error_format) - } + Some(modifiers) => parse_native_lib_modifiers(kind, modifiers, error_format, matches), } } @@ -2012,7 +1993,23 @@ fn parse_native_lib_modifiers( mut kind: NativeLibKind, modifiers: &str, error_format: ErrorOutputType, + matches: &getopts::Matches, ) -> (NativeLibKind, Option<bool>) { + let report_unstable_modifier = |modifier| { + if !nightly_options::is_unstable_enabled(matches) { + let why = if nightly_options::match_is_nightly_build(matches) { + " and only accepted on the nightly compiler" + } else { + ", the `-Z unstable-options` flag must also be passed to use it" + }; + early_error( + error_format, + &format!("{modifier} linking modifier is currently unstable{why}"), + ) + } + }; + + let mut has_duplicate_modifiers = false; let mut verbatim = None; for modifier in modifiers.split(',') { let (modifier, value) = match modifier.strip_prefix(&['+', '-']) { @@ -2026,6 +2023,10 @@ fn parse_native_lib_modifiers( match (modifier, &mut kind) { ("bundle", NativeLibKind::Static { bundle, .. }) => { + report_unstable_modifier(modifier); + if bundle.is_some() { + has_duplicate_modifiers = true; + } *bundle = Some(value); } ("bundle", _) => early_error( @@ -2034,9 +2035,18 @@ fn parse_native_lib_modifiers( `static` linking kind", ), - ("verbatim", _) => verbatim = Some(value), + ("verbatim", _) => { + report_unstable_modifier(modifier); + if verbatim.is_some() { + has_duplicate_modifiers = true; + } + verbatim = Some(value); + } ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => { + if whole_archive.is_some() { + has_duplicate_modifiers = true; + } *whole_archive = Some(value); } ("whole-archive", _) => early_error( @@ -2047,6 +2057,10 @@ fn parse_native_lib_modifiers( ("as-needed", NativeLibKind::Dylib { as_needed }) | ("as-needed", NativeLibKind::Framework { as_needed }) => { + report_unstable_modifier(modifier); + if as_needed.is_some() { + has_duplicate_modifiers = true; + } *as_needed = Some(value); } ("as-needed", _) => early_error( @@ -2055,6 +2069,8 @@ fn parse_native_lib_modifiers( `dylib` and `framework` linking kinds", ), + // Note: this error also excludes the case with empty modifier + // string, like `modifiers = ""`. _ => early_error( error_format, &format!( @@ -2064,6 +2080,9 @@ fn parse_native_lib_modifiers( ), } } + if has_duplicate_modifiers { + report_unstable_modifier("duplicating") + } (kind, verbatim) } diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs index 281fc887633..c1fd3c7c61b 100644 --- a/compiler/rustc_session/src/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -75,6 +75,12 @@ pub struct NativeLib { pub dll_imports: Vec<DllImport>, } +impl NativeLib { + pub fn has_modifiers(&self) -> bool { + self.verbatim.is_some() || self.kind.has_modifiers() + } +} + #[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic)] pub struct DllImport { pub name: Symbol, diff --git a/compiler/rustc_session/src/utils.rs b/compiler/rustc_session/src/utils.rs index a33f94013d2..6a8775bd10b 100644 --- a/compiler/rustc_session/src/utils.rs +++ b/compiler/rustc_session/src/utils.rs @@ -43,6 +43,20 @@ pub enum NativeLibKind { Unspecified, } +impl NativeLibKind { + pub fn has_modifiers(&self) -> bool { + match self { + NativeLibKind::Static { bundle, whole_archive } => { + bundle.is_some() || whole_archive.is_some() + } + NativeLibKind::Dylib { as_needed } | NativeLibKind::Framework { as_needed } => { + as_needed.is_some() + } + NativeLibKind::RawDylib | NativeLibKind::Unspecified => false, + } + } +} + rustc_data_structures::impl_stable_hash_via_hash!(NativeLibKind); #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)] @@ -53,6 +67,12 @@ pub struct NativeLib { pub verbatim: Option<bool>, } +impl NativeLib { + pub fn has_modifiers(&self) -> bool { + self.verbatim.is_some() || self.kind.has_modifiers() + } +} + rustc_data_structures::impl_stable_hash_via_hash!(NativeLib); /// A path that has been canonicalized along with its original, non-canonicalized form diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 84dbad846dd..0bca0a99e15 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -272,6 +272,7 @@ symbols! { __D, __H, __S, + __awaitee, __try_var, _d, _e, @@ -722,6 +723,7 @@ symbols! { generators, generic_arg_infer, generic_associated_types, + generic_associated_types_extended, generic_const_exprs, generic_param_attrs, get_context, @@ -1018,7 +1020,6 @@ symbols! { pattern_parentheses, phantom_data, pin, - pinned, platform_intrinsics, plugin, plugin_registrar, diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 36eddf7784b..d95512bb88f 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -5,6 +5,7 @@ use super::*; use crate::infer::region_constraints::{Constraint, RegionConstraintData}; use crate::infer::InferCtxt; +use crate::traits::project::ProjectAndUnifyResult; use rustc_middle::ty::fold::TypeFolder; use rustc_middle::ty::{Region, RegionVid, Term}; @@ -751,7 +752,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { debug!("Projecting and unifying projection predicate {:?}", predicate); match project::poly_project_and_unify_type(select, &obligation.with(p)) { - Err(e) => { + ProjectAndUnifyResult::MismatchedProjectionTypes(e) => { debug!( "evaluate_nested_obligations: Unable to unify predicate \ '{:?}' '{:?}', bailing out", @@ -759,11 +760,11 @@ impl<'tcx> AutoTraitFinder<'tcx> { ); return false; } - Ok(Err(project::InProgress)) => { + ProjectAndUnifyResult::Recursive => { debug!("evaluate_nested_obligations: recursive projection predicate"); return false; } - Ok(Ok(Some(v))) => { + ProjectAndUnifyResult::Holds(v) => { // We only care about sub-obligations // when we started out trying to unify // some inference variables. See the comment above @@ -782,7 +783,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { } } } - Ok(Ok(None)) => { + ProjectAndUnifyResult::FailedNormalization => { // It's ok not to make progress when have no inference variables - // in that case, we were only performing unification to check if an // error occurred (which would indicate that it's impossible for our diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs index 4b6784aee97..866bb6109e0 100644 --- a/compiler/rustc_trait_selection/src/traits/codegen.rs +++ b/compiler/rustc_trait_selection/src/traits/codegen.rs @@ -19,6 +19,7 @@ use rustc_middle::ty::{self, TyCtxt}; /// obligations *could be* resolved if we wanted to. /// /// This also expects that `trait_ref` is fully normalized. +#[instrument(level = "debug", skip(tcx))] pub fn codegen_fulfill_obligation<'tcx>( tcx: TyCtxt<'tcx>, (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>), @@ -27,11 +28,6 @@ pub fn codegen_fulfill_obligation<'tcx>( let trait_ref = tcx.erase_regions(trait_ref); // We expect the input to be fully normalized. debug_assert_eq!(trait_ref, tcx.normalize_erasing_regions(param_env, trait_ref)); - debug!( - "codegen_fulfill_obligation(trait_ref={:?}, def_id={:?})", - (param_env, trait_ref), - trait_ref.def_id() - ); // Do the initial selection for the obligation. This yields the // shallow result we are looking for -- that is, what specific impl. @@ -80,25 +76,22 @@ pub fn codegen_fulfill_obligation<'tcx>( } }; - debug!("fulfill_obligation: selection={:?}", selection); + debug!(?selection); // Currently, we use a fulfillment context to completely resolve // all nested obligations. This is because they can inform the // inference of the impl's type parameters. let mut fulfill_cx = FulfillmentContext::new(); let impl_source = selection.map(|predicate| { - debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate); fulfill_cx.register_predicate_obligation(&infcx, predicate); }); let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, impl_source); - // There should be no opaque types during codegen, they all get revealed. - let opaque_types = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); - if !opaque_types.is_empty() { - bug!("{:#?}", opaque_types); - } + // Opaque types may have gotten their hidden types constrained, but we can ignore them safely + // as they will get constrained elsewhere, too. + let _opaque_types = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); - debug!("Cache miss: {:?} => {:?}", trait_ref, impl_source); + debug!("Cache miss: {trait_ref:?} => {impl_source:?}"); Ok(&*tcx.arena.alloc(impl_source)) }) } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 1b862834467..d0b8b0281c5 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -14,7 +14,7 @@ use rustc_middle::ty::{self, Binder, Const, Ty, TypeFoldable}; use std::marker::PhantomData; use super::const_evaluatable; -use super::project; +use super::project::{self, ProjectAndUnifyResult}; use super::select::SelectionContext; use super::wf; use super::CodeAmbiguity; @@ -753,8 +753,8 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { } match project::poly_project_and_unify_type(self.selcx, &project_obligation) { - Ok(Ok(Some(os))) => ProcessResult::Changed(mk_pending(os)), - Ok(Ok(None)) => { + ProjectAndUnifyResult::Holds(os) => ProcessResult::Changed(mk_pending(os)), + ProjectAndUnifyResult::FailedNormalization => { stalled_on.clear(); stalled_on.extend(substs_infer_vars( self.selcx, @@ -763,10 +763,12 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { ProcessResult::Unchanged } // Let the caller handle the recursion - Ok(Err(project::InProgress)) => ProcessResult::Changed(mk_pending(vec![ + ProjectAndUnifyResult::Recursive => ProcessResult::Changed(mk_pending(vec![ project_obligation.with(project_obligation.predicate.to_predicate(tcx)), ])), - Err(e) => ProcessResult::Error(CodeProjectionError(e)), + ProjectAndUnifyResult::MismatchedProjectionTypes(e) => { + ProcessResult::Error(CodeProjectionError(e)) + } } } } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index d4ec677a0b1..2251f992e4d 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -28,7 +28,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_infer::infer::resolve::OpportunisticRegionResolver; use rustc_middle::traits::select::OverflowError; -use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; +use rustc_middle::ty::fold::{MaxUniverse, TypeFoldable, TypeFolder}; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{self, Term, ToPredicate, Ty, TyCtxt}; use rustc_span::symbol::sym; @@ -144,6 +144,18 @@ impl<'tcx> ProjectionCandidateSet<'tcx> { } } +/// Takes the place of a +/// Result< +/// Result<Option<Vec<PredicateObligation<'tcx>>>, InProgress>, +/// MismatchedProjectionTypes<'tcx>, +/// > +pub(super) enum ProjectAndUnifyResult<'tcx> { + Holds(Vec<PredicateObligation<'tcx>>), + FailedNormalization, + Recursive, + MismatchedProjectionTypes(MismatchedProjectionTypes<'tcx>), +} + /// Evaluates constraints of the form: /// /// for<...> <T as Trait>::U == V @@ -167,19 +179,47 @@ impl<'tcx> ProjectionCandidateSet<'tcx> { pub(super) fn poly_project_and_unify_type<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &PolyProjectionObligation<'tcx>, -) -> Result< - Result<Option<Vec<PredicateObligation<'tcx>>>, InProgress>, - MismatchedProjectionTypes<'tcx>, -> { +) -> ProjectAndUnifyResult<'tcx> { let infcx = selcx.infcx(); - infcx.commit_if_ok(|_snapshot| { + let r = infcx.commit_if_ok(|_snapshot| { + let old_universe = infcx.universe(); let placeholder_predicate = infcx.replace_bound_vars_with_placeholders(obligation.predicate); + let new_universe = infcx.universe(); let placeholder_obligation = obligation.with(placeholder_predicate); - let result = project_and_unify_type(selcx, &placeholder_obligation)?; - Ok(result) - }) + match project_and_unify_type(selcx, &placeholder_obligation) { + ProjectAndUnifyResult::MismatchedProjectionTypes(e) => Err(e), + ProjectAndUnifyResult::Holds(obligations) + if old_universe != new_universe + && selcx.tcx().features().generic_associated_types_extended => + { + // If the `generic_associated_types_extended` feature is active, then we ignore any + // obligations references lifetimes from any universe greater than or equal to the + // universe just created. Otherwise, we can end up with something like `for<'a> I: 'a`, + // which isn't quite what we want. Ideally, we want either an implied + // `for<'a where I: 'a> I: 'a` or we want to "lazily" check these hold when we + // substitute concrete regions. There is design work to be done here; until then, + // however, this allows experimenting potential GAT features without running into + // well-formedness issues. + let new_obligations = obligations + .into_iter() + .filter(|obligation| { + let mut visitor = MaxUniverse::new(); + obligation.predicate.visit_with(&mut visitor); + visitor.max_universe() < new_universe + }) + .collect(); + Ok(ProjectAndUnifyResult::Holds(new_obligations)) + } + other => Ok(other), + } + }); + + match r { + Ok(inner) => inner, + Err(err) => ProjectAndUnifyResult::MismatchedProjectionTypes(err), + } } /// Evaluates constraints of the form: @@ -189,15 +229,11 @@ pub(super) fn poly_project_and_unify_type<'cx, 'tcx>( /// If successful, this may result in additional obligations. /// /// See [poly_project_and_unify_type] for an explanation of the return value. +#[tracing::instrument(level = "debug", skip(selcx))] fn project_and_unify_type<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionObligation<'tcx>, -) -> Result< - Result<Option<Vec<PredicateObligation<'tcx>>>, InProgress>, - MismatchedProjectionTypes<'tcx>, -> { - debug!(?obligation, "project_and_unify_type"); - +) -> ProjectAndUnifyResult<'tcx> { let mut obligations = vec![]; let infcx = selcx.infcx(); @@ -210,8 +246,8 @@ fn project_and_unify_type<'cx, 'tcx>( &mut obligations, ) { Ok(Some(n)) => n, - Ok(None) => return Ok(Ok(None)), - Err(InProgress) => return Ok(Err(InProgress)), + Ok(None) => return ProjectAndUnifyResult::FailedNormalization, + Err(InProgress) => return ProjectAndUnifyResult::Recursive, }; debug!(?normalized, ?obligations, "project_and_unify_type result"); let actual = obligation.predicate.term; @@ -231,11 +267,11 @@ fn project_and_unify_type<'cx, 'tcx>( match infcx.at(&obligation.cause, obligation.param_env).eq(normalized, actual) { Ok(InferOk { obligations: inferred_obligations, value: () }) => { obligations.extend(inferred_obligations); - Ok(Ok(Some(obligations))) + ProjectAndUnifyResult::Holds(obligations) } Err(err) => { - debug!("project_and_unify_type: equating types encountered error {:?}", err); - Err(MismatchedProjectionTypes { err }) + debug!("equating types encountered error {:?}", err); + ProjectAndUnifyResult::MismatchedProjectionTypes(MismatchedProjectionTypes { err }) } } } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 42f17721f9b..4f033d45c1f 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -21,6 +21,7 @@ use super::{ use crate::infer::{InferCtxt, InferOk, TypeFreshener}; use crate::traits::error_reporting::InferCtxtExt; +use crate::traits::project::ProjectAndUnifyResult; use crate::traits::project::ProjectionCacheKeyExt; use crate::traits::ProjectionCacheKey; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -525,7 +526,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let data = bound_predicate.rebind(data); let project_obligation = obligation.with(data); match project::poly_project_and_unify_type(self, &project_obligation) { - Ok(Ok(Some(mut subobligations))) => { + ProjectAndUnifyResult::Holds(mut subobligations) => { 'compute_res: { // If we've previously marked this projection as 'complete', then // use the final cached result (either `EvaluatedToOk` or @@ -573,9 +574,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { res } } - Ok(Ok(None)) => Ok(EvaluatedToAmbig), - Ok(Err(project::InProgress)) => Ok(EvaluatedToRecur), - Err(_) => Ok(EvaluatedToErr), + ProjectAndUnifyResult::FailedNormalization => Ok(EvaluatedToAmbig), + ProjectAndUnifyResult::Recursive => Ok(EvaluatedToRecur), + ProjectAndUnifyResult::MismatchedProjectionTypes(_) => Ok(EvaluatedToErr), } } diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index b04d304d2ca..0d522702e67 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -2186,7 +2186,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } // Case 3. Reference to a top-level value. - DefKind::Fn | DefKind::Const | DefKind::ConstParam | DefKind::Static => { + DefKind::Fn | DefKind::Const | DefKind::ConstParam | DefKind::Static(_) => { path_segs.push(PathSeg(def_id, last)); } diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index 7f5ab8e4f42..d2b462b5959 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -184,7 +184,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::Path { res: hir::def::Res::Def( - hir::def::DefKind::Static | hir::def::DefKind::Const, + hir::def::DefKind::Static(_) | hir::def::DefKind::Const, def_id, ), .. diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index ecbd1e46349..2065de24754 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -52,7 +52,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { wbcx.visit_node_id(param.pat.span, param.hir_id); } // Type only exists for constants and statics, not functions. - match self.tcx.hir().body_owner_kind(item_id) { + match self.tcx.hir().body_owner_kind(item_def_id) { hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => { wbcx.visit_node_id(body.value.span, item_id); } diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 6a4c5d4a6c7..3078eba9dc2 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -85,7 +85,6 @@ pub fn provide(providers: &mut Providers) { impl_trait_ref, impl_polarity, is_foreign_item, - static_mutability, generator_kind, codegen_fn_attrs, asm_target_features, @@ -2602,20 +2601,6 @@ fn is_foreign_item(tcx: TyCtxt<'_>, def_id: DefId) -> bool { } } -fn static_mutability(tcx: TyCtxt<'_>, def_id: DefId) -> Option<hir::Mutability> { - match tcx.hir().get_if_local(def_id) { - Some( - Node::Item(&hir::Item { kind: hir::ItemKind::Static(_, mutbl, _), .. }) - | Node::ForeignItem(&hir::ForeignItem { - kind: hir::ForeignItemKind::Static(_, mutbl), - .. - }), - ) => Some(mutbl), - Some(_) => None, - _ => bug!("static_mutability applied to non-local def-id {:?}", def_id), - } -} - fn generator_kind(tcx: TyCtxt<'_>, def_id: DefId) -> Option<hir::GeneratorKind> { match tcx.hir().get_if_local(def_id) { Some(Node::Expr(&rustc_hir::Expr { diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index b08e08a27d0..055e391d706 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -723,10 +723,8 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { let upvars = tcx.upvars_mentioned(self.body_owner); // For purposes of this function, generator and closures are equivalent. - let body_owner_is_closure = matches!( - tcx.hir().body_owner_kind(tcx.hir().local_def_id_to_hir_id(self.body_owner)), - hir::BodyOwnerKind::Closure, - ); + let body_owner_is_closure = + matches!(tcx.hir().body_owner_kind(self.body_owner), hir::BodyOwnerKind::Closure,); // If we have a nested closure, we want to include the fake reads present in the nested closure. if let Some(fake_reads) = self.mc.typeck_results.closure_fake_reads.get(&closure_def_id) { diff --git a/compiler/rustc_typeck/src/mem_categorization.rs b/compiler/rustc_typeck/src/mem_categorization.rs index 1464420090b..85e9a670ffb 100644 --- a/compiler/rustc_typeck/src/mem_categorization.rs +++ b/compiler/rustc_typeck/src/mem_categorization.rs @@ -404,7 +404,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { ) | Res::SelfCtor(..) => Ok(self.cat_rvalue(hir_id, span, expr_ty)), - Res::Def(DefKind::Static, _) => { + Res::Def(DefKind::Static(_), _) => { Ok(PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::StaticItem, Vec::new())) } |
