Auto merge of #144841 - cjgillot:typeck-no-attrs, r=davidtwco

Access less HIR attributes from typeck

Typeck relies on attributes to modify its own behaviour. This is a problem, as this means that `typeck(some function)` may depend on the span and doc-comments of many other functions.

This PR attempts to reduce such accesses to attributes. This yields to a sizeable perf improvement: https://github.com/rust-lang/rust/pull/144841#issuecomment-3153339771

Fixes https://github.com/rust-lang/rust/issues/124352
This commit is contained in:
bors 2025-08-27 01:11:24 +00:00
commit 269d5b56bc
10 changed files with 62 additions and 39 deletions

View file

@ -511,7 +511,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Untranslatable diagnostics are okay for rustc internals
#[allow(rustc::untranslatable_diagnostic)]
#[allow(rustc::diagnostic_outside_of_impl)]
if self.tcx.has_attr(def_id, sym::rustc_evaluate_where_clauses) {
if self.has_rustc_attrs
&& self.tcx.has_attr(def_id, sym::rustc_evaluate_where_clauses)
{
let predicates = self.tcx.predicates_of(def_id);
let predicates = predicates.instantiate(self.tcx, args);
for (predicate, predicate_span) in predicates {
@ -894,7 +896,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
// If we have `rustc_do_not_const_check`, do not check `[const]` bounds.
if self.tcx.has_attr(self.body_id, sym::rustc_do_not_const_check) {
if self.has_rustc_attrs && self.tcx.has_attr(self.body_id, sym::rustc_do_not_const_check) {
return;
}

View file

@ -126,6 +126,10 @@ pub(crate) struct FnCtxt<'a, 'tcx> {
/// These are stored here so we may collect them when canonicalizing user
/// type ascriptions later.
pub(super) trait_ascriptions: RefCell<ItemLocalMap<Vec<ty::Clause<'tcx>>>>,
/// Whether the current crate enables the `rustc_attrs` feature.
/// This allows to skip processing attributes in many places.
pub(super) has_rustc_attrs: bool,
}
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@ -154,6 +158,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
diverging_fallback_behavior,
diverging_block_behavior,
trait_ascriptions: Default::default(),
has_rustc_attrs: root_ctxt.tcx.features().rustc_attrs(),
}
}
@ -525,10 +530,13 @@ fn parse_never_type_options_attr(
let mut fallback = None;
let mut block = None;
let items = tcx
.get_attr(CRATE_DEF_ID, sym::rustc_never_type_options)
.map(|attr| attr.meta_item_list().unwrap())
.unwrap_or_default();
let items = if tcx.features().rustc_attrs() {
tcx.get_attr(CRATE_DEF_ID, sym::rustc_never_type_options)
.map(|attr| attr.meta_item_list().unwrap())
} else {
None
};
let items = items.unwrap_or_default();
for item in items {
if item.has_name(sym::fallback) && fallback.is_none() {

View file

@ -46,12 +46,12 @@ use rustc_data_structures::unord::UnordSet;
use rustc_errors::codes::*;
use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err};
use rustc_hir as hir;
use rustc_hir::attrs::AttributeKind;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{HirId, HirIdMap, Node, find_attr};
use rustc_hir::{HirId, HirIdMap, Node};
use rustc_hir_analysis::check::{check_abi, check_custom_abi};
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
use rustc_infer::traits::{ObligationCauseCode, ObligationInspector, WellFormedLoc};
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::query::Providers;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::{bug, span_bug};
@ -174,7 +174,7 @@ fn typeck_with_inspect<'tcx>(
.map(|(idx, ty)| fcx.normalize(arg_span(idx), ty)),
);
if find_attr!(tcx.get_all_attrs(def_id), AttributeKind::Naked(..)) {
if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NAKED) {
naked_functions::typeck_naked_fn(tcx, def_id, body);
}

View file

@ -777,31 +777,16 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
self.assemble_inherent_candidates_from_object(generalized_self_ty);
self.assemble_inherent_impl_candidates_for_type(p.def_id(), receiver_steps);
if self.tcx.has_attr(p.def_id(), sym::rustc_has_incoherent_inherent_impls) {
self.assemble_inherent_candidates_for_incoherent_ty(
raw_self_ty,
receiver_steps,
);
}
self.assemble_inherent_candidates_for_incoherent_ty(raw_self_ty, receiver_steps);
}
ty::Adt(def, _) => {
let def_id = def.did();
self.assemble_inherent_impl_candidates_for_type(def_id, receiver_steps);
if self.tcx.has_attr(def_id, sym::rustc_has_incoherent_inherent_impls) {
self.assemble_inherent_candidates_for_incoherent_ty(
raw_self_ty,
receiver_steps,
);
}
self.assemble_inherent_candidates_for_incoherent_ty(raw_self_ty, receiver_steps);
}
ty::Foreign(did) => {
self.assemble_inherent_impl_candidates_for_type(did, receiver_steps);
if self.tcx.has_attr(did, sym::rustc_has_incoherent_inherent_impls) {
self.assemble_inherent_candidates_for_incoherent_ty(
raw_self_ty,
receiver_steps,
);
}
self.assemble_inherent_candidates_for_incoherent_ty(raw_self_ty, receiver_steps);
}
ty::Param(_) => {
self.assemble_inherent_candidates_from_param(raw_self_ty);
@ -2400,17 +2385,14 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
if !self.is_relevant_kind_for_mode(x.kind) {
return false;
}
if self.matches_by_doc_alias(x.def_id) {
return true;
}
match edit_distance_with_substrings(
if let Some(d) = edit_distance_with_substrings(
name.as_str(),
x.name().as_str(),
max_dist,
) {
Some(d) => d > 0,
None => false,
return d > 0;
}
self.matches_by_doc_alias(x.def_id)
})
.copied()
.collect()

View file

@ -1747,7 +1747,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
fn should_log_capture_analysis(&self, closure_def_id: LocalDefId) -> bool {
self.tcx.has_attr(closure_def_id, sym::rustc_capture_analysis)
self.has_rustc_attrs && self.tcx.has_attr(closure_def_id, sym::rustc_capture_analysis)
}
fn log_capture_analysis_first_pass(

View file

@ -45,7 +45,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// This attribute causes us to dump some writeback information
// in the form of errors, which is used for unit tests.
let rustc_dump_user_args = self.tcx.has_attr(item_def_id, sym::rustc_dump_user_args);
let rustc_dump_user_args =
self.has_rustc_attrs && self.tcx.has_attr(item_def_id, sym::rustc_dump_user_args);
let mut wbcx = WritebackCx::new(self, body, rustc_dump_user_args);
for param in body.params {

View file

@ -6,6 +6,7 @@ use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_macros::{Decodable, Encodable, HashStable};
use rustc_span::symbol::sym;
use tracing::debug;
use crate::query::LocalCrate;
@ -239,6 +240,12 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait
/// Query provider for `incoherent_impls`.
pub(super) fn incoherent_impls_provider(tcx: TyCtxt<'_>, simp: SimplifiedType) -> &[DefId] {
if let Some(def_id) = simp.def()
&& !tcx.has_attr(def_id, sym::rustc_has_incoherent_inherent_impls)
{
return &[];
}
let mut impls = Vec::new();
for cnum in iter::once(LOCAL_CRATE).chain(tcx.crates(()).iter().copied()) {
for &impl_def_id in tcx.crate_incoherent_impls((cnum, simp)) {

View file

@ -1,4 +0,0 @@
//@ known-bug: #124352
#![rustc_never_type_options(: Unsize<U> = "hi")]
fn main() {}

View file

@ -0,0 +1,8 @@
//! Regression test for #124352
//! The `rustc_*` attribute is malformed, but ICEing without a `feature(rustc_attrs)` is still bad.
#![rustc_never_type_options(: Unsize<U> = "hi")]
//~^ ERROR expected unsuffixed literal, found `:`
//~| ERROR use of an internal attribute
fn main() {}

View file

@ -0,0 +1,19 @@
error: expected unsuffixed literal, found `:`
--> $DIR/malformed-never-type-options.rs:4:29
|
LL | #![rustc_never_type_options(: Unsize<U> = "hi")]
| ^
error[E0658]: use of an internal attribute
--> $DIR/malformed-never-type-options.rs:4:1
|
LL | #![rustc_never_type_options(: Unsize<U> = "hi")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
= note: the `#[rustc_never_type_options]` attribute is an internal implementation detail that will never be stable
= note: `rustc_never_type_options` is used to experiment with never type fallback and work on never type stabilization
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0658`.