Skip to content

Commit 085744b

Browse files
committed
Auto merge of #130036 - weiznich:diagnostic_unstable_tracking, r=compiler-errors
Correctly handle stability of `#[diagnostic]` attributes This commit changes the way we treat the stability of attributes in the `#[diagnostic]` namespace. Instead of relaying on ad-hoc checks to ensure at call side that a certain attribute is really usable at that location it centralises the logic to one place. For diagnostic attributes comming from other crates it just skips serializing attributes that are not stable and that do not have the corresponding feature enabled. For attributes from the current crate we can just use the feature information provided by `TyCtx`. r​? `@compiler-errors`
2 parents adf8d16 + 7c9e818 commit 085744b

File tree

6 files changed

+51
-9
lines changed

6 files changed

+51
-9
lines changed

Diff for: compiler/rustc_feature/src/builtin_attrs.rs

+8
Original file line numberDiff line numberDiff line change
@@ -1186,3 +1186,11 @@ pub static BUILTIN_ATTRIBUTE_MAP: LazyLock<FxHashMap<Symbol, &BuiltinAttribute>>
11861186
}
11871187
map
11881188
});
1189+
1190+
pub fn is_stable_diagnostic_attribute(sym: Symbol, features: &Features) -> bool {
1191+
match sym {
1192+
sym::on_unimplemented => true,
1193+
sym::do_not_recommend => features.do_not_recommend,
1194+
_ => false,
1195+
}
1196+
}

Diff for: compiler/rustc_feature/src/lib.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,9 @@ pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option<NonZero<u
130130
pub use accepted::ACCEPTED_FEATURES;
131131
pub use builtin_attrs::{
132132
deprecated_attributes, encode_cross_crate, find_gated_cfg, is_builtin_attr_name,
133-
is_valid_for_get_attr, AttributeDuplicates, AttributeGate, AttributeSafety, AttributeTemplate,
134-
AttributeType, BuiltinAttribute, GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
133+
is_stable_diagnostic_attribute, is_valid_for_get_attr, AttributeDuplicates, AttributeGate,
134+
AttributeSafety, AttributeTemplate, AttributeType, BuiltinAttribute, GatedCfg,
135+
BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
135136
};
136137
pub use removed::REMOVED_FEATURES;
137138
pub use unstable::{Features, INCOMPATIBLE_FEATURES, UNSTABLE_FEATURES};

Diff for: compiler/rustc_hir_analysis/src/collect.rs

-2
Original file line numberDiff line numberDiff line change
@@ -1698,8 +1698,6 @@ fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::ImplTrai
16981698
trait_ref: ty::EarlyBinder::bind(trait_ref),
16991699
safety: impl_.safety,
17001700
polarity: polarity_of_impl(tcx, def_id, impl_, item.span),
1701-
do_not_recommend: tcx.features().do_not_recommend
1702-
&& tcx.has_attrs_with_path(def_id, &[sym::diagnostic, sym::do_not_recommend]),
17031701
}
17041702
})
17051703
}

Diff for: compiler/rustc_metadata/src/rmeta/encoder.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
99
use rustc_data_structures::memmap::{Mmap, MmapMut};
1010
use rustc_data_structures::sync::{join, par_for_each_in, Lrc};
1111
use rustc_data_structures::temp_dir::MaybeTempDir;
12+
use rustc_feature::Features;
1213
use rustc_hir as hir;
1314
use rustc_hir::def_id::{LocalDefId, LocalDefIdSet, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE};
1415
use rustc_hir::definitions::DefPathData;
@@ -797,9 +798,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
797798
}
798799
}
799800

800-
struct AnalyzeAttrState {
801+
struct AnalyzeAttrState<'a> {
801802
is_exported: bool,
802803
is_doc_hidden: bool,
804+
features: &'a Features,
803805
}
804806

805807
/// Returns whether an attribute needs to be recorded in metadata, that is, if it's usable and
@@ -812,7 +814,7 @@ struct AnalyzeAttrState {
812814
/// visibility: this is a piece of data that can be computed once per defid, and not once per
813815
/// attribute. Some attributes would only be usable downstream if they are public.
814816
#[inline]
815-
fn analyze_attr(attr: &Attribute, state: &mut AnalyzeAttrState) -> bool {
817+
fn analyze_attr(attr: &Attribute, state: &mut AnalyzeAttrState<'_>) -> bool {
816818
let mut should_encode = false;
817819
if !rustc_feature::encode_cross_crate(attr.name_or_empty()) {
818820
// Attributes not marked encode-cross-crate don't need to be encoded for downstream crates.
@@ -837,6 +839,9 @@ fn analyze_attr(attr: &Attribute, state: &mut AnalyzeAttrState) -> bool {
837839
}
838840
}
839841
}
842+
} else if attr.path().starts_with(&[sym::diagnostic]) && attr.path().len() == 2 {
843+
should_encode =
844+
rustc_feature::is_stable_diagnostic_attribute(attr.path()[1], state.features);
840845
} else {
841846
should_encode = true;
842847
}
@@ -1343,6 +1348,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
13431348
let mut state = AnalyzeAttrState {
13441349
is_exported: tcx.effective_visibilities(()).is_exported(def_id),
13451350
is_doc_hidden: false,
1351+
features: &tcx.features(),
13461352
};
13471353
let attr_iter = tcx
13481354
.hir()

Diff for: compiler/rustc_middle/src/ty/context.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -3183,8 +3183,7 @@ impl<'tcx> TyCtxt<'tcx> {
31833183

31843184
/// Whether this is a trait implementation that has `#[diagnostic::do_not_recommend]`
31853185
pub fn do_not_recommend_impl(self, def_id: DefId) -> bool {
3186-
matches!(self.def_kind(def_id), DefKind::Impl { of_trait: true })
3187-
&& self.impl_trait_header(def_id).is_some_and(|header| header.do_not_recommend)
3186+
self.get_diagnostic_attr(def_id, sym::do_not_recommend).is_some()
31883187
}
31893188
}
31903189

Diff for: compiler/rustc_middle/src/ty/mod.rs

+31-1
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,6 @@ pub struct ImplTraitHeader<'tcx> {
263263
pub trait_ref: ty::EarlyBinder<'tcx, ty::TraitRef<'tcx>>,
264264
pub polarity: ImplPolarity,
265265
pub safety: hir::Safety,
266-
pub do_not_recommend: bool,
267266
}
268267

269268
#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)]
@@ -1797,6 +1796,37 @@ impl<'tcx> TyCtxt<'tcx> {
17971796
}
17981797
}
17991798

1799+
/// Get an attribute from the diagnostic attribute namespace
1800+
///
1801+
/// This function requests an attribute with the following structure:
1802+
///
1803+
/// `#[diagnostic::$attr]`
1804+
///
1805+
/// This function performs feature checking, so if an attribute is returned
1806+
/// it can be used by the consumer
1807+
pub fn get_diagnostic_attr(
1808+
self,
1809+
did: impl Into<DefId>,
1810+
attr: Symbol,
1811+
) -> Option<&'tcx ast::Attribute> {
1812+
let did: DefId = did.into();
1813+
if did.as_local().is_some() {
1814+
// it's a crate local item, we need to check feature flags
1815+
if rustc_feature::is_stable_diagnostic_attribute(attr, self.features()) {
1816+
self.get_attrs_by_path(did, &[sym::diagnostic, sym::do_not_recommend]).next()
1817+
} else {
1818+
None
1819+
}
1820+
} else {
1821+
// we filter out unstable diagnostic attributes before
1822+
// encoding attributes
1823+
debug_assert!(rustc_feature::encode_cross_crate(attr));
1824+
self.item_attrs(did)
1825+
.iter()
1826+
.find(|a| matches!(a.path().as_ref(), [sym::diagnostic, a] if *a == attr))
1827+
}
1828+
}
1829+
18001830
pub fn get_attrs_by_path<'attr>(
18011831
self,
18021832
did: DefId,

0 commit comments

Comments
 (0)