summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_passes
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_passes')
-rw-r--r--compiler/rustc_passes/messages.ftl24
-rw-r--r--compiler/rustc_passes/src/check_attr.rs129
-rw-r--r--compiler/rustc_passes/src/check_const.rs12
-rw-r--r--compiler/rustc_passes/src/dead.rs144
-rw-r--r--compiler/rustc_passes/src/entry.rs8
-rw-r--r--compiler/rustc_passes/src/errors.rs55
-rw-r--r--compiler/rustc_passes/src/hir_id_validator.rs5
-rw-r--r--compiler/rustc_passes/src/hir_stats.rs8
-rw-r--r--compiler/rustc_passes/src/layout_test.rs5
-rw-r--r--compiler/rustc_passes/src/liveness.rs15
-rw-r--r--compiler/rustc_passes/src/loops.rs4
-rw-r--r--compiler/rustc_passes/src/naked_functions.rs4
-rw-r--r--compiler/rustc_passes/src/reachable.rs20
-rw-r--r--compiler/rustc_passes/src/stability.rs20
-rw-r--r--compiler/rustc_passes/src/weak_lang_items.rs2
15 files changed, 343 insertions, 112 deletions
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index a607e483c..6eacbebe7 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -98,6 +98,9 @@ passes_collapse_debuginfo =
`collapse_debuginfo` attribute should be applied to macro definitions
.label = not a macro definition
+passes_confusables = attribute should be applied to an inherent method
+ .label = not an inherent method
+
passes_const_impl_const_trait =
const `impl`s must be for traits marked with `#[const_trait]`
.note = this trait must be annotated with `#[const_trait]`
@@ -208,6 +211,17 @@ passes_doc_keyword_not_mod =
passes_doc_keyword_only_impl =
`#[doc(keyword = "...")]` should be used on impl blocks
+passes_doc_masked_not_extern_crate_self =
+ this attribute cannot be applied to an `extern crate self` item
+ .label = not applicable on `extern crate self` items
+ .extern_crate_self_label = `extern crate self` defined here
+
+passes_doc_masked_only_extern_crate =
+ this attribute can only be applied to an `extern crate` item
+ .label = only applicable on `extern crate` items
+ .not_an_extern_crate_label = not an `extern crate` item
+ .note = read <https://doc.rust-lang.org/unstable-book/language-features/doc-masked.html> for more information
+
passes_doc_test_literal = `#![doc(test(...)]` does not take a literal
passes_doc_test_takes_list =
@@ -266,6 +280,9 @@ passes_duplicate_lang_item_crate_depends =
.first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path}
.second_definition_path = second definition in `{$crate_name}` loaded from {$path}
+passes_empty_confusables =
+ expected at least one confusable name
+
passes_export_name =
attribute should be applied to a free function, impl method or static
.label = not a free function, impl method or static
@@ -326,6 +343,9 @@ passes_implied_feature_not_exist =
passes_incorrect_do_not_recommend_location =
`#[do_not_recommend]` can only be placed on trait implementations
+passes_incorrect_meta_item = expected a quoted string literal
+passes_incorrect_meta_item_suggestion = consider surrounding this with quotes
+
passes_incorrect_target =
`{$name}` language item must be applied to a {$kind} with {$at_least ->
[true] at least {$num}
@@ -408,6 +428,10 @@ passes_link_section =
passes_macro_export =
`#[macro_export]` only has an effect on macro definitions
+passes_macro_export_on_decl_macro =
+ `#[macro_export]` has no effect on declarative macro definitions
+ .note = declarative macros follow the same exporting rules as regular items
+
passes_macro_use =
`#[{$name}]` only has an effect on `extern crate` and modules
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 073760f39..197b335bd 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -10,7 +10,7 @@ use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{Applicability, IntoDiagnosticArg, MultiSpan};
use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
use rustc_hir as hir;
-use rustc_hir::def_id::LocalDefId;
+use rustc_hir::def_id::LocalModDefId;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{
self, FnSig, ForeignItem, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID, CRATE_OWNER_ID,
@@ -183,6 +183,7 @@ impl CheckAttrVisitor<'_> {
| sym::rustc_allowed_through_unstable_modules
| sym::rustc_promotable => self.check_stability_promotable(&attr, span, target),
sym::link_ordinal => self.check_link_ordinal(&attr, span, target),
+ sym::rustc_confusables => self.check_confusables(&attr, target),
_ => true,
};
@@ -694,7 +695,6 @@ impl CheckAttrVisitor<'_> {
| Target::GlobalAsm
| Target::TyAlias
| Target::OpaqueTy
- | Target::ImplTraitPlaceholder
| Target::Enum
| Target::Variant
| Target::Struct
@@ -878,6 +878,44 @@ impl CheckAttrVisitor<'_> {
}
}
+ fn check_doc_masked(
+ &self,
+ attr: &Attribute,
+ meta: &NestedMetaItem,
+ hir_id: HirId,
+ target: Target,
+ ) -> bool {
+ if target != Target::ExternCrate {
+ self.tcx.emit_spanned_lint(
+ INVALID_DOC_ATTRIBUTES,
+ hir_id,
+ meta.span(),
+ errors::DocMaskedOnlyExternCrate {
+ attr_span: meta.span(),
+ item_span: (attr.style == AttrStyle::Outer)
+ .then(|| self.tcx.hir().span(hir_id)),
+ },
+ );
+ return false;
+ }
+
+ if self.tcx.extern_mod_stmt_cnum(hir_id.owner).is_none() {
+ self.tcx.emit_spanned_lint(
+ INVALID_DOC_ATTRIBUTES,
+ hir_id,
+ meta.span(),
+ errors::DocMaskedNotExternCrateSelf {
+ attr_span: meta.span(),
+ item_span: (attr.style == AttrStyle::Outer)
+ .then(|| self.tcx.hir().span(hir_id)),
+ },
+ );
+ return false;
+ }
+
+ true
+ }
+
/// Checks that an attribute is *not* used at the crate level. Returns `true` if valid.
fn check_attr_not_crate_level(
&self,
@@ -1048,6 +1086,17 @@ impl CheckAttrVisitor<'_> {
is_valid = false;
}
+ sym::masked
+ if !self.check_doc_masked(
+ attr,
+ meta,
+ hir_id,
+ target,
+ ) =>
+ {
+ is_valid = false;
+ }
+
// no_default_passes: deprecated
// passes: deprecated
// plugins: removed, but rustdoc warns about it itself
@@ -1433,9 +1482,9 @@ impl CheckAttrVisitor<'_> {
};
let Some(ItemLike::Item(Item {
- kind: ItemKind::Fn(FnSig { decl, .. }, generics, _),
- ..
- })) = item else {
+ kind: ItemKind::Fn(FnSig { decl, .. }, generics, _), ..
+ })) = item
+ else {
bug!("should be a function item");
};
@@ -1986,6 +2035,46 @@ impl CheckAttrVisitor<'_> {
}
}
+ fn check_confusables(&self, attr: &Attribute, target: Target) -> bool {
+ match target {
+ Target::Method(MethodKind::Inherent) => {
+ let Some(meta) = attr.meta() else {
+ return false;
+ };
+ let ast::MetaItem { kind: MetaItemKind::List(ref metas), .. } = meta else {
+ return false;
+ };
+
+ let mut candidates = Vec::new();
+
+ for meta in metas {
+ let NestedMetaItem::Lit(meta_lit) = meta else {
+ self.tcx.sess.emit_err(errors::IncorrectMetaItem {
+ span: meta.span(),
+ suggestion: errors::IncorrectMetaItemSuggestion {
+ lo: meta.span().shrink_to_lo(),
+ hi: meta.span().shrink_to_hi(),
+ },
+ });
+ return false;
+ };
+ candidates.push(meta_lit.symbol);
+ }
+
+ if candidates.is_empty() {
+ self.tcx.sess.emit_err(errors::EmptyConfusables { span: attr.span });
+ return false;
+ }
+
+ true
+ }
+ _ => {
+ self.tcx.sess.emit_err(errors::Confusables { attr_span: attr.span });
+ false
+ }
+ }
+ }
+
fn check_deprecated(&self, hir_id: HirId, attr: &Attribute, _span: Span, target: Target) {
match target {
Target::Closure | Target::Expression | Target::Statement | Target::Arm => {
@@ -2044,6 +2133,20 @@ impl CheckAttrVisitor<'_> {
);
}
}
+ } else {
+ // special case when `#[macro_export]` is applied to a macro 2.0
+ let (macro_definition, _) =
+ self.tcx.hir().find(hir_id).unwrap().expect_item().expect_macro();
+ let is_decl_macro = !macro_definition.macro_rules;
+
+ if is_decl_macro {
+ self.tcx.emit_spanned_lint(
+ UNUSED_ATTRIBUTES,
+ hir_id,
+ attr.span,
+ errors::MacroExport::OnDeclMacro,
+ );
+ }
}
}
@@ -2107,8 +2210,12 @@ impl CheckAttrVisitor<'_> {
}
let tcx = self.tcx;
- let Some(token_stream_def_id) = tcx.get_diagnostic_item(sym::TokenStream) else { return; };
- let Some(token_stream) = tcx.type_of(token_stream_def_id).no_bound_vars() else { return; };
+ let Some(token_stream_def_id) = tcx.get_diagnostic_item(sym::TokenStream) else {
+ return;
+ };
+ let Some(token_stream) = tcx.type_of(token_stream_def_id).no_bound_vars() else {
+ return;
+ };
let def_id = hir_id.expect_owner().def_id;
let param_env = ty::ParamEnv::empty();
@@ -2117,10 +2224,10 @@ impl CheckAttrVisitor<'_> {
let ocx = ObligationCtxt::new(&infcx);
let span = tcx.def_span(def_id);
- let fresh_substs = infcx.fresh_substs_for_item(span, def_id.to_def_id());
+ let fresh_args = infcx.fresh_args_for_item(span, def_id.to_def_id());
let sig = tcx.liberate_late_bound_regions(
def_id.to_def_id(),
- tcx.fn_sig(def_id).subst(tcx, fresh_substs),
+ tcx.fn_sig(def_id).instantiate(tcx, fresh_args),
);
let mut cause = ObligationCause::misc(span, def_id);
@@ -2358,10 +2465,10 @@ fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>)
}
}
-fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
+fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
let check_attr_visitor = &mut CheckAttrVisitor { tcx, abort: Cell::new(false) };
tcx.hir().visit_item_likes_in_module(module_def_id, check_attr_visitor);
- if module_def_id.is_top_level_module() {
+ if module_def_id.to_local_def_id().is_top_level_module() {
check_attr_visitor.check_attributes(CRATE_HIR_ID, DUMMY_SP, Target::Mod, None);
check_invalid_crate_level_attr(tcx, tcx.hir().krate_attrs());
}
diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs
index fc437c429..8437e9a40 100644
--- a/compiler/rustc_passes/src/check_const.rs
+++ b/compiler/rustc_passes/src/check_const.rs
@@ -9,7 +9,7 @@
use rustc_attr as attr;
use rustc_hir as hir;
-use rustc_hir::def_id::LocalDefId;
+use rustc_hir::def_id::{LocalDefId, LocalModDefId};
use rustc_hir::intravisit::{self, Visitor};
use rustc_middle::hir::nested_filter;
use rustc_middle::query::Providers;
@@ -45,7 +45,7 @@ impl NonConstExpr {
Self::Loop(ForLoop) | Self::Match(ForLoopDesugar) => &[sym::const_for],
- Self::Match(TryDesugar) => &[sym::const_try],
+ Self::Match(TryDesugar(_)) => &[sym::const_try],
// All other expressions are allowed.
Self::Loop(Loop | While) | Self::Match(Normal | FormatArgs) => &[],
@@ -55,7 +55,7 @@ impl NonConstExpr {
}
}
-fn check_mod_const_bodies(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
+fn check_mod_const_bodies(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
let mut vis = CheckConstVisitor::new(tcx);
tcx.hir().visit_item_likes_in_module(module_def_id, &mut vis);
}
@@ -157,10 +157,8 @@ impl<'tcx> CheckConstVisitor<'tcx> {
// is a pretty narrow case, however.
if tcx.sess.is_nightly_build() {
for gate in missing_secondary {
- let note = format!(
- "add `#![feature({})]` to the crate attributes to enable",
- gate,
- );
+ let note =
+ format!("add `#![feature({gate})]` to the crate attributes to enable",);
err.help(note);
}
}
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index d5ac1cd9c..d1c3bcf38 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -4,10 +4,11 @@
use hir::def_id::{LocalDefIdMap, LocalDefIdSet};
use itertools::Itertools;
+use rustc_data_structures::unord::UnordSet;
use rustc_errors::MultiSpan;
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Res};
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{Node, PatKind, TyKind};
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
@@ -42,8 +43,16 @@ fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
)
}
+/// Determine if a work from the worklist is coming from the a `#[allow]`
+/// or a `#[expect]` of `dead_code`
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
+enum ComesFromAllowExpect {
+ Yes,
+ No,
+}
+
struct MarkSymbolVisitor<'tcx> {
- worklist: Vec<LocalDefId>,
+ worklist: Vec<(LocalDefId, ComesFromAllowExpect)>,
tcx: TyCtxt<'tcx>,
maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>,
live_symbols: LocalDefIdSet,
@@ -72,7 +81,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
fn check_def_id(&mut self, def_id: DefId) {
if let Some(def_id) = def_id.as_local() {
if should_explore(self.tcx, def_id) || self.struct_constructors.contains_key(&def_id) {
- self.worklist.push(def_id);
+ self.worklist.push((def_id, ComesFromAllowExpect::No));
}
self.live_symbols.insert(def_id);
}
@@ -87,7 +96,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
fn handle_res(&mut self, res: Res) {
match res {
- Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::TyAlias, def_id) => {
+ Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::TyAlias { .. }, def_id) => {
self.check_def_id(def_id);
}
_ if self.in_pat => {}
@@ -269,14 +278,16 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
}
fn mark_live_symbols(&mut self) {
- let mut scanned = LocalDefIdSet::default();
- while let Some(id) = self.worklist.pop() {
- if !scanned.insert(id) {
+ let mut scanned = UnordSet::default();
+ while let Some(work) = self.worklist.pop() {
+ if !scanned.insert(work) {
continue;
}
+ let (id, comes_from_allow_expect) = work;
+
// Avoid accessing the HIR for the synthesized associated type generated for RPITITs.
- if self.tcx.opt_rpitit_info(id.to_def_id()).is_some() {
+ if self.tcx.is_impl_trait_in_trait(id.to_def_id()) {
self.live_symbols.insert(id);
continue;
}
@@ -286,7 +297,30 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
let id = self.struct_constructors.get(&id).copied().unwrap_or(id);
if let Some(node) = self.tcx.hir().find_by_def_id(id) {
- self.live_symbols.insert(id);
+ // When using `#[allow]` or `#[expect]` of `dead_code`, we do a QOL improvement
+ // by declaring fn calls, statics, ... within said items as live, as well as
+ // the item itself, although technically this is not the case.
+ //
+ // This means that the lint for said items will never be fired.
+ //
+ // This doesn't make any difference for the item declared with `#[allow]`, as
+ // the lint firing will be a nop, as it will be silenced by the `#[allow]` of
+ // the item.
+ //
+ // However, for `#[expect]`, the presence or absence of the lint is relevant,
+ // so we don't add it to the list of live symbols when it comes from a
+ // `#[expect]`. This means that we will correctly report an item as live or not
+ // for the `#[expect]` case.
+ //
+ // Note that an item can and will be duplicated on the worklist with different
+ // `ComesFromAllowExpect`, particulary if it was added from the
+ // `effective_visibilities` query or from the `#[allow]`/`#[expect]` checks,
+ // this "duplication" is essential as otherwise a function with `#[expect]`
+ // called from a `pub fn` may be falsely reported as not live, falsely
+ // triggering the `unfulfilled_lint_expectations` lint.
+ if comes_from_allow_expect != ComesFromAllowExpect::Yes {
+ self.live_symbols.insert(id);
+ }
self.visit_node(node);
}
}
@@ -304,7 +338,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
if let Some(trait_of) = self.tcx.trait_id_of_impl(impl_of)
&& self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads)
{
- let trait_ref = self.tcx.impl_trait_ref(impl_of).unwrap().subst_identity();
+ let trait_ref = self.tcx.impl_trait_ref(impl_of).unwrap().instantiate_identity();
if let ty::Adt(adt_def, _) = trait_ref.self_ty().kind()
&& let Some(adt_def_id) = adt_def.did().as_local()
{
@@ -353,7 +387,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
//// This is done to handle the case where, for example, the static
//// method of a private type is used, but the type itself is never
//// called directly.
- let self_ty = self.tcx.type_of(item).subst_identity();
+ let self_ty = self.tcx.type_of(item).instantiate_identity();
match *self_ty.kind() {
ty::Adt(def, _) => self.check_def_id(def.did()),
ty::Foreign(did) => self.check_def_id(did),
@@ -513,16 +547,20 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
}
}
-fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
+fn has_allow_dead_code_or_lang_attr(
+ tcx: TyCtxt<'_>,
+ def_id: LocalDefId,
+) -> Option<ComesFromAllowExpect> {
fn has_lang_attr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
tcx.has_attr(def_id, sym::lang)
// Stable attribute for #[lang = "panic_impl"]
|| tcx.has_attr(def_id, sym::panic_handler)
}
- fn has_allow_dead_code(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
+ fn has_allow_expect_dead_code(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- tcx.lint_level_at_node(lint::builtin::DEAD_CODE, hir_id).0 == lint::Allow
+ let lint_level = tcx.lint_level_at_node(lint::builtin::DEAD_CODE, hir_id).0;
+ matches!(lint_level, lint::Allow | lint::Expect(_))
}
fn has_used_like_attr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
@@ -537,9 +575,13 @@ fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool
}
}
- has_allow_dead_code(tcx, def_id)
- || has_used_like_attr(tcx, def_id)
- || has_lang_attr(tcx, def_id)
+ if has_allow_expect_dead_code(tcx, def_id) {
+ Some(ComesFromAllowExpect::Yes)
+ } else if has_used_like_attr(tcx, def_id) || has_lang_attr(tcx, def_id) {
+ Some(ComesFromAllowExpect::No)
+ } else {
+ None
+ }
}
// These check_* functions seeds items that
@@ -557,21 +599,23 @@ fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool
// * Implementations of traits and trait methods
fn check_item<'tcx>(
tcx: TyCtxt<'tcx>,
- worklist: &mut Vec<LocalDefId>,
+ worklist: &mut Vec<(LocalDefId, ComesFromAllowExpect)>,
struct_constructors: &mut LocalDefIdMap<LocalDefId>,
id: hir::ItemId,
) {
let allow_dead_code = has_allow_dead_code_or_lang_attr(tcx, id.owner_id.def_id);
- if allow_dead_code {
- worklist.push(id.owner_id.def_id);
+ if let Some(comes_from_allow) = allow_dead_code {
+ worklist.push((id.owner_id.def_id, comes_from_allow));
}
match tcx.def_kind(id.owner_id) {
DefKind::Enum => {
let item = tcx.hir().item(id);
if let hir::ItemKind::Enum(ref enum_def, _) = item.kind {
- if allow_dead_code {
- worklist.extend(enum_def.variants.iter().map(|variant| variant.def_id));
+ if let Some(comes_from_allow) = allow_dead_code {
+ worklist.extend(
+ enum_def.variants.iter().map(|variant| (variant.def_id, comes_from_allow)),
+ );
}
for variant in enum_def.variants {
@@ -583,7 +627,7 @@ fn check_item<'tcx>(
}
DefKind::Impl { of_trait } => {
if of_trait {
- worklist.push(id.owner_id.def_id);
+ worklist.push((id.owner_id.def_id, ComesFromAllowExpect::No));
}
// get DefIds from another query
@@ -594,8 +638,10 @@ fn check_item<'tcx>(
// And we access the Map here to get HirId from LocalDefId
for id in local_def_ids {
- if of_trait || has_allow_dead_code_or_lang_attr(tcx, id) {
- worklist.push(id);
+ if of_trait {
+ worklist.push((id, ComesFromAllowExpect::No));
+ } else if let Some(comes_from_allow) = has_allow_dead_code_or_lang_attr(tcx, id) {
+ worklist.push((id, comes_from_allow));
}
}
}
@@ -609,43 +655,59 @@ fn check_item<'tcx>(
}
DefKind::GlobalAsm => {
// global_asm! is always live.
- worklist.push(id.owner_id.def_id);
+ worklist.push((id.owner_id.def_id, ComesFromAllowExpect::No));
}
_ => {}
}
}
-fn check_trait_item(tcx: TyCtxt<'_>, worklist: &mut Vec<LocalDefId>, id: hir::TraitItemId) {
+fn check_trait_item(
+ tcx: TyCtxt<'_>,
+ worklist: &mut Vec<(LocalDefId, ComesFromAllowExpect)>,
+ id: hir::TraitItemId,
+) {
use hir::TraitItemKind::{Const, Fn};
if matches!(tcx.def_kind(id.owner_id), DefKind::AssocConst | DefKind::AssocFn) {
let trait_item = tcx.hir().trait_item(id);
if matches!(trait_item.kind, Const(_, Some(_)) | Fn(_, hir::TraitFn::Provided(_)))
- && has_allow_dead_code_or_lang_attr(tcx, trait_item.owner_id.def_id)
+ && let Some(comes_from_allow) = has_allow_dead_code_or_lang_attr(tcx, trait_item.owner_id.def_id)
{
- worklist.push(trait_item.owner_id.def_id);
+ worklist.push((trait_item.owner_id.def_id, comes_from_allow));
}
}
}
-fn check_foreign_item(tcx: TyCtxt<'_>, worklist: &mut Vec<LocalDefId>, id: hir::ForeignItemId) {
+fn check_foreign_item(
+ tcx: TyCtxt<'_>,
+ worklist: &mut Vec<(LocalDefId, ComesFromAllowExpect)>,
+ id: hir::ForeignItemId,
+) {
if matches!(tcx.def_kind(id.owner_id), DefKind::Static(_) | DefKind::Fn)
- && has_allow_dead_code_or_lang_attr(tcx, id.owner_id.def_id)
+ && let Some(comes_from_allow) = has_allow_dead_code_or_lang_attr(tcx, id.owner_id.def_id)
{
- worklist.push(id.owner_id.def_id);
+ worklist.push((id.owner_id.def_id, comes_from_allow));
}
}
-fn create_and_seed_worklist(tcx: TyCtxt<'_>) -> (Vec<LocalDefId>, LocalDefIdMap<LocalDefId>) {
+fn create_and_seed_worklist(
+ tcx: TyCtxt<'_>,
+) -> (Vec<(LocalDefId, ComesFromAllowExpect)>, LocalDefIdMap<LocalDefId>) {
let effective_visibilities = &tcx.effective_visibilities(());
// see `MarkSymbolVisitor::struct_constructors`
let mut struct_constructors = Default::default();
let mut worklist = effective_visibilities
.iter()
.filter_map(|(&id, effective_vis)| {
- effective_vis.is_public_at_level(Level::Reachable).then_some(id)
+ effective_vis
+ .is_public_at_level(Level::Reachable)
+ .then_some(id)
+ .map(|id| (id, ComesFromAllowExpect::No))
})
// Seed entry point
- .chain(tcx.entry_fn(()).and_then(|(def_id, _)| def_id.as_local()))
+ .chain(
+ tcx.entry_fn(())
+ .and_then(|(def_id, _)| def_id.as_local().map(|id| (id, ComesFromAllowExpect::No))),
+ )
.collect::<Vec<_>>();
let crate_items = tcx.hir_crate_items(());
@@ -707,7 +769,7 @@ impl<'tcx> DeadVisitor<'tcx> {
if self.live_symbols.contains(&field.did.expect_local()) {
return ShouldWarnAboutField::No;
}
- let field_type = self.tcx.type_of(field.did).subst_identity();
+ let field_type = self.tcx.type_of(field.did).instantiate_identity();
if field_type.is_phantom_data() {
return ShouldWarnAboutField::No;
}
@@ -861,7 +923,7 @@ impl<'tcx> DeadVisitor<'tcx> {
| DefKind::Fn
| DefKind::Static(_)
| DefKind::Const
- | DefKind::TyAlias
+ | DefKind::TyAlias { .. }
| DefKind::Enum
| DefKind::Union
| DefKind::ForeignTy => self.warn_dead_code(def_id, "used"),
@@ -878,13 +940,11 @@ impl<'tcx> DeadVisitor<'tcx> {
return true;
};
- self.live_symbols.contains(&def_id)
- || has_allow_dead_code_or_lang_attr(self.tcx, def_id)
- || name.as_str().starts_with('_')
+ self.live_symbols.contains(&def_id) || name.as_str().starts_with('_')
}
}
-fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalDefId) {
+fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
let (live_symbols, ignored_derived_traits) = tcx.live_symbols_and_ignored_derived_traits(());
let mut visitor = DeadVisitor { tcx, live_symbols, ignored_derived_traits };
@@ -909,7 +969,7 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalDefId) {
if !live_symbols.contains(&item.owner_id.def_id) {
let parent = tcx.local_parent(item.owner_id.def_id);
- if parent != module && !live_symbols.contains(&parent) {
+ if parent != module.to_local_def_id() && !live_symbols.contains(&parent) {
// We already have diagnosed something.
continue;
}
diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs
index ffd8f77b7..4f71704b8 100644
--- a/compiler/rustc_passes/src/entry.rs
+++ b/compiler/rustc_passes/src/entry.rs
@@ -31,7 +31,7 @@ struct EntryContext<'tcx> {
}
fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> {
- let any_exe = tcx.sess.crate_types().iter().any(|ty| *ty == CrateType::Executable);
+ let any_exe = tcx.crate_types().iter().any(|ty| *ty == CrateType::Executable);
if !any_exe {
// No need to find a main function.
return None;
@@ -187,12 +187,6 @@ fn sigpipe(tcx: TyCtxt<'_>, def_id: DefId) -> u8 {
fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) {
let sp = tcx.def_span(CRATE_DEF_ID);
- if tcx.sess.parse_sess.reached_eof.load(rustc_data_structures::sync::Ordering::Relaxed) {
- // There's an unclosed brace that made the parser reach `Eof`, we shouldn't complain about
- // the missing `fn main()` then as it might have been hidden inside an unclosed block.
- tcx.sess.delay_span_bug(sp, "`main` not found, but expected unclosed brace error");
- return;
- }
// There is no main function.
let mut has_filename = true;
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 3fe7feb9d..683717344 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -267,6 +267,25 @@ pub struct DocInlineOnlyUse {
pub item_span: Option<Span>,
}
+#[derive(LintDiagnostic)]
+#[diag(passes_doc_masked_only_extern_crate)]
+#[note]
+pub struct DocMaskedOnlyExternCrate {
+ #[label]
+ pub attr_span: Span,
+ #[label(passes_not_an_extern_crate_label)]
+ pub item_span: Option<Span>,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(passes_doc_masked_not_extern_crate_self)]
+pub struct DocMaskedNotExternCrateSelf {
+ #[label]
+ pub attr_span: Span,
+ #[label(passes_extern_crate_self_label)]
+ pub item_span: Option<Span>,
+}
+
#[derive(Diagnostic)]
#[diag(passes_doc_attr_not_crate_level)]
pub struct DocAttrNotCrateLevel<'a> {
@@ -618,6 +637,38 @@ pub struct LinkOrdinal {
}
#[derive(Diagnostic)]
+#[diag(passes_confusables)]
+pub struct Confusables {
+ #[primary_span]
+ pub attr_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_empty_confusables)]
+pub(crate) struct EmptyConfusables {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_incorrect_meta_item, code = "E0539")]
+pub(crate) struct IncorrectMetaItem {
+ #[primary_span]
+ pub span: Span,
+ #[subdiagnostic]
+ pub suggestion: IncorrectMetaItemSuggestion,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(passes_incorrect_meta_item_suggestion, applicability = "maybe-incorrect")]
+pub(crate) struct IncorrectMetaItemSuggestion {
+ #[suggestion_part(code = "\"")]
+ pub lo: Span,
+ #[suggestion_part(code = "\"")]
+ pub hi: Span,
+}
+
+#[derive(Diagnostic)]
#[diag(passes_stability_promotable)]
pub struct StabilityPromotable {
#[primary_span]
@@ -639,6 +690,10 @@ pub enum MacroExport {
#[diag(passes_macro_export)]
Normal,
+ #[diag(passes_macro_export_on_decl_macro)]
+ #[note]
+ OnDeclMacro,
+
#[diag(passes_invalid_macro_export_arguments)]
UnknownItem { name: Symbol },
diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs
index 363e17436..f825363ae 100644
--- a/compiler/rustc_passes/src/hir_id_validator.rs
+++ b/compiler/rustc_passes/src/hir_id_validator.rs
@@ -89,9 +89,8 @@ impl<'a, 'hir> HirIdValidator<'a, 'hir> {
self.error(|| {
format!(
- "ItemLocalIds not assigned densely in {}. \
- Max ItemLocalId = {}, missing IDs = {:#?}; seen IDs = {:#?}",
- pretty_owner, max, missing_items, seen_items
+ "ItemLocalIds not assigned densely in {pretty_owner}. \
+ Max ItemLocalId = {max}, missing IDs = {missing_items:#?}; seen IDs = {seen_items:#?}"
)
});
}
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index 6c748147a..5aa8aef6a 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -126,12 +126,12 @@ impl<'k> StatCollector<'k> {
let total_size = nodes.iter().map(|(_, node)| node.stats.count * node.stats.size).sum();
- eprintln!("{} {}", prefix, title);
+ eprintln!("{prefix} {title}");
eprintln!(
"{} {:<18}{:>18}{:>14}{:>14}",
prefix, "Name", "Accumulated Size", "Count", "Item Size"
);
- eprintln!("{} ----------------------------------------------------------------", prefix);
+ eprintln!("{prefix} ----------------------------------------------------------------");
let percent = |m, n| (m * 100) as f64 / n as f64;
@@ -163,9 +163,9 @@ impl<'k> StatCollector<'k> {
}
}
}
- eprintln!("{} ----------------------------------------------------------------", prefix);
+ eprintln!("{prefix} ----------------------------------------------------------------");
eprintln!("{} {:<18}{:>10}", prefix, "Total", to_readable_str(total_size));
- eprintln!("{}", prefix);
+ eprintln!("{prefix}");
}
}
diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs
index 098107f8f..a7a8af864 100644
--- a/compiler/rustc_passes/src/layout_test.rs
+++ b/compiler/rustc_passes/src/layout_test.rs
@@ -16,7 +16,7 @@ pub fn test_layout(tcx: TyCtxt<'_>) {
for id in tcx.hir().items() {
if matches!(
tcx.def_kind(id.owner_id),
- DefKind::TyAlias | DefKind::Enum | DefKind::Struct | DefKind::Union
+ DefKind::TyAlias { .. } | DefKind::Enum | DefKind::Struct | DefKind::Union
) {
for attr in tcx.get_attrs(id.owner_id, sym::rustc_layout) {
dump_layout_of(tcx, id.owner_id.def_id, attr);
@@ -27,9 +27,8 @@ pub fn test_layout(tcx: TyCtxt<'_>) {
}
fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
- let tcx = tcx;
let param_env = tcx.param_env(item_def_id);
- let ty = tcx.type_of(item_def_id).subst_identity();
+ let ty = tcx.type_of(item_def_id).instantiate_identity();
match tcx.layout_of(param_env.and(ty)) {
Ok(ty_layout) => {
// Check out the `#[rustc_layout(..)]` attribute to tell what to dump.
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index 803ca05b2..20e996eae 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -605,7 +605,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
for var_idx in 0..self.ir.var_kinds.len() {
let var = Variable::from(var_idx);
if test(var) {
- write!(wr, " {:?}", var)?;
+ write!(wr, " {var:?}")?;
}
}
Ok(())
@@ -747,7 +747,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
let ty = self.typeck_results.node_type(hir_id);
match ty.kind() {
- ty::Closure(_def_id, substs) => match substs.as_closure().kind() {
+ ty::Closure(_def_id, args) => match args.as_closure().kind() {
ty::ClosureKind::Fn => {}
ty::ClosureKind::FnMut => {}
ty::ClosureKind::FnOnce => return succ,
@@ -1061,7 +1061,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
self.propagate_through_expr(&l, ln)
}
- hir::ExprKind::Index(ref l, ref r) | hir::ExprKind::Binary(_, ref l, ref r) => {
+ hir::ExprKind::Index(ref l, ref r, _) | hir::ExprKind::Binary(_, ref l, ref r) => {
let r_succ = self.propagate_through_expr(&r, succ);
self.propagate_through_expr(&l, r_succ)
}
@@ -1105,7 +1105,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
}
// Then do a second pass for inputs
- let mut succ = succ;
for (op, _op_sp) in asm.operands.iter().rev() {
match op {
hir::InlineAsmOperand::In { expr, .. } => {
@@ -1683,12 +1682,16 @@ impl<'tcx> Liveness<'_, 'tcx> {
opt_body: Option<&hir::Body<'_>>,
) -> Vec<errors::UnusedVariableStringInterp> {
let mut suggs = Vec::new();
- let Some(opt_body) = opt_body else { return suggs; };
+ let Some(opt_body) = opt_body else {
+ return suggs;
+ };
let mut visitor = CollectLitsVisitor { lit_exprs: vec![] };
intravisit::walk_body(&mut visitor, opt_body);
for lit_expr in visitor.lit_exprs {
let hir::ExprKind::Lit(litx) = &lit_expr.kind else { continue };
- let rustc_ast::LitKind::Str(syb, _) = litx.node else{ continue; };
+ let rustc_ast::LitKind::Str(syb, _) = litx.node else {
+ continue;
+ };
let name_str: &str = syb.as_str();
let name_pa = format!("{{{name}}}");
if name_str.contains(&name_pa) {
diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs
index 7c64df6a5..0aaf85086 100644
--- a/compiler/rustc_passes/src/loops.rs
+++ b/compiler/rustc_passes/src/loops.rs
@@ -1,7 +1,7 @@
use Context::*;
use rustc_hir as hir;
-use rustc_hir::def_id::LocalDefId;
+use rustc_hir::def_id::LocalModDefId;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{Destination, Movability, Node};
use rustc_middle::hir::map::Map;
@@ -34,7 +34,7 @@ struct CheckLoopVisitor<'a, 'hir> {
cx: Context,
}
-fn check_mod_loops(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
+fn check_mod_loops(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
tcx.hir().visit_item_likes_in_module(
module_def_id,
&mut CheckLoopVisitor { sess: &tcx.sess, hir_map: tcx.hir(), cx: Normal },
diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs
index 769b38900..7f36c59ad 100644
--- a/compiler/rustc_passes/src/naked_functions.rs
+++ b/compiler/rustc_passes/src/naked_functions.rs
@@ -3,7 +3,7 @@
use rustc_ast::InlineAsmOptions;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
-use rustc_hir::def_id::LocalDefId;
+use rustc_hir::def_id::{LocalDefId, LocalModDefId};
use rustc_hir::intravisit::Visitor;
use rustc_hir::{ExprKind, InlineAsmOperand, StmtKind};
use rustc_middle::query::Providers;
@@ -23,7 +23,7 @@ pub(crate) fn provide(providers: &mut Providers) {
*providers = Providers { check_mod_naked_functions, ..*providers };
}
-fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
+fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
let items = tcx.hir_module_items(module_def_id);
for def_id in items.definitions() {
if !matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) {
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index 160528e40..e62833b35 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -98,15 +98,11 @@ impl<'tcx> Visitor<'tcx> for ReachableContext<'tcx> {
self.worklist.push(def_id);
} else {
match res {
- // If this path leads to a constant, then we need to
- // recurse into the constant to continue finding
- // items that are reachable.
- Res::Def(DefKind::Const | DefKind::AssocConst, _) => {
+ // Reachable constants and reachable statics can have their contents inlined
+ // into other crates. Mark them as reachable and recurse into their body.
+ Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::Static(_), _) => {
self.worklist.push(def_id);
}
-
- // If this wasn't a static, then the destination is
- // surely reachable.
_ => {
self.reachable_symbols.insert(def_id);
}
@@ -236,7 +232,7 @@ impl<'tcx> ReachableContext<'tcx> {
// Reachable constants will be inlined into other crates
// unconditionally, so we need to make sure that their
// contents are also reachable.
- hir::ItemKind::Const(_, init) | hir::ItemKind::Static(_, _, init) => {
+ hir::ItemKind::Const(_, _, init) | hir::ItemKind::Static(_, _, init) => {
self.visit_nested_body(init);
}
@@ -364,10 +360,10 @@ fn has_custom_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
fn reachable_set(tcx: TyCtxt<'_>, (): ()) -> LocalDefIdSet {
let effective_visibilities = &tcx.effective_visibilities(());
- let any_library =
- tcx.sess.crate_types().iter().any(|ty| {
- *ty == CrateType::Rlib || *ty == CrateType::Dylib || *ty == CrateType::ProcMacro
- });
+ let any_library = tcx
+ .crate_types()
+ .iter()
+ .any(|ty| *ty == CrateType::Rlib || *ty == CrateType::Dylib || *ty == CrateType::ProcMacro);
let mut reachable_context = ReachableContext {
tcx,
maybe_typeck_results: None,
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index b81b7ad60..9c265e8ec 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -9,7 +9,7 @@ use rustc_attr::{
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
+use rustc_hir::def_id::{LocalDefId, LocalModDefId, CRATE_DEF_ID};
use rustc_hir::hir_id::CRATE_HIR_ID;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant};
@@ -115,7 +115,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
let attrs = self.tcx.hir().attrs(self.tcx.hir().local_def_id_to_hir_id(def_id));
debug!("annotate(id = {:?}, attrs = {:?})", def_id, attrs);
- let depr = attr::find_deprecation(&self.tcx.sess, attrs);
+ let depr = attr::find_deprecation(self.tcx.sess, self.tcx.features(), attrs);
let mut is_deprecated = false;
if let Some((depr, span)) = &depr {
is_deprecated = true;
@@ -682,7 +682,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
/// Cross-references the feature names of unstable APIs with enabled
/// features and possibly prints errors.
-fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
+fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
tcx.hir().visit_item_likes_in_module(module_def_id, &mut Checker { tcx });
}
@@ -732,13 +732,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
// For implementations of traits, check the stability of each item
// individually as it's possible to have a stable trait with unstable
// items.
- hir::ItemKind::Impl(hir::Impl {
- of_trait: Some(ref t),
- self_ty,
- items,
- constness,
- ..
- }) => {
+ hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref t), self_ty, items, .. }) => {
let features = self.tcx.features();
if features.staged_api {
let attrs = self.tcx.hir().attrs(item.hir_id());
@@ -769,7 +763,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
// `#![feature(const_trait_impl)]` is unstable, so any impl declared stable
// needs to have an error emitted.
if features.const_trait_impl
- && *constness == hir::Constness::Const
+ && self.tcx.is_const_trait_impl_raw(item.owner_id.to_def_id())
&& const_stab.is_some_and(|(stab, _)| stab.is_const_stable())
{
self.tcx.sess.emit_err(errors::TraitImplConstStable { span: item.span });
@@ -856,7 +850,9 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
/// See issue #94972 for details on why this is a special case
fn is_unstable_reexport(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
// Get the LocalDefId so we can lookup the item to check the kind.
- let Some(owner) = id.as_owner() else { return false; };
+ let Some(owner) = id.as_owner() else {
+ return false;
+ };
let def_id = owner.def_id;
let Some(stab) = tcx.stability().local_stability(def_id) else {
diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs
index fc6372cf9..75e071f1f 100644
--- a/compiler/rustc_passes/src/weak_lang_items.rs
+++ b/compiler/rustc_passes/src/weak_lang_items.rs
@@ -43,7 +43,7 @@ pub fn check_crate(tcx: TyCtxt<'_>, items: &mut lang_items::LanguageItems) {
fn verify(tcx: TyCtxt<'_>, items: &lang_items::LanguageItems) {
// We only need to check for the presence of weak lang items if we're
// emitting something that's not an rlib.
- let needs_check = tcx.sess.crate_types().iter().any(|kind| match *kind {
+ let needs_check = tcx.crate_types().iter().any(|kind| match *kind {
CrateType::Dylib
| CrateType::ProcMacro
| CrateType::Cdylib