diff options
Diffstat (limited to 'compiler')
68 files changed, 952 insertions, 672 deletions
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 99034799b3c..16224d71e45 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -345,17 +345,14 @@ impl Token { } pub fn is_op(&self) -> bool { - !matches!( - self.kind, - OpenDelim(..) - | CloseDelim(..) - | Literal(..) - | DocComment(..) - | Ident(..) - | Lifetime(..) - | Interpolated(..) - | Eof - ) + match self.kind { + Eq | Lt | Le | EqEq | Ne | Ge | Gt | AndAnd | OrOr | Not | Tilde | BinOp(_) + | BinOpEq(_) | At | Dot | DotDot | DotDotDot | DotDotEq | Comma | Semi | Colon + | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar | Question | SingleQuote => true, + + OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..) + | Lifetime(..) | Interpolated(..) | Eof => false, + } } pub fn is_like_plus(&self) -> bool { diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 824206a99d8..4d2049cbc41 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -304,9 +304,20 @@ pub struct AttributesData { #[derive(Clone, Debug, Default, Encodable, Decodable)] pub struct TokenStream(pub(crate) Lrc<Vec<TokenTree>>); +/// Similar to `proc_macro::Spacing`, but for tokens. +/// +/// Note that all `ast::TokenTree::Token` instances have a `Spacing`, but when +/// we convert to `proc_macro::TokenTree` for proc macros only `Punct` +/// `TokenTree`s have a `proc_macro::Spacing`. #[derive(Clone, Copy, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)] pub enum Spacing { + /// The token is not immediately followed by an operator token (as + /// determined by `Token::is_op`). E.g. a `+` token is `Alone` in `+ =`, + /// `+/*foo*/=`, `+ident`, and `+()`. Alone, + + /// The token is immediately followed by an operator token. E.g. a `+` + /// token is `Joint` in `+=` and `++`. Joint, } diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index b15e2d084ef..8b07c110663 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -159,7 +159,7 @@ pub fn make_format_args( append_newline: bool, ) -> Result<FormatArgs, ()> { let msg = "format argument must be a string literal"; - let fmt_span = efmt.span; + let unexpanded_fmt_span = efmt.span; let (fmt_str, fmt_style, fmt_span) = match expr_to_spanned_string(ecx, efmt, msg) { Ok(mut fmt) if append_newline => { fmt.0 = Symbol::intern(&format!("{}\n", fmt.0)); @@ -174,7 +174,7 @@ pub fn make_format_args( }; if !suggested { err.span_suggestion( - fmt_span.shrink_to_lo(), + unexpanded_fmt_span.shrink_to_lo(), "you might be missing a string literal to format with", format!("\"{}\", ", sugg_fmt), Applicability::MaybeIncorrect, @@ -192,7 +192,7 @@ pub fn make_format_args( }; let fmt_str = fmt_str.as_str(); // for the suggestions below - let fmt_snippet = ecx.source_map().span_to_snippet(fmt_span).ok(); + let fmt_snippet = ecx.source_map().span_to_snippet(unexpanded_fmt_span).ok(); let mut parser = parse::Parser::new( fmt_str, str_style, diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index f058503064b..c7ea7de8f4e 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -7,7 +7,7 @@ #![feature(box_patterns)] #![feature(decl_macro)] #![feature(if_let_guard)] -#![feature(is_some_with)] +#![feature(is_some_and)] #![feature(is_sorted)] #![feature(let_chains)] #![feature(proc_macro_internals)] diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 7efb6cc61ee..705141614e2 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -115,7 +115,7 @@ pub fn expand_test_or_bench( // reworked in the future to not need it, it'd be nice. _ => diag.struct_span_err(attr_sp, msg).forget_guarantee(), }; - err.span_label(attr_sp, "the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions") + err.span_label(attr_sp, "the `#[test]` macro causes a function to be run on a test and has no effect on non-functions") .span_label(item.span, format!("expected a non-associated function, found {} {}", item.kind.article(), item.kind.descr())) .span_suggestion(attr_sp, "replace with conditional compilation to make the item only exist when tests are being run", "#[cfg(test)]", Applicability::MaybeIncorrect) .emit(); diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index 0f663a26732..f79ef11720d 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -32,6 +32,7 @@ fn declare_raw_fn<'ll>( name: &str, callconv: llvm::CallConv, unnamed: llvm::UnnamedAddr, + visibility: llvm::Visibility, ty: &'ll Type, ) -> &'ll Value { debug!("declare_raw_fn(name={:?}, ty={:?})", name, ty); @@ -41,6 +42,7 @@ fn declare_raw_fn<'ll>( llvm::SetFunctionCallConv(llfn, callconv); llvm::SetUnnamedAddress(llfn, unnamed); + llvm::set_visibility(llfn, visibility); let mut attrs = SmallVec::<[_; 4]>::new(); @@ -78,7 +80,14 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { unnamed: llvm::UnnamedAddr, fn_type: &'ll Type, ) -> &'ll Value { - declare_raw_fn(self, name, llvm::CCallConv, unnamed, fn_type) + // Declare C ABI functions with the visibility used by C by default. + let visibility = if self.tcx.sess.target.default_hidden_visibility { + llvm::Visibility::Hidden + } else { + llvm::Visibility::Default + }; + + declare_raw_fn(self, name, llvm::CCallConv, unnamed, visibility, fn_type) } /// Declare a Rust function. @@ -95,6 +104,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { name, fn_abi.llvm_cconv(), llvm::UnnamedAddr::Global, + llvm::Visibility::Default, fn_abi.llvm_type(self), ); fn_abi.apply_attrs_llfn(self, llfn); diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 7c4c7db1035..ebdaf61e439 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -20,7 +20,7 @@ Rust MIR: a lowered representation of Rust. #![feature(trusted_step)] #![feature(try_blocks)] #![feature(yeet_expr)] -#![feature(is_some_with)] +#![feature(is_some_and)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] diff --git a/compiler/rustc_data_structures/src/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs index 937cb671573..fe257e10205 100644 --- a/compiler/rustc_data_structures/src/sorted_map.rs +++ b/compiler/rustc_data_structures/src/sorted_map.rs @@ -96,6 +96,23 @@ impl<K: Ord, V> SortedMap<K, V> { } } + /// Gets a mutable reference to the value in the entry, or insert a new one. + #[inline] + pub fn get_mut_or_insert_default(&mut self, key: K) -> &mut V + where + K: Eq, + V: Default, + { + let index = match self.lookup_index_for(&key) { + Ok(index) => index, + Err(index) => { + self.data.insert(index, (key, V::default())); + index + } + }; + unsafe { &mut self.data.get_unchecked_mut(index).1 } + } + #[inline] pub fn clear(&mut self) { self.data.clear(); diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 49dcc2ba021..31e410aaaf0 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -364,9 +364,10 @@ impl Diagnostic { // The lint index inside the attribute is manually transferred here. let lint_index = expectation_id.get_lint_index(); expectation_id.set_lint_index(None); - let mut stable_id = *unstable_to_stable + let mut stable_id = unstable_to_stable .get(&expectation_id) - .expect("each unstable `LintExpectationId` must have a matching stable id"); + .expect("each unstable `LintExpectationId` must have a matching stable id") + .normalize(); stable_id.set_lint_index(lint_index); *expectation_id = stable_id; diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index c8711ec6e25..7c312da6279 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1211,7 +1211,7 @@ impl HandlerInner { if let Some(expectation_id) = diagnostic.level.get_expectation_id() { self.suppressed_expected_diag = true; - self.fulfilled_expectations.insert(expectation_id); + self.fulfilled_expectations.insert(expectation_id.normalize()); } if matches!(diagnostic.level, Warning(_)) diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 59a7b668a83..ff09a9fb87a 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -110,10 +110,14 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre tokenstream::TokenTree::Token(token, spacing) => (token, spacing == Joint), }; + // Split the operator into one or more `Punct`s, one per character. + // The final one inherits the jointness of the original token. Any + // before that get `joint = true`. let mut op = |s: &str| { assert!(s.is_ascii()); - trees.extend(s.as_bytes().iter().enumerate().map(|(idx, &ch)| { - TokenTree::Punct(Punct { ch, joint: joint || idx != s.len() - 1, span }) + trees.extend(s.bytes().enumerate().map(|(idx, ch)| { + let is_final = idx == s.len() - 1; + TokenTree::Punct(Punct { ch, joint: if is_final { joint } else { true }, span }) })); }; diff --git a/compiler/rustc_hir_analysis/src/check/expr.rs b/compiler/rustc_hir_analysis/src/check/expr.rs index 48a4f40780b..09362eab673 100644 --- a/compiler/rustc_hir_analysis/src/check/expr.rs +++ b/compiler/rustc_hir_analysis/src/check/expr.rs @@ -41,6 +41,7 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase}; use rustc_middle::ty::error::TypeError::FieldMisMatch; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, AdtKind, Ty, TypeVisitable}; +use rustc_session::errors::ExprParenthesesNeeded; use rustc_session::parse::feature_err; use rustc_span::hygiene::DesugaringKind; use rustc_span::lev_distance::find_best_match_for_name; @@ -394,7 +395,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(sp) = tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp) { - tcx.sess.parse_sess.expr_parentheses_needed(&mut err, *sp); + err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp)); } err.emit(); oprnd_t = tcx.ty_error(); diff --git a/compiler/rustc_hir_analysis/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_hir_analysis/src/check/fn_ctxt/suggestions.rs index c32d1309031..05ed3b29972 100644 --- a/compiler/rustc_hir_analysis/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_analysis/src/check/fn_ctxt/suggestions.rs @@ -15,6 +15,7 @@ use rustc_infer::infer::{self, TyCtxtInferExt}; use rustc_infer::traits::{self, StatementAsExpression}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Binder, IsSuggestable, ToPredicate, Ty}; +use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::symbol::sym; use rustc_span::Span; use rustc_trait_selection::infer::InferCtxtExt; @@ -895,7 +896,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let sp = self.tcx.sess.source_map().start_point(expr.span); if let Some(sp) = self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp) { // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }` - self.tcx.sess.parse_sess.expr_parentheses_needed(err, *sp); + err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp)); } } diff --git a/compiler/rustc_hir_analysis/src/check/op.rs b/compiler/rustc_hir_analysis/src/check/op.rs index 4754717c29a..2d7d9020e3e 100644 --- a/compiler/rustc_hir_analysis/src/check/op.rs +++ b/compiler/rustc_hir_analysis/src/check/op.rs @@ -13,6 +13,7 @@ use rustc_middle::ty::adjustment::{ }; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitable}; +use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::Spanned; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; @@ -677,7 +678,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If the previous expression was a block expression, suggest parentheses // (turning this into a binary subtraction operation instead.) // for example, `{2} - 2` -> `({2}) - 2` (see src\test\ui\parser\expr-as-stmt.rs) - self.tcx.sess.parse_sess.expr_parentheses_needed(&mut err, *sp); + err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp)); } else { match actual.kind() { Uint(_) if op == hir::UnOp::Neg => { diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 1859473166a..d31b9b7ae46 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -70,7 +70,7 @@ This API is completely unstable and subject to change. #![feature(once_cell)] #![feature(slice_partition_dedup)] #![feature(try_blocks)] -#![feature(is_some_with)] +#![feature(is_some_and)] #![feature(type_alias_impl_trait)] #![recursion_limit = "256"] diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 87007728e9d..74e35afc87d 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -558,7 +558,7 @@ pub struct LateContext<'tcx> { /// Context for lint checking of the AST, after expansion, before lowering to HIR. pub struct EarlyContext<'a> { - pub builder: LintLevelsBuilder<'a>, + pub builder: LintLevelsBuilder<'a, crate::levels::TopDown>, pub buffered: LintBuffer, } diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 18d30e1435b..f7759bec908 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -58,6 +58,7 @@ impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> { F: FnOnce(&mut Self), { let is_crate_node = id == ast::CRATE_NODE_ID; + debug!(?id); let push = self.context.builder.push(attrs, is_crate_node, None); self.check_id(id); diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs index af13f453a50..4c3c39734dd 100644 --- a/compiler/rustc_lint/src/expect.rs +++ b/compiler/rustc_lint/src/expect.rs @@ -16,8 +16,10 @@ fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) { return; } + let lint_expectations = tcx.lint_expectations(()); let fulfilled_expectations = tcx.sess.diagnostic().steal_fulfilled_expectation_ids(); - let lint_expectations = &tcx.lint_levels(()).lint_expectations; + + tracing::debug!(?lint_expectations, ?fulfilled_expectations); for (id, expectation) in lint_expectations { // This check will always be true, since `lint_expectations` only diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 82382350823..be1d7d98aa6 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -5,11 +5,13 @@ use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, DiagnosticMessage, MultiSpan}; use rustc_hir as hir; -use rustc_hir::{intravisit, HirId}; +use rustc_hir::intravisit::{self, Visitor}; +use rustc_hir::HirId; +use rustc_index::vec::IndexVec; use rustc_middle::hir::nested_filter; use rustc_middle::lint::{ - struct_lint_level, LevelAndSource, LintExpectation, LintLevelMap, LintLevelSets, - LintLevelSource, LintSet, LintStackIndex, COMMAND_LINE, + reveal_actual_level, struct_lint_level, LevelAndSource, LintExpectation, LintLevelSource, + ShallowLintLevelMap, }; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{RegisteredTools, TyCtxt}; @@ -27,47 +29,408 @@ use crate::errors::{ UnknownToolInScopedLint, }; -fn lint_levels(tcx: TyCtxt<'_>, (): ()) -> LintLevelMap { - let store = unerased_lint_store(tcx); - let levels = - LintLevelsBuilder::new(tcx.sess, false, &store, &tcx.resolutions(()).registered_tools); - let mut builder = LintLevelMapBuilder { levels, tcx }; - let krate = tcx.hir().krate(); +/// Collection of lint levels for the whole crate. +/// This is used by AST-based lints, which do not +/// wait until we have built HIR to be emitted. +#[derive(Debug)] +struct LintLevelSets { + /// Linked list of specifications. + list: IndexVec<LintStackIndex, LintSet>, +} + +rustc_index::newtype_index! { + struct LintStackIndex { + ENCODABLE = custom, // we don't need encoding + const COMMAND_LINE = 0, + } +} - builder.levels.id_to_set.reserve(krate.owners.len() + 1); +/// Specifications found at this position in the stack. This map only represents the lints +/// found for one set of attributes (like `shallow_lint_levels_on` does). +/// +/// We store the level specifications as a linked list. +/// Each `LintSet` represents a set of attributes on the same AST node. +/// The `parent` forms a linked list that matches the AST tree. +/// This way, walking the linked list is equivalent to walking the AST bottom-up +/// to find the specifications for a given lint. +#[derive(Debug)] +struct LintSet { + // -A,-W,-D flags, a `Symbol` for the flag itself and `Level` for which + // flag. + specs: FxHashMap<LintId, LevelAndSource>, + parent: LintStackIndex, +} - let push = - builder.levels.push(tcx.hir().attrs(hir::CRATE_HIR_ID), true, Some(hir::CRATE_HIR_ID)); +impl LintLevelSets { + fn new() -> Self { + LintLevelSets { list: IndexVec::new() } + } + + fn get_lint_level( + &self, + lint: &'static Lint, + idx: LintStackIndex, + aux: Option<&FxHashMap<LintId, LevelAndSource>>, + sess: &Session, + ) -> LevelAndSource { + let lint = LintId::of(lint); + let (level, mut src) = self.raw_lint_id_level(lint, idx, aux); + let level = reveal_actual_level(level, &mut src, sess, lint, |id| { + self.raw_lint_id_level(id, idx, aux) + }); + (level, src) + } + + fn raw_lint_id_level( + &self, + id: LintId, + mut idx: LintStackIndex, + aux: Option<&FxHashMap<LintId, LevelAndSource>>, + ) -> (Option<Level>, LintLevelSource) { + if let Some(specs) = aux { + if let Some(&(level, src)) = specs.get(&id) { + return (Some(level), src); + } + } + loop { + let LintSet { ref specs, parent } = self.list[idx]; + if let Some(&(level, src)) = specs.get(&id) { + return (Some(level), src); + } + if idx == COMMAND_LINE { + return (None, LintLevelSource::Default); + } + idx = parent; + } + } +} - builder.levels.register_id(hir::CRATE_HIR_ID); +fn lint_expectations(tcx: TyCtxt<'_>, (): ()) -> Vec<(LintExpectationId, LintExpectation)> { + let store = unerased_lint_store(tcx); + + let mut builder = LintLevelsBuilder { + sess: tcx.sess, + provider: QueryMapExpectationsWrapper { + tcx, + cur: hir::CRATE_HIR_ID, + specs: ShallowLintLevelMap::default(), + expectations: Vec::new(), + unstable_to_stable_ids: FxHashMap::default(), + empty: FxHashMap::default(), + }, + warn_about_weird_lints: false, + store, + registered_tools: &tcx.resolutions(()).registered_tools, + }; + + builder.add_command_line(); + builder.add_id(hir::CRATE_HIR_ID); tcx.hir().walk_toplevel_module(&mut builder); - builder.levels.pop(push); - builder.levels.update_unstable_expectation_ids(); - builder.levels.build_map() + tcx.sess.diagnostic().update_unstable_expectation_id(&builder.provider.unstable_to_stable_ids); + + builder.provider.expectations } -pub struct LintLevelsBuilder<'s> { - sess: &'s Session, - lint_expectations: Vec<(LintExpectationId, LintExpectation)>, - /// Each expectation has a stable and an unstable identifier. This map - /// is used to map from unstable to stable [`LintExpectationId`]s. - expectation_id_map: FxHashMap<LintExpectationId, LintExpectationId>, +#[instrument(level = "trace", skip(tcx), ret)] +fn shallow_lint_levels_on(tcx: TyCtxt<'_>, owner: hir::OwnerId) -> ShallowLintLevelMap { + let store = unerased_lint_store(tcx); + let attrs = tcx.hir_attrs(owner); + + let mut levels = LintLevelsBuilder { + sess: tcx.sess, + provider: LintLevelQueryMap { + tcx, + cur: owner.into(), + specs: ShallowLintLevelMap::default(), + empty: FxHashMap::default(), + attrs, + }, + warn_about_weird_lints: false, + store, + registered_tools: &tcx.resolutions(()).registered_tools, + }; + + if owner == hir::CRATE_OWNER_ID { + levels.add_command_line(); + } + + match attrs.map.range(..) { + // There is only something to do if there are attributes at all. + [] => {} + // Most of the time, there is only one attribute. Avoid fetching HIR in that case. + [(local_id, _)] => levels.add_id(HirId { owner, local_id: *local_id }), + // Otherwise, we need to visit the attributes in source code order, so we fetch HIR and do + // a standard visit. + // FIXME(#102522) Just iterate on attrs once that iteration order matches HIR's. + _ => match tcx.hir().expect_owner(owner) { + hir::OwnerNode::Item(item) => levels.visit_item(item), + hir::OwnerNode::ForeignItem(item) => levels.visit_foreign_item(item), + hir::OwnerNode::TraitItem(item) => levels.visit_trait_item(item), + hir::OwnerNode::ImplItem(item) => levels.visit_impl_item(item), + hir::OwnerNode::Crate(mod_) => { + levels.add_id(hir::CRATE_HIR_ID); + levels.visit_mod(mod_, mod_.spans.inner_span, hir::CRATE_HIR_ID) + } + }, + } + + let specs = levels.provider.specs; + + #[cfg(debug_assertions)] + for (_, v) in specs.specs.iter() { + debug_assert!(!v.is_empty()); + } + + specs +} + +pub struct TopDown { sets: LintLevelSets, - id_to_set: FxHashMap<HirId, LintStackIndex>, cur: LintStackIndex, +} + +pub trait LintLevelsProvider { + fn current_specs(&self) -> &FxHashMap<LintId, LevelAndSource>; + fn insert(&mut self, id: LintId, lvl: LevelAndSource); + fn get_lint_level(&self, lint: &'static Lint, sess: &Session) -> LevelAndSource; + fn push_expectation(&mut self, _id: LintExpectationId, _expectation: LintExpectation) {} +} + +impl LintLevelsProvider for TopDown { + fn current_specs(&self) -> &FxHashMap<LintId, LevelAndSource> { + &self.sets.list[self.cur].specs + } + + fn insert(&mut self, id: LintId, lvl: LevelAndSource) { + self.sets.list[self.cur].specs.insert(id, lvl); + } + + fn get_lint_level(&self, lint: &'static Lint, sess: &Session) -> LevelAndSource { + self.sets.get_lint_level(lint, self.cur, Some(self.current_specs()), sess) + } +} + +struct LintLevelQueryMap<'tcx> { + tcx: TyCtxt<'tcx>, + cur: HirId, + specs: ShallowLintLevelMap, + /// Empty hash map to simplify code. + empty: FxHashMap<LintId, LevelAndSource>, + attrs: &'tcx hir::AttributeMap<'tcx>, +} + +impl LintLevelsProvider for LintLevelQueryMap<'_> { + fn current_specs(&self) -> &FxHashMap<LintId, LevelAndSource> { + self.specs.specs.get(&self.cur.local_id).unwrap_or(&self.empty) + } + fn insert(&mut self, id: LintId, lvl: LevelAndSource) { + self.specs.specs.get_mut_or_insert_default(self.cur.local_id).insert(id, lvl); + } + fn get_lint_level(&self, lint: &'static Lint, _: &Session) -> LevelAndSource { + self.specs.lint_level_id_at_node(self.tcx, LintId::of(lint), self.cur) + } +} + +struct QueryMapExpectationsWrapper<'tcx> { + tcx: TyCtxt<'tcx>, + cur: HirId, + specs: ShallowLintLevelMap, + expectations: Vec<(LintExpectationId, LintExpectation)>, + unstable_to_stable_ids: FxHashMap<LintExpectationId, LintExpectationId>, + /// Empty hash map to simplify code. + empty: FxHashMap<LintId, LevelAndSource>, +} + +impl LintLevelsProvider for QueryMapExpectationsWrapper<'_> { + fn current_specs(&self) -> &FxHashMap<LintId, LevelAndSource> { + self.specs.specs.get(&self.cur.local_id).unwrap_or(&self.empty) + } + fn insert(&mut self, id: LintId, lvl: LevelAndSource) { + let specs = self.specs.specs.get_mut_or_insert_default(self.cur.local_id); + specs.clear(); + specs.insert(id, lvl); + } + fn get_lint_level(&self, lint: &'static Lint, _: &Session) -> LevelAndSource { + self.specs.lint_level_id_at_node(self.tcx, LintId::of(lint), self.cur) + } + fn push_expectation(&mut self, id: LintExpectationId, expectation: LintExpectation) { + let LintExpectationId::Stable { attr_id: Some(attr_id), hir_id, attr_index, .. } = id else { bug!("unstable expectation id should already be mapped") }; + let key = LintExpectationId::Unstable { attr_id, lint_index: None }; + + if !self.unstable_to_stable_ids.contains_key(&key) { + self.unstable_to_stable_ids.insert( + key, + LintExpectationId::Stable { hir_id, attr_index, lint_index: None, attr_id: None }, + ); + } + + self.expectations.push((id.normalize(), expectation)); + } +} + +impl<'tcx> LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> { + fn add_id(&mut self, hir_id: HirId) { + self.provider.cur = hir_id; + self.add( + self.provider.attrs.get(hir_id.local_id), + hir_id == hir::CRATE_HIR_ID, + Some(hir_id), + ); + } +} + +impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> { + type NestedFilter = nested_filter::OnlyBodies; + + fn nested_visit_map(&mut self) -> Self::Map { + self.provider.tcx.hir() + } + + fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { + self.add_id(param.hir_id); + intravisit::walk_param(self, param); + } + + fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) { + self.add_id(it.hir_id()); + intravisit::walk_item(self, it); + } + + fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) { + self.add_id(it.hir_id()); + intravisit::walk_foreign_item(self, it); + } + + fn visit_stmt(&mut self, e: &'tcx hir::Stmt<'tcx>) { + // We will call `add_id` when we walk + // the `StmtKind`. The outer statement itself doesn't + // define the lint levels. + intravisit::walk_stmt(self, e); + } + + fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) { + self.add_id(e.hir_id); + intravisit::walk_expr(self, e); + } + + fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) { + self.add_id(s.hir_id); + intravisit::walk_field_def(self, s); + } + + fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) { + self.add_id(v.id); + intravisit::walk_variant(self, v); + } + + fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) { + self.add_id(l.hir_id); + intravisit::walk_local(self, l); + } + + fn visit_arm(&mut self, a: &'tcx hir::Arm<'tcx>) { + self.add_id(a.hir_id); + intravisit::walk_arm(self, a); + } + + fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { + self.add_id(trait_item.hir_id()); + intravisit::walk_trait_item(self, trait_item); + } + + fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { + self.add_id(impl_item.hir_id()); + intravisit::walk_impl_item(self, impl_item); + } +} + +impl<'tcx> LintLevelsBuilder<'_, QueryMapExpectationsWrapper<'tcx>> { + fn add_id(&mut self, hir_id: HirId) { + self.provider.cur = hir_id; + self.add(self.provider.tcx.hir().attrs(hir_id), hir_id == hir::CRATE_HIR_ID, Some(hir_id)); + } +} + +impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, QueryMapExpectationsWrapper<'tcx>> { + type NestedFilter = nested_filter::All; + + fn nested_visit_map(&mut self) -> Self::Map { + self.provider.tcx.hir() + } + + fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { + self.add_id(param.hir_id); + intravisit::walk_param(self, param); + } + + fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) { + self.add_id(it.hir_id()); + intravisit::walk_item(self, it); + } + + fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) { + self.add_id(it.hir_id()); + intravisit::walk_foreign_item(self, it); + } + + fn visit_stmt(&mut self, e: &'tcx hir::Stmt<'tcx>) { + // We will call `add_id` when we walk + // the `StmtKind`. The outer statement itself doesn't + // define the lint levels. + intravisit::walk_stmt(self, e); + } + + fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) { + self.add_id(e.hir_id); + intravisit::walk_expr(self, e); + } + + fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) { + self.add_id(s.hir_id); + intravisit::walk_field_def(self, s); + } + + fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) { + self.add_id(v.id); + intravisit::walk_variant(self, v); + } + + fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) { + self.add_id(l.hir_id); + intravisit::walk_local(self, l); + } + + fn visit_arm(&mut self, a: &'tcx hir::Arm<'tcx>) { + self.add_id(a.hir_id); + intravisit::walk_arm(self, a); + } + + fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { + self.add_id(trait_item.hir_id()); + intravisit::walk_trait_item(self, trait_item); + } + + fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { + self.add_id(impl_item.hir_id()); + intravisit::walk_impl_item(self, impl_item); + } +} + +pub struct LintLevelsBuilder<'s, P> { + sess: &'s Session, + provider: P, warn_about_weird_lints: bool, store: &'s LintStore, registered_tools: &'s RegisteredTools, } -pub struct BuilderPush { +pub(crate) struct BuilderPush { prev: LintStackIndex, - pub changed: bool, } -impl<'s> LintLevelsBuilder<'s> { - pub fn new( +impl<'s> LintLevelsBuilder<'s, TopDown> { + pub(crate) fn new( sess: &'s Session, warn_about_weird_lints: bool, store: &'s LintStore, @@ -75,20 +438,74 @@ impl<'s> LintLevelsBuilder<'s> { ) -> Self { let mut builder = LintLevelsBuilder { sess, - lint_expectations: Default::default(), - expectation_id_map: Default::default(), - sets: LintLevelSets::new(), - cur: COMMAND_LINE, - id_to_set: Default::default(), + provider: TopDown { sets: LintLevelSets::new(), cur: COMMAND_LINE }, warn_about_weird_lints, store, registered_tools, }; - builder.process_command_line(sess, store); - assert_eq!(builder.sets.list.len(), 1); + builder.process_command_line(); + assert_eq!(builder.provider.sets.list.len(), 1); builder } + fn process_command_line(&mut self) { + self.provider.cur = self + .provider + .sets + .list + .push(LintSet { specs: FxHashMap::default(), parent: COMMAND_LINE }); + self.add_command_line(); + } + + /// Pushes a list of AST lint attributes onto this context. + /// + /// This function will return a `BuilderPush` object which should be passed + /// to `pop` when this scope for the attributes provided is exited. + /// + /// This function will perform a number of tasks: + /// + /// * It'll validate all lint-related attributes in `attrs` + /// * It'll mark all lint-related attributes as used + /// * Lint levels will be updated based on the attributes provided + /// * Lint attributes are validated, e.g., a `#[forbid]` can't be switched to + /// `#[allow]` + /// + /// Don't forget to call `pop`! + pub(crate) fn push( + &mut self, + attrs: &[ast::Attribute], + is_crate_node: bool, + source_hir_id: Option<HirId>, + ) -> BuilderPush { + let prev = self.provider.cur; + self.provider.cur = + self.provider.sets.list.push(LintSet { specs: FxHashMap::default(), parent: prev }); + + self.add(attrs, is_crate_node, source_hir_id); + + if self.provider.current_specs().is_empty() { + self.provider.sets.list.pop(); + self.provider.cur = prev; + } + + BuilderPush { prev } + } + + /// Called after `push` when the scope of a set of attributes are exited. + pub(crate) fn pop(&mut self, push: BuilderPush) { + self.provider.cur = push.prev; + std::mem::forget(push); + } +} + +#[cfg(debug_assertions)] +impl Drop for BuilderPush { + fn drop(&mut self) { + panic!("Found a `push` without a `pop`."); + } +} + +impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { pub(crate) fn sess(&self) -> &Session { self.sess } @@ -98,24 +515,20 @@ impl<'s> LintLevelsBuilder<'s> { } fn current_specs(&self) -> &FxHashMap<LintId, LevelAndSource> { - &self.sets.list[self.cur].specs + self.provider.current_specs() } - fn current_specs_mut(&mut self) -> &mut FxHashMap<LintId, LevelAndSource> { - &mut self.sets.list[self.cur].specs + fn insert(&mut self, id: LintId, lvl: LevelAndSource) { + self.provider.insert(id, lvl) } - fn process_command_line(&mut self, sess: &Session, store: &LintStore) { - self.sets.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid); - - self.cur = - self.sets.list.push(LintSet { specs: FxHashMap::default(), parent: COMMAND_LINE }); - for &(ref lint_name, level) in &sess.opts.lint_opts { - store.check_lint_name_cmdline(sess, &lint_name, level, self.registered_tools); + fn add_command_line(&mut self) { + for &(ref lint_name, level) in &self.sess.opts.lint_opts { + self.store.check_lint_name_cmdline(self.sess, &lint_name, level, self.registered_tools); let orig_level = level; let lint_flag_val = Symbol::intern(lint_name); - let Ok(ids) = store.find_lints(&lint_name) else { + let Ok(ids) = self.store.find_lints(&lint_name) else { // errors handled in check_lint_name_cmdline above continue }; @@ -129,7 +542,7 @@ impl<'s> LintLevelsBuilder<'s> { if self.check_gated_lint(id, DUMMY_SP) { let src = LintLevelSource::CommandLine(lint_flag_val, orig_level); - self.current_specs_mut().insert(id, (level, src)); + self.insert(id, (level, src)); } } } @@ -138,9 +551,11 @@ impl<'s> LintLevelsBuilder<'s> { /// Attempts to insert the `id` to `level_src` map entry. If unsuccessful /// (e.g. if a forbid was already inserted on the same scope), then emits a /// diagnostic with no change to `specs`. - fn insert_spec(&mut self, id: LintId, (level, src): LevelAndSource) { - let (old_level, old_src) = - self.sets.get_lint_level(id.lint, self.cur, Some(self.current_specs()), &self.sess); + fn insert_spec(&mut self, id: LintId, (mut level, src): LevelAndSource) { + let (old_level, old_src) = self.provider.get_lint_level(id.lint, &self.sess); + if let Level::Expect(id) = &mut level && let LintExpectationId::Stable { .. } = id { + *id = id.normalize(); + } // Setting to a non-forbid level is an error if the lint previously had // a forbid level. Note that this is not necessarily true even with a // `#[forbid(..)]` attribute present, as that is overridden by `--cap-lints`. @@ -158,7 +573,7 @@ impl<'s> LintLevelsBuilder<'s> { let id_name = id.lint.name_lower(); let fcw_warning = match old_src { LintLevelSource::Default => false, - LintLevelSource::Node(symbol, _, _) => self.store.is_lint_group(symbol), + LintLevelSource::Node { name, .. } => self.store.is_lint_group(name), LintLevelSource::CommandLine(symbol, _) => self.store.is_lint_group(symbol), }; debug!( @@ -178,8 +593,8 @@ impl<'s> LintLevelsBuilder<'s> { id.to_string() )); } - LintLevelSource::Node(_, forbid_source_span, reason) => { - diag.span_label(forbid_source_span, "`forbid` level set here"); + LintLevelSource::Node { span, reason, .. } => { + diag.span_label(span, "`forbid` level set here"); if let Some(rationale) = reason { diag.note(rationale.as_str()); } @@ -199,11 +614,8 @@ impl<'s> LintLevelsBuilder<'s> { LintLevelSource::Default => { OverruledAttributeSub::DefaultSource { id: id.to_string() } } - LintLevelSource::Node(_, forbid_source_span, reason) => { - OverruledAttributeSub::NodeSource { - span: forbid_source_span, - reason, - } + LintLevelSource::Node { span, reason, .. } => { + OverruledAttributeSub::NodeSource { span, reason } } LintLevelSource::CommandLine(_, _) => { OverruledAttributeSub::CommandLineSource @@ -244,45 +656,21 @@ impl<'s> LintLevelsBuilder<'s> { match (old_level, level) { // If the new level is an expectation store it in `ForceWarn` - (Level::ForceWarn(_), Level::Expect(expectation_id)) => self - .current_specs_mut() - .insert(id, (Level::ForceWarn(Some(expectation_id)), old_src)), - // Keep `ForceWarn` level but drop the expectation - (Level::ForceWarn(_), _) => { - self.current_specs_mut().insert(id, (Level::ForceWarn(None), old_src)) + (Level::ForceWarn(_), Level::Expect(expectation_id)) => { + self.insert(id, (Level::ForceWarn(Some(expectation_id)), old_src)) } + // Keep `ForceWarn` level but drop the expectation + (Level::ForceWarn(_), _) => self.insert(id, (Level::ForceWarn(None), old_src)), // Set the lint level as normal - _ => self.current_specs_mut().insert(id, (level, src)), + _ => self.insert(id, (level, src)), }; } - /// Pushes a list of AST lint attributes onto this context. - /// - /// This function will return a `BuilderPush` object which should be passed - /// to `pop` when this scope for the attributes provided is exited. - /// - /// This function will perform a number of tasks: - /// - /// * It'll validate all lint-related attributes in `attrs` - /// * It'll mark all lint-related attributes as used - /// * Lint levels will be updated based on the attributes provided - /// * Lint attributes are validated, e.g., a `#[forbid]` can't be switched to - /// `#[allow]` - /// - /// Don't forget to call `pop`! - pub(crate) fn push( - &mut self, - attrs: &[ast::Attribute], - is_crate_node: bool, - source_hir_id: Option<HirId>, - ) -> BuilderPush { - let prev = self.cur; - self.cur = self.sets.list.push(LintSet { specs: FxHashMap::default(), parent: prev }); - + fn add(&mut self, attrs: &[ast::Attribute], is_crate_node: bool, source_hir_id: Option<HirId>) { let sess = self.sess; for (attr_index, attr) in attrs.iter().enumerate() { if attr.has_name(sym::automatically_derived) { - self.current_specs_mut().insert( + self.insert( LintId::of(SINGLE_USE_LIFETIMES), (Level::Allow, LintLevelSource::Default), ); @@ -293,7 +681,17 @@ impl<'s> LintLevelsBuilder<'s> { None => continue, // This is the only lint level with a `LintExpectationId` that can be created from an attribute Some(Level::Expect(unstable_id)) if let Some(hir_id) = source_hir_id => { - let stable_id = self.create_stable_id(unstable_id, hir_id, attr_index); + let LintExpectationId::Unstable { attr_id, lint_index } = unstable_id + else { bug!("stable id Level::from_attr") }; + + let stable_id = LintExpectationId::Stable { + hir_id, + attr_index: attr_index.try_into().unwrap(), + lint_index, + // we pass the previous unstable attr_id such that we can trace the ast id when building a map + // to go from unstable to stable id. + attr_id: Some(attr_id), + }; Level::Expect(stable_id) } @@ -408,7 +806,7 @@ impl<'s> LintLevelsBuilder<'s> { [lint] => *lint == LintId::of(UNFULFILLED_LINT_EXPECTATIONS), _ => false, }; - self.lint_expectations.push(( + self.provider.push_expectation( expect_id, LintExpectation::new( reason, @@ -416,13 +814,19 @@ impl<'s> LintLevelsBuilder<'s> { is_unfulfilled_lint_expectations, tool_name, ), - )); + ); } - let src = LintLevelSource::Node( - meta_item.path.segments.last().expect("empty lint name").ident.name, - sp, + let src = LintLevelSource::Node { + name: meta_item + .path + .segments + .last() + .expect("empty lint name") + .ident + .name, + span: sp, reason, - ); + }; for &id in *ids { if self.check_gated_lint(id, attr.span) { self.insert_spec(id, (level, src)); @@ -435,31 +839,26 @@ impl<'s> LintLevelsBuilder<'s> { Ok(ids) => { let complete_name = &format!("{}::{}", tool_ident.unwrap().name, name); - let src = LintLevelSource::Node( - Symbol::intern(complete_name), - sp, + let src = LintLevelSource::Node { + name: Symbol::intern(complete_name), + span: sp, reason, - ); + }; for &id in ids { if self.check_gated_lint(id, attr.span) { self.insert_spec(id, (level, src)); } } if let Level::Expect(expect_id) = level { - self.lint_expectations.push(( + self.provider.push_expectation( expect_id, LintExpectation::new(reason, sp, false, tool_name), - )); + ); } } Err((Some(ids), ref new_lint_name)) => { let lint = builtin::RENAMED_AND_REMOVED_LINTS; - let (lvl, src) = self.sets.get_lint_level( - lint, - self.cur, - Some(self.current_specs()), - &sess, - ); + let (lvl, src) = self.provider.get_lint_level(lint, &sess); struct_lint_level( self.sess, lint, @@ -481,19 +880,19 @@ impl<'s> LintLevelsBuilder<'s> { }, ); - let src = LintLevelSource::Node( - Symbol::intern(&new_lint_name), - sp, + let src = LintLevelSource::Node { + name: Symbol::intern(&new_lint_name), + span: sp, reason, - ); + }; for id in ids { self.insert_spec(*id, (level, src)); } if let Level::Expect(expect_id) = level { - self.lint_expectations.push(( + self.provider.push_expectation( expect_id, LintExpectation::new(reason, sp, false, tool_name), - )); + ); } } Err((None, _)) => { @@ -519,12 +918,7 @@ impl<'s> LintLevelsBuilder<'s> { CheckLintNameResult::Warning(msg, renamed) => { let lint = builtin::RENAMED_AND_REMOVED_LINTS; - let (renamed_lint_level, src) = self.sets.get_lint_level( - lint, - self.cur, - Some(self.current_specs()), - &sess, - ); + let (renamed_lint_level, src) = self.provider.get_lint_level(lint, &sess); struct_lint_level( self.sess, lint, @@ -547,12 +941,7 @@ impl<'s> LintLevelsBuilder<'s> { } CheckLintNameResult::NoLint(suggestion) => { let lint = builtin::UNKNOWN_LINTS; - let (level, src) = self.sets.get_lint_level( - lint, - self.cur, - Some(self.current_specs()), - self.sess, - ); + let (level, src) = self.provider.get_lint_level(lint, self.sess); let name = if let Some(tool_ident) = tool_ident { format!("{}::{}", tool_ident.name, name) } else { @@ -588,17 +977,21 @@ impl<'s> LintLevelsBuilder<'s> { if let CheckLintNameResult::Ok(ids) = self.store.check_lint_name(&new_name, None, self.registered_tools) { - let src = LintLevelSource::Node(Symbol::intern(&new_name), sp, reason); + let src = LintLevelSource::Node { + name: Symbol::intern(&new_name), + span: sp, + reason, + }; for &id in ids { if self.check_gated_lint(id, attr.span) { self.insert_spec(id, (level, src)); } } if let Level::Expect(expect_id) = level { - self.lint_expectations.push(( + self.provider.push_expectation( expect_id, LintExpectation::new(reason, sp, false, tool_name), - )); + ); } } else { panic!("renamed lint does not exist: {}", new_name); @@ -613,13 +1006,12 @@ impl<'s> LintLevelsBuilder<'s> { continue; } - let LintLevelSource::Node(lint_attr_name, lint_attr_span, _) = *src else { + let LintLevelSource::Node { name: lint_attr_name, span: lint_attr_span, .. } = *src else { continue }; let lint = builtin::UNUSED_ATTRIBUTES; - let (lint_level, lint_src) = - self.sets.get_lint_level(lint, self.cur, Some(self.current_specs()), self.sess); + let (lint_level, lint_src) = self.provider.get_lint_level(lint, &self.sess); struct_lint_level( self.sess, lint, @@ -637,32 +1029,13 @@ impl<'s> LintLevelsBuilder<'s> { break; } } - - if self.current_specs().is_empty() { - self.sets.list.pop(); - self.cur = prev; - } - - BuilderPush { prev, changed: prev != self.cur } - } - - fn create_stable_id( - &mut self, - unstable_id: LintExpectationId, - hir_id: HirId, - attr_index: usize, - ) -> LintExpectationId { - let stable_id = - LintExpectationId::Stable { hir_id, attr_index: attr_index as u16, lint_index: None }; - - self.expectation_id_map.insert(unstable_id, stable_id); - - stable_id } /// Checks if the lint is gated on a feature that is not enabled. /// /// Returns `true` if the lint's feature is enabled. + // FIXME only emit this once for each attribute, instead of repeating it 4 times for + // pre-expansion lints, post-expansion lints, `shallow_lint_levels_on` and `lint_expectations`. fn check_gated_lint(&self, lint_id: LintId, span: Span) -> bool { if let Some(feature) = lint_id.lint.feature_gate { if !self.sess.features_untracked().enabled(feature) { @@ -689,19 +1062,14 @@ impl<'s> LintLevelsBuilder<'s> { true } - /// Called after `push` when the scope of a set of attributes are exited. - pub fn pop(&mut self, push: BuilderPush) { - self.cur = push.prev; - } - /// Find the lint level for a lint. - pub fn lint_level(&self, lint: &'static Lint) -> (Level, LintLevelSource) { - self.sets.get_lint_level(lint, self.cur, None, self.sess) + pub fn lint_level(&self, lint: &'static Lint) -> LevelAndSource { + self.provider.get_lint_level(lint, self.sess) } /// Used to emit a lint-related diagnostic based on the current state of /// this lint context. - pub fn struct_lint( + pub(crate) fn struct_lint( &self, lint: &'static Lint, span: Option<MultiSpan>, @@ -713,141 +1081,8 @@ impl<'s> LintLevelsBuilder<'s> { let (level, src) = self.lint_level(lint); struct_lint_level(self.sess, lint, level, src, span, msg, decorate) } - - /// Registers the ID provided with the current set of lints stored in - /// this context. - pub fn register_id(&mut self, id: HirId) { - self.id_to_set.insert(id, self.cur); - } - - fn update_unstable_expectation_ids(&self) { - self.sess.diagnostic().update_unstable_expectation_id(&self.expectation_id_map); - } - - pub fn build_map(self) -> LintLevelMap { - LintLevelMap { - sets: self.sets, - id_to_set: self.id_to_set, - lint_expectations: self.lint_expectations, - } - } -} - -struct LintLevelMapBuilder<'tcx> { - levels: LintLevelsBuilder<'tcx>, - tcx: TyCtxt<'tcx>, -} - -impl LintLevelMapBuilder<'_> { - fn with_lint_attrs<F>(&mut self, id: hir::HirId, f: F) - where - F: FnOnce(&mut Self), - { - let is_crate_hir = id == hir::CRATE_HIR_ID; - let attrs = self.tcx.hir().attrs(id); - let push = self.levels.push(attrs, is_crate_hir, Some(id)); - - if push.changed { - self.levels.register_id(id); - } - f(self); - self.levels.pop(push); - } -} - -impl<'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'tcx> { - type NestedFilter = nested_filter::All; - - fn nested_visit_map(&mut self) -> Self::Map { - self.tcx.hir() - } - - fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { - self.with_lint_attrs(param.hir_id, |builder| { - intravisit::walk_param(builder, param); - }); - } - - fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) { - self.with_lint_attrs(it.hir_id(), |builder| { - intravisit::walk_item(builder, it); - }); - } - - fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) { - self.with_lint_attrs(it.hir_id(), |builder| { - intravisit::walk_foreign_item(builder, it); - }) - } - - fn visit_stmt(&mut self, e: &'tcx hir::Stmt<'tcx>) { - // We will call `with_lint_attrs` when we walk - // the `StmtKind`. The outer statement itself doesn't - // define the lint levels. - intravisit::walk_stmt(self, e); - } - - fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) { - self.with_lint_attrs(e.hir_id, |builder| { - intravisit::walk_expr(builder, e); - }) - } - - fn visit_expr_field(&mut self, field: &'tcx hir::ExprField<'tcx>) { - self.with_lint_attrs(field.hir_id, |builder| { - intravisit::walk_expr_field(builder, field); - }) - } - - fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) { - self.with_lint_attrs(s.hir_id, |builder| { - intravisit::walk_field_def(builder, s); - }) - } - - fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) { - self.with_lint_attrs(v.id, |builder| { - intravisit::walk_variant(builder, v); - }) - } - - fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) { - self.with_lint_attrs(l.hir_id, |builder| { - intravisit::walk_local(builder, l); - }) - } - - fn visit_arm(&mut self, a: &'tcx hir::Arm<'tcx>) { - self.with_lint_attrs(a.hir_id, |builder| { - intravisit::walk_arm(builder, a); - }) - } - - fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { - self.with_lint_attrs(trait_item.hir_id(), |builder| { - intravisit::walk_trait_item(builder, trait_item); - }); - } - - fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { - self.with_lint_attrs(impl_item.hir_id(), |builder| { - intravisit::walk_impl_item(builder, impl_item); - }); - } - - fn visit_pat_field(&mut self, field: &'tcx hir::PatField<'tcx>) { - self.with_lint_attrs(field.hir_id, |builder| { - intravisit::walk_pat_field(builder, field); - }) - } - - fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) { - self.with_lint_attrs(p.hir_id, |builder| { - intravisit::walk_generic_param(builder, p); - }); - } } -pub fn provide(providers: &mut Providers) { - providers.lint_levels = lint_levels; +pub(crate) fn provide(providers: &mut Providers) { + *providers = Providers { shallow_lint_levels_on, lint_expectations, ..*providers }; } diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 11b2d057a07..cbe7afc8e55 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -92,7 +92,7 @@ pub enum LintExpectationId { /// stable and can be cached. The additional index ensures that nodes with /// several expectations can correctly match diagnostics to the individual /// expectation. - Stable { hir_id: HirId, attr_index: u16, lint_index: Option<u16> }, + Stable { hir_id: HirId, attr_index: u16, lint_index: Option<u16>, attr_id: Option<AttrId> }, } impl LintExpectationId { @@ -116,13 +116,31 @@ impl LintExpectationId { *lint_index = new_lint_index } + + /// Prepares the id for hashing. Removes references to the ast. + /// Should only be called when the id is stable. + pub fn normalize(self) -> Self { + match self { + Self::Stable { hir_id, attr_index, lint_index, .. } => { + Self::Stable { hir_id, attr_index, lint_index, attr_id: None } + } + Self::Unstable { .. } => { + unreachable!("`normalize` called when `ExpectationId` is unstable") + } + } + } } impl<HCX: rustc_hir::HashStableContext> HashStable<HCX> for LintExpectationId { #[inline] fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) { match self { - LintExpectationId::Stable { hir_id, attr_index, lint_index: Some(lint_index) } => { + LintExpectationId::Stable { + hir_id, + attr_index, + lint_index: Some(lint_index), + attr_id: _, + } => { hir_id.hash_stable(hcx, hasher); attr_index.hash_stable(hcx, hasher); lint_index.hash_stable(hcx, hasher); @@ -142,9 +160,12 @@ impl<HCX: rustc_hir::HashStableContext> ToStableHashKey<HCX> for LintExpectation #[inline] fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType { match self { - LintExpectationId::Stable { hir_id, attr_index, lint_index: Some(lint_index) } => { - (*hir_id, *attr_index, *lint_index) - } + LintExpectationId::Stable { + hir_id, + attr_index, + lint_index: Some(lint_index), + attr_id: _, + } => (*hir_id, *attr_index, *lint_index), _ => { unreachable!("HashStable should only be called for a filled `LintExpectationId`") } diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index 40b9d73db94..6b556826918 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -62,7 +62,7 @@ use crate::ty::TyCtxt; use rustc_data_structures::fingerprint::Fingerprint; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; use rustc_hir::definitions::DefPathHash; -use rustc_hir::{HirId, OwnerId}; +use rustc_hir::{HirId, ItemLocalId, OwnerId}; use rustc_query_system::dep_graph::FingerprintStyle; use rustc_span::symbol::Symbol; use std::hash::Hash; @@ -194,7 +194,7 @@ impl DepNodeExt for DepNode { let kind = dep_kind_from_label_string(label)?; match tcx.fingerprint_style(kind) { - FingerprintStyle::Opaque => Err(()), + FingerprintStyle::Opaque | FingerprintStyle::HirId => Err(()), FingerprintStyle::Unit => Ok(DepNode::new_no_params(tcx, kind)), FingerprintStyle::DefPathHash => { Ok(DepNode::from_def_path_hash(tcx, def_path_hash, kind)) @@ -344,7 +344,7 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for (DefId, DefId) { impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for HirId { #[inline(always)] fn fingerprint_style() -> FingerprintStyle { - FingerprintStyle::Opaque + FingerprintStyle::HirId } // We actually would not need to specialize the implementation of this @@ -353,10 +353,36 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for HirId { #[inline(always)] fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { let HirId { owner, local_id } = *self; - let def_path_hash = tcx.def_path_hash(owner.to_def_id()); - let local_id = Fingerprint::from_smaller_hash(local_id.as_u32().into()); + Fingerprint::new( + // `owner` is local, so is completely defined by the local hash + def_path_hash.local_hash(), + local_id.as_u32().into(), + ) + } - def_path_hash.0.combine(local_id) + #[inline(always)] + fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { + let HirId { owner, local_id } = *self; + format!("{}.{}", tcx.def_path_str(owner.to_def_id()), local_id.as_u32()) + } + + #[inline(always)] + fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> { + if tcx.fingerprint_style(dep_node.kind) == FingerprintStyle::HirId { + let (local_hash, local_id) = Fingerprint::from(dep_node.hash).as_value(); + let def_path_hash = DefPathHash::new(tcx.sess.local_stable_crate_id(), local_hash); + let def_id = tcx + .def_path_hash_to_def_id(def_path_hash, &mut || { + panic!("Failed to extract HirId: {:?} {}", dep_node.kind, dep_node.hash) + }) + .expect_local(); + let local_id = local_id + .try_into() + .unwrap_or_else(|_| panic!("local id should be u32, found {:?}", local_id)); + Some(HirId { owner: OwnerId { def_id }, local_id: ItemLocalId::from_u32(local_id) }) + } else { + None + } } } diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 8523b5ca0ec..b78c3f85596 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -61,7 +61,7 @@ pub struct ParentHirIterator<'hir> { } impl<'hir> Iterator for ParentHirIterator<'hir> { - type Item = (HirId, Node<'hir>); + type Item = HirId; fn next(&mut self) -> Option<Self::Item> { if self.current_id == CRATE_HIR_ID { @@ -77,10 +77,7 @@ impl<'hir> Iterator for ParentHirIterator<'hir> { } self.current_id = parent_id; - if let Some(node) = self.map.find(parent_id) { - return Some((parent_id, node)); - } - // If this `HirId` doesn't have an entry, skip it and look for its `parent_id`. + return Some(parent_id); } } } @@ -393,8 +390,8 @@ impl<'hir> Map<'hir> { } pub fn enclosing_body_owner(self, hir_id: HirId) -> LocalDefId { - for (parent, _) in self.parent_iter(hir_id) { - if let Some(body) = self.find(parent).map(associated_body).flatten() { + for (_, node) in self.parent_iter(hir_id) { + if let Some(body) = associated_body(node) { return self.body_owner_def_id(body); } } @@ -635,13 +632,20 @@ impl<'hir> Map<'hir> { /// Returns an iterator for the nodes in the ancestor tree of the `current_id` /// until the crate root is reached. Prefer this over your own loop using `get_parent_node`. #[inline] - pub fn parent_iter(self, current_id: HirId) -> ParentHirIterator<'hir> { + pub fn parent_id_iter(self, current_id: HirId) -> impl Iterator<Item = HirId> + 'hir { ParentHirIterator { current_id, map: self } } /// Returns an iterator for the nodes in the ancestor tree of the `current_id` /// until the crate root is reached. Prefer this over your own loop using `get_parent_node`. #[inline] + pub fn parent_iter(self, current_id: HirId) -> impl Iterator<Item = (HirId, Node<'hir>)> { + self.parent_id_iter(current_id).filter_map(move |id| Some((id, self.find(id)?))) + } + + /// Returns an iterator for the nodes in the ancestor tree of the `current_id` + /// until the crate root is reached. Prefer this over your own loop using `get_parent_node`. + #[inline] pub fn parent_owner_iter(self, current_id: HirId) -> ParentOwnerIterator<'hir> { ParentOwnerIterator { current_id, map: self } } @@ -937,9 +941,19 @@ impl<'hir> Map<'hir> { let span = match self.find(hir_id)? { // Function-like. - Node::Item(Item { kind: ItemKind::Fn(sig, ..), .. }) - | Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(sig, ..), .. }) - | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(sig, ..), .. }) => sig.span, + Node::Item(Item { kind: ItemKind::Fn(sig, ..), span: outer_span, .. }) + | Node::TraitItem(TraitItem { + kind: TraitItemKind::Fn(sig, ..), + span: outer_span, + .. + }) + | Node::ImplItem(ImplItem { + kind: ImplItemKind::Fn(sig, ..), span: outer_span, .. + }) => { + // Ensure that the returned span has the item's SyntaxContext, and not the + // SyntaxContext of the visibility. + sig.span.find_ancestor_in_same_ctxt(*outer_span).unwrap_or(*outer_span) + } // Constants and Statics. Node::Item(Item { kind: @@ -981,7 +995,11 @@ impl<'hir> Map<'hir> { } // Other cases. Node::Item(item) => match &item.kind { - ItemKind::Use(path, _) => path.span, + ItemKind::Use(path, _) => { + // Ensure that the returned span has the item's SyntaxContext, and not the + // SyntaxContext of the path. + path.span.find_ancestor_in_same_ctxt(item.span).unwrap_or(item.span) + } _ => named_span(item.span, item.ident, item.kind.generics()), }, Node::Variant(variant) => named_span(variant.span, variant.ident, None), @@ -991,11 +1009,17 @@ impl<'hir> Map<'hir> { _ => named_span(item.span, item.ident, None), }, Node::Ctor(_) => return self.opt_span(self.get_parent_node(hir_id)), - Node::Expr(Expr { kind: ExprKind::Closure(Closure { fn_decl_span, .. }), .. }) => { - *fn_decl_span + Node::Expr(Expr { + kind: ExprKind::Closure(Closure { fn_decl_span, .. }), + span, + .. + }) => { + // Ensure that the returned span has the item's SyntaxContext. + fn_decl_span.find_ancestor_in_same_ctxt(*span).unwrap_or(*span) } _ => self.span_with_body(hir_id), }; + debug_assert_eq!(span.ctxt(), self.span_with_body(hir_id).ctxt()); Some(span) } diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 328b7ad6a49..7b0054a96d3 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -1,20 +1,20 @@ use std::cmp; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::sorted_map::SortedMap; use rustc_errors::{Diagnostic, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, MultiSpan}; -use rustc_hir::HirId; -use rustc_index::vec::IndexVec; -use rustc_query_system::ich::StableHashingContext; +use rustc_hir::{HirId, ItemLocalId}; use rustc_session::lint::{ builtin::{self, FORBIDDEN_LINT_GROUPS}, - FutureIncompatibilityReason, Level, Lint, LintExpectationId, LintId, + FutureIncompatibilityReason, Level, Lint, LintId, }; use rustc_session::Session; use rustc_span::hygiene::MacroKind; use rustc_span::source_map::{DesugaringKind, ExpnKind}; use rustc_span::{symbol, Span, Symbol, DUMMY_SP}; +use crate::ty::TyCtxt; + /// How a lint level was set. #[derive(Clone, Copy, PartialEq, Eq, HashStable, Debug)] pub enum LintLevelSource { @@ -23,7 +23,12 @@ pub enum LintLevelSource { Default, /// Lint level was set by an attribute. - Node(Symbol, Span, Option<Symbol> /* RFC 2383 reason */), + Node { + name: Symbol, + span: Span, + /// RFC 2383 reason + reason: Option<Symbol>, + }, /// Lint level was set by a command-line flag. /// The provided `Level` is the level specified on the command line. @@ -35,7 +40,7 @@ impl LintLevelSource { pub fn name(&self) -> Symbol { match *self { LintLevelSource::Default => symbol::kw::Default, - LintLevelSource::Node(name, _, _) => name, + LintLevelSource::Node { name, .. } => name, LintLevelSource::CommandLine(name, _) => name, } } @@ -43,7 +48,7 @@ impl LintLevelSource { pub fn span(&self) -> Span { match *self { LintLevelSource::Default => DUMMY_SP, - LintLevelSource::Node(_, span, _) => span, + LintLevelSource::Node { span, .. } => span, LintLevelSource::CommandLine(_, _) => DUMMY_SP, } } @@ -52,145 +57,137 @@ impl LintLevelSource { /// A tuple of a lint level and its source. pub type LevelAndSource = (Level, LintLevelSource); -#[derive(Debug, HashStable)] -pub struct LintLevelSets { - pub list: IndexVec<LintStackIndex, LintSet>, - pub lint_cap: Level, -} - -rustc_index::newtype_index! { - #[derive(HashStable)] - pub struct LintStackIndex { - const COMMAND_LINE = 0, - } -} - -#[derive(Debug, HashStable)] -pub struct LintSet { - // -A,-W,-D flags, a `Symbol` for the flag itself and `Level` for which - // flag. - pub specs: FxHashMap<LintId, LevelAndSource>, - - pub parent: LintStackIndex, +/// Return type for the `shallow_lint_levels_on` query. +/// +/// This map represents the set of allowed lints and allowance levels given +/// by the attributes for *a single HirId*. +#[derive(Default, Debug, HashStable)] +pub struct ShallowLintLevelMap { + pub specs: SortedMap<ItemLocalId, FxHashMap<LintId, LevelAndSource>>, } -impl LintLevelSets { - pub fn new() -> Self { - LintLevelSets { list: IndexVec::new(), lint_cap: Level::Forbid } - } - - pub fn get_lint_level( - &self, - lint: &'static Lint, - idx: LintStackIndex, - aux: Option<&FxHashMap<LintId, LevelAndSource>>, - sess: &Session, - ) -> LevelAndSource { - let (level, mut src) = self.get_lint_id_level(LintId::of(lint), idx, aux); - - // If `level` is none then we actually assume the default level for this - // lint. - let mut level = level.unwrap_or_else(|| lint.default_level(sess.edition())); - - // If we're about to issue a warning, check at the last minute for any - // directives against the warnings "lint". If, for example, there's an - // `allow(warnings)` in scope then we want to respect that instead. - // - // We exempt `FORBIDDEN_LINT_GROUPS` from this because it specifically - // triggers in cases (like #80988) where you have `forbid(warnings)`, - // and so if we turned that into an error, it'd defeat the purpose of the - // future compatibility warning. - if level == Level::Warn && LintId::of(lint) != LintId::of(FORBIDDEN_LINT_GROUPS) { - let (warnings_level, warnings_src) = - self.get_lint_id_level(LintId::of(builtin::WARNINGS), idx, aux); - if let Some(configured_warning_level) = warnings_level { - if configured_warning_level != Level::Warn { - level = configured_warning_level; - src = warnings_src; - } +/// From an initial level and source, verify the effect of special annotations: +/// `warnings` lint level and lint caps. +/// +/// The return of this function is suitable for diagnostics. +pub fn reveal_actual_level( + level: Option<Level>, + src: &mut LintLevelSource, + sess: &Session, + lint: LintId, + probe_for_lint_level: impl FnOnce(LintId) -> (Option<Level>, LintLevelSource), +) -> Level { + // If `level` is none then we actually assume the default level for this lint. + let mut level = level.unwrap_or_else(|| lint.lint.default_level(sess.edition())); + + // If we're about to issue a warning, check at the last minute for any + // directives against the warnings "lint". If, for example, there's an + // `allow(warnings)` in scope then we want to respect that instead. + // + // We exempt `FORBIDDEN_LINT_GROUPS` from this because it specifically + // triggers in cases (like #80988) where you have `forbid(warnings)`, + // and so if we turned that into an error, it'd defeat the purpose of the + // future compatibility warning. + if level == Level::Warn && lint != LintId::of(FORBIDDEN_LINT_GROUPS) { + let (warnings_level, warnings_src) = probe_for_lint_level(LintId::of(builtin::WARNINGS)); + if let Some(configured_warning_level) = warnings_level { + if configured_warning_level != Level::Warn { + level = configured_warning_level; + *src = warnings_src; } } + } - // Ensure that we never exceed the `--cap-lints` argument - // unless the source is a --force-warn - level = if let LintLevelSource::CommandLine(_, Level::ForceWarn(_)) = src { - level - } else { - cmp::min(level, self.lint_cap) - }; - - if let Some(driver_level) = sess.driver_lint_caps.get(&LintId::of(lint)) { - // Ensure that we never exceed driver level. - level = cmp::min(*driver_level, level); - } + // Ensure that we never exceed the `--cap-lints` argument unless the source is a --force-warn + level = if let LintLevelSource::CommandLine(_, Level::ForceWarn(_)) = src { + level + } else { + cmp::min(level, sess.opts.lint_cap.unwrap_or(Level::Forbid)) + }; - (level, src) + if let Some(driver_level) = sess.driver_lint_caps.get(&lint) { + // Ensure that we never exceed driver level. + level = cmp::min(*driver_level, level); } - pub fn get_lint_id_level( + level +} + +impl ShallowLintLevelMap { + /// Perform a deep probe in the HIR tree looking for the actual level for the lint. + /// This lint level is not usable for diagnostics, it needs to be corrected by + /// `reveal_actual_level` beforehand. + #[instrument(level = "trace", skip(self, tcx), ret)] + fn probe_for_lint_level( &self, + tcx: TyCtxt<'_>, id: LintId, - mut idx: LintStackIndex, - aux: Option<&FxHashMap<LintId, LevelAndSource>>, + start: HirId, ) -> (Option<Level>, LintLevelSource) { - if let Some(specs) = aux { - if let Some(&(level, src)) = specs.get(&id) { - return (Some(level), src); - } + if let Some(map) = self.specs.get(&start.local_id) + && let Some(&(level, src)) = map.get(&id) + { + return (Some(level), src); } - loop { - let LintSet { ref specs, parent } = self.list[idx]; - if let Some(&(level, src)) = specs.get(&id) { - return (Some(level), src); + + let mut owner = start.owner; + let mut specs = &self.specs; + + for parent in tcx.hir().parent_id_iter(start) { + if parent.owner != owner { + owner = parent.owner; + specs = &tcx.shallow_lint_levels_on(owner).specs; } - if idx == COMMAND_LINE { - return (None, LintLevelSource::Default); + if let Some(map) = specs.get(&parent.local_id) + && let Some(&(level, src)) = map.get(&id) + { + return (Some(level), src); } - idx = parent; } - } -} -#[derive(Debug)] -pub struct LintLevelMap { - /// This is a collection of lint expectations as described in RFC 2383, that - /// can be fulfilled during this compilation session. This means that at least - /// one expected lint is currently registered in the lint store. - /// - /// The [`LintExpectationId`] is stored as a part of the [`Expect`](Level::Expect) - /// lint level. - pub lint_expectations: Vec<(LintExpectationId, LintExpectation)>, - pub sets: LintLevelSets, - pub id_to_set: FxHashMap<HirId, LintStackIndex>, -} + (None, LintLevelSource::Default) + } -impl LintLevelMap { - /// If the `id` was previously registered with `register_id` when building - /// this `LintLevelMap` this returns the corresponding lint level and source - /// of the lint level for the lint provided. - /// - /// If the `id` was not previously registered, returns `None`. If `None` is - /// returned then the parent of `id` should be acquired and this function - /// should be called again. - pub fn level_and_source( + /// Fetch and return the user-visible lint level for the given lint at the given HirId. + #[instrument(level = "trace", skip(self, tcx), ret)] + pub fn lint_level_id_at_node( &self, - lint: &'static Lint, - id: HirId, - session: &Session, - ) -> Option<LevelAndSource> { - self.id_to_set.get(&id).map(|idx| self.sets.get_lint_level(lint, *idx, None, session)) + tcx: TyCtxt<'_>, + lint: LintId, + cur: HirId, + ) -> (Level, LintLevelSource) { + let (level, mut src) = self.probe_for_lint_level(tcx, lint, cur); + let level = reveal_actual_level(level, &mut src, tcx.sess, lint, |lint| { + self.probe_for_lint_level(tcx, lint, cur) + }); + (level, src) } } -impl<'a> HashStable<StableHashingContext<'a>> for LintLevelMap { - #[inline] - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let LintLevelMap { ref sets, ref id_to_set, ref lint_expectations } = *self; +impl TyCtxt<'_> { + /// Fetch and return the user-visible lint level for the given lint at the given HirId. + pub fn lint_level_at_node(self, lint: &'static Lint, id: HirId) -> (Level, LintLevelSource) { + self.shallow_lint_levels_on(id.owner).lint_level_id_at_node(self, LintId::of(lint), id) + } - id_to_set.hash_stable(hcx, hasher); - lint_expectations.hash_stable(hcx, hasher); + /// Walks upwards from `id` to find a node which might change lint levels with attributes. + /// It stops at `bound` and just returns it if reached. + pub fn maybe_lint_level_root_bounded(self, mut id: HirId, bound: HirId) -> HirId { + let hir = self.hir(); + loop { + if id == bound { + return bound; + } - hcx.while_hashing_spans(true, |hcx| sets.hash_stable(hcx, hasher)) + if hir.attrs(id).iter().any(|attr| Level::from_attr(attr).is_some()) { + return id; + } + let next = hir.get_parent_node(id); + if next == id { + bug!("lint traversal reached the root of the crate"); + } + id = next; + } } } @@ -261,11 +258,11 @@ pub fn explain_lint_level_source( )); } } - LintLevelSource::Node(lint_attr_name, src, reason) => { + LintLevelSource::Node { name: lint_attr_name, span, reason, .. } => { if let Some(rationale) = reason { err.note(rationale.as_str()); } - err.span_note_once(src, "the lint level is defined here"); + err.span_note_once(span, "the lint level is defined here"); if lint_attr_name.as_str() != name { let level_str = level.as_str(); err.note_once(&format!( @@ -277,29 +274,28 @@ pub fn explain_lint_level_source( } } -pub fn struct_lint_level<'s, 'd>( - sess: &'s Session, +pub fn struct_lint_level( + sess: &Session, lint: &'static Lint, level: Level, src: LintLevelSource, span: Option<MultiSpan>, msg: impl Into<DiagnosticMessage>, - decorate: impl 'd - + for<'a, 'b> FnOnce( + decorate: impl for<'a, 'b> FnOnce( &'b mut DiagnosticBuilder<'a, ()>, ) -> &'b mut DiagnosticBuilder<'a, ()>, ) { // Avoid codegen bloat from monomorphization by immediately doing dyn dispatch of `decorate` to // the "real" work. - fn struct_lint_level_impl<'s, 'd>( - sess: &'s Session, + fn struct_lint_level_impl( + sess: &Session, lint: &'static Lint, level: Level, src: LintLevelSource, span: Option<MultiSpan>, msg: impl Into<DiagnosticMessage>, decorate: Box< - dyn 'd + dyn '_ + for<'a, 'b> FnOnce( &'b mut DiagnosticBuilder<'a, ()>, ) -> &'b mut DiagnosticBuilder<'a, ()>, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index fb867f8b46b..cf5b365b27c 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -274,10 +274,15 @@ rustc_queries! { separate_provide_extern } - query lint_levels(_: ()) -> LintLevelMap { + query shallow_lint_levels_on(key: hir::OwnerId) -> rustc_middle::lint::ShallowLintLevelMap { + eval_always // fetches `resolutions` arena_cache - eval_always - desc { "computing the lint levels for items in this crate" } + desc { |tcx| "looking up lint levels for `{}`", tcx.def_path_str(key.to_def_id()) } + } + + query lint_expectations(_: ()) -> Vec<(LintExpectationId, LintExpectation)> { + arena_cache + desc { "computing `#[expect]`ed lints in this crate" } } query parent_module_from_def_id(key: LocalDefId) -> LocalDefId { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index a3489226f62..97646003e73 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -4,7 +4,7 @@ use crate::arena::Arena; use crate::dep_graph::{DepGraph, DepKindStruct}; use crate::hir::place::Place as HirPlace; use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos}; -use crate::lint::{struct_lint_level, LintLevelSource}; +use crate::lint::struct_lint_level; use crate::middle::codegen_fn_attrs::CodegenFnAttrs; use crate::middle::resolve_lifetime; use crate::middle::stability; @@ -57,7 +57,7 @@ use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use rustc_session::config::{CrateType, OutputFilenames}; use rustc_session::cstore::CrateStoreDyn; use rustc_session::errors::TargetDataLayoutErrorsWrapper; -use rustc_session::lint::{Level, Lint}; +use rustc_session::lint::Lint; use rustc_session::Limit; use rustc_session::Session; use rustc_span::def_id::{DefPathHash, StableCrateId}; @@ -2812,44 +2812,6 @@ impl<'tcx> TyCtxt<'tcx> { iter.intern_with(|xs| self.intern_bound_variable_kinds(xs)) } - /// Walks upwards from `id` to find a node which might change lint levels with attributes. - /// It stops at `bound` and just returns it if reached. - pub fn maybe_lint_level_root_bounded(self, mut id: HirId, bound: HirId) -> HirId { - let hir = self.hir(); - loop { - if id == bound { - return bound; - } - - if hir.attrs(id).iter().any(|attr| Level::from_attr(attr).is_some()) { - return id; - } - let next = hir.get_parent_node(id); - if next == id { - bug!("lint traversal reached the root of the crate"); - } - id = next; - } - } - - pub fn lint_level_at_node( - self, - lint: &'static Lint, - mut id: hir::HirId, - ) -> (Level, LintLevelSource) { - let sets = self.lint_levels(()); - loop { - if let Some(pair) = sets.level_and_source(lint, id, self.sess) { - return pair; - } - let next = self.hir().get_parent_node(id); - if next == id { - bug!("lint traversal reached the root of the crate"); - } - id = next; - } - } - /// Emit a lint at `span` from a lint struct (some type that implements `DecorateLint`, /// typically generated by `#[derive(LintDiagnostic)]`). pub fn emit_spanned_lint( diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index 169da348a29..b6cda34c51f 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -1,6 +1,6 @@ use crate::dep_graph; use crate::infer::canonical::{self, Canonical}; -use crate::lint::LintLevelMap; +use crate::lint::LintExpectation; use crate::metadata::ModChild; use crate::middle::codegen_fn_attrs::CodegenFnAttrs; use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; @@ -51,6 +51,7 @@ use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec}; use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion}; use rustc_session::cstore::{CrateDepKind, CrateSource}; use rustc_session::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLib}; +use rustc_session::lint::LintExpectationId; use rustc_session::utils::NativeLibKind; use rustc_session::Limits; use rustc_span::symbol::Symbol; diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index bcd078a8967..88540e13ef2 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -52,7 +52,7 @@ pub(crate) fn parse_token_trees<'a>( let cursor = Cursor::new(src); let string_reader = StringReader { sess, start_pos, pos: start_pos, src, cursor, override_span }; - tokentrees::TokenTreesReader::parse_token_trees(string_reader) + tokentrees::TokenTreesReader::parse_all_token_trees(string_reader) } struct StringReader<'a> { diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index 364753154db..b2701817d48 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -27,7 +27,7 @@ pub(super) struct TokenTreesReader<'a> { } impl<'a> TokenTreesReader<'a> { - pub(super) fn parse_token_trees( + pub(super) fn parse_all_token_trees( string_reader: StringReader<'a>, ) -> (PResult<'a, TokenStream>, Vec<UnmatchedBrace>) { let mut tt_reader = TokenTreesReader { @@ -40,36 +40,51 @@ impl<'a> TokenTreesReader<'a> { last_delim_empty_block_spans: FxHashMap::default(), matching_block_spans: Vec::new(), }; - let res = tt_reader.parse_all_token_trees(); + let res = tt_reader.parse_token_trees(/* is_delimited */ false); (res, tt_reader.unmatched_braces) } - // Parse a stream of tokens into a list of `TokenTree`s, up to an `Eof`. - fn parse_all_token_trees(&mut self) -> PResult<'a, TokenStream> { + // Parse a stream of tokens into a list of `TokenTree`s. + fn parse_token_trees(&mut self, is_delimited: bool) -> PResult<'a, TokenStream> { self.token = self.string_reader.next_token().0; - let mut buf = TokenStreamBuilder::default(); + let mut buf = Vec::new(); loop { match self.token.kind { token::OpenDelim(delim) => buf.push(self.parse_token_tree_open_delim(delim)), - token::CloseDelim(delim) => return Err(self.close_delim_err(delim)), - token::Eof => return Ok(buf.into_token_stream()), - _ => buf.push(self.parse_token_tree_non_delim_non_eof()), - } - } - } - - // Parse a stream of tokens into a list of `TokenTree`s, up to a `CloseDelim`. - fn parse_token_trees_until_close_delim(&mut self) -> TokenStream { - let mut buf = TokenStreamBuilder::default(); - loop { - match self.token.kind { - token::OpenDelim(delim) => buf.push(self.parse_token_tree_open_delim(delim)), - token::CloseDelim(..) => return buf.into_token_stream(), + token::CloseDelim(delim) => { + return if is_delimited { + Ok(TokenStream::new(buf)) + } else { + Err(self.close_delim_err(delim)) + }; + } token::Eof => { - self.eof_err().emit(); - return buf.into_token_stream(); + if is_delimited { + self.eof_err().emit(); + } + return Ok(TokenStream::new(buf)); + } + _ => { + // Get the next normal token. This might require getting multiple adjacent + // single-char tokens and joining them together. + let (this_spacing, next_tok) = loop { + let (next_tok, is_next_tok_preceded_by_whitespace) = + self.string_reader.next_token(); + if !is_next_tok_preceded_by_whitespace { + if let Some(glued) = self.token.glue(&next_tok) { + self.token = glued; + } else { + let this_spacing = + if next_tok.is_op() { Spacing::Joint } else { Spacing::Alone }; + break (this_spacing, next_tok); + } + } else { + break (Spacing::Alone, next_tok); + } + }; + let this_tok = std::mem::replace(&mut self.token, next_tok); + buf.push(TokenTree::Token(this_tok, this_spacing)); } - _ => buf.push(self.parse_token_tree_non_delim_non_eof()), } } } @@ -113,14 +128,12 @@ impl<'a> TokenTreesReader<'a> { // The span for beginning of the delimited section let pre_span = self.token.span; - // Move past the open delimiter. self.open_braces.push((open_delim, self.token.span)); - self.token = self.string_reader.next_token().0; // Parse the token trees within the delimiters. // We stop at any delimiter so we can try to recover if the user // uses an incorrect delimiter. - let tts = self.parse_token_trees_until_close_delim(); + let tts = self.parse_token_trees(/* is_delimited */ true).unwrap(); // Expand to cover the entire delimited token tree let delim_span = DelimSpan::from_pair(pre_span, self.token.span); @@ -242,43 +255,4 @@ impl<'a> TokenTreesReader<'a> { err.span_label(self.token.span, "unexpected closing delimiter"); err } - - #[inline] - fn parse_token_tree_non_delim_non_eof(&mut self) -> TokenTree { - // `this_spacing` for the returned token refers to whether the token is - // immediately followed by another op token. It is determined by the - // next token: its kind and its `preceded_by_whitespace` status. - let (next_tok, is_next_tok_preceded_by_whitespace) = self.string_reader.next_token(); - let this_spacing = if is_next_tok_preceded_by_whitespace || !next_tok.is_op() { - Spacing::Alone - } else { - Spacing::Joint - }; - let this_tok = std::mem::replace(&mut self.token, next_tok); - TokenTree::Token(this_tok, this_spacing) - } -} - -#[derive(Default)] -struct TokenStreamBuilder { - buf: Vec<TokenTree>, -} - -impl TokenStreamBuilder { - #[inline(always)] - fn push(&mut self, tree: TokenTree) { - if let Some(TokenTree::Token(prev_token, Spacing::Joint)) = self.buf.last() - && let TokenTree::Token(token, joint) = &tree - && let Some(glued) = prev_token.glue(token) - { - self.buf.pop(); - self.buf.push(TokenTree::Token(glued, *joint)); - } else { - self.buf.push(tree) - } - } - - fn into_token_stream(self) -> TokenStream { - TokenStream::new(self.buf) - } } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index b512f26335f..f57bd9cec19 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -33,6 +33,7 @@ use rustc_errors::{ fluent, Applicability, DiagnosticBuilder, DiagnosticMessage, Handler, MultiSpan, PResult, }; use rustc_errors::{pluralize, Diagnostic, ErrorGuaranteed, IntoDiagnostic}; +use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{Span, SpanSnippetError, DUMMY_SP}; @@ -2049,7 +2050,7 @@ impl<'a> Parser<'a> { let mut err = self.struct_span_err(span, &msg); let sp = self.sess.source_map().start_point(self.token.span); if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&sp) { - self.sess.expr_parentheses_needed(&mut err, *sp); + err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp)); } err.span_label(span, "expected expression"); err diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 8b328e593ae..11301f03e48 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1310,7 +1310,7 @@ impl<'a> Parser<'a> { // If the input is something like `if a { 1 } else { 2 } | if a { 3 } else { 4 }` // then suggest parens around the lhs. if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&lo) { - self.sess.expr_parentheses_needed(&mut err, *sp); + err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp)); } err }) diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 2aebaf7c3af..b934e087608 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -302,7 +302,10 @@ impl TokenCursor { fn desugar(&mut self, attr_style: AttrStyle, data: Symbol, span: Span) -> (Token, Spacing) { // Searches for the occurrences of `"#*` and returns the minimum number of `#`s - // required to wrap the text. + // required to wrap the text. E.g. + // - `abc d` is wrapped as `r"abc d"` (num_of_hashes = 0) + // - `abc "d"` is wrapped as `r#"abc "d""#` (num_of_hashes = 1) + // - `abc "##d##"` is wrapped as `r###"abc "d""###` (num_of_hashes = 3) let mut num_of_hashes = 0; let mut count = 0; for ch in data.as_str().chars() { @@ -314,6 +317,7 @@ impl TokenCursor { num_of_hashes = cmp::max(num_of_hashes, count); } + // `/// foo` becomes `doc = r"foo". let delim_span = DelimSpan::from_single(span); let body = TokenTree::Delimited( delim_span, diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 542a1ac5dc6..0250b518243 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -10,6 +10,7 @@ use rustc_ast::{ }; use rustc_ast_pretty::pprust; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult}; +use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::{respan, Span, Spanned}; use rustc_span::symbol::{kw, sym, Ident}; @@ -693,7 +694,7 @@ impl<'a> Parser<'a> { let sp = self.sess.source_map().start_point(self.token.span); if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&sp) { - self.sess.expr_parentheses_needed(&mut err, *sp); + err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp)); } Err(err) diff --git a/compiler/rustc_query_impl/src/keys.rs b/compiler/rustc_query_impl/src/keys.rs index 47762440e29..cdbf734cdbe 100644 --- a/compiler/rustc_query_impl/src/keys.rs +++ b/compiler/rustc_query_impl/src/keys.rs @@ -1,7 +1,7 @@ //! Defines the set of legal keys that can be used in queries. use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; -use rustc_hir::hir_id::OwnerId; +use rustc_hir::hir_id::{HirId, OwnerId}; use rustc_middle::infer::canonical::Canonical; use rustc_middle::mir; use rustc_middle::traits; @@ -557,3 +557,19 @@ impl<'tcx> Key for (Ty<'tcx>, ty::ValTree<'tcx>) { DUMMY_SP } } + +impl Key for HirId { + #[inline(always)] + fn query_crate_is_local(&self) -> bool { + true + } + + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { + tcx.hir().span(*self) + } + + #[inline(always)] + fn key_as_def_id(&self) -> Option<DefId> { + None + } +} diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs index 5003a14b910..da2075fd5aa 100644 --- a/compiler/rustc_query_system/src/dep_graph/mod.rs +++ b/compiler/rustc_query_system/src/dep_graph/mod.rs @@ -94,6 +94,8 @@ impl<T: DepContext> HasDepContext for T { pub enum FingerprintStyle { /// The fingerprint is actually a DefPathHash. DefPathHash, + /// The fingerprint is actually a HirId. + HirId, /// Query key was `()` or equivalent, so fingerprint is just zero. Unit, /// Some opaque hash. @@ -104,7 +106,9 @@ impl FingerprintStyle { #[inline] pub fn reconstructible(self) -> bool { match self { - FingerprintStyle::DefPathHash | FingerprintStyle::Unit => true, + FingerprintStyle::DefPathHash | FingerprintStyle::Unit | FingerprintStyle::HirId => { + true + } FingerprintStyle::Opaque => false, } } diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index d97e1df2a16..2c3d8d5283b 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -2,9 +2,7 @@ //! It also serves as an input to the parser itself. use crate::config::CheckCfg; -use crate::errors::{ - ExprParenthesesNeeded, FeatureDiagnosticForIssue, FeatureDiagnosticHelp, FeatureGateError, -}; +use crate::errors::{FeatureDiagnosticForIssue, FeatureDiagnosticHelp, FeatureGateError}; use crate::lint::{ builtin::UNSTABLE_SYNTAX_PRE_EXPANSION, BufferedEarlyLint, BuiltinLintDiagnostics, Lint, LintId, }; @@ -13,8 +11,8 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_data_structures::sync::{Lock, Lrc}; use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler}; use rustc_errors::{ - fallback_fluent_bundle, AddToDiagnostic, Diagnostic, DiagnosticBuilder, DiagnosticId, - DiagnosticMessage, EmissionGuarantee, ErrorGuaranteed, IntoDiagnostic, MultiSpan, StashKey, + fallback_fluent_bundle, Diagnostic, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, + EmissionGuarantee, ErrorGuaranteed, IntoDiagnostic, MultiSpan, StashKey, }; use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures}; use rustc_span::edition::Edition; @@ -324,12 +322,6 @@ impl ParseSess { }); } - /// Extend an error with a suggestion to wrap an expression with parentheses to allow the - /// parser to continue parsing the following operation as part of the same expression. - pub fn expr_parentheses_needed(&self, err: &mut Diagnostic, span: Span) { - ExprParenthesesNeeded::surrounding(span).add_to_diagnostic(err); - } - pub fn save_proc_macro_span(&self, span: Span) -> usize { let mut spans = self.proc_macro_quoted_spans.lock(); spans.push(span); diff --git a/compiler/rustc_target/src/spec/i386_apple_ios.rs b/compiler/rustc_target/src/spec/i386_apple_ios.rs index 8b6266c5800..b85214a9c6b 100644 --- a/compiler/rustc_target/src/spec/i386_apple_ios.rs +++ b/compiler/rustc_target/src/spec/i386_apple_ios.rs @@ -14,8 +14,7 @@ pub fn target() -> Target { arch: "x86".into(), options: TargetOptions { max_atomic_width: Some(64), - // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved - stack_probes: StackProbeType::Call, + stack_probes: StackProbeType::X86, ..base }, } diff --git a/compiler/rustc_target/src/spec/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/i686_apple_darwin.rs index 5e9ceb844f7..99b9d88e642 100644 --- a/compiler/rustc_target/src/spec/i686_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/i686_apple_darwin.rs @@ -7,8 +7,7 @@ pub fn target() -> Target { base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]); base.link_env_remove.to_mut().extend(super::apple_base::macos_link_env_remove()); - // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved - base.stack_probes = StackProbeType::Call; + base.stack_probes = StackProbeType::X86; base.frame_pointer = FramePointer::Always; // Clang automatically chooses a more specific target based on diff --git a/compiler/rustc_target/src/spec/i686_linux_android.rs b/compiler/rustc_target/src/spec/i686_linux_android.rs index bdaf5c99069..c7c30c23901 100644 --- a/compiler/rustc_target/src/spec/i686_linux_android.rs +++ b/compiler/rustc_target/src/spec/i686_linux_android.rs @@ -11,8 +11,7 @@ pub fn target() -> Target { // https://developer.android.com/ndk/guides/abis.html#x86 base.cpu = "pentiumpro".into(); base.features = "+mmx,+sse,+sse2,+sse3,+ssse3".into(); - // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved - base.stack_probes = StackProbeType::Call; + base.stack_probes = StackProbeType::X86; Target { llvm_target: "i686-linux-android".into(), diff --git a/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs b/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs index aff284bf2bc..7d201245006 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs @@ -5,8 +5,7 @@ pub fn target() -> Target { base.cpu = "pentium4".into(); base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32", "-Wl,-znotext"]); - // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved - base.stack_probes = StackProbeType::Call; + base.stack_probes = StackProbeType::X86; Target { llvm_target: "i686-unknown-freebsd".into(), diff --git a/compiler/rustc_target/src/spec/i686_unknown_haiku.rs b/compiler/rustc_target/src/spec/i686_unknown_haiku.rs index 87aa74e406c..357cc547fa0 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_haiku.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_haiku.rs @@ -5,8 +5,7 @@ pub fn target() -> Target { base.cpu = "pentium4".into(); base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]); - // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved - base.stack_probes = StackProbeType::Call; + base.stack_probes = StackProbeType::X86; Target { llvm_target: "i686-unknown-haiku".into(), diff --git a/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs index f62029c9067..bb7b5680298 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs @@ -6,8 +6,7 @@ pub fn target() -> Target { base.max_atomic_width = Some(64); base.supported_sanitizers = SanitizerSet::ADDRESS; base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]); - // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved - base.stack_probes = StackProbeType::Call; + base.stack_probes = StackProbeType::X86; Target { llvm_target: "i686-unknown-linux-gnu".into(), diff --git a/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs index d9492804349..f6047919674 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs @@ -5,8 +5,7 @@ pub fn target() -> Target { base.cpu = "pentium4".into(); base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32", "-Wl,-melf_i386"]); - // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved - base.stack_probes = StackProbeType::Call; + base.stack_probes = StackProbeType::X86; // The unwinder used by i686-unknown-linux-musl, the LLVM libunwind // implementation, apparently relies on frame pointers existing... somehow. diff --git a/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs b/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs index 8de698b51f0..0fd2d1231df 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs @@ -5,8 +5,7 @@ pub fn target() -> Target { base.cpu = "pentium4".into(); base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]); - // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved - base.stack_probes = StackProbeType::Call; + base.stack_probes = StackProbeType::X86; Target { llvm_target: "i686-unknown-netbsdelf".into(), diff --git a/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs b/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs index 7f25a1a16c1..2952c043daa 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs @@ -5,8 +5,7 @@ pub fn target() -> Target { base.cpu = "pentium4".into(); base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32", "-fuse-ld=lld"]); - // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved - base.stack_probes = StackProbeType::Call; + base.stack_probes = StackProbeType::X86; Target { llvm_target: "i686-unknown-openbsd".into(), diff --git a/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs b/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs index f62404e8279..4a0d98efd82 100644 --- a/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs @@ -5,8 +5,7 @@ pub fn target() -> Target { base.cpu = "pentium4".into(); base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]); - // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved - base.stack_probes = StackProbeType::Call; + base.stack_probes = StackProbeType::X86; Target { llvm_target: "i686-unknown-linux-gnu".into(), diff --git a/compiler/rustc_target/src/spec/linux_kernel_base.rs b/compiler/rustc_target/src/spec/linux_kernel_base.rs index 0f5d85205f8..f41533a9548 100644 --- a/compiler/rustc_target/src/spec/linux_kernel_base.rs +++ b/compiler/rustc_target/src/spec/linux_kernel_base.rs @@ -6,8 +6,7 @@ pub fn opts() -> TargetOptions { env: "gnu".into(), disable_redzone: true, panic_strategy: PanicStrategy::Abort, - // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved - stack_probes: StackProbeType::Call, + stack_probes: StackProbeType::X86, frame_pointer: FramePointer::Always, position_independent_executables: true, needs_plt: true, diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 35b4cce50a0..af85e2f4feb 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -635,6 +635,10 @@ pub enum StackProbeType { } impl StackProbeType { + // LLVM X86 targets (ix86 and x86_64) can use inline-asm stack probes starting with LLVM 16. + // Notable past issues were rust#83139 (fixed in 14) and rust#84667 (fixed in 16). + const X86: Self = Self::InlineOrCall { min_llvm_version_for_inline: (16, 0, 0) }; + fn from_json(json: &Json) -> Result<Self, String> { let object = json.as_object().ok_or_else(|| "expected a JSON object")?; let kind = object diff --git a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs index 176c9dd6b76..ad96923320c 100644 --- a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs @@ -9,8 +9,7 @@ pub fn target() -> Target { base.frame_pointer = FramePointer::Always; base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); base.link_env_remove.to_mut().extend(super::apple_base::macos_link_env_remove()); - // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved - base.stack_probes = StackProbeType::Call; + base.stack_probes = StackProbeType::X86; base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::LEAK | SanitizerSet::THREAD; diff --git a/compiler/rustc_target/src/spec/x86_64_apple_ios.rs b/compiler/rustc_target/src/spec/x86_64_apple_ios.rs index 5e64ed0cff6..e6143025d6d 100644 --- a/compiler/rustc_target/src/spec/x86_64_apple_ios.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_ios.rs @@ -13,8 +13,7 @@ pub fn target() -> Target { arch: "x86_64".into(), options: TargetOptions { max_atomic_width: Some(64), - // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved - stack_probes: StackProbeType::Call, + stack_probes: StackProbeType::X86, ..base }, } diff --git a/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs index 2122bcd37fc..61591dacf45 100644 --- a/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs @@ -15,8 +15,7 @@ pub fn target() -> Target { arch: "x86_64".into(), options: TargetOptions { max_atomic_width: Some(64), - // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved - stack_probes: StackProbeType::Call, + stack_probes: StackProbeType::X86, ..base }, } diff --git a/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs index a848c5a0aff..3d54da0867c 100644 --- a/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs @@ -10,8 +10,7 @@ pub fn target() -> Target { arch: "x86_64".into(), options: TargetOptions { max_atomic_width: Some(64), - // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved - stack_probes: StackProbeType::Call, + stack_probes: StackProbeType::X86, ..base }, } diff --git a/compiler/rustc_target/src/spec/x86_64_apple_watchos_sim.rs b/compiler/rustc_target/src/spec/x86_64_apple_watchos_sim.rs index 4dff3c2f209..e499b1985e7 100644 --- a/compiler/rustc_target/src/spec/x86_64_apple_watchos_sim.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_watchos_sim.rs @@ -15,8 +15,7 @@ pub fn target() -> Target { arch: "x86_64".into(), options: TargetOptions { max_atomic_width: Some(64), - // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved - stack_probes: StackProbeType::Call, + stack_probes: StackProbeType::X86, forces_embed_bitcode: true, // Taken from a clang build on Xcode 11.4.1. // These arguments are not actually invoked - they just have diff --git a/compiler/rustc_target/src/spec/x86_64_fuchsia.rs b/compiler/rustc_target/src/spec/x86_64_fuchsia.rs index 4f88fc3500b..532dd6d0742 100644 --- a/compiler/rustc_target/src/spec/x86_64_fuchsia.rs +++ b/compiler/rustc_target/src/spec/x86_64_fuchsia.rs @@ -4,8 +4,7 @@ pub fn target() -> Target { let mut base = super::fuchsia_base::opts(); base.cpu = "x86-64".into(); base.max_atomic_width = Some(64); - // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved - base.stack_probes = StackProbeType::Call; + base.stack_probes = StackProbeType::X86; base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI; Target { diff --git a/compiler/rustc_target/src/spec/x86_64_linux_android.rs b/compiler/rustc_target/src/spec/x86_64_linux_android.rs index 6d19cf26574..4db5ec7fd28 100644 --- a/compiler/rustc_target/src/spec/x86_64_linux_android.rs +++ b/compiler/rustc_target/src/spec/x86_64_linux_android.rs @@ -7,8 +7,7 @@ pub fn target() -> Target { base.features = "+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+popcnt".into(); base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); - // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved - base.stack_probes = StackProbeType::Call; + base.stack_probes = StackProbeType::X86; Target { llvm_target: "x86_64-linux-android".into(), diff --git a/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs b/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs index 0550b221fd9..974359a138b 100644 --- a/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs +++ b/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs @@ -6,8 +6,7 @@ pub fn target() -> Target { base.cpu = "x86-64".into(); base.vendor = "pc".into(); base.max_atomic_width = Some(64); - // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved - base.stack_probes = StackProbeType::Call; + base.stack_probes = StackProbeType::X86; base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI; Target { diff --git a/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs b/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs index cbe87589a70..a2fe371a2b8 100644 --- a/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs +++ b/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs @@ -6,8 +6,7 @@ pub fn target() -> Target { base.cpu = "x86-64".into(); base.vendor = "sun".into(); base.max_atomic_width = Some(64); - // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved - base.stack_probes = StackProbeType::Call; + base.stack_probes = StackProbeType::X86; Target { llvm_target: "x86_64-pc-solaris".into(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs b/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs index 746f6478178..989e6432b66 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs @@ -5,8 +5,7 @@ pub fn target() -> Target { base.cpu = "x86-64".into(); base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); - // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved - base.stack_probes = StackProbeType::Call; + base.stack_probes = StackProbeType::X86; Target { llvm_target: "x86_64-unknown-dragonfly".into(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs index b30784ed692..24b5b4beebc 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs @@ -5,8 +5,7 @@ pub fn target() -> Target { base.cpu = "x86-64".into(); base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); - // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved - base.stack_probes = StackProbeType::Call; + base.stack_probes = StackProbeType::X86; base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::MEMORY | SanitizerSet::THREAD; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs b/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs index d6d03362982..e3f14aeeea9 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs @@ -5,8 +5,7 @@ pub fn target() -> Target { base.cpu = "x86-64".into(); base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); - // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved - base.stack_probes = StackProbeType::Call; + base.stack_probes = StackProbeType::X86; // This option is required to build executables on Haiku x86_64 base.position_independent_executables = true; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs b/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs index d315301615b..fb1af33f80a 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs @@ -5,8 +5,7 @@ pub fn target() -> Target { base.cpu = "x86-64".into(); base.max_atomic_width = Some(64); base.features = "+rdrnd,+rdseed".into(); - // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved - base.stack_probes = StackProbeType::Call; + base.stack_probes = StackProbeType::X86; Target { llvm_target: "x86_64-unknown-hermit".into(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs index 956be0353fa..34e20544da6 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs @@ -5,8 +5,7 @@ pub fn target() -> Target { base.cpu = "x86-64".into(); base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); - // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved - base.stack_probes = StackProbeType::Call; + base.stack_probes = StackProbeType::X86; base.static_position_independent_executables = true; base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs index 140882747c2..23a1f5d80f2 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs @@ -6,8 +6,7 @@ pub fn target() -> Target { base.abi = "x32".into(); base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gcc, &["-mx32"]); - // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved - base.stack_probes = StackProbeType::Call; + base.stack_probes = StackProbeType::X86; base.has_thread_local = false; // BUG(GabrielMajeri): disabling the PLT on x86_64 Linux with x32 ABI // breaks code gen. See LLVM bug 36743 diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs index 87e7784d1f9..179f0995456 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs @@ -5,8 +5,7 @@ pub fn target() -> Target { base.cpu = "x86-64".into(); base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); - // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved - base.stack_probes = StackProbeType::Call; + base.stack_probes = StackProbeType::X86; base.static_position_independent_executables = true; base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs index d3a67619aa8..ac77dfb6415 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs @@ -5,8 +5,7 @@ pub fn target() -> Target { base.cpu = "x86-64".into(); base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); - // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved - base.stack_probes = StackProbeType::Call; + base.stack_probes = StackProbeType::X86; base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::LEAK diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_none.rs b/compiler/rustc_target/src/spec/x86_64_unknown_none.rs index b9a345127e3..871cdd02078 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_none.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_none.rs @@ -11,8 +11,7 @@ pub fn target() -> Target { let opts = TargetOptions { cpu: "x86-64".into(), max_atomic_width: Some(64), - // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved - stack_probes: StackProbeType::Call, + stack_probes: StackProbeType::X86, position_independent_executables: true, static_position_independent_executables: true, relro_level: RelroLevel::Full, diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs index f50c6bceec9..b8084d513f7 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs @@ -5,8 +5,7 @@ pub fn target() -> Target { base.cpu = "x86-64".into(); base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); - // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved - base.stack_probes = StackProbeType::Call; + base.stack_probes = StackProbeType::X86; Target { llvm_target: "x86_64-unknown-openbsd".into(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs b/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs index 668ae905417..a2a143f856d 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs @@ -5,8 +5,7 @@ pub fn target() -> Target { base.cpu = "x86-64".into(); base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); - // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved - base.stack_probes = StackProbeType::Call; + base.stack_probes = StackProbeType::X86; Target { llvm_target: "x86_64-unknown-redox".into(), diff --git a/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs index 1298974952f..187027d3889 100644 --- a/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs @@ -5,8 +5,7 @@ pub fn target() -> Target { base.cpu = "x86-64".into(); base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); - // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved - base.stack_probes = StackProbeType::Call; + base.stack_probes = StackProbeType::X86; base.disable_redzone = true; Target { |
